@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 +756 -170
- package/dist/index.js.map +1 -1
- package/package.json +5 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
-
import
|
|
3
|
+
import chalk7 from 'chalk';
|
|
4
4
|
import { createRequire } from 'module';
|
|
5
|
-
import
|
|
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 =
|
|
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(
|
|
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(
|
|
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 =
|
|
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(
|
|
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 ?
|
|
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(
|
|
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 =
|
|
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(
|
|
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(
|
|
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 =
|
|
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(
|
|
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(
|
|
1155
|
+
console.log(chalk7.green(`
|
|
1153
1156
|
\u2705 ${result.message}`));
|
|
1154
1157
|
if (manifest.app?.name) {
|
|
1155
|
-
console.log(
|
|
1158
|
+
console.log(chalk7.blue(`
|
|
1156
1159
|
\u{1F4F1} App: ${manifest.app.name}`));
|
|
1157
1160
|
console.log(
|
|
1158
|
-
|
|
1161
|
+
chalk7.blue(`\u{1F464} Developer: ${manifest.app.developer_pubkey}`)
|
|
1159
1162
|
);
|
|
1160
|
-
console.log(
|
|
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(
|
|
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 =
|
|
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(
|
|
1183
|
-
console.log(
|
|
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(
|
|
1188
|
+
console.log(chalk7.green("Website:"), profile.website);
|
|
1186
1189
|
}
|
|
1187
1190
|
if (profile.proofs.length > 0) {
|
|
1188
|
-
console.log(
|
|
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 ?
|
|
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(
|
|
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(
|
|
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 =
|
|
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(
|
|
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(
|
|
1239
|
+
console.log(chalk7.green(`
|
|
1237
1240
|
\u2705 ${result.message}`));
|
|
1238
|
-
console.log(
|
|
1241
|
+
console.log(chalk7.blue(`
|
|
1239
1242
|
\u{1F464} Developer: ${displayName}`));
|
|
1240
|
-
console.log(
|
|
1243
|
+
console.log(chalk7.blue(`\u{1F511} Public Key: ${pubkey}`));
|
|
1241
1244
|
if (options.website) {
|
|
1242
|
-
console.log(
|
|
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(
|
|
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 =
|
|
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(
|
|
1271
|
-
console.log(
|
|
1272
|
-
console.log(
|
|
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(
|
|
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(
|
|
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 =
|
|
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(
|
|
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(
|
|
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) =>
|
|
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 =
|
|
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(
|
|
1602
|
+
console.log(chalk7.blue("\n\u{1F4F1} Local Registry Status:"));
|
|
1600
1603
|
console.log(
|
|
1601
|
-
|
|
1604
|
+
chalk7.green(
|
|
1602
1605
|
`\u2705 Server: http://${config.getHost()}:${config.getPort()}`
|
|
1603
1606
|
)
|
|
1604
1607
|
);
|
|
1605
1608
|
console.log(
|
|
1606
|
-
|
|
1609
|
+
chalk7.green(
|
|
1607
1610
|
`\u{1F310} Public URL: http://${config.getPublicHost()}:${config.getPort()}`
|
|
1608
1611
|
)
|
|
1609
1612
|
);
|
|
1610
|
-
console.log(
|
|
1613
|
+
console.log(chalk7.green(`\u{1F4C1} Data: ${config.getDataDir()}`));
|
|
1611
1614
|
console.log(
|
|
1612
|
-
|
|
1615
|
+
chalk7.green(
|
|
1613
1616
|
`\u{1F4CB} Health: http://${config.getHost()}:${config.getPort()}/healthz`
|
|
1614
1617
|
)
|
|
1615
1618
|
);
|
|
1616
1619
|
console.log(
|
|
1617
|
-
|
|
1620
|
+
chalk7.green(
|
|
1618
1621
|
`\u{1F4CA} Stats: http://${config.getHost()}:${config.getPort()}/stats`
|
|
1619
1622
|
)
|
|
1620
1623
|
);
|
|
1621
1624
|
console.log(
|
|
1622
|
-
|
|
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(
|
|
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 =
|
|
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(
|
|
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 =
|
|
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(
|
|
1662
|
-
console.log(
|
|
1663
|
-
console.log(
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
1691
|
+
chalk7.yellow("\u26A0\uFE0F This will delete all local registry data!")
|
|
1689
1692
|
);
|
|
1690
|
-
console.log(
|
|
1693
|
+
console.log(chalk7.yellow(" Use --force flag to confirm"));
|
|
1691
1694
|
return;
|
|
1692
1695
|
}
|
|
1693
|
-
const spinner2 =
|
|
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(
|
|
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(
|
|
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 =
|
|
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(
|
|
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(
|
|
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 =
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
1762
|
+
chalk7.green("\u2705 Local registry populated with sample applications")
|
|
1760
1763
|
);
|
|
1761
1764
|
console.log(
|
|
1762
|
-
|
|
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(
|
|
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
|
|
2105
|
-
if (!
|
|
2106
|
-
|
|
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
|
-
|
|
2126
|
-
path7.
|
|
2127
|
-
|
|
2111
|
+
fs9.writeFileSync(
|
|
2112
|
+
path7.join(outputDir, "manifest.json"),
|
|
2113
|
+
JSON.stringify(manifest, null, 2)
|
|
2128
2114
|
);
|
|
2129
|
-
fs9.
|
|
2130
|
-
|
|
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
|
-
|
|
2231
|
-
|
|
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
|
-
|
|
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(
|
|
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: (
|
|
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
|
-
|
|
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(
|
|
2684
|
+
console.log(chalk7.green("\u2705 API key set successfully"));
|
|
2682
2685
|
console.log(
|
|
2683
|
-
|
|
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(
|
|
2690
|
-
console.log(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
2730
|
-
console.log(
|
|
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(
|
|
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(
|
|
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 =
|
|
2755
|
+
urlSource = chalk7.yellow("(from CALIMERO_REGISTRY_URL env var)");
|
|
2753
2756
|
} else if (configFileExists) {
|
|
2754
|
-
urlSource =
|
|
2757
|
+
urlSource = chalk7.gray("(from config file)");
|
|
2755
2758
|
} else {
|
|
2756
|
-
urlSource =
|
|
2759
|
+
urlSource = chalk7.gray("(default)");
|
|
2757
2760
|
}
|
|
2758
|
-
console.log(` ${
|
|
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 =
|
|
2766
|
+
apiKeySource = chalk7.yellow("(from CALIMERO_API_KEY env var)");
|
|
2764
2767
|
} else if (configFileExists) {
|
|
2765
|
-
apiKeySource =
|
|
2768
|
+
apiKeySource = chalk7.gray("(from config file)");
|
|
2766
2769
|
} else {
|
|
2767
|
-
apiKeySource =
|
|
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(` ${
|
|
2773
|
+
console.log(` ${chalk7.bold("API Key:")} ${masked} ${apiKeySource}`);
|
|
2771
2774
|
} else {
|
|
2772
|
-
console.log(` ${
|
|
2775
|
+
console.log(` ${chalk7.bold("API Key:")} ${chalk7.gray("(not set)")}`);
|
|
2773
2776
|
}
|
|
2774
|
-
console.log(
|
|
2777
|
+
console.log(chalk7.blue(`
|
|
2775
2778
|
\u{1F4C1} Config file: ${configPath}`));
|
|
2776
2779
|
if (!configFileExists) {
|
|
2777
|
-
console.log(
|
|
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(
|
|
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
|
-
|
|
2795
|
+
chalk7.red("\u274C Configuration reset requires --force flag")
|
|
2793
2796
|
);
|
|
2794
2797
|
console.log(
|
|
2795
|
-
|
|
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(
|
|
2804
|
-
console.log(
|
|
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(
|
|
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
|
|
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(
|
|
3440
|
+
console.error(chalk7.red("Error:"), err.message);
|
|
2855
3441
|
} else {
|
|
2856
|
-
console.error(
|
|
3442
|
+
console.error(chalk7.red("Unknown error occurred"));
|
|
2857
3443
|
}
|
|
2858
3444
|
process.exit(1);
|
|
2859
3445
|
}
|