@calimero-network/registry-cli 1.16.0 → 1.17.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/README.md +74 -641
- package/dist/index.js +473 -1247
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,456 +1,185 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
-
import
|
|
3
|
+
import chalk4 from 'chalk';
|
|
4
4
|
import { createRequire } from 'module';
|
|
5
|
-
import
|
|
6
|
-
import { table } from 'table';
|
|
5
|
+
import ora4 from 'ora';
|
|
7
6
|
import axios from 'axios';
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import crypto2 from 'crypto';
|
|
7
|
+
import fs7, { existsSync, writeFileSync } from 'fs';
|
|
8
|
+
import path5 from 'path';
|
|
9
|
+
import os2 from 'os';
|
|
12
10
|
import fastify from 'fastify';
|
|
13
11
|
import cors from '@fastify/cors';
|
|
12
|
+
import crypto2 from 'crypto';
|
|
14
13
|
import * as tar from 'tar';
|
|
15
14
|
|
|
16
|
-
var
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
baseURL: config.baseURL || "http://localhost:8082",
|
|
44
|
-
timeout: config.timeout || 1e4,
|
|
45
|
-
headers: {
|
|
46
|
-
"Content-Type": "application/json",
|
|
47
|
-
...config.headers
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
this.api.interceptors.response.use(
|
|
51
|
-
(response) => response,
|
|
52
|
-
(error) => {
|
|
53
|
-
const apiError = {
|
|
54
|
-
message: error.response?.data?.message || error.message,
|
|
55
|
-
code: error.response?.data?.code,
|
|
56
|
-
details: error.response?.data?.details
|
|
15
|
+
var DEFAULT_REGISTRY_URL = "https://apps.calimero.network";
|
|
16
|
+
function defaultConfig() {
|
|
17
|
+
return { registry: { url: DEFAULT_REGISTRY_URL } };
|
|
18
|
+
}
|
|
19
|
+
var RemoteConfig = class {
|
|
20
|
+
configPath;
|
|
21
|
+
config;
|
|
22
|
+
constructor() {
|
|
23
|
+
this.configPath = path5.join(
|
|
24
|
+
os2.homedir(),
|
|
25
|
+
".calimero-registry",
|
|
26
|
+
"remote-config.json"
|
|
27
|
+
);
|
|
28
|
+
this.config = this.loadConfig();
|
|
29
|
+
}
|
|
30
|
+
loadConfig() {
|
|
31
|
+
const defaults = defaultConfig();
|
|
32
|
+
if (fs7.existsSync(this.configPath)) {
|
|
33
|
+
try {
|
|
34
|
+
const existingConfig = JSON.parse(
|
|
35
|
+
fs7.readFileSync(this.configPath, "utf8")
|
|
36
|
+
);
|
|
37
|
+
return {
|
|
38
|
+
registry: {
|
|
39
|
+
...defaults.registry,
|
|
40
|
+
...existingConfig.registry || {}
|
|
41
|
+
}
|
|
57
42
|
};
|
|
58
|
-
|
|
43
|
+
} catch {
|
|
44
|
+
console.warn("Failed to load existing config, using defaults");
|
|
59
45
|
}
|
|
60
|
-
|
|
46
|
+
}
|
|
47
|
+
return defaults;
|
|
61
48
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
* // Filter by developer
|
|
76
|
-
* const devApps = await client.getApps({ dev: 'ed25519:abc123...' });
|
|
77
|
-
*
|
|
78
|
-
* // Filter by name
|
|
79
|
-
* const walletApps = await client.getApps({ name: 'wallet' });
|
|
80
|
-
*
|
|
81
|
-
* // Filter by both
|
|
82
|
-
* const filteredApps = await client.getApps({
|
|
83
|
-
* dev: 'ed25519:abc123...',
|
|
84
|
-
* name: 'wallet'
|
|
85
|
-
* });
|
|
86
|
-
* ```
|
|
87
|
-
*
|
|
88
|
-
* @throws {ApiError} When the API request fails
|
|
89
|
-
*/
|
|
90
|
-
async getApps(params) {
|
|
91
|
-
const response = await this.api.get("/apps", { params });
|
|
92
|
-
return response.data;
|
|
49
|
+
saveConfig() {
|
|
50
|
+
const configDir = path5.dirname(this.configPath);
|
|
51
|
+
if (!fs7.existsSync(configDir)) {
|
|
52
|
+
fs7.mkdirSync(configDir, { recursive: true });
|
|
53
|
+
}
|
|
54
|
+
const configToSave = {
|
|
55
|
+
registry: {
|
|
56
|
+
url: this.config.registry.url,
|
|
57
|
+
// Save API key if it exists in config (regardless of env var)
|
|
58
|
+
...this.config.registry.apiKey ? { apiKey: this.config.registry.apiKey } : {}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
fs7.writeFileSync(this.configPath, JSON.stringify(configToSave, null, 2));
|
|
93
62
|
}
|
|
94
63
|
/**
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
* @returns Promise resolving to an array of version information
|
|
100
|
-
*
|
|
101
|
-
* @example
|
|
102
|
-
* ```typescript
|
|
103
|
-
* const versions = await client.getAppVersions(
|
|
104
|
-
* 'ed25519:abc123...',
|
|
105
|
-
* 'my-wallet-app'
|
|
106
|
-
* );
|
|
107
|
-
*
|
|
108
|
-
* versions.forEach(version => {
|
|
109
|
-
* console.log(`Version ${version.semver}: ${version.cid}`);
|
|
110
|
-
* if (version.yanked) {
|
|
111
|
-
* console.log(' ⚠️ This version has been yanked');
|
|
112
|
-
* }
|
|
113
|
-
* });
|
|
114
|
-
* ```
|
|
115
|
-
*
|
|
116
|
-
* @throws {ApiError} When the application is not found or request fails
|
|
64
|
+
* Get registry URL with priority:
|
|
65
|
+
* 1. Environment variable CALIMERO_REGISTRY_URL
|
|
66
|
+
* 2. Config file value
|
|
67
|
+
* 3. Default value
|
|
117
68
|
*/
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
return response.data;
|
|
69
|
+
getRegistryUrl() {
|
|
70
|
+
return process.env.CALIMERO_REGISTRY_URL || this.config.registry.url || DEFAULT_REGISTRY_URL;
|
|
121
71
|
}
|
|
122
72
|
/**
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
* @param appId - Unique application identifier
|
|
126
|
-
* @param semver - Semantic version (e.g., '1.0.0', '2.1.3')
|
|
127
|
-
* @returns Promise resolving to the application manifest
|
|
128
|
-
*
|
|
129
|
-
* @example
|
|
130
|
-
* ```typescript
|
|
131
|
-
* const manifest = await client.getAppManifest('my-wallet-app', '1.2.0');
|
|
132
|
-
*
|
|
133
|
-
* console.log(`App: ${manifest.app.name}`);
|
|
134
|
-
* console.log(`Version: ${manifest.version.semver}`);
|
|
135
|
-
* console.log(`Supported chains: ${manifest.supported_chains.join(', ')}`);
|
|
136
|
-
*
|
|
137
|
-
* // Check permissions
|
|
138
|
-
* manifest.permissions.forEach(perm => {
|
|
139
|
-
* console.log(`Permission: ${perm.cap} (${perm.bytes} bytes)`);
|
|
140
|
-
* });
|
|
141
|
-
*
|
|
142
|
-
* // List artifacts
|
|
143
|
-
* manifest.artifacts.forEach(artifact => {
|
|
144
|
-
* console.log(`Artifact: ${artifact.type} -> ${artifact.cid}`);
|
|
145
|
-
* });
|
|
146
|
-
* ```
|
|
147
|
-
*
|
|
148
|
-
* @throws {ApiError} When the manifest is not found or request fails
|
|
73
|
+
* Set registry URL
|
|
149
74
|
*/
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
75
|
+
setRegistryUrl(url) {
|
|
76
|
+
this.config.registry.url = url;
|
|
77
|
+
this.saveConfig();
|
|
153
78
|
}
|
|
154
79
|
/**
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
* @example
|
|
161
|
-
* ```typescript
|
|
162
|
-
* const profile = await client.getDeveloper('ed25519:abc123...');
|
|
163
|
-
*
|
|
164
|
-
* console.log(`Developer: ${profile.display_name}`);
|
|
165
|
-
* if (profile.website) {
|
|
166
|
-
* console.log(`Website: ${profile.website}`);
|
|
167
|
-
* }
|
|
168
|
-
*
|
|
169
|
-
* // Check verification proofs
|
|
170
|
-
* profile.proofs.forEach(proof => {
|
|
171
|
-
* const status = proof.verified ? '✅' : '❌';
|
|
172
|
-
* console.log(`${status} ${proof.type}: ${proof.value}`);
|
|
173
|
-
* });
|
|
174
|
-
* ```
|
|
175
|
-
*
|
|
176
|
-
* @throws {ApiError} When the developer is not found or request fails
|
|
80
|
+
* Get API key with priority:
|
|
81
|
+
* 1. Environment variable CALIMERO_API_KEY
|
|
82
|
+
* 2. Config file value
|
|
83
|
+
* 3. undefined
|
|
177
84
|
*/
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
return response.data;
|
|
85
|
+
getApiKey() {
|
|
86
|
+
return process.env.CALIMERO_API_KEY || this.config.registry.apiKey;
|
|
181
87
|
}
|
|
182
88
|
/**
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
* @param pubkey - Developer's public key (Ed25519 format)
|
|
186
|
-
* @param appName - Name of the application
|
|
187
|
-
* @param semver - Semantic version (e.g., '1.0.0', '2.1.3')
|
|
188
|
-
* @returns Promise resolving to the attestation information
|
|
189
|
-
*
|
|
190
|
-
* @example
|
|
191
|
-
* ```typescript
|
|
192
|
-
* const attestation = await client.getAttestation(
|
|
193
|
-
* 'ed25519:abc123...',
|
|
194
|
-
* 'my-wallet-app',
|
|
195
|
-
* '1.2.0'
|
|
196
|
-
* );
|
|
197
|
-
*
|
|
198
|
-
* console.log(`Status: ${attestation.status}`);
|
|
199
|
-
* console.log(`Timestamp: ${attestation.timestamp}`);
|
|
200
|
-
* if (attestation.comment) {
|
|
201
|
-
* console.log(`Comment: ${attestation.comment}`);
|
|
202
|
-
* }
|
|
203
|
-
*
|
|
204
|
-
* // Check status
|
|
205
|
-
* switch (attestation.status) {
|
|
206
|
-
* case 'ok':
|
|
207
|
-
* console.log('✅ Application is verified and safe');
|
|
208
|
-
* break;
|
|
209
|
-
* case 'yanked':
|
|
210
|
-
* console.log('⚠️ Application has been yanked');
|
|
211
|
-
* break;
|
|
212
|
-
* case 'tested':
|
|
213
|
-
* console.log('🧪 Application is in testing phase');
|
|
214
|
-
* break;
|
|
215
|
-
* }
|
|
216
|
-
* ```
|
|
217
|
-
*
|
|
218
|
-
* @throws {ApiError} When the attestation is not found or request fails
|
|
89
|
+
* Set API key (stored in config file)
|
|
219
90
|
*/
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
);
|
|
224
|
-
return response.data;
|
|
91
|
+
setApiKey(apiKey) {
|
|
92
|
+
this.config.registry.apiKey = apiKey;
|
|
93
|
+
this.saveConfig();
|
|
225
94
|
}
|
|
226
95
|
/**
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
* @param manifest - Complete application manifest with signature
|
|
230
|
-
* @returns Promise resolving to submission result
|
|
231
|
-
*
|
|
232
|
-
* @example
|
|
233
|
-
* ```typescript
|
|
234
|
-
* const manifest: AppManifest = {
|
|
235
|
-
* manifest_version: '1.0.0',
|
|
236
|
-
* app: {
|
|
237
|
-
* name: 'my-wallet-app',
|
|
238
|
-
* developer_pubkey: 'ed25519:abc123...',
|
|
239
|
-
* id: 'unique-app-id',
|
|
240
|
-
* alias: 'My Wallet',
|
|
241
|
-
* },
|
|
242
|
-
* version: {
|
|
243
|
-
* semver: '1.0.0',
|
|
244
|
-
* },
|
|
245
|
-
* supported_chains: ['mainnet', 'testnet'],
|
|
246
|
-
* permissions: [
|
|
247
|
-
* { cap: 'wallet', bytes: 1024 },
|
|
248
|
-
* { cap: 'network', bytes: 512 },
|
|
249
|
-
* ],
|
|
250
|
-
* artifacts: [
|
|
251
|
-
* {
|
|
252
|
-
* type: 'wasm',
|
|
253
|
-
* target: 'browser',
|
|
254
|
-
* cid: 'QmHash...',
|
|
255
|
-
* size: 1024000,
|
|
256
|
-
* },
|
|
257
|
-
* ],
|
|
258
|
-
* metadata: {
|
|
259
|
-
* description: 'A secure wallet application',
|
|
260
|
-
* author: 'John Doe',
|
|
261
|
-
* },
|
|
262
|
-
* distribution: 'ipfs',
|
|
263
|
-
* signature: {
|
|
264
|
-
* alg: 'ed25519',
|
|
265
|
-
* sig: 'signature...',
|
|
266
|
-
* signed_at: '2024-01-01T00:00:00Z',
|
|
267
|
-
* },
|
|
268
|
-
* };
|
|
269
|
-
*
|
|
270
|
-
* const result = await client.submitAppManifest(manifest);
|
|
271
|
-
*
|
|
272
|
-
* if (result.success) {
|
|
273
|
-
* console.log('✅ Manifest submitted successfully');
|
|
274
|
-
* console.log(result.message);
|
|
275
|
-
* } else {
|
|
276
|
-
* console.log('❌ Submission failed');
|
|
277
|
-
* console.log(result.message);
|
|
278
|
-
* }
|
|
279
|
-
* ```
|
|
280
|
-
*
|
|
281
|
-
* @throws {ApiError} When the submission fails (validation errors, etc.)
|
|
96
|
+
* Remove API key from config
|
|
282
97
|
*/
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
98
|
+
removeApiKey() {
|
|
99
|
+
delete this.config.registry.apiKey;
|
|
100
|
+
this.saveConfig();
|
|
286
101
|
}
|
|
287
102
|
/**
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
* @param pubkey - Developer's public key (Ed25519 format)
|
|
291
|
-
* @param profile - Developer profile information
|
|
292
|
-
* @returns Promise resolving to submission result
|
|
293
|
-
*
|
|
294
|
-
* @example
|
|
295
|
-
* ```typescript
|
|
296
|
-
* const profile: DeveloperProfile = {
|
|
297
|
-
* display_name: 'John Doe',
|
|
298
|
-
* website: 'https://johndoe.dev',
|
|
299
|
-
* proofs: [
|
|
300
|
-
* {
|
|
301
|
-
* type: 'github',
|
|
302
|
-
* value: 'johndoe',
|
|
303
|
-
* verified: true,
|
|
304
|
-
* },
|
|
305
|
-
* {
|
|
306
|
-
* type: 'twitter',
|
|
307
|
-
* value: '@johndoe',
|
|
308
|
-
* verified: false,
|
|
309
|
-
* },
|
|
310
|
-
* ],
|
|
311
|
-
* };
|
|
312
|
-
*
|
|
313
|
-
* const result = await client.submitDeveloperProfile(
|
|
314
|
-
* 'ed25519:abc123...',
|
|
315
|
-
* profile
|
|
316
|
-
* );
|
|
317
|
-
*
|
|
318
|
-
* if (result.success) {
|
|
319
|
-
* console.log('✅ Profile submitted successfully');
|
|
320
|
-
* } else {
|
|
321
|
-
* console.log('❌ Submission failed:', result.message);
|
|
322
|
-
* }
|
|
323
|
-
* ```
|
|
324
|
-
*
|
|
325
|
-
* @throws {ApiError} When the submission fails (validation errors, etc.)
|
|
103
|
+
* Get full configuration
|
|
326
104
|
*/
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
105
|
+
getConfig() {
|
|
106
|
+
return {
|
|
107
|
+
registry: {
|
|
108
|
+
url: this.getRegistryUrl(),
|
|
109
|
+
// Don't expose API key in getConfig (security)
|
|
110
|
+
apiKey: this.getApiKey() ? "***" : void 0
|
|
111
|
+
}
|
|
112
|
+
};
|
|
333
113
|
}
|
|
334
114
|
/**
|
|
335
|
-
*
|
|
336
|
-
*
|
|
337
|
-
* @param pubkey - Developer's public key (Ed25519 format)
|
|
338
|
-
* @param appName - Name of the application
|
|
339
|
-
* @param semver - Semantic version (e.g., '1.0.0', '2.1.3')
|
|
340
|
-
* @param attestation - Attestation information
|
|
341
|
-
* @returns Promise resolving to submission result
|
|
342
|
-
*
|
|
343
|
-
* @example
|
|
344
|
-
* ```typescript
|
|
345
|
-
* const attestation: Attestation = {
|
|
346
|
-
* status: 'ok',
|
|
347
|
-
* comment: 'Passed security audit and functionality testing',
|
|
348
|
-
* timestamp: new Date().toISOString(),
|
|
349
|
-
* };
|
|
350
|
-
*
|
|
351
|
-
* const result = await client.submitAttestation(
|
|
352
|
-
* 'ed25519:abc123...',
|
|
353
|
-
* 'my-wallet-app',
|
|
354
|
-
* '1.2.0',
|
|
355
|
-
* attestation
|
|
356
|
-
* );
|
|
357
|
-
*
|
|
358
|
-
* if (result.success) {
|
|
359
|
-
* console.log('✅ Attestation submitted successfully');
|
|
360
|
-
* } else {
|
|
361
|
-
* console.log('❌ Submission failed:', result.message);
|
|
362
|
-
* }
|
|
363
|
-
* ```
|
|
364
|
-
*
|
|
365
|
-
* @throws {ApiError} When the submission fails (validation errors, etc.)
|
|
115
|
+
* Get config file path
|
|
366
116
|
*/
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
`/attestations/${pubkey}/${appName}/${semver}`,
|
|
370
|
-
attestation
|
|
371
|
-
);
|
|
372
|
-
return response.data;
|
|
117
|
+
getConfigPath() {
|
|
118
|
+
return this.configPath;
|
|
373
119
|
}
|
|
374
120
|
/**
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
* @returns Promise resolving to health status
|
|
378
|
-
*
|
|
379
|
-
* @example
|
|
380
|
-
* ```typescript
|
|
381
|
-
* try {
|
|
382
|
-
* const health = await client.healthCheck();
|
|
383
|
-
* console.log(`API Status: ${health.status}`);
|
|
384
|
-
*
|
|
385
|
-
* if (health.status === 'ok') {
|
|
386
|
-
* console.log('✅ API is healthy');
|
|
387
|
-
* } else {
|
|
388
|
-
* console.log('⚠️ API has issues');
|
|
389
|
-
* }
|
|
390
|
-
* } catch (error) {
|
|
391
|
-
* console.log('❌ API is not responding');
|
|
392
|
-
* }
|
|
393
|
-
* ```
|
|
394
|
-
*
|
|
395
|
-
* @throws {ApiError} When the API is not responding
|
|
121
|
+
* Reset to defaults
|
|
396
122
|
*/
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
123
|
+
reset() {
|
|
124
|
+
this.config = defaultConfig();
|
|
125
|
+
this.saveConfig();
|
|
400
126
|
}
|
|
401
127
|
};
|
|
128
|
+
function defaultConfig2() {
|
|
129
|
+
return {
|
|
130
|
+
server: {
|
|
131
|
+
// Reset used to say localhost here, but never reached the listener:
|
|
132
|
+
// `local start` sets the host on every run and defaults to 0.0.0.0,
|
|
133
|
+
// which is also what publicHost assumes, since a container reaching
|
|
134
|
+
// host.docker.internal cannot be served from loopback.
|
|
135
|
+
host: "0.0.0.0",
|
|
136
|
+
port: 8082,
|
|
137
|
+
publicHost: "host.docker.internal"
|
|
138
|
+
},
|
|
139
|
+
data: {
|
|
140
|
+
dir: path5.join(os2.homedir(), ".calimero-registry", "data"),
|
|
141
|
+
artifactsDir: path5.join(os2.homedir(), ".calimero-registry", "artifacts")
|
|
142
|
+
},
|
|
143
|
+
artifacts: {
|
|
144
|
+
storageDir: path5.join(os2.homedir(), ".calimero-registry", "artifacts"),
|
|
145
|
+
serveLocal: true,
|
|
146
|
+
copyArtifacts: true,
|
|
147
|
+
maxFileSize: "100MB",
|
|
148
|
+
allowedTypes: ["wasm", "js", "html"]
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
402
152
|
var LocalConfig = class {
|
|
403
153
|
configPath;
|
|
404
154
|
dataDir;
|
|
405
155
|
config;
|
|
406
156
|
constructor() {
|
|
407
|
-
this.configPath =
|
|
408
|
-
|
|
157
|
+
this.configPath = path5.join(
|
|
158
|
+
os2.homedir(),
|
|
409
159
|
".calimero-registry",
|
|
410
160
|
"config.json"
|
|
411
161
|
);
|
|
412
|
-
this.dataDir =
|
|
162
|
+
this.dataDir = path5.join(os2.homedir(), ".calimero-registry");
|
|
413
163
|
this.config = this.loadConfig();
|
|
414
164
|
}
|
|
415
165
|
loadConfig() {
|
|
416
|
-
const
|
|
417
|
-
|
|
418
|
-
port: 8082,
|
|
419
|
-
host: "0.0.0.0",
|
|
420
|
-
publicHost: "host.docker.internal"
|
|
421
|
-
},
|
|
422
|
-
data: {
|
|
423
|
-
dir: path7.join(os.homedir(), ".calimero-registry", "data"),
|
|
424
|
-
artifactsDir: path7.join(
|
|
425
|
-
os.homedir(),
|
|
426
|
-
".calimero-registry",
|
|
427
|
-
"artifacts"
|
|
428
|
-
)
|
|
429
|
-
},
|
|
430
|
-
artifacts: {
|
|
431
|
-
storageDir: path7.join(os.homedir(), ".calimero-registry", "artifacts"),
|
|
432
|
-
serveLocal: true,
|
|
433
|
-
copyArtifacts: true,
|
|
434
|
-
maxFileSize: "100MB",
|
|
435
|
-
allowedTypes: ["wasm", "js", "html"]
|
|
436
|
-
}
|
|
437
|
-
};
|
|
438
|
-
if (fs9.existsSync(this.configPath)) {
|
|
166
|
+
const defaults = defaultConfig2();
|
|
167
|
+
if (fs7.existsSync(this.configPath)) {
|
|
439
168
|
try {
|
|
440
169
|
const existingConfig = JSON.parse(
|
|
441
|
-
|
|
170
|
+
fs7.readFileSync(this.configPath, "utf8")
|
|
442
171
|
);
|
|
443
172
|
return {
|
|
444
173
|
server: {
|
|
445
|
-
...
|
|
174
|
+
...defaults.server,
|
|
446
175
|
...existingConfig.server || {}
|
|
447
176
|
},
|
|
448
177
|
data: {
|
|
449
|
-
...
|
|
178
|
+
...defaults.data,
|
|
450
179
|
...existingConfig.data || {}
|
|
451
180
|
},
|
|
452
181
|
artifacts: {
|
|
453
|
-
...
|
|
182
|
+
...defaults.artifacts,
|
|
454
183
|
...existingConfig.artifacts || {}
|
|
455
184
|
}
|
|
456
185
|
};
|
|
@@ -458,14 +187,14 @@ var LocalConfig = class {
|
|
|
458
187
|
console.warn("Failed to load existing config, using defaults");
|
|
459
188
|
}
|
|
460
189
|
}
|
|
461
|
-
return
|
|
190
|
+
return defaults;
|
|
462
191
|
}
|
|
463
192
|
saveConfig() {
|
|
464
|
-
const configDir =
|
|
465
|
-
if (!
|
|
466
|
-
|
|
193
|
+
const configDir = path5.dirname(this.configPath);
|
|
194
|
+
if (!fs7.existsSync(configDir)) {
|
|
195
|
+
fs7.mkdirSync(configDir, { recursive: true });
|
|
467
196
|
}
|
|
468
|
-
|
|
197
|
+
fs7.writeFileSync(this.configPath, JSON.stringify(this.config, null, 2));
|
|
469
198
|
}
|
|
470
199
|
// Server configuration
|
|
471
200
|
getPort() {
|
|
@@ -495,7 +224,8 @@ var LocalConfig = class {
|
|
|
495
224
|
}
|
|
496
225
|
setDataDir(dir) {
|
|
497
226
|
this.config.data.dir = dir;
|
|
498
|
-
this.config.
|
|
227
|
+
this.config.data.artifactsDir = path5.join(dir, "artifacts");
|
|
228
|
+
this.config.artifacts.storageDir = path5.join(dir, "artifacts");
|
|
499
229
|
this.saveConfig();
|
|
500
230
|
}
|
|
501
231
|
getArtifactsDir() {
|
|
@@ -519,12 +249,12 @@ var LocalConfig = class {
|
|
|
519
249
|
const dirs = [
|
|
520
250
|
this.getDataDir(),
|
|
521
251
|
this.getArtifactsDir(),
|
|
522
|
-
|
|
523
|
-
|
|
252
|
+
path5.join(this.getDataDir(), "backups"),
|
|
253
|
+
path5.join(this.getDataDir(), "logs")
|
|
524
254
|
];
|
|
525
255
|
dirs.forEach((dir) => {
|
|
526
|
-
if (!
|
|
527
|
-
|
|
256
|
+
if (!fs7.existsSync(dir)) {
|
|
257
|
+
fs7.mkdirSync(dir, { recursive: true });
|
|
528
258
|
}
|
|
529
259
|
});
|
|
530
260
|
}
|
|
@@ -537,30 +267,121 @@ var LocalConfig = class {
|
|
|
537
267
|
}
|
|
538
268
|
// Reset to defaults
|
|
539
269
|
reset() {
|
|
540
|
-
this.config =
|
|
541
|
-
server: {
|
|
542
|
-
port: 8082,
|
|
543
|
-
host: "localhost"
|
|
544
|
-
},
|
|
545
|
-
data: {
|
|
546
|
-
dir: path7.join(os.homedir(), ".calimero-registry", "data"),
|
|
547
|
-
artifactsDir: path7.join(
|
|
548
|
-
os.homedir(),
|
|
549
|
-
".calimero-registry",
|
|
550
|
-
"artifacts"
|
|
551
|
-
)
|
|
552
|
-
},
|
|
553
|
-
artifacts: {
|
|
554
|
-
storageDir: path7.join(os.homedir(), ".calimero-registry", "artifacts"),
|
|
555
|
-
serveLocal: true,
|
|
556
|
-
copyArtifacts: true,
|
|
557
|
-
maxFileSize: "100MB",
|
|
558
|
-
allowedTypes: ["wasm", "js", "html"]
|
|
559
|
-
}
|
|
560
|
-
};
|
|
270
|
+
this.config = defaultConfig2();
|
|
561
271
|
this.saveConfig();
|
|
562
272
|
}
|
|
563
273
|
};
|
|
274
|
+
|
|
275
|
+
// src/commands/health.ts
|
|
276
|
+
var healthCommand = new Command("health").description("Check the health of the Calimero Registry API").action(async (options, command) => {
|
|
277
|
+
const globalOpts = command.parent?.opts();
|
|
278
|
+
let url;
|
|
279
|
+
if (globalOpts?.local) {
|
|
280
|
+
const local = new LocalConfig();
|
|
281
|
+
url = `http://${local.getHost()}:${local.getPort()}/healthz`;
|
|
282
|
+
} else {
|
|
283
|
+
const base = (globalOpts?.url || new RemoteConfig().getRegistryUrl()).trim().replace(/\/$/, "");
|
|
284
|
+
url = `${base}/api/healthz`;
|
|
285
|
+
}
|
|
286
|
+
const spinner2 = ora4("Checking API health...").start();
|
|
287
|
+
try {
|
|
288
|
+
const { data } = await axios.get(url, {
|
|
289
|
+
timeout: parseInt(globalOpts?.timeout || "10000"),
|
|
290
|
+
headers: { Accept: "application/json" }
|
|
291
|
+
});
|
|
292
|
+
if (data?.status !== "ok") {
|
|
293
|
+
throw new Error(
|
|
294
|
+
`unexpected response from ${url}: ${JSON.stringify(data)}`
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
spinner2.succeed("API is healthy");
|
|
298
|
+
console.log(chalk4.green(`Status: ${data.status}`));
|
|
299
|
+
if (data.timestamp) {
|
|
300
|
+
console.log(chalk4.gray(`Checked: ${data.timestamp}`));
|
|
301
|
+
}
|
|
302
|
+
} catch (error) {
|
|
303
|
+
spinner2.fail("API health check failed");
|
|
304
|
+
const reason = error instanceof Error && error.message || axios.isAxiosError(error) && error.code || "no response";
|
|
305
|
+
console.error(chalk4.red(`Error: ${reason}`));
|
|
306
|
+
console.error(chalk4.gray(`Tried: ${url}`));
|
|
307
|
+
if (globalOpts?.local) {
|
|
308
|
+
console.error(
|
|
309
|
+
chalk4.gray('Is it running? "calimero-registry local start"')
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
process.exit(1);
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
async function uploadToIPFS(filePath) {
|
|
316
|
+
try {
|
|
317
|
+
if (!existsSync(filePath)) {
|
|
318
|
+
throw new Error(`File not found: ${filePath}`);
|
|
319
|
+
}
|
|
320
|
+
const simulatedCid = "QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG";
|
|
321
|
+
console.log("\u26A0\uFE0F Using simulated IPFS upload for demo purposes");
|
|
322
|
+
console.log(" In production, use a service like Pinata or Infura");
|
|
323
|
+
return simulatedCid;
|
|
324
|
+
} catch (error) {
|
|
325
|
+
throw new Error(
|
|
326
|
+
`Failed to upload to IPFS: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
327
|
+
{ cause: error }
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
async function downloadFromIPFS(cid, outputPath) {
|
|
332
|
+
try {
|
|
333
|
+
console.log("\u26A0\uFE0F Using simulated IPFS download for demo purposes");
|
|
334
|
+
console.log(" In production, use a service like Pinata or Infura");
|
|
335
|
+
const simulatedContent = `Simulated IPFS file content for CID: ${cid}
|
|
336
|
+
This is a demo file that would normally contain the actual application data.`;
|
|
337
|
+
const finalOutputPath = outputPath || `${cid}.wasm`;
|
|
338
|
+
writeFileSync(finalOutputPath, simulatedContent);
|
|
339
|
+
return finalOutputPath;
|
|
340
|
+
} catch (error) {
|
|
341
|
+
throw new Error(
|
|
342
|
+
`Failed to download from IPFS: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
343
|
+
{ cause: error }
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
var spinner = (text) => ora4(text);
|
|
348
|
+
|
|
349
|
+
// src/commands/ipfs.ts
|
|
350
|
+
var ipfsCommand = new Command("ipfs").description("IPFS operations").addCommand(
|
|
351
|
+
new Command("upload").description("Upload a file to IPFS").argument("<file>", "Path to the file to upload").action(async (file) => {
|
|
352
|
+
const s = spinner("Uploading to IPFS...").start();
|
|
353
|
+
try {
|
|
354
|
+
const cid = await uploadToIPFS(file);
|
|
355
|
+
s.succeed(`File uploaded successfully!`);
|
|
356
|
+
console.log(`CID: ${cid}`);
|
|
357
|
+
console.log(`Gateway URL: https://ipfs.io/ipfs/${cid}`);
|
|
358
|
+
} catch (error) {
|
|
359
|
+
s.fail("Upload failed");
|
|
360
|
+
console.error(
|
|
361
|
+
"Error:",
|
|
362
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
363
|
+
);
|
|
364
|
+
process.exit(1);
|
|
365
|
+
}
|
|
366
|
+
})
|
|
367
|
+
).addCommand(
|
|
368
|
+
new Command("download").description("Download a file from IPFS").argument("<cid>", "IPFS CID to download").argument("[output]", "Output file path (optional)").action(async (cid, output) => {
|
|
369
|
+
const s = spinner("Downloading from IPFS...").start();
|
|
370
|
+
try {
|
|
371
|
+
const outputPath = await downloadFromIPFS(cid, output);
|
|
372
|
+
s.succeed(`File downloaded successfully!`);
|
|
373
|
+
console.log(`Saved to: ${outputPath}`);
|
|
374
|
+
console.log(`Gateway URL: https://ipfs.io/ipfs/${cid}`);
|
|
375
|
+
} catch (error) {
|
|
376
|
+
s.fail("Download failed");
|
|
377
|
+
console.error(
|
|
378
|
+
"Error:",
|
|
379
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
380
|
+
);
|
|
381
|
+
process.exit(1);
|
|
382
|
+
}
|
|
383
|
+
})
|
|
384
|
+
);
|
|
564
385
|
var LocalDataStore = class {
|
|
565
386
|
config;
|
|
566
387
|
data;
|
|
@@ -569,12 +390,12 @@ var LocalDataStore = class {
|
|
|
569
390
|
artifactsFile;
|
|
570
391
|
constructor(config) {
|
|
571
392
|
this.config = config;
|
|
572
|
-
this.appsFile =
|
|
573
|
-
this.bundleManifestsFile =
|
|
393
|
+
this.appsFile = path5.join(config.getDataDir(), "apps.json");
|
|
394
|
+
this.bundleManifestsFile = path5.join(
|
|
574
395
|
config.getDataDir(),
|
|
575
396
|
"bundle_manifests.json"
|
|
576
397
|
);
|
|
577
|
-
this.artifactsFile =
|
|
398
|
+
this.artifactsFile = path5.join(config.getDataDir(), "artifacts.json");
|
|
578
399
|
this.data = {
|
|
579
400
|
apps: /* @__PURE__ */ new Map(),
|
|
580
401
|
bundleManifests: /* @__PURE__ */ new Map(),
|
|
@@ -584,21 +405,21 @@ var LocalDataStore = class {
|
|
|
584
405
|
}
|
|
585
406
|
loadData() {
|
|
586
407
|
try {
|
|
587
|
-
if (
|
|
588
|
-
const appsData = JSON.parse(
|
|
408
|
+
if (fs7.existsSync(this.appsFile)) {
|
|
409
|
+
const appsData = JSON.parse(fs7.readFileSync(this.appsFile, "utf8"));
|
|
589
410
|
this.data.apps = new Map(Object.entries(appsData));
|
|
590
411
|
}
|
|
591
|
-
if (
|
|
412
|
+
if (fs7.existsSync(this.bundleManifestsFile)) {
|
|
592
413
|
const bundleManifestsData = JSON.parse(
|
|
593
|
-
|
|
414
|
+
fs7.readFileSync(this.bundleManifestsFile, "utf8")
|
|
594
415
|
);
|
|
595
416
|
this.data.bundleManifests = new Map(
|
|
596
417
|
Object.entries(bundleManifestsData)
|
|
597
418
|
);
|
|
598
419
|
}
|
|
599
|
-
if (
|
|
420
|
+
if (fs7.existsSync(this.artifactsFile)) {
|
|
600
421
|
const artifactsData = JSON.parse(
|
|
601
|
-
|
|
422
|
+
fs7.readFileSync(this.artifactsFile, "utf8")
|
|
602
423
|
);
|
|
603
424
|
this.data.artifacts = new Map(Object.entries(artifactsData));
|
|
604
425
|
}
|
|
@@ -610,14 +431,14 @@ var LocalDataStore = class {
|
|
|
610
431
|
try {
|
|
611
432
|
this.config.ensureDirectories();
|
|
612
433
|
const appsObj = Object.fromEntries(this.data.apps);
|
|
613
|
-
|
|
434
|
+
fs7.writeFileSync(this.appsFile, JSON.stringify(appsObj, null, 2));
|
|
614
435
|
const bundleManifestsObj = Object.fromEntries(this.data.bundleManifests);
|
|
615
|
-
|
|
436
|
+
fs7.writeFileSync(
|
|
616
437
|
this.bundleManifestsFile,
|
|
617
438
|
JSON.stringify(bundleManifestsObj, null, 2)
|
|
618
439
|
);
|
|
619
440
|
const artifactsObj = Object.fromEntries(this.data.artifacts);
|
|
620
|
-
|
|
441
|
+
fs7.writeFileSync(
|
|
621
442
|
this.artifactsFile,
|
|
622
443
|
JSON.stringify(artifactsObj, null, 2)
|
|
623
444
|
);
|
|
@@ -695,14 +516,14 @@ var LocalDataStore = class {
|
|
|
695
516
|
// Backup and restore
|
|
696
517
|
async backup(outputPath) {
|
|
697
518
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
698
|
-
const backupPath = outputPath ||
|
|
519
|
+
const backupPath = outputPath || path5.join(
|
|
699
520
|
this.config.getDataDir(),
|
|
700
521
|
"backups",
|
|
701
522
|
`backup-${timestamp}.json`
|
|
702
523
|
);
|
|
703
|
-
const backupDir =
|
|
704
|
-
if (!
|
|
705
|
-
|
|
524
|
+
const backupDir = path5.dirname(backupPath);
|
|
525
|
+
if (!fs7.existsSync(backupDir)) {
|
|
526
|
+
fs7.mkdirSync(backupDir, { recursive: true });
|
|
706
527
|
}
|
|
707
528
|
const backupData = {
|
|
708
529
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -710,14 +531,14 @@ var LocalDataStore = class {
|
|
|
710
531
|
bundleManifests: Object.fromEntries(this.data.bundleManifests),
|
|
711
532
|
artifacts: Object.fromEntries(this.data.artifacts)
|
|
712
533
|
};
|
|
713
|
-
|
|
534
|
+
fs7.writeFileSync(backupPath, JSON.stringify(backupData, null, 2));
|
|
714
535
|
return backupPath;
|
|
715
536
|
}
|
|
716
537
|
async restore(backupPath) {
|
|
717
|
-
if (!
|
|
538
|
+
if (!fs7.existsSync(backupPath)) {
|
|
718
539
|
throw new Error(`Backup file not found: ${backupPath}`);
|
|
719
540
|
}
|
|
720
|
-
const backupData = JSON.parse(
|
|
541
|
+
const backupData = JSON.parse(fs7.readFileSync(backupPath, "utf8"));
|
|
721
542
|
this.data.apps = new Map(Object.entries(backupData.apps || {}));
|
|
722
543
|
this.data.bundleManifests = new Map(
|
|
723
544
|
Object.entries(backupData.bundleManifests || {})
|
|
@@ -788,48 +609,48 @@ var LocalArtifactServer = class {
|
|
|
788
609
|
this.ensureArtifactsDir();
|
|
789
610
|
}
|
|
790
611
|
ensureArtifactsDir() {
|
|
791
|
-
if (!
|
|
792
|
-
|
|
612
|
+
if (!fs7.existsSync(this.artifactsDir)) {
|
|
613
|
+
fs7.mkdirSync(this.artifactsDir, { recursive: true });
|
|
793
614
|
}
|
|
794
615
|
}
|
|
795
616
|
// Copy artifact to local storage
|
|
796
617
|
async copyArtifactToLocal(sourcePath, appId, version2, filename) {
|
|
797
|
-
if (!
|
|
618
|
+
if (!fs7.existsSync(sourcePath)) {
|
|
798
619
|
throw new Error(`Source file not found: ${sourcePath}`);
|
|
799
620
|
}
|
|
800
|
-
const appVersionDir =
|
|
801
|
-
if (!
|
|
802
|
-
|
|
621
|
+
const appVersionDir = path5.join(this.artifactsDir, appId, version2);
|
|
622
|
+
if (!fs7.existsSync(appVersionDir)) {
|
|
623
|
+
fs7.mkdirSync(appVersionDir, { recursive: true });
|
|
803
624
|
}
|
|
804
|
-
const targetPath =
|
|
805
|
-
|
|
625
|
+
const targetPath = path5.join(appVersionDir, filename);
|
|
626
|
+
fs7.copyFileSync(sourcePath, targetPath);
|
|
806
627
|
const fileHash = await this.calculateFileHash(targetPath);
|
|
807
628
|
this.dataStore.setArtifactPath(fileHash, targetPath);
|
|
808
629
|
return targetPath;
|
|
809
630
|
}
|
|
810
631
|
// Serve artifact by app ID, version, and filename
|
|
811
632
|
async serveArtifact(appId, version2, filename) {
|
|
812
|
-
const artifactPath =
|
|
813
|
-
if (!
|
|
633
|
+
const artifactPath = path5.join(this.artifactsDir, appId, version2, filename);
|
|
634
|
+
if (!fs7.existsSync(artifactPath)) {
|
|
814
635
|
throw new Error(`Artifact not found: ${artifactPath}`);
|
|
815
636
|
}
|
|
816
|
-
return
|
|
637
|
+
return fs7.readFileSync(artifactPath);
|
|
817
638
|
}
|
|
818
639
|
// Serve artifact by hash
|
|
819
640
|
async serveByHash(hash) {
|
|
820
641
|
const artifactPath = this.dataStore.getArtifactPath(hash);
|
|
821
|
-
if (!artifactPath || !
|
|
642
|
+
if (!artifactPath || !fs7.existsSync(artifactPath)) {
|
|
822
643
|
throw new Error(`Artifact not found for hash: ${hash}`);
|
|
823
644
|
}
|
|
824
|
-
return
|
|
645
|
+
return fs7.readFileSync(artifactPath);
|
|
825
646
|
}
|
|
826
647
|
// Validate artifact file
|
|
827
648
|
async validateArtifact(filePath) {
|
|
828
|
-
if (!
|
|
649
|
+
if (!fs7.existsSync(filePath)) {
|
|
829
650
|
throw new Error(`File not found: ${filePath}`);
|
|
830
651
|
}
|
|
831
|
-
const stats =
|
|
832
|
-
const fileBuffer =
|
|
652
|
+
const stats = fs7.statSync(filePath);
|
|
653
|
+
const fileBuffer = fs7.readFileSync(filePath);
|
|
833
654
|
const sha256 = crypto2.createHash("sha256").update(fileBuffer).digest("hex");
|
|
834
655
|
return {
|
|
835
656
|
size: stats.size,
|
|
@@ -838,7 +659,7 @@ var LocalArtifactServer = class {
|
|
|
838
659
|
}
|
|
839
660
|
// Calculate file hash
|
|
840
661
|
async calculateFileHash(filePath) {
|
|
841
|
-
const fileBuffer =
|
|
662
|
+
const fileBuffer = fs7.readFileSync(filePath);
|
|
842
663
|
return crypto2.createHash("sha256").update(fileBuffer).digest("hex");
|
|
843
664
|
}
|
|
844
665
|
// Get artifact URL for local serving
|
|
@@ -851,37 +672,15 @@ var LocalArtifactServer = class {
|
|
|
851
672
|
const baseUrl = `http://${this.config.getPublicHost()}:${this.config.getPort()}`;
|
|
852
673
|
return `${baseUrl}/artifacts/${hash}`;
|
|
853
674
|
}
|
|
854
|
-
// Update manifest artifact to use local URLs (and preserve HTTP access)
|
|
855
|
-
updateManifestArtifact(manifest) {
|
|
856
|
-
const updatedManifest = { ...manifest };
|
|
857
|
-
if (!manifest.artifact?.uri) {
|
|
858
|
-
return updatedManifest;
|
|
859
|
-
}
|
|
860
|
-
const uri = manifest.artifact.uri;
|
|
861
|
-
if (uri.startsWith("/")) {
|
|
862
|
-
updatedManifest.artifact = {
|
|
863
|
-
...manifest.artifact,
|
|
864
|
-
uri: `${this.getArtifactUrl(manifest.id, manifest.version, path7.basename(manifest.artifact.uri))}`
|
|
865
|
-
};
|
|
866
|
-
} else if (uri.startsWith("file://")) {
|
|
867
|
-
const filePath = uri.replace("file://", "");
|
|
868
|
-
const filename = path7.basename(filePath);
|
|
869
|
-
updatedManifest.artifact = {
|
|
870
|
-
...manifest.artifact,
|
|
871
|
-
uri: this.getArtifactUrl(manifest.id, manifest.version, filename)
|
|
872
|
-
};
|
|
873
|
-
}
|
|
874
|
-
return updatedManifest;
|
|
875
|
-
}
|
|
876
675
|
// Clean up old artifacts
|
|
877
676
|
async cleanupOldArtifacts(maxAge = 30 * 24 * 60 * 60 * 1e3) {
|
|
878
677
|
const now = Date.now();
|
|
879
678
|
const getAllFiles = (dir) => {
|
|
880
679
|
let files = [];
|
|
881
|
-
const items =
|
|
680
|
+
const items = fs7.readdirSync(dir);
|
|
882
681
|
for (const item of items) {
|
|
883
|
-
const fullPath =
|
|
884
|
-
const stat =
|
|
682
|
+
const fullPath = path5.join(dir, item);
|
|
683
|
+
const stat = fs7.statSync(fullPath);
|
|
885
684
|
if (stat.isDirectory()) {
|
|
886
685
|
files = files.concat(getAllFiles(fullPath));
|
|
887
686
|
} else {
|
|
@@ -892,10 +691,10 @@ var LocalArtifactServer = class {
|
|
|
892
691
|
};
|
|
893
692
|
const allFiles = getAllFiles(this.artifactsDir);
|
|
894
693
|
for (const file of allFiles) {
|
|
895
|
-
const stats =
|
|
694
|
+
const stats = fs7.statSync(file);
|
|
896
695
|
const age = now - stats.mtime.getTime();
|
|
897
696
|
if (age > maxAge) {
|
|
898
|
-
|
|
697
|
+
fs7.unlinkSync(file);
|
|
899
698
|
console.log(`Cleaned up old artifact: ${file}`);
|
|
900
699
|
}
|
|
901
700
|
}
|
|
@@ -907,10 +706,10 @@ var LocalArtifactServer = class {
|
|
|
907
706
|
let oldestFile = null;
|
|
908
707
|
const getAllFiles = (dir) => {
|
|
909
708
|
let files = [];
|
|
910
|
-
const items =
|
|
709
|
+
const items = fs7.readdirSync(dir);
|
|
911
710
|
for (const item of items) {
|
|
912
|
-
const fullPath =
|
|
913
|
-
const stat =
|
|
711
|
+
const fullPath = path5.join(dir, item);
|
|
712
|
+
const stat = fs7.statSync(fullPath);
|
|
914
713
|
if (stat.isDirectory()) {
|
|
915
714
|
files = files.concat(getAllFiles(fullPath));
|
|
916
715
|
} else {
|
|
@@ -919,10 +718,10 @@ var LocalArtifactServer = class {
|
|
|
919
718
|
}
|
|
920
719
|
return files;
|
|
921
720
|
};
|
|
922
|
-
if (
|
|
721
|
+
if (fs7.existsSync(this.artifactsDir)) {
|
|
923
722
|
const allFiles = getAllFiles(this.artifactsDir);
|
|
924
723
|
for (const file of allFiles) {
|
|
925
|
-
const stats =
|
|
724
|
+
const stats = fs7.statSync(file);
|
|
926
725
|
totalFiles++;
|
|
927
726
|
totalSize += stats.size;
|
|
928
727
|
if (!oldestFile || stats.mtime < oldestFile) {
|
|
@@ -937,459 +736,6 @@ var LocalArtifactServer = class {
|
|
|
937
736
|
};
|
|
938
737
|
}
|
|
939
738
|
};
|
|
940
|
-
var RemoteRegistryClient = class {
|
|
941
|
-
client;
|
|
942
|
-
constructor(baseURL, timeout) {
|
|
943
|
-
this.client = new CalimeroRegistryClient({
|
|
944
|
-
baseURL,
|
|
945
|
-
timeout
|
|
946
|
-
});
|
|
947
|
-
}
|
|
948
|
-
async getApps(filters) {
|
|
949
|
-
return await this.client.getApps(filters);
|
|
950
|
-
}
|
|
951
|
-
async getAppVersions(appId) {
|
|
952
|
-
return await this.client.getAppVersions(appId);
|
|
953
|
-
}
|
|
954
|
-
async getAppManifest(appId, semver) {
|
|
955
|
-
return await this.client.getAppManifest(appId, semver);
|
|
956
|
-
}
|
|
957
|
-
async submitAppManifest(manifest) {
|
|
958
|
-
return await this.client.submitAppManifest(manifest);
|
|
959
|
-
}
|
|
960
|
-
async healthCheck() {
|
|
961
|
-
return await this.client.healthCheck();
|
|
962
|
-
}
|
|
963
|
-
};
|
|
964
|
-
var LocalRegistryClient = class {
|
|
965
|
-
config;
|
|
966
|
-
dataStore;
|
|
967
|
-
artifactServer;
|
|
968
|
-
constructor() {
|
|
969
|
-
this.config = new LocalConfig();
|
|
970
|
-
this.dataStore = new LocalDataStore(this.config);
|
|
971
|
-
this.artifactServer = new LocalArtifactServer(this.config, this.dataStore);
|
|
972
|
-
}
|
|
973
|
-
async getApps(filters) {
|
|
974
|
-
return this.dataStore.getApps(filters);
|
|
975
|
-
}
|
|
976
|
-
async getAppVersions(appId) {
|
|
977
|
-
return this.dataStore.getAppVersions(appId);
|
|
978
|
-
}
|
|
979
|
-
async getAppManifest(appId, semver) {
|
|
980
|
-
const manifest = this.dataStore.getManifest(appId, semver);
|
|
981
|
-
if (!manifest) {
|
|
982
|
-
throw new Error("Manifest not found");
|
|
983
|
-
}
|
|
984
|
-
return this.artifactServer.updateManifestArtifact(manifest);
|
|
985
|
-
}
|
|
986
|
-
async submitAppManifest(manifest) {
|
|
987
|
-
if (!this.validateManifest(manifest)) {
|
|
988
|
-
throw new Error("Invalid manifest structure");
|
|
989
|
-
}
|
|
990
|
-
const processedManifest = await this.processManifestArtifacts(manifest);
|
|
991
|
-
const manifestKey = `${processedManifest.id}/${processedManifest.version}`;
|
|
992
|
-
this.dataStore.setManifest(manifestKey, processedManifest);
|
|
993
|
-
const appSummary = {
|
|
994
|
-
id: processedManifest.id,
|
|
995
|
-
name: processedManifest.name,
|
|
996
|
-
latest_version: processedManifest.version,
|
|
997
|
-
latest_digest: processedManifest.artifact.digest
|
|
998
|
-
};
|
|
999
|
-
this.dataStore.setApp(processedManifest.id, appSummary);
|
|
1000
|
-
return {
|
|
1001
|
-
success: true,
|
|
1002
|
-
message: "App version registered successfully"
|
|
1003
|
-
};
|
|
1004
|
-
}
|
|
1005
|
-
async healthCheck() {
|
|
1006
|
-
return { status: "ok" };
|
|
1007
|
-
}
|
|
1008
|
-
validateManifest(manifest) {
|
|
1009
|
-
return !!(manifest.manifest_version && manifest.id && manifest.name && manifest.version && manifest.artifact && manifest.artifact.type && manifest.artifact.target && manifest.artifact.digest && manifest.artifact.uri);
|
|
1010
|
-
}
|
|
1011
|
-
async processManifestArtifacts(manifest) {
|
|
1012
|
-
const processedManifest = { ...manifest };
|
|
1013
|
-
if (manifest.artifact?.uri?.startsWith("file://")) {
|
|
1014
|
-
const filePath = manifest.artifact.uri.replace("file://", "");
|
|
1015
|
-
if (fs9.existsSync(filePath)) {
|
|
1016
|
-
const filename = path7.basename(filePath);
|
|
1017
|
-
try {
|
|
1018
|
-
await this.artifactServer.copyArtifactToLocal(
|
|
1019
|
-
filePath,
|
|
1020
|
-
manifest.id,
|
|
1021
|
-
manifest.version,
|
|
1022
|
-
filename
|
|
1023
|
-
);
|
|
1024
|
-
processedManifest.artifact = {
|
|
1025
|
-
...manifest.artifact,
|
|
1026
|
-
uri: this.artifactServer.getArtifactUrl(
|
|
1027
|
-
manifest.id,
|
|
1028
|
-
manifest.version,
|
|
1029
|
-
filename
|
|
1030
|
-
)
|
|
1031
|
-
};
|
|
1032
|
-
} catch (error) {
|
|
1033
|
-
console.warn(`Failed to copy artifact ${filePath}:`, error);
|
|
1034
|
-
}
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
return processedManifest;
|
|
1038
|
-
}
|
|
1039
|
-
};
|
|
1040
|
-
function createRegistryClient(useLocal, baseURL, timeout) {
|
|
1041
|
-
if (useLocal) {
|
|
1042
|
-
return new LocalRegistryClient();
|
|
1043
|
-
} else {
|
|
1044
|
-
return new RemoteRegistryClient(
|
|
1045
|
-
baseURL || "http://localhost:8082",
|
|
1046
|
-
timeout || 1e4
|
|
1047
|
-
);
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
var appsCommand = new Command("apps").description("Manage self-sovereign applications").addCommand(
|
|
1051
|
-
new Command("list").description("List all applications").option("-n, --name <name>", "Filter by application name").action(async (options, command) => {
|
|
1052
|
-
const globalOpts = command.parent?.parent?.opts();
|
|
1053
|
-
const useLocal = globalOpts?.local || false;
|
|
1054
|
-
const client = createRegistryClient(
|
|
1055
|
-
useLocal,
|
|
1056
|
-
globalOpts?.url,
|
|
1057
|
-
parseInt(globalOpts?.timeout || "10000")
|
|
1058
|
-
);
|
|
1059
|
-
const spinner2 = ora7("Fetching applications...").start();
|
|
1060
|
-
try {
|
|
1061
|
-
const apps = await client.getApps({
|
|
1062
|
-
name: options.name
|
|
1063
|
-
});
|
|
1064
|
-
spinner2.succeed(`Found ${apps.length} application(s)`);
|
|
1065
|
-
if (apps.length === 0) {
|
|
1066
|
-
console.log(chalk7.yellow("No applications found"));
|
|
1067
|
-
return;
|
|
1068
|
-
}
|
|
1069
|
-
const tableData = [
|
|
1070
|
-
["ID", "Name", "Latest Version", "Digest"],
|
|
1071
|
-
...apps.map((app) => [
|
|
1072
|
-
app.id,
|
|
1073
|
-
app.name,
|
|
1074
|
-
app.latest_version,
|
|
1075
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1076
|
-
(app.latest_digest || app.latest_cid || "N/A").toString().substring(0, 12) + "..."
|
|
1077
|
-
])
|
|
1078
|
-
];
|
|
1079
|
-
console.log(table(tableData));
|
|
1080
|
-
} catch (error) {
|
|
1081
|
-
spinner2.fail("Failed to fetch applications");
|
|
1082
|
-
if (error instanceof Error) {
|
|
1083
|
-
console.error(chalk7.red(`Error: ${error.message}`));
|
|
1084
|
-
}
|
|
1085
|
-
process.exit(1);
|
|
1086
|
-
}
|
|
1087
|
-
})
|
|
1088
|
-
).addCommand(
|
|
1089
|
-
new Command("versions").description("List versions of a specific application").argument("<appId>", "Application ID").action(async (appId, options, command) => {
|
|
1090
|
-
const globalOpts = command.parent?.parent?.opts();
|
|
1091
|
-
const useLocal = globalOpts?.local || false;
|
|
1092
|
-
const client = createRegistryClient(
|
|
1093
|
-
useLocal,
|
|
1094
|
-
globalOpts?.url,
|
|
1095
|
-
parseInt(globalOpts?.timeout || "10000")
|
|
1096
|
-
);
|
|
1097
|
-
const spinner2 = ora7(`Fetching versions for ${appId}...`).start();
|
|
1098
|
-
try {
|
|
1099
|
-
const versions = await client.getAppVersions(appId);
|
|
1100
|
-
spinner2.succeed(`Found ${versions.length} version(s)`);
|
|
1101
|
-
if (versions.length === 0) {
|
|
1102
|
-
console.log(chalk7.yellow("No versions found"));
|
|
1103
|
-
return;
|
|
1104
|
-
}
|
|
1105
|
-
const tableData = [
|
|
1106
|
-
["Version", "CID", "Yanked"],
|
|
1107
|
-
...versions.map((version2) => [
|
|
1108
|
-
version2.semver,
|
|
1109
|
-
version2.cid.substring(0, 12) + "...",
|
|
1110
|
-
version2.yanked ? chalk7.red("Yes") : chalk7.green("No")
|
|
1111
|
-
])
|
|
1112
|
-
];
|
|
1113
|
-
console.log(table(tableData));
|
|
1114
|
-
} catch (error) {
|
|
1115
|
-
spinner2.fail("Failed to fetch versions");
|
|
1116
|
-
if (error instanceof Error) {
|
|
1117
|
-
console.error(chalk7.red(`Error: ${error.message}`));
|
|
1118
|
-
}
|
|
1119
|
-
process.exit(1);
|
|
1120
|
-
}
|
|
1121
|
-
})
|
|
1122
|
-
).addCommand(
|
|
1123
|
-
new Command("manifest").description("Get manifest for a specific application version").argument("<appId>", "Application ID").argument("<version>", "Application version").action(async (appId, version2, options, command) => {
|
|
1124
|
-
const globalOpts = command.parent?.parent?.opts();
|
|
1125
|
-
const useLocal = globalOpts?.local || false;
|
|
1126
|
-
const client = createRegistryClient(
|
|
1127
|
-
useLocal,
|
|
1128
|
-
globalOpts?.url,
|
|
1129
|
-
parseInt(globalOpts?.timeout || "10000")
|
|
1130
|
-
);
|
|
1131
|
-
const spinner2 = ora7(
|
|
1132
|
-
`Fetching manifest for ${appId}@${version2}...`
|
|
1133
|
-
).start();
|
|
1134
|
-
try {
|
|
1135
|
-
const manifest = await client.getAppManifest(appId, version2);
|
|
1136
|
-
spinner2.succeed("Manifest fetched successfully");
|
|
1137
|
-
console.log(chalk7.blue("\nApplication Manifest:"));
|
|
1138
|
-
console.log(JSON.stringify(manifest, null, 2));
|
|
1139
|
-
} catch (error) {
|
|
1140
|
-
spinner2.fail("Failed to fetch manifest");
|
|
1141
|
-
if (error instanceof Error) {
|
|
1142
|
-
console.error(chalk7.red(`Error: ${error.message}`));
|
|
1143
|
-
}
|
|
1144
|
-
process.exit(1);
|
|
1145
|
-
}
|
|
1146
|
-
})
|
|
1147
|
-
).addCommand(
|
|
1148
|
-
new Command("submit").description("Submit a new application manifest").argument("<manifest-file>", "Path to the manifest JSON file").action(async (manifestFile, options, command) => {
|
|
1149
|
-
const globalOpts = command.parent?.parent?.opts();
|
|
1150
|
-
const useLocal = globalOpts?.local || false;
|
|
1151
|
-
const client = createRegistryClient(
|
|
1152
|
-
useLocal,
|
|
1153
|
-
globalOpts?.url,
|
|
1154
|
-
parseInt(globalOpts?.timeout || "10000")
|
|
1155
|
-
);
|
|
1156
|
-
const spinner2 = ora7("Reading manifest file...").start();
|
|
1157
|
-
try {
|
|
1158
|
-
const manifestPath = path7.resolve(manifestFile);
|
|
1159
|
-
if (!fs9.existsSync(manifestPath)) {
|
|
1160
|
-
spinner2.fail("Manifest file not found");
|
|
1161
|
-
console.error(chalk7.red(`File not found: ${manifestFile}`));
|
|
1162
|
-
process.exit(1);
|
|
1163
|
-
}
|
|
1164
|
-
const manifestContent = fs9.readFileSync(manifestPath, "utf8");
|
|
1165
|
-
const manifest = JSON.parse(manifestContent);
|
|
1166
|
-
spinner2.text = "Submitting application manifest...";
|
|
1167
|
-
const result = await client.submitAppManifest(manifest);
|
|
1168
|
-
spinner2.succeed("Application submitted successfully");
|
|
1169
|
-
console.log(chalk7.green(`
|
|
1170
|
-
\u2705 ${result.message}`));
|
|
1171
|
-
if (manifest.app?.name) {
|
|
1172
|
-
console.log(chalk7.blue(`
|
|
1173
|
-
\u{1F4F1} App: ${manifest.app.name}`));
|
|
1174
|
-
console.log(
|
|
1175
|
-
chalk7.blue(`\u{1F464} Developer: ${manifest.app.developer_pubkey}`)
|
|
1176
|
-
);
|
|
1177
|
-
console.log(chalk7.blue(`\u{1F4E6} Version: ${manifest.version?.semver}`));
|
|
1178
|
-
}
|
|
1179
|
-
} catch (error) {
|
|
1180
|
-
spinner2.fail("Failed to submit application");
|
|
1181
|
-
if (error instanceof Error) {
|
|
1182
|
-
console.error(chalk7.red(`Error: ${error.message}`));
|
|
1183
|
-
}
|
|
1184
|
-
process.exit(1);
|
|
1185
|
-
}
|
|
1186
|
-
})
|
|
1187
|
-
);
|
|
1188
|
-
var developersCommand = new Command("developers").description("Manage developer profiles").addCommand(
|
|
1189
|
-
new Command("get").description("Get developer profile information").argument("<pubkey>", "Developer public key").action(async (pubkey, options, command) => {
|
|
1190
|
-
const globalOpts = command.parent?.parent?.opts();
|
|
1191
|
-
const client = new CalimeroRegistryClient({
|
|
1192
|
-
baseURL: globalOpts?.url || "http://localhost:8082",
|
|
1193
|
-
timeout: parseInt(globalOpts?.timeout || "10000")
|
|
1194
|
-
});
|
|
1195
|
-
const spinner2 = ora7("Fetching developer profile...").start();
|
|
1196
|
-
try {
|
|
1197
|
-
const profile = await client.getDeveloper(pubkey);
|
|
1198
|
-
spinner2.succeed("Developer profile fetched successfully");
|
|
1199
|
-
console.log(chalk7.blue("\nDeveloper Profile:"));
|
|
1200
|
-
console.log(chalk7.green("Display Name:"), profile.display_name);
|
|
1201
|
-
if (profile.website) {
|
|
1202
|
-
console.log(chalk7.green("Website:"), profile.website);
|
|
1203
|
-
}
|
|
1204
|
-
if (profile.proofs.length > 0) {
|
|
1205
|
-
console.log(chalk7.green("\nProofs:"));
|
|
1206
|
-
const tableData = [
|
|
1207
|
-
["Type", "Value", "Verified"],
|
|
1208
|
-
...profile.proofs.map((proof) => [
|
|
1209
|
-
proof.type,
|
|
1210
|
-
proof.value.substring(0, 20) + "...",
|
|
1211
|
-
proof.verified ? chalk7.green("Yes") : chalk7.red("No")
|
|
1212
|
-
])
|
|
1213
|
-
];
|
|
1214
|
-
console.log(table(tableData));
|
|
1215
|
-
} else {
|
|
1216
|
-
console.log(chalk7.yellow("\nNo proofs found"));
|
|
1217
|
-
}
|
|
1218
|
-
} catch (error) {
|
|
1219
|
-
spinner2.fail("Failed to fetch developer profile");
|
|
1220
|
-
if (error instanceof Error) {
|
|
1221
|
-
console.error(chalk7.red(`Error: ${error.message}`));
|
|
1222
|
-
}
|
|
1223
|
-
process.exit(1);
|
|
1224
|
-
}
|
|
1225
|
-
})
|
|
1226
|
-
).addCommand(
|
|
1227
|
-
new Command("create").description("Create a new developer profile").argument("<pubkey>", "Developer public key").argument("<display-name>", "Display name for the developer").option("-w, --website <url>", "Developer website URL").option("-p, --proofs <proofs>", "JSON string of proofs array").action(async (pubkey, displayName, options, command) => {
|
|
1228
|
-
const globalOpts = command.parent?.parent?.opts();
|
|
1229
|
-
const client = new CalimeroRegistryClient({
|
|
1230
|
-
baseURL: globalOpts?.url || "http://localhost:8082",
|
|
1231
|
-
timeout: parseInt(globalOpts?.timeout || "10000")
|
|
1232
|
-
});
|
|
1233
|
-
const spinner2 = ora7("Creating developer profile...").start();
|
|
1234
|
-
try {
|
|
1235
|
-
let proofs = [];
|
|
1236
|
-
if (options.proofs) {
|
|
1237
|
-
try {
|
|
1238
|
-
proofs = JSON.parse(options.proofs);
|
|
1239
|
-
} catch {
|
|
1240
|
-
spinner2.fail("Invalid proofs JSON format");
|
|
1241
|
-
console.error(chalk7.red("Proofs must be a valid JSON array"));
|
|
1242
|
-
process.exit(1);
|
|
1243
|
-
}
|
|
1244
|
-
}
|
|
1245
|
-
const profile = {
|
|
1246
|
-
pubkey,
|
|
1247
|
-
display_name: displayName,
|
|
1248
|
-
website: options.website,
|
|
1249
|
-
proofs
|
|
1250
|
-
};
|
|
1251
|
-
const result = await client.submitDeveloperProfile(pubkey, profile);
|
|
1252
|
-
spinner2.succeed("Developer profile created successfully");
|
|
1253
|
-
console.log(chalk7.green(`
|
|
1254
|
-
\u2705 ${result.message}`));
|
|
1255
|
-
console.log(chalk7.blue(`
|
|
1256
|
-
\u{1F464} Developer: ${displayName}`));
|
|
1257
|
-
console.log(chalk7.blue(`\u{1F511} Public Key: ${pubkey}`));
|
|
1258
|
-
if (options.website) {
|
|
1259
|
-
console.log(chalk7.blue(`\u{1F310} Website: ${options.website}`));
|
|
1260
|
-
}
|
|
1261
|
-
} catch (error) {
|
|
1262
|
-
spinner2.fail("Failed to create developer profile");
|
|
1263
|
-
if (error instanceof Error) {
|
|
1264
|
-
console.error(chalk7.red(`Error: ${error.message}`));
|
|
1265
|
-
}
|
|
1266
|
-
process.exit(1);
|
|
1267
|
-
}
|
|
1268
|
-
})
|
|
1269
|
-
);
|
|
1270
|
-
var attestationsCommand = new Command("attestations").description("Manage application attestations").addCommand(
|
|
1271
|
-
new Command("get").description("Get attestation for a specific application version").argument("<pubkey>", "Developer public key").argument("<name>", "Application name").argument("<version>", "Application version").action(async (pubkey, name, version2, options, command) => {
|
|
1272
|
-
const globalOpts = command.parent?.parent?.opts();
|
|
1273
|
-
const client = new CalimeroRegistryClient({
|
|
1274
|
-
baseURL: globalOpts?.url || "http://localhost:8082",
|
|
1275
|
-
timeout: parseInt(globalOpts?.timeout || "10000")
|
|
1276
|
-
});
|
|
1277
|
-
const spinner2 = ora7(
|
|
1278
|
-
`Fetching attestation for ${name}@${version2}...`
|
|
1279
|
-
).start();
|
|
1280
|
-
try {
|
|
1281
|
-
const attestation = await client.getAttestation(
|
|
1282
|
-
pubkey,
|
|
1283
|
-
name,
|
|
1284
|
-
version2
|
|
1285
|
-
);
|
|
1286
|
-
spinner2.succeed("Attestation fetched successfully");
|
|
1287
|
-
console.log(chalk7.blue("\nAttestation:"));
|
|
1288
|
-
console.log(chalk7.green("Status:"), attestation.status);
|
|
1289
|
-
console.log(chalk7.green("Timestamp:"), attestation.timestamp);
|
|
1290
|
-
if (attestation.comment) {
|
|
1291
|
-
console.log(chalk7.green("Comment:"), attestation.comment);
|
|
1292
|
-
}
|
|
1293
|
-
} catch (error) {
|
|
1294
|
-
spinner2.fail("Failed to fetch attestation");
|
|
1295
|
-
if (error instanceof Error) {
|
|
1296
|
-
console.error(chalk7.red(`Error: ${error.message}`));
|
|
1297
|
-
}
|
|
1298
|
-
process.exit(1);
|
|
1299
|
-
}
|
|
1300
|
-
})
|
|
1301
|
-
);
|
|
1302
|
-
var healthCommand = new Command("health").description("Check the health of the Calimero Registry API").action(async (options, command) => {
|
|
1303
|
-
const globalOpts = command.parent?.opts();
|
|
1304
|
-
const useLocal = globalOpts?.local || false;
|
|
1305
|
-
const client = createRegistryClient(
|
|
1306
|
-
useLocal,
|
|
1307
|
-
globalOpts?.url,
|
|
1308
|
-
parseInt(globalOpts?.timeout || "10000")
|
|
1309
|
-
);
|
|
1310
|
-
const spinner2 = ora7("Checking API health...").start();
|
|
1311
|
-
try {
|
|
1312
|
-
const health = await client.healthCheck();
|
|
1313
|
-
spinner2.succeed("API is healthy");
|
|
1314
|
-
console.log(chalk7.green(`Status: ${health.status}`));
|
|
1315
|
-
} catch (error) {
|
|
1316
|
-
spinner2.fail("API health check failed");
|
|
1317
|
-
if (error instanceof Error) {
|
|
1318
|
-
console.error(chalk7.red(`Error: ${error.message}`));
|
|
1319
|
-
}
|
|
1320
|
-
process.exit(1);
|
|
1321
|
-
}
|
|
1322
|
-
});
|
|
1323
|
-
async function uploadToIPFS(filePath) {
|
|
1324
|
-
try {
|
|
1325
|
-
if (!existsSync(filePath)) {
|
|
1326
|
-
throw new Error(`File not found: ${filePath}`);
|
|
1327
|
-
}
|
|
1328
|
-
const simulatedCid = "QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG";
|
|
1329
|
-
console.log("\u26A0\uFE0F Using simulated IPFS upload for demo purposes");
|
|
1330
|
-
console.log(" In production, use a service like Pinata or Infura");
|
|
1331
|
-
return simulatedCid;
|
|
1332
|
-
} catch (error) {
|
|
1333
|
-
throw new Error(
|
|
1334
|
-
`Failed to upload to IPFS: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1335
|
-
{ cause: error }
|
|
1336
|
-
);
|
|
1337
|
-
}
|
|
1338
|
-
}
|
|
1339
|
-
async function downloadFromIPFS(cid, outputPath) {
|
|
1340
|
-
try {
|
|
1341
|
-
console.log("\u26A0\uFE0F Using simulated IPFS download for demo purposes");
|
|
1342
|
-
console.log(" In production, use a service like Pinata or Infura");
|
|
1343
|
-
const simulatedContent = `Simulated IPFS file content for CID: ${cid}
|
|
1344
|
-
This is a demo file that would normally contain the actual application data.`;
|
|
1345
|
-
const finalOutputPath = outputPath || `${cid}.wasm`;
|
|
1346
|
-
writeFileSync(finalOutputPath, simulatedContent);
|
|
1347
|
-
return finalOutputPath;
|
|
1348
|
-
} catch (error) {
|
|
1349
|
-
throw new Error(
|
|
1350
|
-
`Failed to download from IPFS: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1351
|
-
{ cause: error }
|
|
1352
|
-
);
|
|
1353
|
-
}
|
|
1354
|
-
}
|
|
1355
|
-
var spinner = (text) => ora7(text);
|
|
1356
|
-
|
|
1357
|
-
// src/commands/ipfs.ts
|
|
1358
|
-
var ipfsCommand = new Command("ipfs").description("IPFS operations").addCommand(
|
|
1359
|
-
new Command("upload").description("Upload a file to IPFS").argument("<file>", "Path to the file to upload").action(async (file) => {
|
|
1360
|
-
const s = spinner("Uploading to IPFS...").start();
|
|
1361
|
-
try {
|
|
1362
|
-
const cid = await uploadToIPFS(file);
|
|
1363
|
-
s.succeed(`File uploaded successfully!`);
|
|
1364
|
-
console.log(`CID: ${cid}`);
|
|
1365
|
-
console.log(`Gateway URL: https://ipfs.io/ipfs/${cid}`);
|
|
1366
|
-
} catch (error) {
|
|
1367
|
-
s.fail("Upload failed");
|
|
1368
|
-
console.error(
|
|
1369
|
-
"Error:",
|
|
1370
|
-
error instanceof Error ? error.message : "Unknown error"
|
|
1371
|
-
);
|
|
1372
|
-
process.exit(1);
|
|
1373
|
-
}
|
|
1374
|
-
})
|
|
1375
|
-
).addCommand(
|
|
1376
|
-
new Command("download").description("Download a file from IPFS").argument("<cid>", "IPFS CID to download").argument("[output]", "Output file path (optional)").action(async (cid, output) => {
|
|
1377
|
-
const s = spinner("Downloading from IPFS...").start();
|
|
1378
|
-
try {
|
|
1379
|
-
const outputPath = await downloadFromIPFS(cid, output);
|
|
1380
|
-
s.succeed(`File downloaded successfully!`);
|
|
1381
|
-
console.log(`Saved to: ${outputPath}`);
|
|
1382
|
-
console.log(`Gateway URL: https://ipfs.io/ipfs/${cid}`);
|
|
1383
|
-
} catch (error) {
|
|
1384
|
-
s.fail("Download failed");
|
|
1385
|
-
console.error(
|
|
1386
|
-
"Error:",
|
|
1387
|
-
error instanceof Error ? error.message : "Unknown error"
|
|
1388
|
-
);
|
|
1389
|
-
process.exit(1);
|
|
1390
|
-
}
|
|
1391
|
-
})
|
|
1392
|
-
);
|
|
1393
739
|
var LocalRegistryServer = class {
|
|
1394
740
|
config;
|
|
1395
741
|
dataStore;
|
|
@@ -1446,8 +792,8 @@ var LocalRegistryServer = class {
|
|
|
1446
792
|
async reset() {
|
|
1447
793
|
this.dataStore.reset();
|
|
1448
794
|
const artifactsDir = this.config.getArtifactsDir();
|
|
1449
|
-
if (
|
|
1450
|
-
|
|
795
|
+
if (fs7.existsSync(artifactsDir)) {
|
|
796
|
+
fs7.rmSync(artifactsDir, { recursive: true, force: true });
|
|
1451
797
|
}
|
|
1452
798
|
}
|
|
1453
799
|
async backup(outputPath) {
|
|
@@ -1607,7 +953,7 @@ localCommand.addCommand(
|
|
|
1607
953
|
"Public host exposed in manifest artifact URLs",
|
|
1608
954
|
"host.docker.internal"
|
|
1609
955
|
).action(async (options) => {
|
|
1610
|
-
const spinner2 =
|
|
956
|
+
const spinner2 = ora4("Starting local registry...").start();
|
|
1611
957
|
try {
|
|
1612
958
|
const config = new LocalConfig();
|
|
1613
959
|
config.setHost(options.host);
|
|
@@ -1618,37 +964,37 @@ localCommand.addCommand(
|
|
|
1618
964
|
spinner2.succeed(
|
|
1619
965
|
`Local registry started on http://${config.getHost()}:${config.getPort()}`
|
|
1620
966
|
);
|
|
1621
|
-
console.log(
|
|
967
|
+
console.log(chalk4.blue("\n\u{1F4F1} Local Registry Status:"));
|
|
1622
968
|
console.log(
|
|
1623
|
-
|
|
969
|
+
chalk4.green(
|
|
1624
970
|
`\u2705 Server: http://${config.getHost()}:${config.getPort()}`
|
|
1625
971
|
)
|
|
1626
972
|
);
|
|
1627
973
|
console.log(
|
|
1628
|
-
|
|
974
|
+
chalk4.green(
|
|
1629
975
|
`\u{1F310} Public URL: http://${config.getPublicHost()}:${config.getPort()}`
|
|
1630
976
|
)
|
|
1631
977
|
);
|
|
1632
|
-
console.log(
|
|
978
|
+
console.log(chalk4.green(`\u{1F4C1} Data: ${config.getDataDir()}`));
|
|
1633
979
|
console.log(
|
|
1634
|
-
|
|
980
|
+
chalk4.green(
|
|
1635
981
|
`\u{1F4CB} Health: http://${config.getHost()}:${config.getPort()}/healthz`
|
|
1636
982
|
)
|
|
1637
983
|
);
|
|
1638
984
|
console.log(
|
|
1639
|
-
|
|
985
|
+
chalk4.green(
|
|
1640
986
|
`\u{1F4CA} Stats: http://${config.getHost()}:${config.getPort()}/stats`
|
|
1641
987
|
)
|
|
1642
988
|
);
|
|
1643
989
|
console.log(
|
|
1644
|
-
|
|
990
|
+
chalk4.blue(
|
|
1645
991
|
"\n\u{1F4A1} Use --local flag with other commands to use local registry"
|
|
1646
992
|
)
|
|
1647
993
|
);
|
|
1648
994
|
} catch (error) {
|
|
1649
995
|
spinner2.fail("Failed to start local registry");
|
|
1650
996
|
if (error instanceof Error) {
|
|
1651
|
-
console.error(
|
|
997
|
+
console.error(chalk4.red(`Error: ${error.message}`));
|
|
1652
998
|
}
|
|
1653
999
|
process.exit(1);
|
|
1654
1000
|
}
|
|
@@ -1656,7 +1002,7 @@ localCommand.addCommand(
|
|
|
1656
1002
|
);
|
|
1657
1003
|
localCommand.addCommand(
|
|
1658
1004
|
new Command("stop").description("Stop local registry server").action(async () => {
|
|
1659
|
-
const spinner2 =
|
|
1005
|
+
const spinner2 = ora4("Stopping local registry...").start();
|
|
1660
1006
|
try {
|
|
1661
1007
|
const config = new LocalConfig();
|
|
1662
1008
|
const server = new LocalRegistryServer(config);
|
|
@@ -1665,7 +1011,7 @@ localCommand.addCommand(
|
|
|
1665
1011
|
} catch (error) {
|
|
1666
1012
|
spinner2.fail("Failed to stop local registry");
|
|
1667
1013
|
if (error instanceof Error) {
|
|
1668
|
-
console.error(
|
|
1014
|
+
console.error(chalk4.red(`Error: ${error.message}`));
|
|
1669
1015
|
}
|
|
1670
1016
|
process.exit(1);
|
|
1671
1017
|
}
|
|
@@ -1673,23 +1019,23 @@ localCommand.addCommand(
|
|
|
1673
1019
|
);
|
|
1674
1020
|
localCommand.addCommand(
|
|
1675
1021
|
new Command("status").description("Check local registry status").action(async () => {
|
|
1676
|
-
const spinner2 =
|
|
1022
|
+
const spinner2 = ora4("Checking local registry status...").start();
|
|
1677
1023
|
try {
|
|
1678
1024
|
const config = new LocalConfig();
|
|
1679
1025
|
const server = new LocalRegistryServer(config);
|
|
1680
1026
|
const status = await server.getStatus();
|
|
1681
1027
|
if (status.running) {
|
|
1682
1028
|
spinner2.succeed("Local registry is running");
|
|
1683
|
-
console.log(
|
|
1684
|
-
console.log(
|
|
1685
|
-
console.log(
|
|
1029
|
+
console.log(chalk4.green(`\u2705 Server: ${status.url}`));
|
|
1030
|
+
console.log(chalk4.green(`\u{1F4C1} Data: ${status.dataDir}`));
|
|
1031
|
+
console.log(chalk4.green(`\u{1F4CA} Apps: ${status.appsCount} applications`));
|
|
1686
1032
|
console.log(
|
|
1687
|
-
|
|
1033
|
+
chalk4.green(`\u{1F4E6} Artifacts: ${status.artifactsCount} artifacts`)
|
|
1688
1034
|
);
|
|
1689
1035
|
} else {
|
|
1690
1036
|
spinner2.warn("Local registry is not running");
|
|
1691
1037
|
console.log(
|
|
1692
|
-
|
|
1038
|
+
chalk4.yellow(
|
|
1693
1039
|
'\u{1F4A1} Run "calimero-registry local start" to start the local registry'
|
|
1694
1040
|
)
|
|
1695
1041
|
);
|
|
@@ -1697,7 +1043,7 @@ localCommand.addCommand(
|
|
|
1697
1043
|
} catch (error) {
|
|
1698
1044
|
spinner2.fail("Failed to check local registry status");
|
|
1699
1045
|
if (error instanceof Error) {
|
|
1700
|
-
console.error(
|
|
1046
|
+
console.error(chalk4.red(`Error: ${error.message}`));
|
|
1701
1047
|
}
|
|
1702
1048
|
process.exit(1);
|
|
1703
1049
|
}
|
|
@@ -1707,22 +1053,22 @@ localCommand.addCommand(
|
|
|
1707
1053
|
new Command("reset").description("Reset local registry data").option("-f, --force", "Force reset without confirmation").action(async (options) => {
|
|
1708
1054
|
if (!options.force) {
|
|
1709
1055
|
console.log(
|
|
1710
|
-
|
|
1056
|
+
chalk4.yellow("\u26A0\uFE0F This will delete all local registry data!")
|
|
1711
1057
|
);
|
|
1712
|
-
console.log(
|
|
1058
|
+
console.log(chalk4.yellow(" Use --force flag to confirm"));
|
|
1713
1059
|
return;
|
|
1714
1060
|
}
|
|
1715
|
-
const spinner2 =
|
|
1061
|
+
const spinner2 = ora4("Resetting local registry data...").start();
|
|
1716
1062
|
try {
|
|
1717
1063
|
const config = new LocalConfig();
|
|
1718
1064
|
const server = new LocalRegistryServer(config);
|
|
1719
1065
|
await server.reset();
|
|
1720
1066
|
spinner2.succeed("Local registry data reset");
|
|
1721
|
-
console.log(
|
|
1067
|
+
console.log(chalk4.green("\u2705 All local data has been cleared"));
|
|
1722
1068
|
} catch (error) {
|
|
1723
1069
|
spinner2.fail("Failed to reset local registry data");
|
|
1724
1070
|
if (error instanceof Error) {
|
|
1725
|
-
console.error(
|
|
1071
|
+
console.error(chalk4.red(`Error: ${error.message}`));
|
|
1726
1072
|
}
|
|
1727
1073
|
process.exit(1);
|
|
1728
1074
|
}
|
|
@@ -1730,17 +1076,17 @@ localCommand.addCommand(
|
|
|
1730
1076
|
);
|
|
1731
1077
|
localCommand.addCommand(
|
|
1732
1078
|
new Command("backup").description("Backup local registry data").option("-o, --output <file>", "Output file path").action(async (options) => {
|
|
1733
|
-
const spinner2 =
|
|
1079
|
+
const spinner2 = ora4("Creating backup...").start();
|
|
1734
1080
|
try {
|
|
1735
1081
|
const config = new LocalConfig();
|
|
1736
1082
|
const server = new LocalRegistryServer(config);
|
|
1737
1083
|
const backupPath = await server.backup(options.output);
|
|
1738
1084
|
spinner2.succeed("Backup created successfully");
|
|
1739
|
-
console.log(
|
|
1085
|
+
console.log(chalk4.green(`\u{1F4E6} Backup saved to: ${backupPath}`));
|
|
1740
1086
|
} catch (error) {
|
|
1741
1087
|
spinner2.fail("Failed to create backup");
|
|
1742
1088
|
if (error instanceof Error) {
|
|
1743
|
-
console.error(
|
|
1089
|
+
console.error(chalk4.red(`Error: ${error.message}`));
|
|
1744
1090
|
}
|
|
1745
1091
|
process.exit(1);
|
|
1746
1092
|
}
|
|
@@ -1748,22 +1094,22 @@ localCommand.addCommand(
|
|
|
1748
1094
|
);
|
|
1749
1095
|
localCommand.addCommand(
|
|
1750
1096
|
new Command("restore").description("Restore local registry data from backup").argument("<backup-file>", "Path to backup file").action(async (backupFile) => {
|
|
1751
|
-
const spinner2 =
|
|
1097
|
+
const spinner2 = ora4("Restoring from backup...").start();
|
|
1752
1098
|
try {
|
|
1753
|
-
if (!
|
|
1099
|
+
if (!fs7.existsSync(backupFile)) {
|
|
1754
1100
|
spinner2.fail("Backup file not found");
|
|
1755
|
-
console.error(
|
|
1101
|
+
console.error(chalk4.red(`File not found: ${backupFile}`));
|
|
1756
1102
|
process.exit(1);
|
|
1757
1103
|
}
|
|
1758
1104
|
const config = new LocalConfig();
|
|
1759
1105
|
const server = new LocalRegistryServer(config);
|
|
1760
1106
|
await server.restore(backupFile);
|
|
1761
1107
|
spinner2.succeed("Data restored successfully");
|
|
1762
|
-
console.log(
|
|
1108
|
+
console.log(chalk4.green(`\u2705 Restored from: ${backupFile}`));
|
|
1763
1109
|
} catch (error) {
|
|
1764
1110
|
spinner2.fail("Failed to restore from backup");
|
|
1765
1111
|
if (error instanceof Error) {
|
|
1766
|
-
console.error(
|
|
1112
|
+
console.error(chalk4.red(`Error: ${error.message}`));
|
|
1767
1113
|
}
|
|
1768
1114
|
process.exit(1);
|
|
1769
1115
|
}
|
|
@@ -1771,146 +1117,29 @@ localCommand.addCommand(
|
|
|
1771
1117
|
);
|
|
1772
1118
|
localCommand.addCommand(
|
|
1773
1119
|
new Command("seed").description("Seed local registry with sample data").action(async () => {
|
|
1774
|
-
const spinner2 =
|
|
1120
|
+
const spinner2 = ora4("Seeding local registry with sample data...").start();
|
|
1775
1121
|
try {
|
|
1776
1122
|
const config = new LocalConfig();
|
|
1777
1123
|
const server = new LocalRegistryServer(config);
|
|
1778
1124
|
await server.seed();
|
|
1779
1125
|
spinner2.succeed("Sample data seeded successfully");
|
|
1780
1126
|
console.log(
|
|
1781
|
-
|
|
1127
|
+
chalk4.green("\u2705 Local registry populated with sample applications")
|
|
1782
1128
|
);
|
|
1783
1129
|
console.log(
|
|
1784
|
-
|
|
1785
|
-
'\u{1F4A1} Run "calimero-registry
|
|
1130
|
+
chalk4.blue(
|
|
1131
|
+
'\u{1F4A1} Run "calimero-registry bundle get com.calimero.sample-bundle 1.0.0 --local" to see the sample bundle'
|
|
1786
1132
|
)
|
|
1787
1133
|
);
|
|
1788
1134
|
} catch (error) {
|
|
1789
1135
|
spinner2.fail("Failed to seed sample data");
|
|
1790
1136
|
if (error instanceof Error) {
|
|
1791
|
-
console.error(
|
|
1137
|
+
console.error(chalk4.red(`Error: ${error.message}`));
|
|
1792
1138
|
}
|
|
1793
1139
|
process.exit(1);
|
|
1794
1140
|
}
|
|
1795
1141
|
})
|
|
1796
1142
|
);
|
|
1797
|
-
var RemoteConfig = class {
|
|
1798
|
-
configPath;
|
|
1799
|
-
config;
|
|
1800
|
-
constructor() {
|
|
1801
|
-
this.configPath = path7.join(
|
|
1802
|
-
os.homedir(),
|
|
1803
|
-
".calimero-registry",
|
|
1804
|
-
"remote-config.json"
|
|
1805
|
-
);
|
|
1806
|
-
this.config = this.loadConfig();
|
|
1807
|
-
}
|
|
1808
|
-
loadConfig() {
|
|
1809
|
-
const defaultConfig = {
|
|
1810
|
-
registry: {
|
|
1811
|
-
url: "https://apps.calimero.network"
|
|
1812
|
-
}
|
|
1813
|
-
};
|
|
1814
|
-
if (fs9.existsSync(this.configPath)) {
|
|
1815
|
-
try {
|
|
1816
|
-
const existingConfig = JSON.parse(
|
|
1817
|
-
fs9.readFileSync(this.configPath, "utf8")
|
|
1818
|
-
);
|
|
1819
|
-
return {
|
|
1820
|
-
registry: {
|
|
1821
|
-
...defaultConfig.registry,
|
|
1822
|
-
...existingConfig.registry || {}
|
|
1823
|
-
}
|
|
1824
|
-
};
|
|
1825
|
-
} catch {
|
|
1826
|
-
console.warn("Failed to load existing config, using defaults");
|
|
1827
|
-
}
|
|
1828
|
-
}
|
|
1829
|
-
return defaultConfig;
|
|
1830
|
-
}
|
|
1831
|
-
saveConfig() {
|
|
1832
|
-
const configDir = path7.dirname(this.configPath);
|
|
1833
|
-
if (!fs9.existsSync(configDir)) {
|
|
1834
|
-
fs9.mkdirSync(configDir, { recursive: true });
|
|
1835
|
-
}
|
|
1836
|
-
const configToSave = {
|
|
1837
|
-
registry: {
|
|
1838
|
-
url: this.config.registry.url,
|
|
1839
|
-
// Save API key if it exists in config (regardless of env var)
|
|
1840
|
-
...this.config.registry.apiKey ? { apiKey: this.config.registry.apiKey } : {}
|
|
1841
|
-
}
|
|
1842
|
-
};
|
|
1843
|
-
fs9.writeFileSync(this.configPath, JSON.stringify(configToSave, null, 2));
|
|
1844
|
-
}
|
|
1845
|
-
/**
|
|
1846
|
-
* Get registry URL with priority:
|
|
1847
|
-
* 1. Environment variable CALIMERO_REGISTRY_URL
|
|
1848
|
-
* 2. Config file value
|
|
1849
|
-
* 3. Default value
|
|
1850
|
-
*/
|
|
1851
|
-
getRegistryUrl() {
|
|
1852
|
-
return process.env.CALIMERO_REGISTRY_URL || this.config.registry.url || "https://apps.calimero.network";
|
|
1853
|
-
}
|
|
1854
|
-
/**
|
|
1855
|
-
* Set registry URL
|
|
1856
|
-
*/
|
|
1857
|
-
setRegistryUrl(url) {
|
|
1858
|
-
this.config.registry.url = url;
|
|
1859
|
-
this.saveConfig();
|
|
1860
|
-
}
|
|
1861
|
-
/**
|
|
1862
|
-
* Get API key with priority:
|
|
1863
|
-
* 1. Environment variable CALIMERO_API_KEY
|
|
1864
|
-
* 2. Config file value
|
|
1865
|
-
* 3. undefined
|
|
1866
|
-
*/
|
|
1867
|
-
getApiKey() {
|
|
1868
|
-
return process.env.CALIMERO_API_KEY || this.config.registry.apiKey;
|
|
1869
|
-
}
|
|
1870
|
-
/**
|
|
1871
|
-
* Set API key (stored in config file)
|
|
1872
|
-
*/
|
|
1873
|
-
setApiKey(apiKey) {
|
|
1874
|
-
this.config.registry.apiKey = apiKey;
|
|
1875
|
-
this.saveConfig();
|
|
1876
|
-
}
|
|
1877
|
-
/**
|
|
1878
|
-
* Remove API key from config
|
|
1879
|
-
*/
|
|
1880
|
-
removeApiKey() {
|
|
1881
|
-
delete this.config.registry.apiKey;
|
|
1882
|
-
this.saveConfig();
|
|
1883
|
-
}
|
|
1884
|
-
/**
|
|
1885
|
-
* Get full configuration
|
|
1886
|
-
*/
|
|
1887
|
-
getConfig() {
|
|
1888
|
-
return {
|
|
1889
|
-
registry: {
|
|
1890
|
-
url: this.getRegistryUrl(),
|
|
1891
|
-
// Don't expose API key in getConfig (security)
|
|
1892
|
-
apiKey: this.getApiKey() ? "***" : void 0
|
|
1893
|
-
}
|
|
1894
|
-
};
|
|
1895
|
-
}
|
|
1896
|
-
/**
|
|
1897
|
-
* Get config file path
|
|
1898
|
-
*/
|
|
1899
|
-
getConfigPath() {
|
|
1900
|
-
return this.configPath;
|
|
1901
|
-
}
|
|
1902
|
-
/**
|
|
1903
|
-
* Reset to defaults
|
|
1904
|
-
*/
|
|
1905
|
-
reset() {
|
|
1906
|
-
this.config = {
|
|
1907
|
-
registry: {
|
|
1908
|
-
url: "https://apps.calimero.network"
|
|
1909
|
-
}
|
|
1910
|
-
};
|
|
1911
|
-
this.saveConfig();
|
|
1912
|
-
}
|
|
1913
|
-
};
|
|
1914
1143
|
|
|
1915
1144
|
// src/lib/services.ts
|
|
1916
1145
|
var SERVICE_NAME_RE = /^[a-z0-9][a-z0-9_-]*$/;
|
|
@@ -2026,14 +1255,14 @@ function createCreateCommand() {
|
|
|
2026
1255
|
).option("-o, --output <path>", "Output path for the MPK file").option("--name <name>", "Application name").option("--description <description>", "Application description").option("--author <author>", "Application author").option("--frontend <url>", "Frontend URL").option("--github <url>", "GitHub URL").option("--docs <url>", "Documentation URL").option(
|
|
2027
1256
|
"--export <interface>",
|
|
2028
1257
|
"Export interface (can be specified multiple times)",
|
|
2029
|
-
(value, prev) => {
|
|
2030
|
-
return [...prev
|
|
1258
|
+
(value, prev = []) => {
|
|
1259
|
+
return [...prev, value];
|
|
2031
1260
|
}
|
|
2032
1261
|
).option(
|
|
2033
1262
|
"--use <interface>",
|
|
2034
1263
|
"Use interface (can be specified multiple times)",
|
|
2035
|
-
(value, prev) => {
|
|
2036
|
-
return [...prev
|
|
1264
|
+
(value, prev = []) => {
|
|
1265
|
+
return [...prev, value];
|
|
2037
1266
|
}
|
|
2038
1267
|
).option("--abi <path>", "Path to ABI JSON file to include in bundle").option(
|
|
2039
1268
|
"--service <spec>",
|
|
@@ -2086,13 +1315,13 @@ Note:
|
|
|
2086
1315
|
try {
|
|
2087
1316
|
let manifestConfig = {};
|
|
2088
1317
|
if (options.manifest) {
|
|
2089
|
-
const manifestPath =
|
|
2090
|
-
if (!
|
|
1318
|
+
const manifestPath = path5.resolve(options.manifest);
|
|
1319
|
+
if (!fs7.existsSync(manifestPath)) {
|
|
2091
1320
|
console.error(`\u274C Manifest file not found: ${options.manifest}`);
|
|
2092
1321
|
process.exit(1);
|
|
2093
1322
|
}
|
|
2094
1323
|
try {
|
|
2095
|
-
const manifestContent =
|
|
1324
|
+
const manifestContent = fs7.readFileSync(manifestPath, "utf8");
|
|
2096
1325
|
const parsed = JSON.parse(manifestContent);
|
|
2097
1326
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
2098
1327
|
console.error(`\u274C Invalid manifest file: ${options.manifest}`);
|
|
@@ -2163,13 +1392,13 @@ Note:
|
|
|
2163
1392
|
);
|
|
2164
1393
|
process.exit(1);
|
|
2165
1394
|
}
|
|
2166
|
-
const wasmPath =
|
|
2167
|
-
if (!
|
|
1395
|
+
const wasmPath = path5.resolve(wasmFile);
|
|
1396
|
+
if (!fs7.existsSync(wasmPath)) {
|
|
2168
1397
|
console.error(`\u274C WASM file not found: ${wasmFile}`);
|
|
2169
1398
|
process.exit(1);
|
|
2170
1399
|
}
|
|
2171
|
-
console.log(`\u{1F4E6} Creating MPK bundle from: ${
|
|
2172
|
-
const wasmContent =
|
|
1400
|
+
console.log(`\u{1F4E6} Creating MPK bundle from: ${path5.basename(wasmPath)}`);
|
|
1401
|
+
const wasmContent = fs7.readFileSync(wasmPath);
|
|
2173
1402
|
const wasmSize = wasmContent.length;
|
|
2174
1403
|
const wasmHash = crypto2.createHash("sha256").update(wasmContent).digest("hex");
|
|
2175
1404
|
let abiArtifact = void 0;
|
|
@@ -2178,17 +1407,17 @@ Note:
|
|
|
2178
1407
|
const abiPathFromManifest = typeof manifestConfig.abi === "string" ? manifestConfig.abi : null;
|
|
2179
1408
|
const abiFilePath = abiPathFromOption || abiPathFromManifest;
|
|
2180
1409
|
if (abiFilePath) {
|
|
2181
|
-
const abiResolvedPath = abiPathFromOption ?
|
|
2182
|
-
|
|
1410
|
+
const abiResolvedPath = abiPathFromOption ? path5.resolve(abiFilePath) : options.manifest && abiPathFromManifest ? path5.resolve(
|
|
1411
|
+
path5.dirname(path5.resolve(options.manifest)),
|
|
2183
1412
|
abiFilePath
|
|
2184
|
-
) :
|
|
2185
|
-
if (!
|
|
1413
|
+
) : path5.resolve(abiFilePath);
|
|
1414
|
+
if (!fs7.existsSync(abiResolvedPath)) {
|
|
2186
1415
|
console.error(`\u274C ABI file not found: ${abiFilePath}`);
|
|
2187
1416
|
console.error(` Resolved path: ${abiResolvedPath}`);
|
|
2188
1417
|
process.exit(1);
|
|
2189
1418
|
}
|
|
2190
1419
|
try {
|
|
2191
|
-
abiContent =
|
|
1420
|
+
abiContent = fs7.readFileSync(abiResolvedPath);
|
|
2192
1421
|
JSON.parse(abiContent.toString("utf8"));
|
|
2193
1422
|
const abiHash = crypto2.createHash("sha256").update(abiContent).digest("hex");
|
|
2194
1423
|
abiArtifact = {
|
|
@@ -2197,7 +1426,7 @@ Note:
|
|
|
2197
1426
|
size: abiContent.length
|
|
2198
1427
|
};
|
|
2199
1428
|
console.log(
|
|
2200
|
-
` Including ABI file: ${
|
|
1429
|
+
` Including ABI file: ${path5.basename(abiResolvedPath)}`
|
|
2201
1430
|
);
|
|
2202
1431
|
} catch (error) {
|
|
2203
1432
|
console.error(
|
|
@@ -2221,7 +1450,7 @@ Note:
|
|
|
2221
1450
|
const manifestServices = Array.isArray(
|
|
2222
1451
|
manifestConfig.services
|
|
2223
1452
|
) ? manifestConfig.services : [];
|
|
2224
|
-
const manifestDir = options.manifest ?
|
|
1453
|
+
const manifestDir = options.manifest ? path5.dirname(path5.resolve(options.manifest)) : process.cwd();
|
|
2225
1454
|
const allServiceSources = [
|
|
2226
1455
|
...cliServices.map((src) => ({ src, baseDir: process.cwd() })),
|
|
2227
1456
|
...manifestServices.map((src) => ({ src, baseDir: manifestDir }))
|
|
@@ -2255,15 +1484,15 @@ Note:
|
|
|
2255
1484
|
);
|
|
2256
1485
|
process.exit(1);
|
|
2257
1486
|
}
|
|
2258
|
-
const svcWasmPath =
|
|
2259
|
-
if (!
|
|
1487
|
+
const svcWasmPath = path5.resolve(baseDir, src.wasm);
|
|
1488
|
+
if (!fs7.existsSync(svcWasmPath)) {
|
|
2260
1489
|
console.error(
|
|
2261
1490
|
`\u274C Service "${src.name}" WASM not found: ${src.wasm}`
|
|
2262
1491
|
);
|
|
2263
1492
|
console.error(` Resolved path: ${svcWasmPath}`);
|
|
2264
1493
|
process.exit(1);
|
|
2265
1494
|
}
|
|
2266
|
-
const svcWasmContent =
|
|
1495
|
+
const svcWasmContent = fs7.readFileSync(svcWasmPath);
|
|
2267
1496
|
const svcWasmHash = crypto2.createHash("sha256").update(svcWasmContent).digest("hex");
|
|
2268
1497
|
const wasmArchivePath = serviceWasmPath(src.name);
|
|
2269
1498
|
const entry = {
|
|
@@ -2279,15 +1508,15 @@ Note:
|
|
|
2279
1508
|
content: svcWasmContent
|
|
2280
1509
|
});
|
|
2281
1510
|
if (src.abi) {
|
|
2282
|
-
const svcAbiPath =
|
|
2283
|
-
if (!
|
|
1511
|
+
const svcAbiPath = path5.resolve(baseDir, src.abi);
|
|
1512
|
+
if (!fs7.existsSync(svcAbiPath)) {
|
|
2284
1513
|
console.error(
|
|
2285
1514
|
`\u274C Service "${src.name}" ABI not found: ${src.abi}`
|
|
2286
1515
|
);
|
|
2287
1516
|
console.error(` Resolved path: ${svcAbiPath}`);
|
|
2288
1517
|
process.exit(1);
|
|
2289
1518
|
}
|
|
2290
|
-
const svcAbiContent =
|
|
1519
|
+
const svcAbiContent = fs7.readFileSync(svcAbiPath);
|
|
2291
1520
|
try {
|
|
2292
1521
|
JSON.parse(svcAbiContent.toString("utf8"));
|
|
2293
1522
|
} catch (error) {
|
|
@@ -2313,7 +1542,7 @@ Note:
|
|
|
2313
1542
|
}
|
|
2314
1543
|
serviceArtifacts.push(entry);
|
|
2315
1544
|
console.log(
|
|
2316
|
-
` Including service: ${src.name} (${
|
|
1545
|
+
` Including service: ${src.name} (${path5.basename(svcWasmPath)})`
|
|
2317
1546
|
);
|
|
2318
1547
|
}
|
|
2319
1548
|
const metadata = {
|
|
@@ -2346,30 +1575,30 @@ Note:
|
|
|
2346
1575
|
links: Object.keys(links).length > 0 ? links : void 0,
|
|
2347
1576
|
signature: void 0
|
|
2348
1577
|
};
|
|
2349
|
-
let outputDir = finalOutput ?
|
|
2350
|
-
if (!
|
|
2351
|
-
|
|
1578
|
+
let outputDir = finalOutput ? path5.resolve(finalOutput) : path5.join(process.cwd(), finalPackage, finalVersion);
|
|
1579
|
+
if (!fs7.existsSync(outputDir)) {
|
|
1580
|
+
fs7.mkdirSync(outputDir, { recursive: true });
|
|
2352
1581
|
}
|
|
2353
|
-
|
|
2354
|
-
|
|
1582
|
+
fs7.writeFileSync(
|
|
1583
|
+
path5.join(outputDir, "manifest.json"),
|
|
2355
1584
|
JSON.stringify(manifest, null, 2)
|
|
2356
1585
|
);
|
|
2357
|
-
|
|
1586
|
+
fs7.writeFileSync(path5.join(outputDir, "app.wasm"), wasmContent);
|
|
2358
1587
|
if (abiContent) {
|
|
2359
|
-
|
|
1588
|
+
fs7.writeFileSync(path5.join(outputDir, "abi.json"), abiContent);
|
|
2360
1589
|
}
|
|
2361
|
-
const servicesDir =
|
|
1590
|
+
const servicesDir = path5.join(outputDir, "services");
|
|
2362
1591
|
for (const { relPath, content } of serviceFilesToWrite) {
|
|
2363
|
-
const dest =
|
|
2364
|
-
const rel =
|
|
2365
|
-
if (rel.startsWith("..") ||
|
|
1592
|
+
const dest = path5.join(outputDir, relPath);
|
|
1593
|
+
const rel = path5.relative(servicesDir, dest);
|
|
1594
|
+
if (rel.startsWith("..") || path5.isAbsolute(rel)) {
|
|
2366
1595
|
console.error(
|
|
2367
1596
|
`\u274C Refusing to write service file outside services/: ${relPath}`
|
|
2368
1597
|
);
|
|
2369
1598
|
process.exit(1);
|
|
2370
1599
|
}
|
|
2371
|
-
|
|
2372
|
-
|
|
1600
|
+
fs7.mkdirSync(path5.dirname(dest), { recursive: true });
|
|
1601
|
+
fs7.writeFileSync(dest, content);
|
|
2373
1602
|
}
|
|
2374
1603
|
console.log(`\u2705 Bundle files written to: ${outputDir}`);
|
|
2375
1604
|
console.log(` Package: ${finalPackage}`);
|
|
@@ -2386,7 +1615,7 @@ Note:
|
|
|
2386
1615
|
console.log("");
|
|
2387
1616
|
console.log("Next steps:");
|
|
2388
1617
|
console.log(
|
|
2389
|
-
` 1. Sign the manifest: mero-sign sign ${
|
|
1618
|
+
` 1. Sign the manifest: mero-sign sign ${path5.join(outputDir, "manifest.json")} --key key.json`
|
|
2390
1619
|
);
|
|
2391
1620
|
console.log(
|
|
2392
1621
|
` 2. Push the bundle: calimero-registry bundle push ${outputDir} --remote`
|
|
@@ -2455,30 +1684,30 @@ Note:
|
|
|
2455
1684
|
);
|
|
2456
1685
|
process.exit(1);
|
|
2457
1686
|
}
|
|
2458
|
-
const fullPath =
|
|
2459
|
-
if (!
|
|
1687
|
+
const fullPath = path5.resolve(bundleFile);
|
|
1688
|
+
if (!fs7.existsSync(fullPath)) {
|
|
2460
1689
|
console.error(`\u274C File not found: ${bundleFile}`);
|
|
2461
1690
|
process.exit(1);
|
|
2462
1691
|
}
|
|
2463
1692
|
mpkPath = fullPath;
|
|
2464
|
-
if (
|
|
2465
|
-
const manifestInDir =
|
|
2466
|
-
const wasmInDir =
|
|
2467
|
-
if (!
|
|
1693
|
+
if (fs7.statSync(fullPath).isDirectory()) {
|
|
1694
|
+
const manifestInDir = path5.join(fullPath, "manifest.json");
|
|
1695
|
+
const wasmInDir = path5.join(fullPath, "app.wasm");
|
|
1696
|
+
if (!fs7.existsSync(manifestInDir)) {
|
|
2468
1697
|
console.error(
|
|
2469
1698
|
`\u274C manifest.json not found in directory: ${fullPath}`
|
|
2470
1699
|
);
|
|
2471
1700
|
process.exit(1);
|
|
2472
1701
|
}
|
|
2473
|
-
if (!
|
|
1702
|
+
if (!fs7.existsSync(wasmInDir)) {
|
|
2474
1703
|
console.error(`\u274C app.wasm not found in directory: ${fullPath}`);
|
|
2475
1704
|
process.exit(1);
|
|
2476
1705
|
}
|
|
2477
|
-
tempMpk =
|
|
1706
|
+
tempMpk = path5.join(fullPath, `.temp-push-${Date.now()}.mpk`);
|
|
2478
1707
|
let dirManifest;
|
|
2479
1708
|
try {
|
|
2480
1709
|
dirManifest = JSON.parse(
|
|
2481
|
-
|
|
1710
|
+
fs7.readFileSync(manifestInDir, "utf8")
|
|
2482
1711
|
);
|
|
2483
1712
|
} catch (e) {
|
|
2484
1713
|
console.error(
|
|
@@ -2511,7 +1740,7 @@ Note:
|
|
|
2511
1740
|
process.exit(1);
|
|
2512
1741
|
}
|
|
2513
1742
|
for (const f of archiveFiles) {
|
|
2514
|
-
if (!
|
|
1743
|
+
if (!fs7.existsSync(path5.join(fullPath, f))) {
|
|
2515
1744
|
console.error(
|
|
2516
1745
|
`\u274C Bundle file referenced by manifest not found: ${f}`
|
|
2517
1746
|
);
|
|
@@ -2527,7 +1756,7 @@ Note:
|
|
|
2527
1756
|
`\u{1F4E6} Packed directory into temporary bundle (${archiveFiles.length} files)`
|
|
2528
1757
|
);
|
|
2529
1758
|
}
|
|
2530
|
-
console.log(`\u{1F4E6} Processing bundle: ${
|
|
1759
|
+
console.log(`\u{1F4E6} Processing bundle: ${path5.basename(mpkPath)}`);
|
|
2531
1760
|
const manifest = await extractManifest(mpkPath);
|
|
2532
1761
|
if (!manifest) {
|
|
2533
1762
|
console.error("\u274C manifest.json not found in bundle");
|
|
@@ -2574,8 +1803,8 @@ Note:
|
|
|
2574
1803
|
console.error("\u274C Failed to push bundle:", message);
|
|
2575
1804
|
process.exit(1);
|
|
2576
1805
|
} finally {
|
|
2577
|
-
if (tempMpk &&
|
|
2578
|
-
|
|
1806
|
+
if (tempMpk && fs7.existsSync(tempMpk)) {
|
|
1807
|
+
fs7.rmSync(tempMpk);
|
|
2579
1808
|
}
|
|
2580
1809
|
}
|
|
2581
1810
|
});
|
|
@@ -2643,12 +1872,12 @@ Examples:
|
|
|
2643
1872
|
};
|
|
2644
1873
|
if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
|
|
2645
1874
|
if (options.manifest) {
|
|
2646
|
-
const manifestPath =
|
|
2647
|
-
if (!
|
|
1875
|
+
const manifestPath = path5.resolve(options.manifest);
|
|
1876
|
+
if (!fs7.existsSync(manifestPath)) {
|
|
2648
1877
|
console.error(`\u274C Manifest file not found: ${options.manifest}`);
|
|
2649
1878
|
process.exit(1);
|
|
2650
1879
|
}
|
|
2651
|
-
const raw =
|
|
1880
|
+
const raw = fs7.readFileSync(manifestPath, "utf8");
|
|
2652
1881
|
let manifest2;
|
|
2653
1882
|
try {
|
|
2654
1883
|
manifest2 = JSON.parse(raw);
|
|
@@ -2735,8 +1964,8 @@ Examples:
|
|
|
2735
1964
|
if (!manifest.links) manifest.links = {};
|
|
2736
1965
|
manifest.links.docs = options.docs;
|
|
2737
1966
|
}
|
|
2738
|
-
const outputPath =
|
|
2739
|
-
|
|
1967
|
+
const outputPath = path5.resolve(options.output || "manifest.json");
|
|
1968
|
+
fs7.writeFileSync(outputPath, JSON.stringify(manifest, null, 2));
|
|
2740
1969
|
console.log(`\u2705 Wrote modified manifest to: ${outputPath}`);
|
|
2741
1970
|
console.log("");
|
|
2742
1971
|
console.log("Next steps:");
|
|
@@ -2756,7 +1985,7 @@ Examples:
|
|
|
2756
1985
|
async function pushToRemote(bundlePath, manifest, registryUrl, apiKey) {
|
|
2757
1986
|
try {
|
|
2758
1987
|
console.log(`\u{1F4E4} Pushing to remote registry: ${registryUrl}`);
|
|
2759
|
-
const bundleBuffer =
|
|
1988
|
+
const bundleBuffer = fs7.readFileSync(bundlePath);
|
|
2760
1989
|
const bundleSize = bundleBuffer.length;
|
|
2761
1990
|
console.log(` Bundle size: ${bundleSize} bytes`);
|
|
2762
1991
|
const bundleHex = bundleBuffer.toString("hex");
|
|
@@ -2936,25 +2165,25 @@ async function extractManifest(bundlePath) {
|
|
|
2936
2165
|
if (entry.path === "manifest.json") ;
|
|
2937
2166
|
}
|
|
2938
2167
|
});
|
|
2939
|
-
const extractDir =
|
|
2940
|
-
if (!
|
|
2941
|
-
|
|
2168
|
+
const extractDir = path5.join(path5.dirname(bundlePath), `.temp-${Date.now()}`);
|
|
2169
|
+
if (!fs7.existsSync(extractDir)) {
|
|
2170
|
+
fs7.mkdirSync(extractDir);
|
|
2942
2171
|
}
|
|
2943
2172
|
try {
|
|
2944
2173
|
await tar.x({
|
|
2945
2174
|
file: bundlePath,
|
|
2946
2175
|
cwd: extractDir,
|
|
2947
|
-
filter: (
|
|
2176
|
+
filter: (path6) => path6 === "manifest.json"
|
|
2948
2177
|
});
|
|
2949
|
-
const manifestPath =
|
|
2950
|
-
if (
|
|
2951
|
-
const content =
|
|
2178
|
+
const manifestPath = path5.join(extractDir, "manifest.json");
|
|
2179
|
+
if (fs7.existsSync(manifestPath)) {
|
|
2180
|
+
const content = fs7.readFileSync(manifestPath, "utf8");
|
|
2952
2181
|
manifestContent = content;
|
|
2953
2182
|
}
|
|
2954
2183
|
} catch {
|
|
2955
2184
|
} finally {
|
|
2956
|
-
if (
|
|
2957
|
-
|
|
2185
|
+
if (fs7.existsSync(extractDir)) {
|
|
2186
|
+
fs7.rmSync(extractDir, { recursive: true, force: true });
|
|
2958
2187
|
}
|
|
2959
2188
|
}
|
|
2960
2189
|
if (manifestContent) {
|
|
@@ -2978,29 +2207,29 @@ function createConfigSetCommand() {
|
|
|
2978
2207
|
case "url":
|
|
2979
2208
|
config.setRegistryUrl(value);
|
|
2980
2209
|
console.log(
|
|
2981
|
-
|
|
2210
|
+
chalk4.green(`\u2705 Registry URL set to: ${chalk4.bold(value)}`)
|
|
2982
2211
|
);
|
|
2983
2212
|
break;
|
|
2984
2213
|
case "api-key":
|
|
2985
2214
|
case "apiKey":
|
|
2986
2215
|
config.setApiKey(value);
|
|
2987
|
-
console.log(
|
|
2216
|
+
console.log(chalk4.green("\u2705 API key set successfully"));
|
|
2988
2217
|
console.log(
|
|
2989
|
-
|
|
2218
|
+
chalk4.yellow(
|
|
2990
2219
|
"\u{1F4A1} Note: API key is stored in plain text. Consider using CALIMERO_API_KEY environment variable for better security."
|
|
2991
2220
|
)
|
|
2992
2221
|
);
|
|
2993
2222
|
break;
|
|
2994
2223
|
default:
|
|
2995
|
-
console.error(
|
|
2996
|
-
console.log(
|
|
2224
|
+
console.error(chalk4.red(`\u274C Unknown configuration key: ${key}`));
|
|
2225
|
+
console.log(chalk4.blue("\nAvailable keys:"));
|
|
2997
2226
|
console.log(" registry-url - Default registry URL");
|
|
2998
2227
|
console.log(" api-key - API key for authentication");
|
|
2999
2228
|
process.exit(1);
|
|
3000
2229
|
}
|
|
3001
2230
|
} catch (error) {
|
|
3002
2231
|
const message = error instanceof Error ? error.message : String(error);
|
|
3003
|
-
console.error(
|
|
2232
|
+
console.error(chalk4.red("\u274C Failed to set configuration:"), message);
|
|
3004
2233
|
process.exit(1);
|
|
3005
2234
|
}
|
|
3006
2235
|
});
|
|
@@ -3022,7 +2251,7 @@ function createConfigGetCommand() {
|
|
|
3022
2251
|
const masked = apiKey.length > 8 ? `${apiKey.substring(0, 4)}...${apiKey.substring(apiKey.length - 4)}` : "***";
|
|
3023
2252
|
console.log(masked);
|
|
3024
2253
|
console.log(
|
|
3025
|
-
|
|
2254
|
+
chalk4.yellow(
|
|
3026
2255
|
'\u{1F4A1} Note: API key is masked. Use "config list" to see source.'
|
|
3027
2256
|
)
|
|
3028
2257
|
);
|
|
@@ -3032,15 +2261,15 @@ function createConfigGetCommand() {
|
|
|
3032
2261
|
break;
|
|
3033
2262
|
}
|
|
3034
2263
|
default:
|
|
3035
|
-
console.error(
|
|
3036
|
-
console.log(
|
|
2264
|
+
console.error(chalk4.red(`\u274C Unknown configuration key: ${key}`));
|
|
2265
|
+
console.log(chalk4.blue("\nAvailable keys:"));
|
|
3037
2266
|
console.log(" registry-url - Default registry URL");
|
|
3038
2267
|
console.log(" api-key - API key for authentication");
|
|
3039
2268
|
process.exit(1);
|
|
3040
2269
|
}
|
|
3041
2270
|
} catch (error) {
|
|
3042
2271
|
const message = error instanceof Error ? error.message : String(error);
|
|
3043
|
-
console.error(
|
|
2272
|
+
console.error(chalk4.red("\u274C Failed to get configuration:"), message);
|
|
3044
2273
|
process.exit(1);
|
|
3045
2274
|
}
|
|
3046
2275
|
});
|
|
@@ -3049,43 +2278,43 @@ function createConfigListCommand() {
|
|
|
3049
2278
|
return new Command("list").description("List all configuration values").alias("ls").action(() => {
|
|
3050
2279
|
try {
|
|
3051
2280
|
const config = new RemoteConfig();
|
|
3052
|
-
console.log(
|
|
2281
|
+
console.log(chalk4.blue("\n\u{1F4CB} Remote Registry Configuration\n"));
|
|
3053
2282
|
const configPath = config.getConfigPath();
|
|
3054
|
-
const configFileExists =
|
|
2283
|
+
const configFileExists = fs7.existsSync(configPath);
|
|
3055
2284
|
const url = config.getRegistryUrl();
|
|
3056
2285
|
let urlSource;
|
|
3057
2286
|
if (process.env.CALIMERO_REGISTRY_URL) {
|
|
3058
|
-
urlSource =
|
|
2287
|
+
urlSource = chalk4.yellow("(from CALIMERO_REGISTRY_URL env var)");
|
|
3059
2288
|
} else if (configFileExists) {
|
|
3060
|
-
urlSource =
|
|
2289
|
+
urlSource = chalk4.gray("(from config file)");
|
|
3061
2290
|
} else {
|
|
3062
|
-
urlSource =
|
|
2291
|
+
urlSource = chalk4.gray("(default)");
|
|
3063
2292
|
}
|
|
3064
|
-
console.log(` ${
|
|
2293
|
+
console.log(` ${chalk4.bold("Registry URL:")} ${url} ${urlSource}`);
|
|
3065
2294
|
const apiKey = config.getApiKey();
|
|
3066
2295
|
if (apiKey) {
|
|
3067
2296
|
let apiKeySource;
|
|
3068
2297
|
if (process.env.CALIMERO_API_KEY) {
|
|
3069
|
-
apiKeySource =
|
|
2298
|
+
apiKeySource = chalk4.yellow("(from CALIMERO_API_KEY env var)");
|
|
3070
2299
|
} else if (configFileExists) {
|
|
3071
|
-
apiKeySource =
|
|
2300
|
+
apiKeySource = chalk4.gray("(from config file)");
|
|
3072
2301
|
} else {
|
|
3073
|
-
apiKeySource =
|
|
2302
|
+
apiKeySource = chalk4.gray("(default)");
|
|
3074
2303
|
}
|
|
3075
2304
|
const masked = apiKey.length > 8 ? `${apiKey.substring(0, 4)}...${apiKey.substring(apiKey.length - 4)}` : "***";
|
|
3076
|
-
console.log(` ${
|
|
2305
|
+
console.log(` ${chalk4.bold("API Key:")} ${masked} ${apiKeySource}`);
|
|
3077
2306
|
} else {
|
|
3078
|
-
console.log(` ${
|
|
2307
|
+
console.log(` ${chalk4.bold("API Key:")} ${chalk4.gray("(not set)")}`);
|
|
3079
2308
|
}
|
|
3080
|
-
console.log(
|
|
2309
|
+
console.log(chalk4.blue(`
|
|
3081
2310
|
\u{1F4C1} Config file: ${configPath}`));
|
|
3082
2311
|
if (!configFileExists) {
|
|
3083
|
-
console.log(
|
|
2312
|
+
console.log(chalk4.gray(" (file does not exist, using defaults)"));
|
|
3084
2313
|
}
|
|
3085
2314
|
console.log();
|
|
3086
2315
|
} catch (error) {
|
|
3087
2316
|
const message = error instanceof Error ? error.message : String(error);
|
|
3088
|
-
console.error(
|
|
2317
|
+
console.error(chalk4.red("\u274C Failed to list configuration:"), message);
|
|
3089
2318
|
process.exit(1);
|
|
3090
2319
|
}
|
|
3091
2320
|
});
|
|
@@ -3095,10 +2324,10 @@ function createConfigResetCommand() {
|
|
|
3095
2324
|
try {
|
|
3096
2325
|
if (!options.force) {
|
|
3097
2326
|
console.error(
|
|
3098
|
-
|
|
2327
|
+
chalk4.red("\u274C Configuration reset requires --force flag")
|
|
3099
2328
|
);
|
|
3100
2329
|
console.log(
|
|
3101
|
-
|
|
2330
|
+
chalk4.yellow(
|
|
3102
2331
|
"\u26A0\uFE0F This will reset all configuration to defaults. Use --force to confirm."
|
|
3103
2332
|
)
|
|
3104
2333
|
);
|
|
@@ -3106,13 +2335,13 @@ function createConfigResetCommand() {
|
|
|
3106
2335
|
}
|
|
3107
2336
|
const config = new RemoteConfig();
|
|
3108
2337
|
config.reset();
|
|
3109
|
-
console.log(
|
|
3110
|
-
console.log(
|
|
2338
|
+
console.log(chalk4.green("\u2705 Configuration reset to defaults"));
|
|
2339
|
+
console.log(chalk4.blue("\nDefault values:"));
|
|
3111
2340
|
console.log(" Registry URL: https://apps.calimero.network");
|
|
3112
2341
|
console.log(" API Key: (not set)");
|
|
3113
2342
|
} catch (error) {
|
|
3114
2343
|
const message = error instanceof Error ? error.message : String(error);
|
|
3115
|
-
console.error(
|
|
2344
|
+
console.error(chalk4.red("\u274C Failed to reset configuration:"), message);
|
|
3116
2345
|
process.exit(1);
|
|
3117
2346
|
}
|
|
3118
2347
|
});
|
|
@@ -3159,13 +2388,13 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3159
2388
|
"List organizations you belong to (uses API token to resolve identity)"
|
|
3160
2389
|
).action(async (_options, command) => {
|
|
3161
2390
|
const { url, timeout } = getGlobalOpts(command);
|
|
3162
|
-
const spinner2 =
|
|
2391
|
+
const spinner2 = ora4("Resolving identity...").start();
|
|
3163
2392
|
let authHeaders;
|
|
3164
2393
|
try {
|
|
3165
2394
|
authHeaders = getAuthHeaders();
|
|
3166
2395
|
} catch (e) {
|
|
3167
2396
|
spinner2.fail("API token required");
|
|
3168
|
-
console.error(
|
|
2397
|
+
console.error(chalk4.red(e instanceof Error ? e.message : String(e)));
|
|
3169
2398
|
process.exit(1);
|
|
3170
2399
|
}
|
|
3171
2400
|
const base = url.replace(/\/$/, "");
|
|
@@ -3179,7 +2408,7 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3179
2408
|
if (status !== 200 || !data?.user?.email) {
|
|
3180
2409
|
spinner2.fail("Could not resolve identity from API token");
|
|
3181
2410
|
console.error(
|
|
3182
|
-
|
|
2411
|
+
chalk4.red(
|
|
3183
2412
|
"Ensure your API token is valid. Get a new one from the web UI."
|
|
3184
2413
|
)
|
|
3185
2414
|
);
|
|
@@ -3189,7 +2418,7 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3189
2418
|
spinner2.text = `Fetching organizations for ${myEmail}...`;
|
|
3190
2419
|
} catch (e) {
|
|
3191
2420
|
spinner2.fail("Request failed");
|
|
3192
|
-
console.error(
|
|
2421
|
+
console.error(chalk4.red(e instanceof Error ? e.message : String(e)));
|
|
3193
2422
|
process.exit(1);
|
|
3194
2423
|
}
|
|
3195
2424
|
const apiUrl = `${base}/api/v2/orgs?member=${encodeURIComponent(myEmail)}`;
|
|
@@ -3201,13 +2430,13 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3201
2430
|
});
|
|
3202
2431
|
if (status !== 200) {
|
|
3203
2432
|
spinner2.fail("Failed to list organizations");
|
|
3204
|
-
console.error(
|
|
2433
|
+
console.error(chalk4.red(JSON.stringify(data)));
|
|
3205
2434
|
process.exit(1);
|
|
3206
2435
|
}
|
|
3207
2436
|
const orgs = Array.isArray(data) ? data : [];
|
|
3208
2437
|
spinner2.succeed(`Found ${orgs.length} organization(s)`);
|
|
3209
2438
|
if (orgs.length === 0) {
|
|
3210
|
-
console.log(
|
|
2439
|
+
console.log(chalk4.yellow("No organizations found"));
|
|
3211
2440
|
return;
|
|
3212
2441
|
}
|
|
3213
2442
|
const memberResults = await Promise.all(
|
|
@@ -3223,13 +2452,13 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3223
2452
|
const myMember = members.find((m) => m.email === myEmail);
|
|
3224
2453
|
const role = myMember?.role ?? "?";
|
|
3225
2454
|
const count = members.length;
|
|
3226
|
-
const roleLabel = role === "admin" ?
|
|
3227
|
-
return `${
|
|
2455
|
+
const roleLabel = role === "admin" ? chalk4.yellow("admin") : chalk4.gray(role);
|
|
2456
|
+
return `${chalk4.white(o.slug)} ${chalk4.gray(o.name)} ${chalk4.gray(`${count} member${count !== 1 ? "s" : ""}`)} ${roleLabel}`;
|
|
3228
2457
|
});
|
|
3229
2458
|
console.log(lines.join("\n"));
|
|
3230
2459
|
} catch (e) {
|
|
3231
2460
|
spinner2.fail("Request failed");
|
|
3232
|
-
console.error(
|
|
2461
|
+
console.error(chalk4.red(e instanceof Error ? e.message : String(e)));
|
|
3233
2462
|
process.exit(1);
|
|
3234
2463
|
}
|
|
3235
2464
|
})
|
|
@@ -3237,7 +2466,7 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3237
2466
|
new Command("create").description("Create a new organization (requires API token)").requiredOption("-n, --name <name>", "Organization display name").requiredOption("-s, --slug <slug>", "Organization slug (e.g. my-org)").action(
|
|
3238
2467
|
async (options, command) => {
|
|
3239
2468
|
const { url, timeout } = getGlobalOpts(command);
|
|
3240
|
-
const spinner2 =
|
|
2469
|
+
const spinner2 = ora4("Creating organization...").start();
|
|
3241
2470
|
try {
|
|
3242
2471
|
const authHeaders = getAuthHeaders();
|
|
3243
2472
|
const pathname = "/api/v2/orgs";
|
|
@@ -3255,15 +2484,15 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3255
2484
|
if (status >= 400) {
|
|
3256
2485
|
const err = data;
|
|
3257
2486
|
spinner2.fail(err?.message || `HTTP ${status}`);
|
|
3258
|
-
console.error(
|
|
2487
|
+
console.error(chalk4.red(JSON.stringify(data)));
|
|
3259
2488
|
process.exit(1);
|
|
3260
2489
|
}
|
|
3261
2490
|
spinner2.succeed("Organization created");
|
|
3262
|
-
console.log(
|
|
2491
|
+
console.log(chalk4.green(JSON.stringify(data, null, 2)));
|
|
3263
2492
|
} catch (e) {
|
|
3264
2493
|
spinner2.fail("Failed");
|
|
3265
2494
|
console.error(
|
|
3266
|
-
|
|
2495
|
+
chalk4.red(e instanceof Error ? e.message : String(e))
|
|
3267
2496
|
);
|
|
3268
2497
|
process.exit(1);
|
|
3269
2498
|
}
|
|
@@ -3274,7 +2503,7 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3274
2503
|
const { url, timeout } = getGlobalOpts(command);
|
|
3275
2504
|
const base = url.replace(/\/$/, "");
|
|
3276
2505
|
const pathname = `/api/v2/orgs/${encodeURIComponent(orgId)}`;
|
|
3277
|
-
const spinner2 =
|
|
2506
|
+
const spinner2 = ora4("Fetching organization...").start();
|
|
3278
2507
|
try {
|
|
3279
2508
|
const { data, status } = await fetchJson(`${base}${pathname}`, { method: "GET", timeout });
|
|
3280
2509
|
if (status === 404) {
|
|
@@ -3283,14 +2512,14 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3283
2512
|
}
|
|
3284
2513
|
if (status !== 200) {
|
|
3285
2514
|
spinner2.fail("Request failed");
|
|
3286
|
-
console.error(
|
|
2515
|
+
console.error(chalk4.red(JSON.stringify(data)));
|
|
3287
2516
|
process.exit(1);
|
|
3288
2517
|
}
|
|
3289
2518
|
spinner2.succeed("OK");
|
|
3290
2519
|
console.log(JSON.stringify(data, null, 2));
|
|
3291
2520
|
} catch (e) {
|
|
3292
2521
|
spinner2.fail("Request failed");
|
|
3293
|
-
console.error(
|
|
2522
|
+
console.error(chalk4.red(e instanceof Error ? e.message : String(e)));
|
|
3294
2523
|
process.exit(1);
|
|
3295
2524
|
}
|
|
3296
2525
|
})
|
|
@@ -3298,7 +2527,7 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3298
2527
|
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(
|
|
3299
2528
|
async (orgId, options, command) => {
|
|
3300
2529
|
const { url, timeout } = getGlobalOpts(command);
|
|
3301
|
-
const spinner2 =
|
|
2530
|
+
const spinner2 = ora4("Updating organization...").start();
|
|
3302
2531
|
try {
|
|
3303
2532
|
const authHeaders = getAuthHeaders();
|
|
3304
2533
|
const pathname = `/api/v2/orgs/${encodeURIComponent(orgId)}`;
|
|
@@ -3323,7 +2552,7 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3323
2552
|
spinner2.fail(
|
|
3324
2553
|
data?.message || `HTTP ${status}`
|
|
3325
2554
|
);
|
|
3326
|
-
console.error(
|
|
2555
|
+
console.error(chalk4.red(JSON.stringify(data)));
|
|
3327
2556
|
process.exit(1);
|
|
3328
2557
|
}
|
|
3329
2558
|
spinner2.succeed("Updated");
|
|
@@ -3331,7 +2560,7 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3331
2560
|
} catch (e) {
|
|
3332
2561
|
spinner2.fail("Failed");
|
|
3333
2562
|
console.error(
|
|
3334
|
-
|
|
2563
|
+
chalk4.red(e instanceof Error ? e.message : String(e))
|
|
3335
2564
|
);
|
|
3336
2565
|
process.exit(1);
|
|
3337
2566
|
}
|
|
@@ -3349,7 +2578,7 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3349
2578
|
});
|
|
3350
2579
|
const confirmed = await new Promise((resolve) => {
|
|
3351
2580
|
rl.question(
|
|
3352
|
-
|
|
2581
|
+
chalk4.yellow(
|
|
3353
2582
|
`Delete organization "${orgId}" and all its members/packages? This cannot be undone. Type "yes" to confirm: `
|
|
3354
2583
|
),
|
|
3355
2584
|
(answer) => {
|
|
@@ -3359,11 +2588,11 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3359
2588
|
);
|
|
3360
2589
|
});
|
|
3361
2590
|
if (!confirmed) {
|
|
3362
|
-
console.log(
|
|
2591
|
+
console.log(chalk4.gray("Aborted."));
|
|
3363
2592
|
return;
|
|
3364
2593
|
}
|
|
3365
2594
|
}
|
|
3366
|
-
const spinner2 =
|
|
2595
|
+
const spinner2 = ora4("Deleting organization...").start();
|
|
3367
2596
|
try {
|
|
3368
2597
|
const authHeaders = getAuthHeaders();
|
|
3369
2598
|
const pathname = `/api/v2/orgs/${encodeURIComponent(orgId)}`;
|
|
@@ -3377,14 +2606,14 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3377
2606
|
spinner2.fail(
|
|
3378
2607
|
data?.message || `HTTP ${status}`
|
|
3379
2608
|
);
|
|
3380
|
-
console.error(
|
|
2609
|
+
console.error(chalk4.red(JSON.stringify(data)));
|
|
3381
2610
|
process.exit(1);
|
|
3382
2611
|
}
|
|
3383
2612
|
spinner2.succeed("Organization deleted");
|
|
3384
2613
|
} catch (e) {
|
|
3385
2614
|
spinner2.fail("Failed");
|
|
3386
2615
|
console.error(
|
|
3387
|
-
|
|
2616
|
+
chalk4.red(e instanceof Error ? e.message : String(e))
|
|
3388
2617
|
);
|
|
3389
2618
|
process.exit(1);
|
|
3390
2619
|
}
|
|
@@ -3396,12 +2625,12 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3396
2625
|
const { url, timeout } = getGlobalOpts(command);
|
|
3397
2626
|
const base = url.replace(/\/$/, "");
|
|
3398
2627
|
const pathname = `/api/v2/orgs/${encodeURIComponent(orgId)}/members`;
|
|
3399
|
-
const spinner2 =
|
|
2628
|
+
const spinner2 = ora4("Fetching members...").start();
|
|
3400
2629
|
try {
|
|
3401
2630
|
const { data, status } = await fetchJson(`${base}${pathname}`, { method: "GET", timeout });
|
|
3402
2631
|
if (status !== 200) {
|
|
3403
2632
|
spinner2.fail("Failed");
|
|
3404
|
-
console.error(
|
|
2633
|
+
console.error(chalk4.red(JSON.stringify(data)));
|
|
3405
2634
|
process.exit(1);
|
|
3406
2635
|
}
|
|
3407
2636
|
spinner2.succeed("OK");
|
|
@@ -3410,7 +2639,7 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3410
2639
|
} catch (e) {
|
|
3411
2640
|
spinner2.fail("Request failed");
|
|
3412
2641
|
console.error(
|
|
3413
|
-
|
|
2642
|
+
chalk4.red(e instanceof Error ? e.message : String(e))
|
|
3414
2643
|
);
|
|
3415
2644
|
process.exit(1);
|
|
3416
2645
|
}
|
|
@@ -3419,7 +2648,7 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3419
2648
|
new Command("add").description("Add a member by email").argument("<orgId>", "Organization id or slug").argument("<email>", "Member email address").option("-r, --role <role>", "Role: member or admin", "member").action(
|
|
3420
2649
|
async (orgId, email, options, command) => {
|
|
3421
2650
|
const { url, timeout } = getGlobalOpts(command);
|
|
3422
|
-
const spinner2 =
|
|
2651
|
+
const spinner2 = ora4("Adding member...").start();
|
|
3423
2652
|
try {
|
|
3424
2653
|
const authHeaders = getAuthHeaders();
|
|
3425
2654
|
const pathname = `/api/v2/orgs/${encodeURIComponent(orgId)}/members`;
|
|
@@ -3438,14 +2667,14 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3438
2667
|
spinner2.fail(
|
|
3439
2668
|
data?.message || `HTTP ${status}`
|
|
3440
2669
|
);
|
|
3441
|
-
console.error(
|
|
2670
|
+
console.error(chalk4.red(JSON.stringify(data)));
|
|
3442
2671
|
process.exit(1);
|
|
3443
2672
|
}
|
|
3444
2673
|
spinner2.succeed("Member added");
|
|
3445
2674
|
} catch (e) {
|
|
3446
2675
|
spinner2.fail("Failed");
|
|
3447
2676
|
console.error(
|
|
3448
|
-
|
|
2677
|
+
chalk4.red(e instanceof Error ? e.message : String(e))
|
|
3449
2678
|
);
|
|
3450
2679
|
process.exit(1);
|
|
3451
2680
|
}
|
|
@@ -3456,7 +2685,7 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3456
2685
|
async (orgId, email, options, command) => {
|
|
3457
2686
|
const { url, timeout } = getGlobalOpts(command);
|
|
3458
2687
|
const role = options.role === "admin" ? "admin" : "member";
|
|
3459
|
-
const spinner2 =
|
|
2688
|
+
const spinner2 = ora4("Updating member role...").start();
|
|
3460
2689
|
try {
|
|
3461
2690
|
const authHeaders = getAuthHeaders();
|
|
3462
2691
|
const pathname = `/api/v2/orgs/${encodeURIComponent(orgId)}/members/${encodeURIComponent(email.trim())}`;
|
|
@@ -3472,14 +2701,14 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3472
2701
|
spinner2.fail(
|
|
3473
2702
|
data?.message || `HTTP ${status}`
|
|
3474
2703
|
);
|
|
3475
|
-
console.error(
|
|
2704
|
+
console.error(chalk4.red(JSON.stringify(data)));
|
|
3476
2705
|
process.exit(1);
|
|
3477
2706
|
}
|
|
3478
2707
|
spinner2.succeed(`Role updated to "${role}"`);
|
|
3479
2708
|
} catch (e) {
|
|
3480
2709
|
spinner2.fail("Failed");
|
|
3481
2710
|
console.error(
|
|
3482
|
-
|
|
2711
|
+
chalk4.red(e instanceof Error ? e.message : String(e))
|
|
3483
2712
|
);
|
|
3484
2713
|
process.exit(1);
|
|
3485
2714
|
}
|
|
@@ -3489,7 +2718,7 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3489
2718
|
new Command("remove").description("Remove a member by email").argument("<orgId>", "Organization id or slug").argument("<email>", "Member email address").action(
|
|
3490
2719
|
async (orgId, email, _options, command) => {
|
|
3491
2720
|
const { url, timeout } = getGlobalOpts(command);
|
|
3492
|
-
const spinner2 =
|
|
2721
|
+
const spinner2 = ora4("Removing member...").start();
|
|
3493
2722
|
try {
|
|
3494
2723
|
const authHeaders = getAuthHeaders();
|
|
3495
2724
|
const pathname = `/api/v2/orgs/${encodeURIComponent(orgId)}/members/${encodeURIComponent(email.trim())}`;
|
|
@@ -3503,14 +2732,14 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3503
2732
|
spinner2.fail(
|
|
3504
2733
|
data?.message || `HTTP ${status}`
|
|
3505
2734
|
);
|
|
3506
|
-
console.error(
|
|
2735
|
+
console.error(chalk4.red(JSON.stringify(data)));
|
|
3507
2736
|
process.exit(1);
|
|
3508
2737
|
}
|
|
3509
2738
|
spinner2.succeed("Member removed");
|
|
3510
2739
|
} catch (e) {
|
|
3511
2740
|
spinner2.fail("Failed");
|
|
3512
2741
|
console.error(
|
|
3513
|
-
|
|
2742
|
+
chalk4.red(e instanceof Error ? e.message : String(e))
|
|
3514
2743
|
);
|
|
3515
2744
|
process.exit(1);
|
|
3516
2745
|
}
|
|
@@ -3522,7 +2751,7 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3522
2751
|
new Command("link").description("Link a package to the organization").argument("<orgId>", "Organization id or slug").argument("<package>", "Package name").action(
|
|
3523
2752
|
async (orgId, pkg, _options, command) => {
|
|
3524
2753
|
const { url, timeout } = getGlobalOpts(command);
|
|
3525
|
-
const spinner2 =
|
|
2754
|
+
const spinner2 = ora4("Linking package...").start();
|
|
3526
2755
|
try {
|
|
3527
2756
|
const authHeaders = getAuthHeaders();
|
|
3528
2757
|
const pathname = `/api/v2/orgs/${encodeURIComponent(orgId)}/packages`;
|
|
@@ -3538,14 +2767,14 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3538
2767
|
spinner2.fail(
|
|
3539
2768
|
data?.message || `HTTP ${status}`
|
|
3540
2769
|
);
|
|
3541
|
-
console.error(
|
|
2770
|
+
console.error(chalk4.red(JSON.stringify(data)));
|
|
3542
2771
|
process.exit(1);
|
|
3543
2772
|
}
|
|
3544
2773
|
spinner2.succeed("Package linked");
|
|
3545
2774
|
} catch (e) {
|
|
3546
2775
|
spinner2.fail("Failed");
|
|
3547
2776
|
console.error(
|
|
3548
|
-
|
|
2777
|
+
chalk4.red(e instanceof Error ? e.message : String(e))
|
|
3549
2778
|
);
|
|
3550
2779
|
process.exit(1);
|
|
3551
2780
|
}
|
|
@@ -3555,7 +2784,7 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3555
2784
|
new Command("unlink").description("Unlink a package from the organization").argument("<orgId>", "Organization id or slug").argument("<package>", "Package name").action(
|
|
3556
2785
|
async (orgId, pkg, _options, command) => {
|
|
3557
2786
|
const { url, timeout } = getGlobalOpts(command);
|
|
3558
|
-
const spinner2 =
|
|
2787
|
+
const spinner2 = ora4("Unlinking package...").start();
|
|
3559
2788
|
try {
|
|
3560
2789
|
const authHeaders = getAuthHeaders();
|
|
3561
2790
|
const pathname = `/api/v2/orgs/${encodeURIComponent(orgId)}/packages/${encodeURIComponent(pkg.trim())}`;
|
|
@@ -3569,14 +2798,14 @@ var orgCommand = new Command("org").description("Manage organizations (create, l
|
|
|
3569
2798
|
spinner2.fail(
|
|
3570
2799
|
data?.message || `HTTP ${status}`
|
|
3571
2800
|
);
|
|
3572
|
-
console.error(
|
|
2801
|
+
console.error(chalk4.red(JSON.stringify(data)));
|
|
3573
2802
|
process.exit(1);
|
|
3574
2803
|
}
|
|
3575
2804
|
spinner2.succeed("Package unlinked");
|
|
3576
2805
|
} catch (e) {
|
|
3577
2806
|
spinner2.fail("Failed");
|
|
3578
2807
|
console.error(
|
|
3579
|
-
|
|
2808
|
+
chalk4.red(e instanceof Error ? e.message : String(e))
|
|
3580
2809
|
);
|
|
3581
2810
|
process.exit(1);
|
|
3582
2811
|
}
|
|
@@ -3596,10 +2825,10 @@ program.addHelpText(
|
|
|
3596
2825
|
"after",
|
|
3597
2826
|
`
|
|
3598
2827
|
Examples:
|
|
3599
|
-
$ calimero-registry
|
|
3600
|
-
$ calimero-registry
|
|
2828
|
+
$ calimero-registry org list
|
|
2829
|
+
$ calimero-registry bundle get com.example.my-app 1.0.0
|
|
3601
2830
|
$ calimero-registry local start
|
|
3602
|
-
$ calimero-registry health
|
|
2831
|
+
$ calimero-registry health
|
|
3603
2832
|
|
|
3604
2833
|
For more information, visit: https://github.com/calimero-network/app-registry
|
|
3605
2834
|
`
|
|
@@ -3611,9 +2840,6 @@ program.option(
|
|
|
3611
2840
|
"10000"
|
|
3612
2841
|
);
|
|
3613
2842
|
program.option("--local", "Use local registry instead of remote API");
|
|
3614
|
-
program.addCommand(appsCommand);
|
|
3615
|
-
program.addCommand(developersCommand);
|
|
3616
|
-
program.addCommand(attestationsCommand);
|
|
3617
2843
|
program.addCommand(healthCommand);
|
|
3618
2844
|
program.addCommand(ipfsCommand);
|
|
3619
2845
|
program.addCommand(localCommand);
|
|
@@ -3628,9 +2854,9 @@ try {
|
|
|
3628
2854
|
process.exit(err.exitCode ?? 0);
|
|
3629
2855
|
}
|
|
3630
2856
|
if (err instanceof Error) {
|
|
3631
|
-
console.error(
|
|
2857
|
+
console.error(chalk4.red("Error:"), err.message);
|
|
3632
2858
|
} else {
|
|
3633
|
-
console.error(
|
|
2859
|
+
console.error(chalk4.red("Unknown error occurred"));
|
|
3634
2860
|
}
|
|
3635
2861
|
process.exit(1);
|
|
3636
2862
|
}
|