@calimero-network/registry-cli 1.1.0 → 1.3.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
@@ -10,6 +10,8 @@ import os from 'os';
10
10
  import crypto from 'crypto';
11
11
  import fastify from 'fastify';
12
12
  import cors from '@fastify/cors';
13
+ import { Buffer } from 'buffer';
14
+ import fetch from 'node-fetch';
13
15
 
14
16
  var LocalConfig = class {
15
17
  constructor() {
@@ -227,7 +229,7 @@ var LocalDataStore = class {
227
229
  getAppVersions(appId) {
228
230
  const versions = [];
229
231
  for (const [key, manifest] of this.data.manifests.entries()) {
230
- if (manifest.app.id === appId) {
232
+ if (key.startsWith(`${appId}/`)) {
231
233
  const semver = key.split("/").pop();
232
234
  versions.push({
233
235
  semver,
@@ -243,12 +245,8 @@ var LocalDataStore = class {
243
245
  }
244
246
  // Manifest management
245
247
  getManifest(appId, semver) {
246
- for (const [, manifest] of this.data.manifests.entries()) {
247
- if (manifest.app.id === appId && manifest.version.semver === semver) {
248
- return manifest;
249
- }
250
- }
251
- return void 0;
248
+ const manifestKey = `${appId}/${semver}`;
249
+ return this.data.manifests.get(manifestKey);
252
250
  }
253
251
  setManifest(manifestKey, manifest) {
254
252
  this.data.manifests.set(manifestKey, manifest);
@@ -370,7 +368,7 @@ var LocalDataStore = class {
370
368
  this.setApp(appKey, app);
371
369
  });
372
370
  sampleManifests.forEach((manifest) => {
373
- const manifestKey = `${manifest.app.developer_pubkey}/${manifest.app.name}/${manifest.version.semver}`;
371
+ const manifestKey = `${manifest.app.app_id}/${manifest.version.semver}`;
374
372
  this.setManifest(manifestKey, manifest);
375
373
  });
376
374
  this.saveData();
@@ -458,7 +456,7 @@ var LocalArtifactServer = class {
458
456
  const filename = path.basename(artifact.path);
459
457
  updatedArtifact.mirrors = [
460
458
  this.getArtifactUrl(
461
- manifest.app.id || manifest.app.name,
459
+ manifest.app.id || manifest.app.name?.replace(/\s+/g, "-").toLowerCase(),
462
460
  manifest.version.semver,
463
461
  filename
464
462
  )
@@ -582,9 +580,9 @@ var LocalRegistryClient = class {
582
580
  throw new Error("Invalid manifest structure");
583
581
  }
584
582
  const processedManifest = await this.processManifestArtifacts(manifest);
585
- const manifestKey = `${manifest.app.developer_pubkey}/${manifest.app.name}/${manifest.version.semver}`;
583
+ const manifestKey = `${manifest.app.app_id}/${manifest.version.semver}`;
586
584
  this.dataStore.setManifest(manifestKey, processedManifest);
587
- const appKey = `${manifest.app.developer_pubkey}/${manifest.app.name}`;
585
+ const appKey = manifest.app.app_id;
588
586
  const appSummary = {
589
587
  name: manifest.app.name,
590
588
  developer_pubkey: manifest.app.developer_pubkey,
@@ -612,7 +610,7 @@ var LocalRegistryClient = class {
612
610
  const processedArtifact = { ...artifact };
613
611
  if (artifact.path && fs3.existsSync(artifact.path)) {
614
612
  const filename = path.basename(artifact.path);
615
- const appId = manifest.app.id || manifest.app.name;
613
+ const appId = manifest.app.id || manifest.app.name?.replace(/\s+/g, "-").toLowerCase();
616
614
  try {
617
615
  await this.artifactServer.copyArtifactToLocal(
618
616
  artifact.path,
@@ -1076,35 +1074,65 @@ var LocalRegistryServer = class {
1076
1074
  });
1077
1075
  this.server.get("/apps", async (request) => {
1078
1076
  const query = request.query;
1077
+ if (query.id && query.versions === "true") {
1078
+ return {
1079
+ id: query.id,
1080
+ versions: this.dataStore.getAppVersions(query.id)
1081
+ };
1082
+ }
1083
+ if (query.id && query.version) {
1084
+ const manifest = this.dataStore.getManifest(query.id, query.version);
1085
+ if (!manifest) {
1086
+ return {
1087
+ statusCode: 404,
1088
+ error: "Not Found",
1089
+ message: "Manifest not found"
1090
+ };
1091
+ }
1092
+ return this.artifactServer.updateManifestArtifacts(manifest);
1093
+ }
1079
1094
  return this.dataStore.getApps(query);
1080
1095
  });
1081
1096
  this.server.get("/apps/:appId", async (request) => {
1082
1097
  const { appId } = request.params;
1083
- return this.dataStore.getAppVersions(appId);
1098
+ const versions = this.dataStore.getAppVersions(appId);
1099
+ return {
1100
+ id: appId,
1101
+ versions
1102
+ };
1084
1103
  });
1085
1104
  this.server.get("/apps/:appId/:semver", async (request) => {
1086
1105
  const { appId, semver } = request.params;
1087
1106
  const manifest = this.dataStore.getManifest(appId, semver);
1088
1107
  if (!manifest) {
1089
- throw this.server.httpErrors.notFound("Manifest not found");
1108
+ return {
1109
+ statusCode: 404,
1110
+ error: "Not Found",
1111
+ message: "Manifest not found"
1112
+ };
1090
1113
  }
1091
1114
  return this.artifactServer.updateManifestArtifacts(manifest);
1092
1115
  });
1093
1116
  this.server.post("/apps", async (request) => {
1094
1117
  const manifest = request.body;
1095
1118
  if (!this.validateManifest(manifest)) {
1096
- throw this.server.httpErrors.badRequest("Invalid manifest structure");
1119
+ return {
1120
+ statusCode: 400,
1121
+ error: "Bad Request",
1122
+ message: "Invalid manifest structure"
1123
+ };
1097
1124
  }
1098
1125
  const processedManifest = await this.processManifestArtifacts(manifest);
1099
- const manifestKey = `${manifest.app.developer_pubkey}/${manifest.app.name}/${manifest.version.semver}`;
1126
+ const manifestKey = `${manifest.app.app_id}/${manifest.version.semver}`;
1100
1127
  this.dataStore.setManifest(manifestKey, processedManifest);
1101
- const appKey = `${manifest.app.developer_pubkey}/${manifest.app.name}`;
1128
+ const appKey = manifest.app.app_id;
1102
1129
  const appSummary = {
1103
1130
  name: manifest.app.name,
1104
1131
  developer_pubkey: manifest.app.developer_pubkey,
1105
1132
  latest_version: manifest.version.semver,
1106
1133
  latest_cid: manifest.artifacts[0]?.cid || "",
1107
- alias: manifest.app.alias
1134
+ alias: manifest.app.name
1135
+ // Use name as alias
1108
1136
  };
1109
1137
  this.dataStore.setApp(appKey, appSummary);
1110
1138
  return {
@@ -1130,7 +1158,11 @@ var LocalRegistryServer = class {
1130
1158
  );
1131
1159
  return artifactData;
1132
1160
  } catch {
1133
- throw this.server.httpErrors.notFound("Artifact not found");
1161
+ return {
1162
+ statusCode: 404,
1163
+ error: "Not Found",
1164
+ message: "Artifact not found"
1165
+ };
1134
1166
  }
1135
1167
  }
1136
1168
  );
@@ -1141,7 +1173,11 @@ var LocalRegistryServer = class {
1141
1173
  reply.header("Content-Type", "application/octet-stream");
1142
1174
  return artifactData;
1143
1175
  } catch {
1144
- throw this.server.httpErrors.notFound("Artifact not found");
1176
+ return {
1177
+ statusCode: 404,
1178
+ error: "Not Found",
1179
+ message: "Artifact not found"
1180
+ };
1145
1181
  }
1146
1182
  });
1147
1183
  this.server.get("/local/status", async () => {
@@ -1165,41 +1201,151 @@ var LocalRegistryServer = class {
1165
1201
  await this.seed();
1166
1202
  return { message: "Sample data seeded successfully" };
1167
1203
  });
1204
+ this.server.post("/v1/apps", async (request, reply) => {
1205
+ const manifest = request.body;
1206
+ if (!manifest.manifest_version || !manifest.id || !manifest.name || !manifest.version) {
1207
+ return reply.code(400).send({
1208
+ error: "invalid_schema",
1209
+ details: "Missing required fields"
1210
+ });
1211
+ }
1212
+ try {
1213
+ const processedManifest = await this.processManifestArtifacts(manifest);
1214
+ const manifestKey = `${manifest.id}/${manifest.version}`;
1215
+ this.dataStore.setManifest(manifestKey, processedManifest);
1216
+ const appKey = manifest.id;
1217
+ const appSummary = {
1218
+ id: manifest.id,
1219
+ name: manifest.name,
1220
+ developer_pubkey: "local-dev-key",
1221
+ latest_version: manifest.version,
1222
+ latest_cid: manifest.artifact?.digest || ""
1223
+ };
1224
+ this.dataStore.setApp(appKey, appSummary);
1225
+ return reply.code(201).send({
1226
+ id: manifest.id,
1227
+ version: manifest.version,
1228
+ canonical_uri: `/v1/apps/${manifest.id}/${manifest.version}`
1229
+ });
1230
+ } catch {
1231
+ return reply.code(409).send({
1232
+ error: "already_exists",
1233
+ details: `${manifest.id}@${manifest.version}`
1234
+ });
1235
+ }
1236
+ });
1237
+ this.server.get("/v1/apps/:id", async (request, reply) => {
1238
+ const { id } = request.params;
1239
+ const versions = this.dataStore.getAppVersions(id);
1240
+ if (!versions || versions.length === 0) {
1241
+ return reply.code(404).send({ error: "not_found", message: "App not found" });
1242
+ }
1243
+ return {
1244
+ id,
1245
+ versions: versions.map((v) => v.semver)
1246
+ };
1247
+ });
1248
+ this.server.get("/v1/apps/:id/:version", async (request, reply) => {
1249
+ const { id, version } = request.params;
1250
+ const { canonical } = request.query;
1251
+ const oldManifest = this.dataStore.getManifest(id, version);
1252
+ if (!oldManifest) {
1253
+ return reply.code(404).send({ error: "not_found", message: "Manifest not found" });
1254
+ }
1255
+ const v1Manifest = {
1256
+ manifest_version: oldManifest.manifest_version,
1257
+ id: oldManifest.app.app_id,
1258
+ name: oldManifest.app.name,
1259
+ version: oldManifest.version.semver,
1260
+ chains: oldManifest.supported_chains,
1261
+ artifact: oldManifest.artifacts[0] ? {
1262
+ type: oldManifest.artifacts[0].type,
1263
+ target: oldManifest.artifacts[0].target,
1264
+ digest: oldManifest.artifacts[0].cid || `sha256:${"0".repeat(64)}`,
1265
+ uri: oldManifest.artifacts[0].path || oldManifest.artifacts[0].mirrors?.[0] || "https://example.com/artifact"
1266
+ } : {
1267
+ type: "wasm",
1268
+ target: "node",
1269
+ digest: `sha256:${"0".repeat(64)}`,
1270
+ uri: "https://example.com/artifact"
1271
+ },
1272
+ _warnings: []
1273
+ };
1274
+ if (canonical === "true") {
1275
+ const canonicalJCS = JSON.stringify(
1276
+ v1Manifest,
1277
+ Object.keys(v1Manifest).sort()
1278
+ );
1279
+ return {
1280
+ canonical_jcs: Buffer.from(canonicalJCS, "utf8").toString("base64")
1281
+ };
1282
+ }
1283
+ return v1Manifest;
1284
+ });
1285
+ this.server.get("/v1/search", async (request, reply) => {
1286
+ const { q } = request.query;
1287
+ if (!q) {
1288
+ return reply.code(400).send({
1289
+ error: "bad_request",
1290
+ message: 'Query parameter "q" is required'
1291
+ });
1292
+ }
1293
+ const apps = this.dataStore.getApps({});
1294
+ const results = apps.filter(
1295
+ (app) => app.name.toLowerCase().includes(q.toLowerCase()) || app.id?.toLowerCase().includes(q.toLowerCase())
1296
+ );
1297
+ return results.map((app) => ({
1298
+ id: app.id || app.name,
1299
+ versions: [app.latest_version]
1300
+ }));
1301
+ });
1302
+ this.server.post("/v1/resolve", async (request, reply) => {
1303
+ const { root } = request.body;
1304
+ if (!root || !root.id || !root.version) {
1305
+ return reply.code(400).send({
1306
+ error: "bad_request",
1307
+ message: "Root app ID and version are required"
1308
+ });
1309
+ }
1310
+ return {
1311
+ plan: [{ action: "install", id: root.id, version: root.version }],
1312
+ satisfies: [],
1313
+ missing: []
1314
+ };
1315
+ });
1168
1316
  }
1169
1317
  validateManifest(manifest) {
1170
- return !!(manifest.manifest_version && manifest.app && manifest.app.name && manifest.app.developer_pubkey && manifest.version && manifest.version.semver && manifest.artifacts && manifest.artifacts.length > 0);
1318
+ return !!(manifest.manifest_version && manifest.app && manifest.app.app_id && manifest.app.name && manifest.app.developer_pubkey && manifest.version && manifest.version.semver && manifest.artifacts && manifest.artifacts.length > 0);
1171
1319
  }
1172
1320
  async processManifestArtifacts(manifest) {
1173
1321
  const processedManifest = { ...manifest };
1174
- if (processedManifest.artifacts) {
1175
- processedManifest.artifacts = await Promise.all(
1176
- processedManifest.artifacts.map(async (artifact) => {
1177
- const processedArtifact = { ...artifact };
1178
- if (artifact.path && fs3.existsSync(artifact.path)) {
1179
- const filename = path.basename(artifact.path);
1180
- const appId = manifest.app.id || manifest.app.name;
1181
- try {
1182
- await this.artifactServer.copyArtifactToLocal(
1183
- artifact.path,
1322
+ if (manifest.artifact && manifest.artifact.uri) {
1323
+ const artifact = manifest.artifact;
1324
+ if (artifact.uri.startsWith("file://")) {
1325
+ const filePath = artifact.uri.replace("file://", "");
1326
+ if (fs3.existsSync(filePath)) {
1327
+ const filename = path.basename(filePath);
1328
+ const appId = manifest.id;
1329
+ try {
1330
+ await this.artifactServer.copyArtifactToLocal(
1331
+ filePath,
1332
+ appId,
1333
+ manifest.version,
1334
+ filename
1335
+ );
1336
+ processedManifest.artifact = {
1337
+ ...artifact,
1338
+ uri: this.artifactServer.getArtifactUrl(
1184
1339
  appId,
1185
- manifest.version.semver,
1340
+ manifest.version,
1186
1341
  filename
1187
- );
1188
- processedArtifact.mirrors = [
1189
- this.artifactServer.getArtifactUrl(
1190
- appId,
1191
- manifest.version.semver,
1192
- filename
1193
- )
1194
- ];
1195
- delete processedArtifact.path;
1196
- } catch (error) {
1197
- console.warn(`Failed to copy artifact ${artifact.path}:`, error);
1198
- }
1342
+ )
1343
+ };
1344
+ } catch (error) {
1345
+ console.warn(`Failed to copy artifact ${filePath}:`, error);
1199
1346
  }
1200
- return processedArtifact;
1201
- })
1202
- );
1347
+ }
1348
+ }
1203
1349
  }
1204
1350
  return processedManifest;
1205
1351
  }
@@ -1384,6 +1530,265 @@ localCommand.addCommand(
1384
1530
  }
1385
1531
  })
1386
1532
  );
1533
+ var v1Command = new Command("v1").description("V1 API commands for Calimero SSApp Registry").addCommand(createPushCommand()).addCommand(createGetCommand()).addCommand(createListCommand()).addCommand(createResolveCommand()).addCommand(createVerifyCommand());
1534
+ function createPushCommand() {
1535
+ return new Command("push").description("Submit a v1 manifest to the registry").argument("<manifest-file>", "Path to manifest JSON file").option("--local", "Use local registry").action(
1536
+ async (manifestFile, options = {}, command) => {
1537
+ try {
1538
+ const globalOpts = command.parent?.parent?.opts();
1539
+ const useLocal = globalOpts?.local || options.local || false;
1540
+ if (!fs3.existsSync(manifestFile)) {
1541
+ console.error(`\u274C Manifest file not found: ${manifestFile}`);
1542
+ process.exit(1);
1543
+ }
1544
+ const manifestContent = fs3.readFileSync(manifestFile, "utf8");
1545
+ const manifest = JSON.parse(manifestContent);
1546
+ if (manifest.manifest_version !== "1.0") {
1547
+ console.error('\u274C Invalid manifest version. Must be "1.0"');
1548
+ process.exit(1);
1549
+ }
1550
+ if (!manifest.id || !manifest.name || !manifest.version) {
1551
+ console.error("\u274C Missing required fields: id, name, version");
1552
+ process.exit(1);
1553
+ }
1554
+ const baseUrl = useLocal ? "http://localhost:8082" : "http://localhost:8080";
1555
+ console.log(
1556
+ `\u{1F4E4} Submitting manifest: ${manifest.id}@${manifest.version}`
1557
+ );
1558
+ console.log(` Name: ${manifest.name}`);
1559
+ console.log(` Chains: ${manifest.chains?.join(", ")}`);
1560
+ console.log(
1561
+ ` Provides: ${manifest.provides?.join(", ") || "none"}`
1562
+ );
1563
+ console.log(
1564
+ ` Requires: ${manifest.requires?.join(", ") || "none"}`
1565
+ );
1566
+ const response = await fetch(`${baseUrl}/v1/apps`, {
1567
+ method: "POST",
1568
+ headers: { "Content-Type": "application/json" },
1569
+ body: JSON.stringify(manifest)
1570
+ });
1571
+ if (!response.ok) {
1572
+ const error = await response.json();
1573
+ throw new Error(`${error.error}: ${error.details}`);
1574
+ }
1575
+ const result = await response.json();
1576
+ console.log("\u2705 Manifest submitted successfully!");
1577
+ console.log(` ID: ${result.id}`);
1578
+ console.log(` Version: ${result.version}`);
1579
+ console.log(` URI: ${result.canonical_uri}`);
1580
+ } catch (error) {
1581
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
1582
+ console.error("\u274C Failed to submit manifest:", errorMessage);
1583
+ process.exit(1);
1584
+ }
1585
+ }
1586
+ );
1587
+ }
1588
+ function createGetCommand() {
1589
+ return new Command("get").description("Get manifest from registry").argument("<app-id>", "Application ID").argument("[version]", "Specific version (optional)").option("--local", "Use local registry").option("--canonical", "Return canonical JCS format").action(
1590
+ async (appId, version, options = {}, command) => {
1591
+ try {
1592
+ const globalOpts = command.parent?.parent?.opts();
1593
+ const useLocal = globalOpts?.local || options.local || false;
1594
+ const baseUrl = useLocal ? "http://localhost:8082" : "http://localhost:8080";
1595
+ if (version) {
1596
+ console.log(`\u{1F4E5} Getting manifest: ${appId}@${version}`);
1597
+ const url = options.canonical ? `/v1/apps/${appId}/${version}?canonical=true` : `/v1/apps/${appId}/${version}`;
1598
+ const response = await fetch(`${baseUrl}${url}`);
1599
+ if (!response.ok) {
1600
+ if (response.status === 404) {
1601
+ console.error(`\u274C Manifest not found: ${appId}@${version}`);
1602
+ } else {
1603
+ console.error(
1604
+ `\u274C Error: ${response.status} ${response.statusText}`
1605
+ );
1606
+ }
1607
+ process.exit(1);
1608
+ }
1609
+ const manifest = await response.json();
1610
+ console.log(JSON.stringify(manifest, null, 2));
1611
+ } else {
1612
+ console.log(`\u{1F4E5} Getting versions for: ${appId}`);
1613
+ const response = await fetch(`${baseUrl}/v1/apps/${appId}`);
1614
+ if (!response.ok) {
1615
+ if (response.status === 404) {
1616
+ console.error(`\u274C App not found: ${appId}`);
1617
+ } else {
1618
+ console.error(
1619
+ `\u274C Error: ${response.status} ${response.statusText}`
1620
+ );
1621
+ }
1622
+ process.exit(1);
1623
+ }
1624
+ const result = await response.json();
1625
+ console.log(`\u{1F4F1} App: ${result.id}`);
1626
+ console.log(`\u{1F4CB} Versions: ${result.versions.join(", ")}`);
1627
+ }
1628
+ } catch (error) {
1629
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
1630
+ console.error("\u274C Failed to get manifest:", errorMessage);
1631
+ process.exit(1);
1632
+ }
1633
+ }
1634
+ );
1635
+ }
1636
+ function createListCommand() {
1637
+ return new Command("ls").description("List applications in registry").option("--local", "Use local registry").option("--search <query>", "Search query").action(
1638
+ async (options = {}, command) => {
1639
+ try {
1640
+ const globalOpts = command.parent?.parent?.opts();
1641
+ const useLocal = globalOpts?.local || options.local || false;
1642
+ const baseUrl = useLocal ? "http://localhost:8082" : "http://localhost:8080";
1643
+ if (options.search) {
1644
+ console.log(`\u{1F50D} Searching for: ${options.search}`);
1645
+ const response = await fetch(
1646
+ `${baseUrl}/v1/search?q=${encodeURIComponent(options.search)}`
1647
+ );
1648
+ if (!response.ok) {
1649
+ console.error(
1650
+ `\u274C Error: ${response.status} ${response.statusText}`
1651
+ );
1652
+ process.exit(1);
1653
+ }
1654
+ const results = await response.json();
1655
+ if (results.length === 0) {
1656
+ console.log("No results found");
1657
+ return;
1658
+ }
1659
+ console.log(`Found ${results.length} result(s):`);
1660
+ results.forEach((result) => {
1661
+ console.log(
1662
+ ` \u{1F4F1} ${result.id}@${result.versions?.[0] || "unknown"}`
1663
+ );
1664
+ if (result.provides?.length > 0) {
1665
+ console.log(` Provides: ${result.provides.join(", ")}`);
1666
+ }
1667
+ if (result.requires?.length > 0) {
1668
+ console.log(` Requires: ${result.requires.join(", ")}`);
1669
+ }
1670
+ });
1671
+ } else {
1672
+ console.log("\u{1F4CB} Listing all applications...");
1673
+ console.log(
1674
+ "Note: Use --search <query> to search for specific apps"
1675
+ );
1676
+ }
1677
+ } catch (error) {
1678
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
1679
+ console.error("\u274C Failed to list applications:", errorMessage);
1680
+ process.exit(1);
1681
+ }
1682
+ }
1683
+ );
1684
+ }
1685
+ function createResolveCommand() {
1686
+ return new Command("resolve").description("Resolve dependencies for an application").argument("<app-id>", "Application ID").argument("<version>", "Application version").option("--local", "Use local registry").action(
1687
+ async (appId, version, options = {}, command) => {
1688
+ try {
1689
+ const globalOpts = command.parent?.parent?.opts();
1690
+ const useLocal = globalOpts?.local || options.local || false;
1691
+ const baseUrl = useLocal ? "http://localhost:8082" : "http://localhost:8080";
1692
+ console.log(`\u{1F50D} Resolving dependencies for: ${appId}@${version}`);
1693
+ const resolveRequest = {
1694
+ root: { id: appId, version },
1695
+ installed: []
1696
+ // Could be extended to support pre-installed apps
1697
+ };
1698
+ const response = await fetch(`${baseUrl}/v1/resolve`, {
1699
+ method: "POST",
1700
+ headers: { "Content-Type": "application/json" },
1701
+ body: JSON.stringify(resolveRequest)
1702
+ });
1703
+ if (!response.ok) {
1704
+ const error = await response.json();
1705
+ console.error(`\u274C Resolution failed: ${error.error}`);
1706
+ console.error(` Details: ${error.details}`);
1707
+ process.exit(1);
1708
+ }
1709
+ const result = await response.json();
1710
+ console.log("\u2705 Dependencies resolved successfully!");
1711
+ console.log(`\u{1F4CB} Installation plan:`);
1712
+ result.plan.forEach(
1713
+ (item) => {
1714
+ console.log(` ${item.action}: ${item.id}@${item.version}`);
1715
+ }
1716
+ );
1717
+ if (result.satisfies?.length > 0) {
1718
+ console.log(`\u2705 Satisfies: ${result.satisfies.join(", ")}`);
1719
+ }
1720
+ if (result.missing?.length > 0) {
1721
+ console.log(`\u274C Missing: ${result.missing.join(", ")}`);
1722
+ }
1723
+ } catch (error) {
1724
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
1725
+ console.error("\u274C Failed to resolve dependencies:", errorMessage);
1726
+ process.exit(1);
1727
+ }
1728
+ }
1729
+ );
1730
+ }
1731
+ function createVerifyCommand() {
1732
+ return new Command("verify").description("Verify manifest signature and integrity").argument("<manifest-file>", "Path to manifest JSON file").action(async (manifestFile) => {
1733
+ try {
1734
+ if (!fs3.existsSync(manifestFile)) {
1735
+ console.error(`\u274C Manifest file not found: ${manifestFile}`);
1736
+ process.exit(1);
1737
+ }
1738
+ const manifestContent = fs3.readFileSync(manifestFile, "utf8");
1739
+ const manifest = JSON.parse(manifestContent);
1740
+ console.log(
1741
+ `\u{1F50D} Verifying manifest: ${manifest.id}@${manifest.version}`
1742
+ );
1743
+ if (manifest.manifest_version !== "1.0") {
1744
+ console.error("\u274C Invalid manifest version");
1745
+ process.exit(1);
1746
+ }
1747
+ const requiredFields = ["id", "name", "version", "chains", "artifact"];
1748
+ const missingFields = requiredFields.filter(
1749
+ (field) => !manifest[field]
1750
+ );
1751
+ if (missingFields.length > 0) {
1752
+ console.error(
1753
+ `\u274C Missing required fields: ${missingFields.join(", ")}`
1754
+ );
1755
+ process.exit(1);
1756
+ }
1757
+ if (manifest.artifact.type !== "wasm" || manifest.artifact.target !== "node") {
1758
+ console.error("\u274C Invalid artifact type or target");
1759
+ process.exit(1);
1760
+ }
1761
+ if (!manifest.artifact.digest.match(/^sha256:[0-9a-f]{64}$/)) {
1762
+ console.error("\u274C Invalid artifact digest format");
1763
+ process.exit(1);
1764
+ }
1765
+ if (!manifest.artifact.uri.match(/^(https:\/\/|ipfs:\/\/)/)) {
1766
+ console.error("\u274C Invalid artifact URI format");
1767
+ process.exit(1);
1768
+ }
1769
+ if (manifest.signature) {
1770
+ console.log("\u{1F510} Verifying signature...");
1771
+ console.log("\u26A0\uFE0F Signature verification not implemented in CLI yet");
1772
+ }
1773
+ console.log("\u2705 Manifest verification passed!");
1774
+ console.log(` ID: ${manifest.id}`);
1775
+ console.log(` Name: ${manifest.name}`);
1776
+ console.log(` Version: ${manifest.version}`);
1777
+ console.log(` Chains: ${manifest.chains.join(", ")}`);
1778
+ console.log(` Artifact: ${manifest.artifact.uri}`);
1779
+ if (manifest.provides?.length > 0) {
1780
+ console.log(` Provides: ${manifest.provides.join(", ")}`);
1781
+ }
1782
+ if (manifest.requires?.length > 0) {
1783
+ console.log(` Requires: ${manifest.requires.join(", ")}`);
1784
+ }
1785
+ } catch (error) {
1786
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
1787
+ console.error("\u274C Failed to verify manifest:", errorMessage);
1788
+ process.exit(1);
1789
+ }
1790
+ });
1791
+ }
1387
1792
 
1388
1793
  // src/index.ts
1389
1794
  var program = new Command();
@@ -1403,6 +1808,7 @@ program.addCommand(attestationsCommand);
1403
1808
  program.addCommand(healthCommand);
1404
1809
  program.addCommand(ipfsCommand);
1405
1810
  program.addCommand(localCommand);
1811
+ program.addCommand(v1Command);
1406
1812
  program.exitOverride();
1407
1813
  try {
1408
1814
  program.parse();