@calimero-network/registry-cli 1.10.0 → 1.11.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
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from 'commander';
3
- import chalk6 from 'chalk';
3
+ import chalk7 from 'chalk';
4
4
  import { createRequire } from 'module';
5
- import ora6 from 'ora';
5
+ import ora7 from 'ora';
6
6
  import { table } from 'table';
7
7
  import axios from 'axios';
8
8
  import fs9, { existsSync, writeFileSync } from 'fs';
@@ -12,6 +12,9 @@ import crypto from 'crypto';
12
12
  import fastify from 'fastify';
13
13
  import cors from '@fastify/cors';
14
14
  import * as tar from 'tar';
15
+ import * as ed25519 from '@noble/ed25519';
16
+ import canonicalize from 'canonicalize';
17
+ import bs58 from 'bs58';
15
18
 
16
19
  var CalimeroRegistryClient = class {
17
20
  /**
@@ -1039,14 +1042,14 @@ var appsCommand = new Command("apps").description("Manage self-sovereign applica
1039
1042
  globalOpts?.url,
1040
1043
  parseInt(globalOpts?.timeout || "10000")
1041
1044
  );
1042
- const spinner2 = ora6("Fetching applications...").start();
1045
+ const spinner2 = ora7("Fetching applications...").start();
1043
1046
  try {
1044
1047
  const apps = await client.getApps({
1045
1048
  name: options.name
1046
1049
  });
1047
1050
  spinner2.succeed(`Found ${apps.length} application(s)`);
1048
1051
  if (apps.length === 0) {
1049
- console.log(chalk6.yellow("No applications found"));
1052
+ console.log(chalk7.yellow("No applications found"));
1050
1053
  return;
1051
1054
  }
1052
1055
  const tableData = [
@@ -1063,7 +1066,7 @@ var appsCommand = new Command("apps").description("Manage self-sovereign applica
1063
1066
  } catch (error) {
1064
1067
  spinner2.fail("Failed to fetch applications");
1065
1068
  if (error instanceof Error) {
1066
- console.error(chalk6.red(`Error: ${error.message}`));
1069
+ console.error(chalk7.red(`Error: ${error.message}`));
1067
1070
  }
1068
1071
  process.exit(1);
1069
1072
  }
@@ -1077,12 +1080,12 @@ var appsCommand = new Command("apps").description("Manage self-sovereign applica
1077
1080
  globalOpts?.url,
1078
1081
  parseInt(globalOpts?.timeout || "10000")
1079
1082
  );
1080
- const spinner2 = ora6(`Fetching versions for ${appId}...`).start();
1083
+ const spinner2 = ora7(`Fetching versions for ${appId}...`).start();
1081
1084
  try {
1082
1085
  const versions = await client.getAppVersions(appId);
1083
1086
  spinner2.succeed(`Found ${versions.length} version(s)`);
1084
1087
  if (versions.length === 0) {
1085
- console.log(chalk6.yellow("No versions found"));
1088
+ console.log(chalk7.yellow("No versions found"));
1086
1089
  return;
1087
1090
  }
1088
1091
  const tableData = [
@@ -1090,14 +1093,14 @@ var appsCommand = new Command("apps").description("Manage self-sovereign applica
1090
1093
  ...versions.map((version2) => [
1091
1094
  version2.semver,
1092
1095
  version2.cid.substring(0, 12) + "...",
1093
- version2.yanked ? chalk6.red("Yes") : chalk6.green("No")
1096
+ version2.yanked ? chalk7.red("Yes") : chalk7.green("No")
1094
1097
  ])
1095
1098
  ];
1096
1099
  console.log(table(tableData));
1097
1100
  } catch (error) {
1098
1101
  spinner2.fail("Failed to fetch versions");
1099
1102
  if (error instanceof Error) {
1100
- console.error(chalk6.red(`Error: ${error.message}`));
1103
+ console.error(chalk7.red(`Error: ${error.message}`));
1101
1104
  }
1102
1105
  process.exit(1);
1103
1106
  }
@@ -1111,18 +1114,18 @@ var appsCommand = new Command("apps").description("Manage self-sovereign applica
1111
1114
  globalOpts?.url,
1112
1115
  parseInt(globalOpts?.timeout || "10000")
1113
1116
  );
1114
- const spinner2 = ora6(
1117
+ const spinner2 = ora7(
1115
1118
  `Fetching manifest for ${appId}@${version2}...`
1116
1119
  ).start();
1117
1120
  try {
1118
1121
  const manifest = await client.getAppManifest(appId, version2);
1119
1122
  spinner2.succeed("Manifest fetched successfully");
1120
- console.log(chalk6.blue("\nApplication Manifest:"));
1123
+ console.log(chalk7.blue("\nApplication Manifest:"));
1121
1124
  console.log(JSON.stringify(manifest, null, 2));
1122
1125
  } catch (error) {
1123
1126
  spinner2.fail("Failed to fetch manifest");
1124
1127
  if (error instanceof Error) {
1125
- console.error(chalk6.red(`Error: ${error.message}`));
1128
+ console.error(chalk7.red(`Error: ${error.message}`));
1126
1129
  }
1127
1130
  process.exit(1);
1128
1131
  }
@@ -1136,12 +1139,12 @@ var appsCommand = new Command("apps").description("Manage self-sovereign applica
1136
1139
  globalOpts?.url,
1137
1140
  parseInt(globalOpts?.timeout || "10000")
1138
1141
  );
1139
- const spinner2 = ora6("Reading manifest file...").start();
1142
+ const spinner2 = ora7("Reading manifest file...").start();
1140
1143
  try {
1141
1144
  const manifestPath = path7.resolve(manifestFile);
1142
1145
  if (!fs9.existsSync(manifestPath)) {
1143
1146
  spinner2.fail("Manifest file not found");
1144
- console.error(chalk6.red(`File not found: ${manifestFile}`));
1147
+ console.error(chalk7.red(`File not found: ${manifestFile}`));
1145
1148
  process.exit(1);
1146
1149
  }
1147
1150
  const manifestContent = fs9.readFileSync(manifestPath, "utf8");
@@ -1149,20 +1152,20 @@ var appsCommand = new Command("apps").description("Manage self-sovereign applica
1149
1152
  spinner2.text = "Submitting application manifest...";
1150
1153
  const result = await client.submitAppManifest(manifest);
1151
1154
  spinner2.succeed("Application submitted successfully");
1152
- console.log(chalk6.green(`
1155
+ console.log(chalk7.green(`
1153
1156
  \u2705 ${result.message}`));
1154
1157
  if (manifest.app?.name) {
1155
- console.log(chalk6.blue(`
1158
+ console.log(chalk7.blue(`
1156
1159
  \u{1F4F1} App: ${manifest.app.name}`));
1157
1160
  console.log(
1158
- chalk6.blue(`\u{1F464} Developer: ${manifest.app.developer_pubkey}`)
1161
+ chalk7.blue(`\u{1F464} Developer: ${manifest.app.developer_pubkey}`)
1159
1162
  );
1160
- console.log(chalk6.blue(`\u{1F4E6} Version: ${manifest.version?.semver}`));
1163
+ console.log(chalk7.blue(`\u{1F4E6} Version: ${manifest.version?.semver}`));
1161
1164
  }
1162
1165
  } catch (error) {
1163
1166
  spinner2.fail("Failed to submit application");
1164
1167
  if (error instanceof Error) {
1165
- console.error(chalk6.red(`Error: ${error.message}`));
1168
+ console.error(chalk7.red(`Error: ${error.message}`));
1166
1169
  }
1167
1170
  process.exit(1);
1168
1171
  }
@@ -1175,33 +1178,33 @@ var developersCommand = new Command("developers").description("Manage developer
1175
1178
  baseURL: globalOpts?.url || "http://localhost:8082",
1176
1179
  timeout: parseInt(globalOpts?.timeout || "10000")
1177
1180
  });
1178
- const spinner2 = ora6("Fetching developer profile...").start();
1181
+ const spinner2 = ora7("Fetching developer profile...").start();
1179
1182
  try {
1180
1183
  const profile = await client.getDeveloper(pubkey);
1181
1184
  spinner2.succeed("Developer profile fetched successfully");
1182
- console.log(chalk6.blue("\nDeveloper Profile:"));
1183
- console.log(chalk6.green("Display Name:"), profile.display_name);
1185
+ console.log(chalk7.blue("\nDeveloper Profile:"));
1186
+ console.log(chalk7.green("Display Name:"), profile.display_name);
1184
1187
  if (profile.website) {
1185
- console.log(chalk6.green("Website:"), profile.website);
1188
+ console.log(chalk7.green("Website:"), profile.website);
1186
1189
  }
1187
1190
  if (profile.proofs.length > 0) {
1188
- console.log(chalk6.green("\nProofs:"));
1191
+ console.log(chalk7.green("\nProofs:"));
1189
1192
  const tableData = [
1190
1193
  ["Type", "Value", "Verified"],
1191
1194
  ...profile.proofs.map((proof) => [
1192
1195
  proof.type,
1193
1196
  proof.value.substring(0, 20) + "...",
1194
- proof.verified ? chalk6.green("Yes") : chalk6.red("No")
1197
+ proof.verified ? chalk7.green("Yes") : chalk7.red("No")
1195
1198
  ])
1196
1199
  ];
1197
1200
  console.log(table(tableData));
1198
1201
  } else {
1199
- console.log(chalk6.yellow("\nNo proofs found"));
1202
+ console.log(chalk7.yellow("\nNo proofs found"));
1200
1203
  }
1201
1204
  } catch (error) {
1202
1205
  spinner2.fail("Failed to fetch developer profile");
1203
1206
  if (error instanceof Error) {
1204
- console.error(chalk6.red(`Error: ${error.message}`));
1207
+ console.error(chalk7.red(`Error: ${error.message}`));
1205
1208
  }
1206
1209
  process.exit(1);
1207
1210
  }
@@ -1213,7 +1216,7 @@ var developersCommand = new Command("developers").description("Manage developer
1213
1216
  baseURL: globalOpts?.url || "http://localhost:8082",
1214
1217
  timeout: parseInt(globalOpts?.timeout || "10000")
1215
1218
  });
1216
- const spinner2 = ora6("Creating developer profile...").start();
1219
+ const spinner2 = ora7("Creating developer profile...").start();
1217
1220
  try {
1218
1221
  let proofs = [];
1219
1222
  if (options.proofs) {
@@ -1221,7 +1224,7 @@ var developersCommand = new Command("developers").description("Manage developer
1221
1224
  proofs = JSON.parse(options.proofs);
1222
1225
  } catch {
1223
1226
  spinner2.fail("Invalid proofs JSON format");
1224
- console.error(chalk6.red("Proofs must be a valid JSON array"));
1227
+ console.error(chalk7.red("Proofs must be a valid JSON array"));
1225
1228
  process.exit(1);
1226
1229
  }
1227
1230
  }
@@ -1233,18 +1236,18 @@ var developersCommand = new Command("developers").description("Manage developer
1233
1236
  };
1234
1237
  const result = await client.submitDeveloperProfile(pubkey, profile);
1235
1238
  spinner2.succeed("Developer profile created successfully");
1236
- console.log(chalk6.green(`
1239
+ console.log(chalk7.green(`
1237
1240
  \u2705 ${result.message}`));
1238
- console.log(chalk6.blue(`
1241
+ console.log(chalk7.blue(`
1239
1242
  \u{1F464} Developer: ${displayName}`));
1240
- console.log(chalk6.blue(`\u{1F511} Public Key: ${pubkey}`));
1243
+ console.log(chalk7.blue(`\u{1F511} Public Key: ${pubkey}`));
1241
1244
  if (options.website) {
1242
- console.log(chalk6.blue(`\u{1F310} Website: ${options.website}`));
1245
+ console.log(chalk7.blue(`\u{1F310} Website: ${options.website}`));
1243
1246
  }
1244
1247
  } catch (error) {
1245
1248
  spinner2.fail("Failed to create developer profile");
1246
1249
  if (error instanceof Error) {
1247
- console.error(chalk6.red(`Error: ${error.message}`));
1250
+ console.error(chalk7.red(`Error: ${error.message}`));
1248
1251
  }
1249
1252
  process.exit(1);
1250
1253
  }
@@ -1257,7 +1260,7 @@ var attestationsCommand = new Command("attestations").description("Manage applic
1257
1260
  baseURL: globalOpts?.url || "http://localhost:8082",
1258
1261
  timeout: parseInt(globalOpts?.timeout || "10000")
1259
1262
  });
1260
- const spinner2 = ora6(
1263
+ const spinner2 = ora7(
1261
1264
  `Fetching attestation for ${name}@${version2}...`
1262
1265
  ).start();
1263
1266
  try {
@@ -1267,16 +1270,16 @@ var attestationsCommand = new Command("attestations").description("Manage applic
1267
1270
  version2
1268
1271
  );
1269
1272
  spinner2.succeed("Attestation fetched successfully");
1270
- console.log(chalk6.blue("\nAttestation:"));
1271
- console.log(chalk6.green("Status:"), attestation.status);
1272
- console.log(chalk6.green("Timestamp:"), attestation.timestamp);
1273
+ console.log(chalk7.blue("\nAttestation:"));
1274
+ console.log(chalk7.green("Status:"), attestation.status);
1275
+ console.log(chalk7.green("Timestamp:"), attestation.timestamp);
1273
1276
  if (attestation.comment) {
1274
- console.log(chalk6.green("Comment:"), attestation.comment);
1277
+ console.log(chalk7.green("Comment:"), attestation.comment);
1275
1278
  }
1276
1279
  } catch (error) {
1277
1280
  spinner2.fail("Failed to fetch attestation");
1278
1281
  if (error instanceof Error) {
1279
- console.error(chalk6.red(`Error: ${error.message}`));
1282
+ console.error(chalk7.red(`Error: ${error.message}`));
1280
1283
  }
1281
1284
  process.exit(1);
1282
1285
  }
@@ -1290,15 +1293,15 @@ var healthCommand = new Command("health").description("Check the health of the C
1290
1293
  globalOpts?.url,
1291
1294
  parseInt(globalOpts?.timeout || "10000")
1292
1295
  );
1293
- const spinner2 = ora6("Checking API health...").start();
1296
+ const spinner2 = ora7("Checking API health...").start();
1294
1297
  try {
1295
1298
  const health = await client.healthCheck();
1296
1299
  spinner2.succeed("API is healthy");
1297
- console.log(chalk6.green(`Status: ${health.status}`));
1300
+ console.log(chalk7.green(`Status: ${health.status}`));
1298
1301
  } catch (error) {
1299
1302
  spinner2.fail("API health check failed");
1300
1303
  if (error instanceof Error) {
1301
- console.error(chalk6.red(`Error: ${error.message}`));
1304
+ console.error(chalk7.red(`Error: ${error.message}`));
1302
1305
  }
1303
1306
  process.exit(1);
1304
1307
  }
@@ -1333,7 +1336,7 @@ This is a demo file that would normally contain the actual application data.`;
1333
1336
  );
1334
1337
  }
1335
1338
  }
1336
- var spinner = (text) => ora6(text);
1339
+ var spinner = (text) => ora7(text);
1337
1340
 
1338
1341
  // src/commands/ipfs.ts
1339
1342
  var ipfsCommand = new Command("ipfs").description("IPFS operations").addCommand(
@@ -1585,7 +1588,7 @@ localCommand.addCommand(
1585
1588
  "Public host exposed in manifest artifact URLs",
1586
1589
  "host.docker.internal"
1587
1590
  ).action(async (options) => {
1588
- const spinner2 = ora6("Starting local registry...").start();
1591
+ const spinner2 = ora7("Starting local registry...").start();
1589
1592
  try {
1590
1593
  const config = new LocalConfig();
1591
1594
  config.setHost(options.host);
@@ -1596,37 +1599,37 @@ localCommand.addCommand(
1596
1599
  spinner2.succeed(
1597
1600
  `Local registry started on http://${config.getHost()}:${config.getPort()}`
1598
1601
  );
1599
- console.log(chalk6.blue("\n\u{1F4F1} Local Registry Status:"));
1602
+ console.log(chalk7.blue("\n\u{1F4F1} Local Registry Status:"));
1600
1603
  console.log(
1601
- chalk6.green(
1604
+ chalk7.green(
1602
1605
  `\u2705 Server: http://${config.getHost()}:${config.getPort()}`
1603
1606
  )
1604
1607
  );
1605
1608
  console.log(
1606
- chalk6.green(
1609
+ chalk7.green(
1607
1610
  `\u{1F310} Public URL: http://${config.getPublicHost()}:${config.getPort()}`
1608
1611
  )
1609
1612
  );
1610
- console.log(chalk6.green(`\u{1F4C1} Data: ${config.getDataDir()}`));
1613
+ console.log(chalk7.green(`\u{1F4C1} Data: ${config.getDataDir()}`));
1611
1614
  console.log(
1612
- chalk6.green(
1615
+ chalk7.green(
1613
1616
  `\u{1F4CB} Health: http://${config.getHost()}:${config.getPort()}/healthz`
1614
1617
  )
1615
1618
  );
1616
1619
  console.log(
1617
- chalk6.green(
1620
+ chalk7.green(
1618
1621
  `\u{1F4CA} Stats: http://${config.getHost()}:${config.getPort()}/stats`
1619
1622
  )
1620
1623
  );
1621
1624
  console.log(
1622
- chalk6.blue(
1625
+ chalk7.blue(
1623
1626
  "\n\u{1F4A1} Use --local flag with other commands to use local registry"
1624
1627
  )
1625
1628
  );
1626
1629
  } catch (error) {
1627
1630
  spinner2.fail("Failed to start local registry");
1628
1631
  if (error instanceof Error) {
1629
- console.error(chalk6.red(`Error: ${error.message}`));
1632
+ console.error(chalk7.red(`Error: ${error.message}`));
1630
1633
  }
1631
1634
  process.exit(1);
1632
1635
  }
@@ -1634,7 +1637,7 @@ localCommand.addCommand(
1634
1637
  );
1635
1638
  localCommand.addCommand(
1636
1639
  new Command("stop").description("Stop local registry server").action(async () => {
1637
- const spinner2 = ora6("Stopping local registry...").start();
1640
+ const spinner2 = ora7("Stopping local registry...").start();
1638
1641
  try {
1639
1642
  const config = new LocalConfig();
1640
1643
  const server = new LocalRegistryServer(config);
@@ -1643,7 +1646,7 @@ localCommand.addCommand(
1643
1646
  } catch (error) {
1644
1647
  spinner2.fail("Failed to stop local registry");
1645
1648
  if (error instanceof Error) {
1646
- console.error(chalk6.red(`Error: ${error.message}`));
1649
+ console.error(chalk7.red(`Error: ${error.message}`));
1647
1650
  }
1648
1651
  process.exit(1);
1649
1652
  }
@@ -1651,23 +1654,23 @@ localCommand.addCommand(
1651
1654
  );
1652
1655
  localCommand.addCommand(
1653
1656
  new Command("status").description("Check local registry status").action(async () => {
1654
- const spinner2 = ora6("Checking local registry status...").start();
1657
+ const spinner2 = ora7("Checking local registry status...").start();
1655
1658
  try {
1656
1659
  const config = new LocalConfig();
1657
1660
  const server = new LocalRegistryServer(config);
1658
1661
  const status = await server.getStatus();
1659
1662
  if (status.running) {
1660
1663
  spinner2.succeed("Local registry is running");
1661
- console.log(chalk6.green(`\u2705 Server: ${status.url}`));
1662
- console.log(chalk6.green(`\u{1F4C1} Data: ${status.dataDir}`));
1663
- console.log(chalk6.green(`\u{1F4CA} Apps: ${status.appsCount} applications`));
1664
+ console.log(chalk7.green(`\u2705 Server: ${status.url}`));
1665
+ console.log(chalk7.green(`\u{1F4C1} Data: ${status.dataDir}`));
1666
+ console.log(chalk7.green(`\u{1F4CA} Apps: ${status.appsCount} applications`));
1664
1667
  console.log(
1665
- chalk6.green(`\u{1F4E6} Artifacts: ${status.artifactsCount} artifacts`)
1668
+ chalk7.green(`\u{1F4E6} Artifacts: ${status.artifactsCount} artifacts`)
1666
1669
  );
1667
1670
  } else {
1668
1671
  spinner2.warn("Local registry is not running");
1669
1672
  console.log(
1670
- chalk6.yellow(
1673
+ chalk7.yellow(
1671
1674
  '\u{1F4A1} Run "calimero-registry local start" to start the local registry'
1672
1675
  )
1673
1676
  );
@@ -1675,7 +1678,7 @@ localCommand.addCommand(
1675
1678
  } catch (error) {
1676
1679
  spinner2.fail("Failed to check local registry status");
1677
1680
  if (error instanceof Error) {
1678
- console.error(chalk6.red(`Error: ${error.message}`));
1681
+ console.error(chalk7.red(`Error: ${error.message}`));
1679
1682
  }
1680
1683
  process.exit(1);
1681
1684
  }
@@ -1685,22 +1688,22 @@ localCommand.addCommand(
1685
1688
  new Command("reset").description("Reset local registry data").option("-f, --force", "Force reset without confirmation").action(async (options) => {
1686
1689
  if (!options.force) {
1687
1690
  console.log(
1688
- chalk6.yellow("\u26A0\uFE0F This will delete all local registry data!")
1691
+ chalk7.yellow("\u26A0\uFE0F This will delete all local registry data!")
1689
1692
  );
1690
- console.log(chalk6.yellow(" Use --force flag to confirm"));
1693
+ console.log(chalk7.yellow(" Use --force flag to confirm"));
1691
1694
  return;
1692
1695
  }
1693
- const spinner2 = ora6("Resetting local registry data...").start();
1696
+ const spinner2 = ora7("Resetting local registry data...").start();
1694
1697
  try {
1695
1698
  const config = new LocalConfig();
1696
1699
  const server = new LocalRegistryServer(config);
1697
1700
  await server.reset();
1698
1701
  spinner2.succeed("Local registry data reset");
1699
- console.log(chalk6.green("\u2705 All local data has been cleared"));
1702
+ console.log(chalk7.green("\u2705 All local data has been cleared"));
1700
1703
  } catch (error) {
1701
1704
  spinner2.fail("Failed to reset local registry data");
1702
1705
  if (error instanceof Error) {
1703
- console.error(chalk6.red(`Error: ${error.message}`));
1706
+ console.error(chalk7.red(`Error: ${error.message}`));
1704
1707
  }
1705
1708
  process.exit(1);
1706
1709
  }
@@ -1708,17 +1711,17 @@ localCommand.addCommand(
1708
1711
  );
1709
1712
  localCommand.addCommand(
1710
1713
  new Command("backup").description("Backup local registry data").option("-o, --output <file>", "Output file path").action(async (options) => {
1711
- const spinner2 = ora6("Creating backup...").start();
1714
+ const spinner2 = ora7("Creating backup...").start();
1712
1715
  try {
1713
1716
  const config = new LocalConfig();
1714
1717
  const server = new LocalRegistryServer(config);
1715
1718
  const backupPath = await server.backup(options.output);
1716
1719
  spinner2.succeed("Backup created successfully");
1717
- console.log(chalk6.green(`\u{1F4E6} Backup saved to: ${backupPath}`));
1720
+ console.log(chalk7.green(`\u{1F4E6} Backup saved to: ${backupPath}`));
1718
1721
  } catch (error) {
1719
1722
  spinner2.fail("Failed to create backup");
1720
1723
  if (error instanceof Error) {
1721
- console.error(chalk6.red(`Error: ${error.message}`));
1724
+ console.error(chalk7.red(`Error: ${error.message}`));
1722
1725
  }
1723
1726
  process.exit(1);
1724
1727
  }
@@ -1726,22 +1729,22 @@ localCommand.addCommand(
1726
1729
  );
1727
1730
  localCommand.addCommand(
1728
1731
  new Command("restore").description("Restore local registry data from backup").argument("<backup-file>", "Path to backup file").action(async (backupFile) => {
1729
- const spinner2 = ora6("Restoring from backup...").start();
1732
+ const spinner2 = ora7("Restoring from backup...").start();
1730
1733
  try {
1731
1734
  if (!fs9.existsSync(backupFile)) {
1732
1735
  spinner2.fail("Backup file not found");
1733
- console.error(chalk6.red(`File not found: ${backupFile}`));
1736
+ console.error(chalk7.red(`File not found: ${backupFile}`));
1734
1737
  process.exit(1);
1735
1738
  }
1736
1739
  const config = new LocalConfig();
1737
1740
  const server = new LocalRegistryServer(config);
1738
1741
  await server.restore(backupFile);
1739
1742
  spinner2.succeed("Data restored successfully");
1740
- console.log(chalk6.green(`\u2705 Restored from: ${backupFile}`));
1743
+ console.log(chalk7.green(`\u2705 Restored from: ${backupFile}`));
1741
1744
  } catch (error) {
1742
1745
  spinner2.fail("Failed to restore from backup");
1743
1746
  if (error instanceof Error) {
1744
- console.error(chalk6.red(`Error: ${error.message}`));
1747
+ console.error(chalk7.red(`Error: ${error.message}`));
1745
1748
  }
1746
1749
  process.exit(1);
1747
1750
  }
@@ -1749,24 +1752,24 @@ localCommand.addCommand(
1749
1752
  );
1750
1753
  localCommand.addCommand(
1751
1754
  new Command("seed").description("Seed local registry with sample data").action(async () => {
1752
- const spinner2 = ora6("Seeding local registry with sample data...").start();
1755
+ const spinner2 = ora7("Seeding local registry with sample data...").start();
1753
1756
  try {
1754
1757
  const config = new LocalConfig();
1755
1758
  const server = new LocalRegistryServer(config);
1756
1759
  await server.seed();
1757
1760
  spinner2.succeed("Sample data seeded successfully");
1758
1761
  console.log(
1759
- chalk6.green("\u2705 Local registry populated with sample applications")
1762
+ chalk7.green("\u2705 Local registry populated with sample applications")
1760
1763
  );
1761
1764
  console.log(
1762
- chalk6.blue(
1765
+ chalk7.blue(
1763
1766
  '\u{1F4A1} Run "calimero-registry apps list --local" to see the sample apps'
1764
1767
  )
1765
1768
  );
1766
1769
  } catch (error) {
1767
1770
  spinner2.fail("Failed to seed sample data");
1768
1771
  if (error instanceof Error) {
1769
- console.error(chalk6.red(`Error: ${error.message}`));
1772
+ console.error(chalk7.red(`Error: ${error.message}`));
1770
1773
  }
1771
1774
  process.exit(1);
1772
1775
  }
@@ -2101,65 +2104,33 @@ Note:
2101
2104
  links: Object.keys(links).length > 0 ? links : void 0,
2102
2105
  signature: void 0
2103
2106
  };
2104
- let outputPath = finalOutput;
2105
- if (!outputPath) {
2106
- const outputDir = path7.join(
2107
- process.cwd(),
2108
- finalPackage,
2109
- finalVersion
2110
- );
2111
- if (!fs9.existsSync(outputDir)) {
2112
- fs9.mkdirSync(outputDir, { recursive: true });
2113
- }
2114
- outputPath = path7.join(
2115
- outputDir,
2116
- `${finalPackage}-${finalVersion}.mpk`
2117
- );
2118
- } else {
2119
- outputPath = path7.resolve(outputPath);
2120
- const outputDir = path7.dirname(outputPath);
2121
- if (!fs9.existsSync(outputDir)) {
2122
- fs9.mkdirSync(outputDir, { recursive: true });
2123
- }
2107
+ let outputDir = finalOutput ? path7.resolve(finalOutput) : path7.join(process.cwd(), finalPackage, finalVersion);
2108
+ if (!fs9.existsSync(outputDir)) {
2109
+ fs9.mkdirSync(outputDir, { recursive: true });
2124
2110
  }
2125
- const tempDir = path7.join(
2126
- path7.dirname(outputPath),
2127
- `.temp-bundle-${Date.now()}`
2111
+ fs9.writeFileSync(
2112
+ path7.join(outputDir, "manifest.json"),
2113
+ JSON.stringify(manifest, null, 2)
2128
2114
  );
2129
- fs9.mkdirSync(tempDir, { recursive: true });
2130
- try {
2131
- fs9.writeFileSync(
2132
- path7.join(tempDir, "manifest.json"),
2133
- JSON.stringify(manifest, null, 2)
2134
- );
2135
- fs9.writeFileSync(path7.join(tempDir, "app.wasm"), wasmContent);
2136
- const archiveFiles = ["manifest.json", "app.wasm"];
2137
- if (abiContent) {
2138
- fs9.writeFileSync(path7.join(tempDir, "abi.json"), abiContent);
2139
- archiveFiles.push("abi.json");
2140
- }
2141
- await tar.create(
2142
- {
2143
- gzip: true,
2144
- file: outputPath,
2145
- cwd: tempDir
2146
- },
2147
- archiveFiles
2148
- );
2149
- const outputSize = fs9.statSync(outputPath).size;
2150
- console.log(`\u2705 Created MPK bundle: ${outputPath}`);
2151
- console.log(` Package: ${finalPackage}`);
2152
- console.log(` Version: ${finalVersion}`);
2153
- console.log(` Size: ${outputSize} bytes`);
2154
- console.log(` WASM Hash: ${wasmHash}`);
2155
- if (abiArtifact) {
2156
- console.log(` ABI Hash: ${abiArtifact.hash}`);
2157
- }
2158
- } finally {
2159
- if (fs9.existsSync(tempDir)) {
2160
- fs9.rmSync(tempDir, { recursive: true, force: true });
2161
- }
2115
+ fs9.writeFileSync(path7.join(outputDir, "app.wasm"), wasmContent);
2116
+ if (abiContent) {
2117
+ fs9.writeFileSync(path7.join(outputDir, "abi.json"), abiContent);
2162
2118
  }
2119
+ console.log(`\u2705 Bundle files written to: ${outputDir}`);
2120
+ console.log(` Package: ${finalPackage}`);
2121
+ console.log(` Version: ${finalVersion}`);
2122
+ console.log(` WASM Hash: ${wasmHash}`);
2123
+ if (abiArtifact) {
2124
+ console.log(` ABI Hash: ${abiArtifact.hash}`);
2125
+ }
2126
+ console.log("");
2127
+ console.log("Next steps:");
2128
+ console.log(
2129
+ ` 1. Sign the manifest: mero-sign sign ${path7.join(outputDir, "manifest.json")} --key key.json`
2130
+ );
2131
+ console.log(
2132
+ ` 2. Push the bundle: calimero-registry bundle push ${outputDir} --remote`
2133
+ );
2163
2134
  } catch (error) {
2164
2135
  const message = error instanceof Error ? error.message : "Unknown error";
2165
2136
  console.error("\u274C Failed to create bundle:", message);
@@ -2201,6 +2172,8 @@ Note:
2201
2172
  - Priority: flag > environment variable > config file > default
2202
2173
  `
2203
2174
  ).action(async (bundleFile, options) => {
2175
+ let mpkPath = "";
2176
+ let tempMpk = null;
2204
2177
  try {
2205
2178
  if (!options.remote && (options.url || options.apiKey)) {
2206
2179
  console.warn(
@@ -2227,8 +2200,34 @@ Note:
2227
2200
  console.error(`\u274C File not found: ${bundleFile}`);
2228
2201
  process.exit(1);
2229
2202
  }
2230
- console.log(`\u{1F4E6} Processing bundle: ${path7.basename(fullPath)}`);
2231
- const manifest = await extractManifest(fullPath);
2203
+ mpkPath = fullPath;
2204
+ if (fs9.statSync(fullPath).isDirectory()) {
2205
+ const manifestInDir = path7.join(fullPath, "manifest.json");
2206
+ const wasmInDir = path7.join(fullPath, "app.wasm");
2207
+ if (!fs9.existsSync(manifestInDir)) {
2208
+ console.error(
2209
+ `\u274C manifest.json not found in directory: ${fullPath}`
2210
+ );
2211
+ process.exit(1);
2212
+ }
2213
+ if (!fs9.existsSync(wasmInDir)) {
2214
+ console.error(`\u274C app.wasm not found in directory: ${fullPath}`);
2215
+ process.exit(1);
2216
+ }
2217
+ tempMpk = path7.join(fullPath, `.temp-push-${Date.now()}.mpk`);
2218
+ const archiveFiles = ["manifest.json", "app.wasm"];
2219
+ if (fs9.existsSync(path7.join(fullPath, "abi.json"))) {
2220
+ archiveFiles.push("abi.json");
2221
+ }
2222
+ await tar.create(
2223
+ { gzip: true, file: tempMpk, cwd: fullPath },
2224
+ archiveFiles
2225
+ );
2226
+ mpkPath = tempMpk;
2227
+ console.log(`\u{1F4E6} Packed directory into temporary bundle`);
2228
+ }
2229
+ console.log(`\u{1F4E6} Processing bundle: ${path7.basename(mpkPath)}`);
2230
+ const manifest = await extractManifest(mpkPath);
2232
2231
  if (!manifest) {
2233
2232
  console.error("\u274C manifest.json not found in bundle");
2234
2233
  process.exit(1);
@@ -2248,7 +2247,7 @@ Note:
2248
2247
  const artifactServer = new LocalArtifactServer(config, store);
2249
2248
  const bundleFilename = `${manifest.package}-${manifest.appVersion}.mpk`;
2250
2249
  const targetPath = await artifactServer.copyArtifactToLocal(
2251
- fullPath,
2250
+ mpkPath,
2252
2251
  manifest.package,
2253
2252
  manifest.appVersion,
2254
2253
  bundleFilename
@@ -2267,12 +2266,16 @@ Note:
2267
2266
  const remoteConfig = new RemoteConfig();
2268
2267
  const registryUrl = options.url || process.env.CALIMERO_REGISTRY_URL || remoteConfig.getRegistryUrl();
2269
2268
  const apiKey = options.apiKey || process.env.CALIMERO_API_KEY || remoteConfig.getApiKey();
2270
- await pushToRemote(fullPath, manifest, registryUrl, apiKey);
2269
+ await pushToRemote(mpkPath, manifest, registryUrl, apiKey);
2271
2270
  }
2272
2271
  } catch (error) {
2273
2272
  const message = error instanceof Error ? error.message : String(error);
2274
2273
  console.error("\u274C Failed to push bundle:", message);
2275
2274
  process.exit(1);
2275
+ } finally {
2276
+ if (tempMpk && fs9.existsSync(tempMpk)) {
2277
+ fs9.rmSync(tempMpk);
2278
+ }
2276
2279
  }
2277
2280
  });
2278
2281
  }
@@ -2638,7 +2641,7 @@ async function extractManifest(bundlePath) {
2638
2641
  await tar.x({
2639
2642
  file: bundlePath,
2640
2643
  cwd: extractDir,
2641
- filter: (path8) => path8 === "manifest.json"
2644
+ filter: (path9) => path9 === "manifest.json"
2642
2645
  });
2643
2646
  const manifestPath = path7.join(extractDir, "manifest.json");
2644
2647
  if (fs9.existsSync(manifestPath)) {
@@ -2672,29 +2675,29 @@ function createConfigSetCommand() {
2672
2675
  case "url":
2673
2676
  config.setRegistryUrl(value);
2674
2677
  console.log(
2675
- chalk6.green(`\u2705 Registry URL set to: ${chalk6.bold(value)}`)
2678
+ chalk7.green(`\u2705 Registry URL set to: ${chalk7.bold(value)}`)
2676
2679
  );
2677
2680
  break;
2678
2681
  case "api-key":
2679
2682
  case "apiKey":
2680
2683
  config.setApiKey(value);
2681
- console.log(chalk6.green("\u2705 API key set successfully"));
2684
+ console.log(chalk7.green("\u2705 API key set successfully"));
2682
2685
  console.log(
2683
- chalk6.yellow(
2686
+ chalk7.yellow(
2684
2687
  "\u{1F4A1} Note: API key is stored in plain text. Consider using CALIMERO_API_KEY environment variable for better security."
2685
2688
  )
2686
2689
  );
2687
2690
  break;
2688
2691
  default:
2689
- console.error(chalk6.red(`\u274C Unknown configuration key: ${key}`));
2690
- console.log(chalk6.blue("\nAvailable keys:"));
2692
+ console.error(chalk7.red(`\u274C Unknown configuration key: ${key}`));
2693
+ console.log(chalk7.blue("\nAvailable keys:"));
2691
2694
  console.log(" registry-url - Default registry URL");
2692
2695
  console.log(" api-key - API key for authentication");
2693
2696
  process.exit(1);
2694
2697
  }
2695
2698
  } catch (error) {
2696
2699
  const message = error instanceof Error ? error.message : String(error);
2697
- console.error(chalk6.red("\u274C Failed to set configuration:"), message);
2700
+ console.error(chalk7.red("\u274C Failed to set configuration:"), message);
2698
2701
  process.exit(1);
2699
2702
  }
2700
2703
  });
@@ -2716,7 +2719,7 @@ function createConfigGetCommand() {
2716
2719
  const masked = apiKey.length > 8 ? `${apiKey.substring(0, 4)}...${apiKey.substring(apiKey.length - 4)}` : "***";
2717
2720
  console.log(masked);
2718
2721
  console.log(
2719
- chalk6.yellow(
2722
+ chalk7.yellow(
2720
2723
  '\u{1F4A1} Note: API key is masked. Use "config list" to see source.'
2721
2724
  )
2722
2725
  );
@@ -2726,15 +2729,15 @@ function createConfigGetCommand() {
2726
2729
  break;
2727
2730
  }
2728
2731
  default:
2729
- console.error(chalk6.red(`\u274C Unknown configuration key: ${key}`));
2730
- console.log(chalk6.blue("\nAvailable keys:"));
2732
+ console.error(chalk7.red(`\u274C Unknown configuration key: ${key}`));
2733
+ console.log(chalk7.blue("\nAvailable keys:"));
2731
2734
  console.log(" registry-url - Default registry URL");
2732
2735
  console.log(" api-key - API key for authentication");
2733
2736
  process.exit(1);
2734
2737
  }
2735
2738
  } catch (error) {
2736
2739
  const message = error instanceof Error ? error.message : String(error);
2737
- console.error(chalk6.red("\u274C Failed to get configuration:"), message);
2740
+ console.error(chalk7.red("\u274C Failed to get configuration:"), message);
2738
2741
  process.exit(1);
2739
2742
  }
2740
2743
  });
@@ -2743,43 +2746,43 @@ function createConfigListCommand() {
2743
2746
  return new Command("list").description("List all configuration values").alias("ls").action(() => {
2744
2747
  try {
2745
2748
  const config = new RemoteConfig();
2746
- console.log(chalk6.blue("\n\u{1F4CB} Remote Registry Configuration\n"));
2749
+ console.log(chalk7.blue("\n\u{1F4CB} Remote Registry Configuration\n"));
2747
2750
  const configPath = config.getConfigPath();
2748
2751
  const configFileExists = fs9.existsSync(configPath);
2749
2752
  const url = config.getRegistryUrl();
2750
2753
  let urlSource;
2751
2754
  if (process.env.CALIMERO_REGISTRY_URL) {
2752
- urlSource = chalk6.yellow("(from CALIMERO_REGISTRY_URL env var)");
2755
+ urlSource = chalk7.yellow("(from CALIMERO_REGISTRY_URL env var)");
2753
2756
  } else if (configFileExists) {
2754
- urlSource = chalk6.gray("(from config file)");
2757
+ urlSource = chalk7.gray("(from config file)");
2755
2758
  } else {
2756
- urlSource = chalk6.gray("(default)");
2759
+ urlSource = chalk7.gray("(default)");
2757
2760
  }
2758
- console.log(` ${chalk6.bold("Registry URL:")} ${url} ${urlSource}`);
2761
+ console.log(` ${chalk7.bold("Registry URL:")} ${url} ${urlSource}`);
2759
2762
  const apiKey = config.getApiKey();
2760
2763
  if (apiKey) {
2761
2764
  let apiKeySource;
2762
2765
  if (process.env.CALIMERO_API_KEY) {
2763
- apiKeySource = chalk6.yellow("(from CALIMERO_API_KEY env var)");
2766
+ apiKeySource = chalk7.yellow("(from CALIMERO_API_KEY env var)");
2764
2767
  } else if (configFileExists) {
2765
- apiKeySource = chalk6.gray("(from config file)");
2768
+ apiKeySource = chalk7.gray("(from config file)");
2766
2769
  } else {
2767
- apiKeySource = chalk6.gray("(default)");
2770
+ apiKeySource = chalk7.gray("(default)");
2768
2771
  }
2769
2772
  const masked = apiKey.length > 8 ? `${apiKey.substring(0, 4)}...${apiKey.substring(apiKey.length - 4)}` : "***";
2770
- console.log(` ${chalk6.bold("API Key:")} ${masked} ${apiKeySource}`);
2773
+ console.log(` ${chalk7.bold("API Key:")} ${masked} ${apiKeySource}`);
2771
2774
  } else {
2772
- console.log(` ${chalk6.bold("API Key:")} ${chalk6.gray("(not set)")}`);
2775
+ console.log(` ${chalk7.bold("API Key:")} ${chalk7.gray("(not set)")}`);
2773
2776
  }
2774
- console.log(chalk6.blue(`
2777
+ console.log(chalk7.blue(`
2775
2778
  \u{1F4C1} Config file: ${configPath}`));
2776
2779
  if (!configFileExists) {
2777
- console.log(chalk6.gray(" (file does not exist, using defaults)"));
2780
+ console.log(chalk7.gray(" (file does not exist, using defaults)"));
2778
2781
  }
2779
2782
  console.log();
2780
2783
  } catch (error) {
2781
2784
  const message = error instanceof Error ? error.message : String(error);
2782
- console.error(chalk6.red("\u274C Failed to list configuration:"), message);
2785
+ console.error(chalk7.red("\u274C Failed to list configuration:"), message);
2783
2786
  process.exit(1);
2784
2787
  }
2785
2788
  });
@@ -2789,10 +2792,10 @@ function createConfigResetCommand() {
2789
2792
  try {
2790
2793
  if (!options.force) {
2791
2794
  console.error(
2792
- chalk6.red("\u274C Configuration reset requires --force flag")
2795
+ chalk7.red("\u274C Configuration reset requires --force flag")
2793
2796
  );
2794
2797
  console.log(
2795
- chalk6.yellow(
2798
+ chalk7.yellow(
2796
2799
  "\u26A0\uFE0F This will reset all configuration to defaults. Use --force to confirm."
2797
2800
  )
2798
2801
  );
@@ -2800,17 +2803,596 @@ function createConfigResetCommand() {
2800
2803
  }
2801
2804
  const config = new RemoteConfig();
2802
2805
  config.reset();
2803
- console.log(chalk6.green("\u2705 Configuration reset to defaults"));
2804
- console.log(chalk6.blue("\nDefault values:"));
2806
+ console.log(chalk7.green("\u2705 Configuration reset to defaults"));
2807
+ console.log(chalk7.blue("\nDefault values:"));
2805
2808
  console.log(" Registry URL: https://apps.calimero.network");
2806
2809
  console.log(" API Key: (not set)");
2807
2810
  } catch (error) {
2808
2811
  const message = error instanceof Error ? error.message : String(error);
2809
- console.error(chalk6.red("\u274C Failed to reset configuration:"), message);
2812
+ console.error(chalk7.red("\u274C Failed to reset configuration:"), message);
2810
2813
  process.exit(1);
2811
2814
  }
2812
2815
  });
2813
2816
  }
2817
+ var ENV_KEYPAIR = "CALIMERO_REGISTRY_KEYPAIR";
2818
+ function base64urlEncode(bytes) {
2819
+ const base64 = Buffer.from(bytes).toString("base64");
2820
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
2821
+ }
2822
+ function buildSignedPayload(method, pathname, body) {
2823
+ const bodyObj = body != null && typeof body === "object" ? body : {};
2824
+ const bodyStr = Object.keys(bodyObj).length > 0 ? canonicalize(bodyObj) : "";
2825
+ return `${method}
2826
+ ${pathname}
2827
+ ${bodyStr}`;
2828
+ }
2829
+ function base64urlDecode(str) {
2830
+ const base64 = str.replace(/-/g, "+").replace(/_/g, "/");
2831
+ const padded = base64.padEnd(
2832
+ base64.length + (4 - base64.length % 4) % 4,
2833
+ "="
2834
+ );
2835
+ return new Uint8Array(Buffer.from(padded, "base64"));
2836
+ }
2837
+ function loadKeypair(options) {
2838
+ if (options?.keypairPath) {
2839
+ const resolved = path7.resolve(options.keypairPath);
2840
+ if (!fs9.existsSync(resolved)) {
2841
+ throw new Error(`Keypair file not found: ${resolved}`);
2842
+ }
2843
+ const raw = fs9.readFileSync(resolved, "utf8");
2844
+ const parsed = JSON.parse(raw);
2845
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed) && parsed.private_key) {
2846
+ const secretKey2 = base64urlDecode(parsed.private_key);
2847
+ const publicKey2 = base64urlDecode(parsed.public_key);
2848
+ if (secretKey2.length !== 32 || publicKey2.length !== 32) {
2849
+ throw new Error(
2850
+ "Invalid key file: private_key and public_key must be 32 bytes each"
2851
+ );
2852
+ }
2853
+ return { publicKey: publicKey2, secretKey: secretKey2 };
2854
+ }
2855
+ if (Array.isArray(parsed) && parsed.length === 64) {
2856
+ const bytes2 = new Uint8Array(parsed);
2857
+ const secretKey2 = bytes2.slice(0, 32);
2858
+ const publicKey2 = bytes2.slice(32, 64);
2859
+ return { publicKey: publicKey2, secretKey: secretKey2 };
2860
+ }
2861
+ throw new Error(
2862
+ "Unrecognised key file format. Expected mero-sign JSON ({ private_key, public_key, signer_id }) or a legacy array of 64 numbers."
2863
+ );
2864
+ }
2865
+ const env = process.env[ENV_KEYPAIR];
2866
+ if (!env || typeof env !== "string" || !env.trim()) {
2867
+ throw new Error(
2868
+ `Missing keypair: set ${ENV_KEYPAIR} (base58 64-byte keypair) or use -k <path>`
2869
+ );
2870
+ }
2871
+ const decoded = bs58.decode(env.trim());
2872
+ if (decoded.length !== 64) {
2873
+ throw new Error(
2874
+ `Invalid keypair: ${ENV_KEYPAIR} must decode to 64 bytes (got ${decoded.length})`
2875
+ );
2876
+ }
2877
+ const bytes = new Uint8Array(decoded);
2878
+ const secretKey = bytes.slice(0, 32);
2879
+ const publicKey = bytes.slice(32, 64);
2880
+ return { publicKey, secretKey };
2881
+ }
2882
+ async function signPayload(payload, secretKey, publicKey) {
2883
+ const message = new TextEncoder().encode(payload);
2884
+ const signature = await ed25519.signAsync(message, secretKey);
2885
+ return {
2886
+ pubkeyBase64url: base64urlEncode(publicKey),
2887
+ signatureBase64url: base64urlEncode(signature)
2888
+ };
2889
+ }
2890
+ async function getSignedHeaders(method, pathname, body, keypair) {
2891
+ const payload = buildSignedPayload(method, pathname, body);
2892
+ const { pubkeyBase64url, signatureBase64url } = await signPayload(
2893
+ payload,
2894
+ keypair.secretKey,
2895
+ keypair.publicKey
2896
+ );
2897
+ return {
2898
+ "X-Pubkey": pubkeyBase64url,
2899
+ "X-Signature": signatureBase64url
2900
+ };
2901
+ }
2902
+ function publicKeyToBase64url(publicKey) {
2903
+ return base64urlEncode(publicKey);
2904
+ }
2905
+
2906
+ // src/commands/org.ts
2907
+ var DEFAULT_TIMEOUT = 1e4;
2908
+ function getGlobalOpts(command) {
2909
+ const opts = command.parent?.parent?.opts() ?? {};
2910
+ const remoteConfig = new RemoteConfig();
2911
+ const url = opts.url || process.env.CALIMERO_REGISTRY_URL || remoteConfig.getRegistryUrl();
2912
+ return {
2913
+ url,
2914
+ timeout: parseInt(String(opts.timeout ?? DEFAULT_TIMEOUT), 10) || DEFAULT_TIMEOUT
2915
+ };
2916
+ }
2917
+ function getKeypairPath(command) {
2918
+ const orgCmd = command.parent?.name() === "org" ? command.parent : command.parent?.parent;
2919
+ return orgCmd?.opts()?.keypair;
2920
+ }
2921
+ async function fetchJson(url, options = {}) {
2922
+ const { timeout = DEFAULT_TIMEOUT, ...init } = options;
2923
+ const controller = new AbortController();
2924
+ const id = setTimeout(() => controller.abort(), timeout);
2925
+ const res = await fetch(url, {
2926
+ ...init,
2927
+ signal: controller.signal,
2928
+ headers: {
2929
+ "Content-Type": "application/json",
2930
+ ...init.headers
2931
+ }
2932
+ });
2933
+ clearTimeout(id);
2934
+ const text = await res.text();
2935
+ const data = text ? JSON.parse(text) : void 0;
2936
+ return { data, status: res.status };
2937
+ }
2938
+ var orgCommand = new Command("org").description("Manage organizations (create, list, members, packages)").option(
2939
+ "-k, --keypair <path>",
2940
+ "Path to Ed25519 keypair JSON (64 bytes). Overrides CALIMERO_REGISTRY_KEYPAIR."
2941
+ ).addCommand(
2942
+ new Command("list").description(
2943
+ "List organizations you belong to (uses keypair pubkey as member)"
2944
+ ).action(async (_options, command) => {
2945
+ const { url, timeout } = getGlobalOpts(command);
2946
+ const keypairPath = getKeypairPath(command);
2947
+ const spinner2 = ora7("Loading keypair...").start();
2948
+ let pubkey;
2949
+ try {
2950
+ const kp = loadKeypair({ keypairPath });
2951
+ pubkey = publicKeyToBase64url(kp.publicKey);
2952
+ spinner2.text = "Fetching organizations...";
2953
+ } catch (e) {
2954
+ spinner2.fail("Keypair required");
2955
+ console.error(chalk7.red(e instanceof Error ? e.message : String(e)));
2956
+ process.exit(1);
2957
+ }
2958
+ const base = url.replace(/\/$/, "");
2959
+ const apiUrl = `${base}/api/v2/orgs?member=${encodeURIComponent(pubkey)}`;
2960
+ try {
2961
+ const { data, status } = await fetchJson(apiUrl, {
2962
+ method: "GET",
2963
+ timeout
2964
+ });
2965
+ if (status !== 200) {
2966
+ spinner2.fail("Failed to list organizations");
2967
+ console.error(chalk7.red(JSON.stringify(data)));
2968
+ process.exit(1);
2969
+ }
2970
+ const orgs = Array.isArray(data) ? data : [];
2971
+ spinner2.succeed(`Found ${orgs.length} organization(s)`);
2972
+ if (orgs.length === 0) {
2973
+ console.log(chalk7.yellow("No organizations found"));
2974
+ return;
2975
+ }
2976
+ const memberResults = await Promise.all(
2977
+ orgs.map(
2978
+ (o) => fetchJson(
2979
+ `${base}/api/v2/orgs/${encodeURIComponent(o.id)}/members`,
2980
+ { method: "GET", timeout }
2981
+ ).catch(() => ({ data: { members: [] }, status: 0 }))
2982
+ )
2983
+ );
2984
+ const lines = orgs.map((o, i) => {
2985
+ const members = memberResults[i].data?.members ?? [];
2986
+ const myMember = members.find((m) => m.pubkey === pubkey);
2987
+ const role = myMember?.role ?? "?";
2988
+ const count = members.length;
2989
+ const roleLabel = role === "admin" ? chalk7.yellow("admin") : chalk7.gray(role);
2990
+ return `${chalk7.white(o.slug)} ${chalk7.gray(o.name)} ${chalk7.gray(`${count} member${count !== 1 ? "s" : ""}`)} ${roleLabel}`;
2991
+ });
2992
+ console.log(lines.join("\n"));
2993
+ } catch (e) {
2994
+ spinner2.fail("Request failed");
2995
+ console.error(chalk7.red(e instanceof Error ? e.message : String(e)));
2996
+ process.exit(1);
2997
+ }
2998
+ })
2999
+ ).addCommand(
3000
+ new Command("create").description("Create a new organization").requiredOption("-n, --name <name>", "Organization display name").requiredOption("-s, --slug <slug>", "Organization slug (e.g. my-org)").action(
3001
+ async (options, command) => {
3002
+ const { url, timeout } = getGlobalOpts(command);
3003
+ const keypairPath = getKeypairPath(command);
3004
+ const spinner2 = ora7("Creating organization...").start();
3005
+ try {
3006
+ const kp = loadKeypair({ keypairPath });
3007
+ const pathname = "/api/v2/orgs";
3008
+ const body = {
3009
+ name: options.name.trim(),
3010
+ slug: options.slug.trim().toLowerCase()
3011
+ };
3012
+ const headers = await getSignedHeaders("POST", pathname, body, kp);
3013
+ const base = url.replace(/\/$/, "");
3014
+ const { data, status } = await fetchJson(`${base}${pathname}`, {
3015
+ method: "POST",
3016
+ body: JSON.stringify(body),
3017
+ timeout,
3018
+ headers: { ...headers }
3019
+ });
3020
+ if (status >= 400) {
3021
+ const err = data;
3022
+ spinner2.fail(err?.message || `HTTP ${status}`);
3023
+ console.error(chalk7.red(JSON.stringify(data)));
3024
+ process.exit(1);
3025
+ }
3026
+ spinner2.succeed("Organization created");
3027
+ console.log(chalk7.green(JSON.stringify(data, null, 2)));
3028
+ } catch (e) {
3029
+ spinner2.fail("Failed");
3030
+ console.error(
3031
+ chalk7.red(e instanceof Error ? e.message : String(e))
3032
+ );
3033
+ process.exit(1);
3034
+ }
3035
+ }
3036
+ )
3037
+ ).addCommand(
3038
+ new Command("get").description("Get organization by id/slug").argument("<orgId>", "Organization id or slug").action(async (orgId, _options, command) => {
3039
+ const { url, timeout } = getGlobalOpts(command);
3040
+ const base = url.replace(/\/$/, "");
3041
+ const pathname = `/api/v2/orgs/${encodeURIComponent(orgId)}`;
3042
+ const spinner2 = ora7("Fetching organization...").start();
3043
+ try {
3044
+ const { data, status } = await fetchJson(`${base}${pathname}`, { method: "GET", timeout });
3045
+ if (status === 404) {
3046
+ spinner2.fail("Organization not found");
3047
+ process.exit(1);
3048
+ }
3049
+ if (status !== 200) {
3050
+ spinner2.fail("Request failed");
3051
+ console.error(chalk7.red(JSON.stringify(data)));
3052
+ process.exit(1);
3053
+ }
3054
+ spinner2.succeed("OK");
3055
+ console.log(JSON.stringify(data, null, 2));
3056
+ } catch (e) {
3057
+ spinner2.fail("Request failed");
3058
+ console.error(chalk7.red(e instanceof Error ? e.message : String(e)));
3059
+ process.exit(1);
3060
+ }
3061
+ })
3062
+ ).addCommand(
3063
+ new Command("update").description("Update organization (name, metadata)").argument("<orgId>", "Organization id or slug").option("-n, --name <name>", "New display name").option("-m, --metadata <json>", "Metadata JSON object").action(
3064
+ async (orgId, options, command) => {
3065
+ const { url, timeout } = getGlobalOpts(command);
3066
+ const keypairPath = getKeypairPath(command);
3067
+ const spinner2 = ora7("Updating organization...").start();
3068
+ try {
3069
+ const kp = loadKeypair({ keypairPath });
3070
+ const pathname = `/api/v2/orgs/${encodeURIComponent(orgId)}`;
3071
+ const body = {};
3072
+ if (options.name !== void 0) body.name = options.name;
3073
+ if (options.metadata !== void 0) {
3074
+ try {
3075
+ body.metadata = JSON.parse(options.metadata);
3076
+ } catch {
3077
+ spinner2.fail("--metadata must be valid JSON");
3078
+ process.exit(1);
3079
+ }
3080
+ }
3081
+ const headers = await getSignedHeaders("PATCH", pathname, body, kp);
3082
+ const base = url.replace(/\/$/, "");
3083
+ const { data, status } = await fetchJson(`${base}${pathname}`, {
3084
+ method: "PATCH",
3085
+ body: Object.keys(body).length > 0 ? JSON.stringify(body) : void 0,
3086
+ timeout,
3087
+ headers: { ...headers }
3088
+ });
3089
+ if (status >= 400) {
3090
+ spinner2.fail(
3091
+ data?.message || `HTTP ${status}`
3092
+ );
3093
+ console.error(chalk7.red(JSON.stringify(data)));
3094
+ process.exit(1);
3095
+ }
3096
+ spinner2.succeed("Updated");
3097
+ console.log(JSON.stringify(data, null, 2));
3098
+ } catch (e) {
3099
+ spinner2.fail("Failed");
3100
+ console.error(
3101
+ chalk7.red(e instanceof Error ? e.message : String(e))
3102
+ );
3103
+ process.exit(1);
3104
+ }
3105
+ }
3106
+ )
3107
+ ).addCommand(
3108
+ new Command("delete").description("Delete an organization and all its data (irreversible)").argument("<orgId>", "Organization id or slug").option("-y, --yes", "Skip confirmation prompt").action(
3109
+ async (orgId, options, command) => {
3110
+ const { url, timeout } = getGlobalOpts(command);
3111
+ const keypairPath = getKeypairPath(command);
3112
+ if (!options.yes) {
3113
+ const { createInterface } = await import('readline');
3114
+ const rl = createInterface({
3115
+ input: process.stdin,
3116
+ output: process.stdout
3117
+ });
3118
+ const confirmed = await new Promise((resolve) => {
3119
+ rl.question(
3120
+ chalk7.yellow(
3121
+ `Delete organization "${orgId}" and all its members/packages? This cannot be undone. Type "yes" to confirm: `
3122
+ ),
3123
+ (answer) => {
3124
+ rl.close();
3125
+ resolve(answer.trim().toLowerCase() === "yes");
3126
+ }
3127
+ );
3128
+ });
3129
+ if (!confirmed) {
3130
+ console.log(chalk7.gray("Aborted."));
3131
+ return;
3132
+ }
3133
+ }
3134
+ const spinner2 = ora7("Deleting organization...").start();
3135
+ try {
3136
+ const kp = loadKeypair({ keypairPath });
3137
+ const pathname = `/api/v2/orgs/${encodeURIComponent(orgId)}`;
3138
+ const headers = await getSignedHeaders(
3139
+ "DELETE",
3140
+ pathname,
3141
+ void 0,
3142
+ kp
3143
+ );
3144
+ const base = url.replace(/\/$/, "");
3145
+ const { data, status } = await fetchJson(`${base}${pathname}`, {
3146
+ method: "DELETE",
3147
+ timeout,
3148
+ headers: { ...headers }
3149
+ });
3150
+ if (status >= 400) {
3151
+ spinner2.fail(
3152
+ data?.message || `HTTP ${status}`
3153
+ );
3154
+ console.error(chalk7.red(JSON.stringify(data)));
3155
+ process.exit(1);
3156
+ }
3157
+ spinner2.succeed("Organization deleted");
3158
+ } catch (e) {
3159
+ spinner2.fail("Failed");
3160
+ console.error(
3161
+ chalk7.red(e instanceof Error ? e.message : String(e))
3162
+ );
3163
+ process.exit(1);
3164
+ }
3165
+ }
3166
+ )
3167
+ ).addCommand(
3168
+ new Command("members").description("List, add, or remove organization members").addCommand(
3169
+ new Command("list").description("List members of an org").argument("<orgId>", "Organization id or slug").action(async (orgId, _options, command) => {
3170
+ const { url, timeout } = getGlobalOpts(command);
3171
+ const base = url.replace(/\/$/, "");
3172
+ const pathname = `/api/v2/orgs/${encodeURIComponent(orgId)}/members`;
3173
+ const spinner2 = ora7("Fetching members...").start();
3174
+ try {
3175
+ const { data, status } = await fetchJson(`${base}${pathname}`, { method: "GET", timeout });
3176
+ if (status !== 200) {
3177
+ spinner2.fail("Failed");
3178
+ console.error(chalk7.red(JSON.stringify(data)));
3179
+ process.exit(1);
3180
+ }
3181
+ spinner2.succeed("OK");
3182
+ const members = data?.members ?? [];
3183
+ console.log(JSON.stringify(members, null, 2));
3184
+ } catch (e) {
3185
+ spinner2.fail("Request failed");
3186
+ console.error(
3187
+ chalk7.red(e instanceof Error ? e.message : String(e))
3188
+ );
3189
+ process.exit(1);
3190
+ }
3191
+ })
3192
+ ).addCommand(
3193
+ new Command("add").description("Add a member by pubkey").argument("<orgId>", "Organization id or slug").argument("<pubkey>", "Member public key").option("-r, --role <role>", "Role: member or admin", "member").action(
3194
+ async (orgId, pubkey, options, command) => {
3195
+ const { url, timeout } = getGlobalOpts(command);
3196
+ const keypairPath = getKeypairPath(command);
3197
+ const spinner2 = ora7("Adding member...").start();
3198
+ try {
3199
+ const kp = loadKeypair({ keypairPath });
3200
+ const pathname = `/api/v2/orgs/${encodeURIComponent(orgId)}/members`;
3201
+ const body = {
3202
+ pubkey: pubkey.trim(),
3203
+ role: options.role === "admin" ? "admin" : "member"
3204
+ };
3205
+ const headers = await getSignedHeaders(
3206
+ "POST",
3207
+ pathname,
3208
+ body,
3209
+ kp
3210
+ );
3211
+ const base = url.replace(/\/$/, "");
3212
+ const { data, status } = await fetchJson(`${base}${pathname}`, {
3213
+ method: "POST",
3214
+ body: JSON.stringify(body),
3215
+ timeout,
3216
+ headers: { ...headers }
3217
+ });
3218
+ if (status >= 400) {
3219
+ spinner2.fail(
3220
+ data?.message || `HTTP ${status}`
3221
+ );
3222
+ console.error(chalk7.red(JSON.stringify(data)));
3223
+ process.exit(1);
3224
+ }
3225
+ spinner2.succeed("Member added");
3226
+ } catch (e) {
3227
+ spinner2.fail("Failed");
3228
+ console.error(
3229
+ chalk7.red(e instanceof Error ? e.message : String(e))
3230
+ );
3231
+ process.exit(1);
3232
+ }
3233
+ }
3234
+ )
3235
+ ).addCommand(
3236
+ new Command("update").description("Update a member role (admin or member)").argument("<orgId>", "Organization id or slug").argument("<pubkey>", "Member public key").requiredOption("-r, --role <role>", "New role: admin or member").action(
3237
+ async (orgId, pubkey, options, command) => {
3238
+ const { url, timeout } = getGlobalOpts(command);
3239
+ const keypairPath = getKeypairPath(command);
3240
+ const role = options.role === "admin" ? "admin" : "member";
3241
+ const spinner2 = ora7("Updating member role...").start();
3242
+ try {
3243
+ const kp = loadKeypair({ keypairPath });
3244
+ const pathname = `/api/v2/orgs/${encodeURIComponent(orgId)}/members/${encodeURIComponent(pubkey.trim())}`;
3245
+ const body = { role };
3246
+ const headers = await getSignedHeaders(
3247
+ "PATCH",
3248
+ pathname,
3249
+ body,
3250
+ kp
3251
+ );
3252
+ const base = url.replace(/\/$/, "");
3253
+ const { data, status } = await fetchJson(`${base}${pathname}`, {
3254
+ method: "PATCH",
3255
+ body: JSON.stringify(body),
3256
+ timeout,
3257
+ headers: { ...headers }
3258
+ });
3259
+ if (status >= 400) {
3260
+ spinner2.fail(
3261
+ data?.message || `HTTP ${status}`
3262
+ );
3263
+ console.error(chalk7.red(JSON.stringify(data)));
3264
+ process.exit(1);
3265
+ }
3266
+ spinner2.succeed(`Role updated to "${role}"`);
3267
+ } catch (e) {
3268
+ spinner2.fail("Failed");
3269
+ console.error(
3270
+ chalk7.red(e instanceof Error ? e.message : String(e))
3271
+ );
3272
+ process.exit(1);
3273
+ }
3274
+ }
3275
+ )
3276
+ ).addCommand(
3277
+ new Command("remove").description("Remove a member by pubkey").argument("<orgId>", "Organization id or slug").argument("<pubkey>", "Member public key").action(
3278
+ async (orgId, pubkey, _options, command) => {
3279
+ const { url, timeout } = getGlobalOpts(command);
3280
+ const keypairPath = getKeypairPath(command);
3281
+ const spinner2 = ora7("Removing member...").start();
3282
+ try {
3283
+ const kp = loadKeypair({ keypairPath });
3284
+ const pathname = `/api/v2/orgs/${encodeURIComponent(orgId)}/members/${encodeURIComponent(pubkey.trim())}`;
3285
+ const headers = await getSignedHeaders(
3286
+ "DELETE",
3287
+ pathname,
3288
+ void 0,
3289
+ kp
3290
+ );
3291
+ const base = url.replace(/\/$/, "");
3292
+ const { data, status } = await fetchJson(`${base}${pathname}`, {
3293
+ method: "DELETE",
3294
+ timeout,
3295
+ headers: { ...headers }
3296
+ });
3297
+ if (status >= 400) {
3298
+ spinner2.fail(
3299
+ data?.message || `HTTP ${status}`
3300
+ );
3301
+ console.error(chalk7.red(JSON.stringify(data)));
3302
+ process.exit(1);
3303
+ }
3304
+ spinner2.succeed("Member removed");
3305
+ } catch (e) {
3306
+ spinner2.fail("Failed");
3307
+ console.error(
3308
+ chalk7.red(e instanceof Error ? e.message : String(e))
3309
+ );
3310
+ process.exit(1);
3311
+ }
3312
+ }
3313
+ )
3314
+ )
3315
+ ).addCommand(
3316
+ new Command("packages").description("Link or unlink packages to the organization").addCommand(
3317
+ new Command("link").description("Link a package to the organization").argument("<orgId>", "Organization id or slug").argument("<package>", "Package name").action(
3318
+ async (orgId, pkg, _options, command) => {
3319
+ const { url, timeout } = getGlobalOpts(command);
3320
+ const keypairPath = getKeypairPath(command);
3321
+ const spinner2 = ora7("Linking package...").start();
3322
+ try {
3323
+ const kp = loadKeypair({ keypairPath });
3324
+ const pathname = `/api/v2/orgs/${encodeURIComponent(orgId)}/packages`;
3325
+ const body = { package: pkg.trim() };
3326
+ const headers = await getSignedHeaders(
3327
+ "POST",
3328
+ pathname,
3329
+ body,
3330
+ kp
3331
+ );
3332
+ const base = url.replace(/\/$/, "");
3333
+ const { data, status } = await fetchJson(`${base}${pathname}`, {
3334
+ method: "POST",
3335
+ body: JSON.stringify(body),
3336
+ timeout,
3337
+ headers: { ...headers }
3338
+ });
3339
+ if (status >= 400) {
3340
+ spinner2.fail(
3341
+ data?.message || `HTTP ${status}`
3342
+ );
3343
+ console.error(chalk7.red(JSON.stringify(data)));
3344
+ process.exit(1);
3345
+ }
3346
+ spinner2.succeed("Package linked");
3347
+ } catch (e) {
3348
+ spinner2.fail("Failed");
3349
+ console.error(
3350
+ chalk7.red(e instanceof Error ? e.message : String(e))
3351
+ );
3352
+ process.exit(1);
3353
+ }
3354
+ }
3355
+ )
3356
+ ).addCommand(
3357
+ new Command("unlink").description("Unlink a package from the organization").argument("<orgId>", "Organization id or slug").argument("<package>", "Package name").action(
3358
+ async (orgId, pkg, _options, command) => {
3359
+ const { url, timeout } = getGlobalOpts(command);
3360
+ const keypairPath = getKeypairPath(command);
3361
+ const spinner2 = ora7("Unlinking package...").start();
3362
+ try {
3363
+ const kp = loadKeypair({ keypairPath });
3364
+ const pathname = `/api/v2/orgs/${encodeURIComponent(orgId)}/packages/${encodeURIComponent(pkg.trim())}`;
3365
+ const headers = await getSignedHeaders(
3366
+ "DELETE",
3367
+ pathname,
3368
+ void 0,
3369
+ kp
3370
+ );
3371
+ const base = url.replace(/\/$/, "");
3372
+ const { data, status } = await fetchJson(`${base}${pathname}`, {
3373
+ method: "DELETE",
3374
+ timeout,
3375
+ headers: { ...headers }
3376
+ });
3377
+ if (status >= 400) {
3378
+ spinner2.fail(
3379
+ data?.message || `HTTP ${status}`
3380
+ );
3381
+ console.error(chalk7.red(JSON.stringify(data)));
3382
+ process.exit(1);
3383
+ }
3384
+ spinner2.succeed("Package unlinked");
3385
+ } catch (e) {
3386
+ spinner2.fail("Failed");
3387
+ console.error(
3388
+ chalk7.red(e instanceof Error ? e.message : String(e))
3389
+ );
3390
+ process.exit(1);
3391
+ }
3392
+ }
3393
+ )
3394
+ )
3395
+ );
2814
3396
 
2815
3397
  // src/index.ts
2816
3398
  var require2 = createRequire(import.meta.url);
@@ -2831,7 +3413,7 @@ Examples:
2831
3413
  For more information, visit: https://github.com/calimero-network/app-registry
2832
3414
  `
2833
3415
  );
2834
- program.option("-u, --url <url>", "Registry API URL", "http://localhost:8082");
3416
+ program.option("-u, --url <url>", "Registry API URL (overrides saved config)");
2835
3417
  program.option(
2836
3418
  "-t, --timeout <timeout>",
2837
3419
  "Request timeout in milliseconds",
@@ -2846,14 +3428,18 @@ program.addCommand(ipfsCommand);
2846
3428
  program.addCommand(localCommand);
2847
3429
  program.addCommand(bundleCommand);
2848
3430
  program.addCommand(configCommand);
3431
+ program.addCommand(orgCommand);
2849
3432
  program.exitOverride();
2850
3433
  try {
2851
3434
  program.parse();
2852
3435
  } catch (err) {
3436
+ if (err && typeof err === "object" && "exitCode" in err) {
3437
+ process.exit(err.exitCode ?? 0);
3438
+ }
2853
3439
  if (err instanceof Error) {
2854
- console.error(chalk6.red("Error:"), err.message);
3440
+ console.error(chalk7.red("Error:"), err.message);
2855
3441
  } else {
2856
- console.error(chalk6.red("Unknown error occurred"));
3442
+ console.error(chalk7.red("Unknown error occurred"));
2857
3443
  }
2858
3444
  process.exit(1);
2859
3445
  }