@calimero-network/registry-cli 1.22.1 → 1.22.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +138 -70
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -5,10 +5,9 @@ import { createRequire } from 'module';
|
|
|
5
5
|
import ora4 from 'ora';
|
|
6
6
|
import axios from 'axios';
|
|
7
7
|
import fs7, { existsSync, writeFileSync } from 'fs';
|
|
8
|
-
import
|
|
8
|
+
import path6 from 'path';
|
|
9
9
|
import os2 from 'os';
|
|
10
10
|
import fastify from 'fastify';
|
|
11
|
-
import cors from '@fastify/cors';
|
|
12
11
|
import crypto2 from 'crypto';
|
|
13
12
|
import * as tar from 'tar';
|
|
14
13
|
|
|
@@ -20,7 +19,7 @@ var RemoteConfig = class {
|
|
|
20
19
|
configPath;
|
|
21
20
|
config;
|
|
22
21
|
constructor() {
|
|
23
|
-
this.configPath =
|
|
22
|
+
this.configPath = path6.join(
|
|
24
23
|
os2.homedir(),
|
|
25
24
|
".calimero-registry",
|
|
26
25
|
"remote-config.json"
|
|
@@ -47,7 +46,7 @@ var RemoteConfig = class {
|
|
|
47
46
|
return defaults;
|
|
48
47
|
}
|
|
49
48
|
saveConfig() {
|
|
50
|
-
const configDir =
|
|
49
|
+
const configDir = path6.dirname(this.configPath);
|
|
51
50
|
if (!fs7.existsSync(configDir)) {
|
|
52
51
|
fs7.mkdirSync(configDir, { recursive: true });
|
|
53
52
|
}
|
|
@@ -128,20 +127,20 @@ var RemoteConfig = class {
|
|
|
128
127
|
function defaultConfig2() {
|
|
129
128
|
return {
|
|
130
129
|
server: {
|
|
131
|
-
//
|
|
132
|
-
//
|
|
133
|
-
//
|
|
134
|
-
// host.docker.internal
|
|
135
|
-
host: "
|
|
130
|
+
// Hardening: default to loopback so the dev server is not reachable from
|
|
131
|
+
// the LAN or a browsing website. Docker users who need container access
|
|
132
|
+
// opt in explicitly with `local start --host 0.0.0.0`; publicHost stays
|
|
133
|
+
// host.docker.internal for the URLs baked into manifests in that case.
|
|
134
|
+
host: "127.0.0.1",
|
|
136
135
|
port: 8082,
|
|
137
136
|
publicHost: "host.docker.internal"
|
|
138
137
|
},
|
|
139
138
|
data: {
|
|
140
|
-
dir:
|
|
141
|
-
artifactsDir:
|
|
139
|
+
dir: path6.join(os2.homedir(), ".calimero-registry", "data"),
|
|
140
|
+
artifactsDir: path6.join(os2.homedir(), ".calimero-registry", "artifacts")
|
|
142
141
|
},
|
|
143
142
|
artifacts: {
|
|
144
|
-
storageDir:
|
|
143
|
+
storageDir: path6.join(os2.homedir(), ".calimero-registry", "artifacts"),
|
|
145
144
|
serveLocal: true,
|
|
146
145
|
copyArtifacts: true,
|
|
147
146
|
maxFileSize: "100MB",
|
|
@@ -154,12 +153,12 @@ var LocalConfig = class {
|
|
|
154
153
|
dataDir;
|
|
155
154
|
config;
|
|
156
155
|
constructor() {
|
|
157
|
-
this.configPath =
|
|
156
|
+
this.configPath = path6.join(
|
|
158
157
|
os2.homedir(),
|
|
159
158
|
".calimero-registry",
|
|
160
159
|
"config.json"
|
|
161
160
|
);
|
|
162
|
-
this.dataDir =
|
|
161
|
+
this.dataDir = path6.join(os2.homedir(), ".calimero-registry");
|
|
163
162
|
this.config = this.loadConfig();
|
|
164
163
|
}
|
|
165
164
|
loadConfig() {
|
|
@@ -190,7 +189,7 @@ var LocalConfig = class {
|
|
|
190
189
|
return defaults;
|
|
191
190
|
}
|
|
192
191
|
saveConfig() {
|
|
193
|
-
const configDir =
|
|
192
|
+
const configDir = path6.dirname(this.configPath);
|
|
194
193
|
if (!fs7.existsSync(configDir)) {
|
|
195
194
|
fs7.mkdirSync(configDir, { recursive: true });
|
|
196
195
|
}
|
|
@@ -224,8 +223,8 @@ var LocalConfig = class {
|
|
|
224
223
|
}
|
|
225
224
|
setDataDir(dir) {
|
|
226
225
|
this.config.data.dir = dir;
|
|
227
|
-
this.config.data.artifactsDir =
|
|
228
|
-
this.config.artifacts.storageDir =
|
|
226
|
+
this.config.data.artifactsDir = path6.join(dir, "artifacts");
|
|
227
|
+
this.config.artifacts.storageDir = path6.join(dir, "artifacts");
|
|
229
228
|
this.saveConfig();
|
|
230
229
|
}
|
|
231
230
|
getArtifactsDir() {
|
|
@@ -249,8 +248,8 @@ var LocalConfig = class {
|
|
|
249
248
|
const dirs = [
|
|
250
249
|
this.getDataDir(),
|
|
251
250
|
this.getArtifactsDir(),
|
|
252
|
-
|
|
253
|
-
|
|
251
|
+
path6.join(this.getDataDir(), "backups"),
|
|
252
|
+
path6.join(this.getDataDir(), "logs")
|
|
254
253
|
];
|
|
255
254
|
dirs.forEach((dir) => {
|
|
256
255
|
if (!fs7.existsSync(dir)) {
|
|
@@ -390,12 +389,12 @@ var LocalDataStore = class {
|
|
|
390
389
|
artifactsFile;
|
|
391
390
|
constructor(config) {
|
|
392
391
|
this.config = config;
|
|
393
|
-
this.appsFile =
|
|
394
|
-
this.bundleManifestsFile =
|
|
392
|
+
this.appsFile = path6.join(config.getDataDir(), "apps.json");
|
|
393
|
+
this.bundleManifestsFile = path6.join(
|
|
395
394
|
config.getDataDir(),
|
|
396
395
|
"bundle_manifests.json"
|
|
397
396
|
);
|
|
398
|
-
this.artifactsFile =
|
|
397
|
+
this.artifactsFile = path6.join(config.getDataDir(), "artifacts.json");
|
|
399
398
|
this.data = {
|
|
400
399
|
apps: /* @__PURE__ */ new Map(),
|
|
401
400
|
bundleManifests: /* @__PURE__ */ new Map(),
|
|
@@ -516,12 +515,12 @@ var LocalDataStore = class {
|
|
|
516
515
|
// Backup and restore
|
|
517
516
|
async backup(outputPath) {
|
|
518
517
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
519
|
-
const backupPath = outputPath ||
|
|
518
|
+
const backupPath = outputPath || path6.join(
|
|
520
519
|
this.config.getDataDir(),
|
|
521
520
|
"backups",
|
|
522
521
|
`backup-${timestamp}.json`
|
|
523
522
|
);
|
|
524
|
-
const backupDir =
|
|
523
|
+
const backupDir = path6.dirname(backupPath);
|
|
525
524
|
if (!fs7.existsSync(backupDir)) {
|
|
526
525
|
fs7.mkdirSync(backupDir, { recursive: true });
|
|
527
526
|
}
|
|
@@ -613,16 +612,30 @@ var LocalArtifactServer = class {
|
|
|
613
612
|
fs7.mkdirSync(this.artifactsDir, { recursive: true });
|
|
614
613
|
}
|
|
615
614
|
}
|
|
615
|
+
/**
|
|
616
|
+
* Hardening: build a path under artifactsDir from untrusted segments (request
|
|
617
|
+
* params, or bundle-provided package/version/filename) and guarantee it stays
|
|
618
|
+
* inside artifactsDir. A `..` or absolute segment would otherwise let a
|
|
619
|
+
* request read or write outside the artifact store (path traversal).
|
|
620
|
+
*/
|
|
621
|
+
resolveArtifactPath(...segments) {
|
|
622
|
+
const base = path6.resolve(this.artifactsDir);
|
|
623
|
+
const resolved = path6.resolve(base, ...segments);
|
|
624
|
+
if (resolved !== base && !resolved.startsWith(base + path6.sep)) {
|
|
625
|
+
throw new Error("Invalid artifact path: escapes artifacts directory");
|
|
626
|
+
}
|
|
627
|
+
return resolved;
|
|
628
|
+
}
|
|
616
629
|
// Copy artifact to local storage
|
|
617
630
|
async copyArtifactToLocal(sourcePath, appId, version2, filename) {
|
|
618
631
|
if (!fs7.existsSync(sourcePath)) {
|
|
619
632
|
throw new Error(`Source file not found: ${sourcePath}`);
|
|
620
633
|
}
|
|
621
|
-
const
|
|
634
|
+
const targetPath = this.resolveArtifactPath(appId, version2, filename);
|
|
635
|
+
const appVersionDir = path6.dirname(targetPath);
|
|
622
636
|
if (!fs7.existsSync(appVersionDir)) {
|
|
623
637
|
fs7.mkdirSync(appVersionDir, { recursive: true });
|
|
624
638
|
}
|
|
625
|
-
const targetPath = path5.join(appVersionDir, filename);
|
|
626
639
|
fs7.copyFileSync(sourcePath, targetPath);
|
|
627
640
|
const fileHash = await this.calculateFileHash(targetPath);
|
|
628
641
|
this.dataStore.setArtifactPath(fileHash, targetPath);
|
|
@@ -630,7 +643,7 @@ var LocalArtifactServer = class {
|
|
|
630
643
|
}
|
|
631
644
|
// Serve artifact by app ID, version, and filename
|
|
632
645
|
async serveArtifact(appId, version2, filename) {
|
|
633
|
-
const artifactPath =
|
|
646
|
+
const artifactPath = this.resolveArtifactPath(appId, version2, filename);
|
|
634
647
|
if (!fs7.existsSync(artifactPath)) {
|
|
635
648
|
throw new Error(`Artifact not found: ${artifactPath}`);
|
|
636
649
|
}
|
|
@@ -679,7 +692,7 @@ var LocalArtifactServer = class {
|
|
|
679
692
|
let files = [];
|
|
680
693
|
const items = fs7.readdirSync(dir);
|
|
681
694
|
for (const item of items) {
|
|
682
|
-
const fullPath =
|
|
695
|
+
const fullPath = path6.join(dir, item);
|
|
683
696
|
const stat = fs7.statSync(fullPath);
|
|
684
697
|
if (stat.isDirectory()) {
|
|
685
698
|
files = files.concat(getAllFiles(fullPath));
|
|
@@ -708,7 +721,7 @@ var LocalArtifactServer = class {
|
|
|
708
721
|
let files = [];
|
|
709
722
|
const items = fs7.readdirSync(dir);
|
|
710
723
|
for (const item of items) {
|
|
711
|
-
const fullPath =
|
|
724
|
+
const fullPath = path6.join(dir, item);
|
|
712
725
|
const stat = fs7.statSync(fullPath);
|
|
713
726
|
if (stat.isDirectory()) {
|
|
714
727
|
files = files.concat(getAllFiles(fullPath));
|
|
@@ -759,9 +772,27 @@ var LocalRegistryServer = class {
|
|
|
759
772
|
level: "info"
|
|
760
773
|
}
|
|
761
774
|
});
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
775
|
+
const allowedHosts = /* @__PURE__ */ new Set();
|
|
776
|
+
for (const name of [
|
|
777
|
+
"localhost",
|
|
778
|
+
"127.0.0.1",
|
|
779
|
+
"[::1]",
|
|
780
|
+
this.config.getPublicHost(),
|
|
781
|
+
host === "0.0.0.0" || host === "::" ? "" : host
|
|
782
|
+
]) {
|
|
783
|
+
if (!name) continue;
|
|
784
|
+
allowedHosts.add(name);
|
|
785
|
+
allowedHosts.add(`${name}:${serverPort}`);
|
|
786
|
+
}
|
|
787
|
+
this.server.addHook("onRequest", async (request, reply) => {
|
|
788
|
+
const hostHeader = (request.headers.host ?? "").toLowerCase();
|
|
789
|
+
if (!allowedHosts.has(hostHeader)) {
|
|
790
|
+
return reply.code(403).send({
|
|
791
|
+
statusCode: 403,
|
|
792
|
+
error: "Forbidden",
|
|
793
|
+
message: "Invalid Host header"
|
|
794
|
+
});
|
|
795
|
+
}
|
|
765
796
|
});
|
|
766
797
|
await this.registerRoutes();
|
|
767
798
|
await this.server.listen({ port: serverPort, host });
|
|
@@ -805,6 +836,20 @@ var LocalRegistryServer = class {
|
|
|
805
836
|
async seed() {
|
|
806
837
|
await this.dataStore.seed();
|
|
807
838
|
}
|
|
839
|
+
/**
|
|
840
|
+
* Hardening: resolve a caller-supplied backup path relative to the CLI data
|
|
841
|
+
* dir and verify it stays inside it. Rejects absolute paths and `..` segments
|
|
842
|
+
* that would escape, so the HTTP backup/restore routes cannot read or write
|
|
843
|
+
* arbitrary filesystem locations.
|
|
844
|
+
*/
|
|
845
|
+
confineToDataDir(candidate) {
|
|
846
|
+
const dataDir = path6.resolve(this.config.getDataDir());
|
|
847
|
+
const resolved = path6.resolve(dataDir, candidate);
|
|
848
|
+
if (resolved !== dataDir && !resolved.startsWith(dataDir + path6.sep)) {
|
|
849
|
+
throw new Error("Path escapes data directory");
|
|
850
|
+
}
|
|
851
|
+
return resolved;
|
|
852
|
+
}
|
|
808
853
|
async registerRoutes() {
|
|
809
854
|
if (!this.server) {
|
|
810
855
|
throw new Error("Server not initialized");
|
|
@@ -868,14 +913,37 @@ var LocalRegistryServer = class {
|
|
|
868
913
|
await this.reset();
|
|
869
914
|
return { message: "Local registry data reset successfully" };
|
|
870
915
|
});
|
|
871
|
-
this.server.
|
|
916
|
+
this.server.post("/local/backup", async (request, reply) => {
|
|
872
917
|
const query = request.query;
|
|
873
|
-
|
|
918
|
+
let output;
|
|
919
|
+
if (query.output) {
|
|
920
|
+
try {
|
|
921
|
+
output = this.confineToDataDir(query.output);
|
|
922
|
+
} catch {
|
|
923
|
+
return reply.code(400).send({
|
|
924
|
+
error: "invalid_path",
|
|
925
|
+
message: "output escapes data dir"
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
const backupPath = await this.backup(output);
|
|
874
930
|
return { backupPath };
|
|
875
931
|
});
|
|
876
|
-
this.server.post("/local/restore", async (request) => {
|
|
877
|
-
const { backupPath } = request.body;
|
|
878
|
-
|
|
932
|
+
this.server.post("/local/restore", async (request, reply) => {
|
|
933
|
+
const { backupPath } = request.body ?? {};
|
|
934
|
+
if (!backupPath) {
|
|
935
|
+
return reply.code(400).send({ error: "invalid_path", message: "backupPath is required" });
|
|
936
|
+
}
|
|
937
|
+
let resolved;
|
|
938
|
+
try {
|
|
939
|
+
resolved = this.confineToDataDir(backupPath);
|
|
940
|
+
} catch {
|
|
941
|
+
return reply.code(400).send({
|
|
942
|
+
error: "invalid_path",
|
|
943
|
+
message: "backupPath escapes data dir"
|
|
944
|
+
});
|
|
945
|
+
}
|
|
946
|
+
await this.restore(resolved);
|
|
879
947
|
return { message: "Data restored successfully" };
|
|
880
948
|
});
|
|
881
949
|
this.server.post("/local/seed", async () => {
|
|
@@ -948,7 +1016,7 @@ var localCommand = new Command("local").description(
|
|
|
948
1016
|
"Manage local registry for development"
|
|
949
1017
|
);
|
|
950
1018
|
localCommand.addCommand(
|
|
951
|
-
new Command("start").description("Start local registry server").option("-p, --port <port>", "Port to run the server on", "8082").option("-h, --host <host>", "Host to bind the server to", "
|
|
1019
|
+
new Command("start").description("Start local registry server").option("-p, --port <port>", "Port to run the server on", "8082").option("-h, --host <host>", "Host to bind the server to", "127.0.0.1").option(
|
|
952
1020
|
"--public-host <host>",
|
|
953
1021
|
"Public host exposed in manifest artifact URLs",
|
|
954
1022
|
"host.docker.internal"
|
|
@@ -1315,7 +1383,7 @@ Note:
|
|
|
1315
1383
|
try {
|
|
1316
1384
|
let manifestConfig = {};
|
|
1317
1385
|
if (options.manifest) {
|
|
1318
|
-
const manifestPath =
|
|
1386
|
+
const manifestPath = path6.resolve(options.manifest);
|
|
1319
1387
|
if (!fs7.existsSync(manifestPath)) {
|
|
1320
1388
|
console.error(`\u274C Manifest file not found: ${options.manifest}`);
|
|
1321
1389
|
process.exit(1);
|
|
@@ -1392,12 +1460,12 @@ Note:
|
|
|
1392
1460
|
);
|
|
1393
1461
|
process.exit(1);
|
|
1394
1462
|
}
|
|
1395
|
-
const wasmPath =
|
|
1463
|
+
const wasmPath = path6.resolve(wasmFile);
|
|
1396
1464
|
if (!fs7.existsSync(wasmPath)) {
|
|
1397
1465
|
console.error(`\u274C WASM file not found: ${wasmFile}`);
|
|
1398
1466
|
process.exit(1);
|
|
1399
1467
|
}
|
|
1400
|
-
console.log(`\u{1F4E6} Creating MPK bundle from: ${
|
|
1468
|
+
console.log(`\u{1F4E6} Creating MPK bundle from: ${path6.basename(wasmPath)}`);
|
|
1401
1469
|
const wasmContent = fs7.readFileSync(wasmPath);
|
|
1402
1470
|
const wasmSize = wasmContent.length;
|
|
1403
1471
|
const wasmHash = crypto2.createHash("sha256").update(wasmContent).digest("hex");
|
|
@@ -1407,10 +1475,10 @@ Note:
|
|
|
1407
1475
|
const abiPathFromManifest = typeof manifestConfig.abi === "string" ? manifestConfig.abi : null;
|
|
1408
1476
|
const abiFilePath = abiPathFromOption || abiPathFromManifest;
|
|
1409
1477
|
if (abiFilePath) {
|
|
1410
|
-
const abiResolvedPath = abiPathFromOption ?
|
|
1411
|
-
|
|
1478
|
+
const abiResolvedPath = abiPathFromOption ? path6.resolve(abiFilePath) : options.manifest && abiPathFromManifest ? path6.resolve(
|
|
1479
|
+
path6.dirname(path6.resolve(options.manifest)),
|
|
1412
1480
|
abiFilePath
|
|
1413
|
-
) :
|
|
1481
|
+
) : path6.resolve(abiFilePath);
|
|
1414
1482
|
if (!fs7.existsSync(abiResolvedPath)) {
|
|
1415
1483
|
console.error(`\u274C ABI file not found: ${abiFilePath}`);
|
|
1416
1484
|
console.error(` Resolved path: ${abiResolvedPath}`);
|
|
@@ -1426,7 +1494,7 @@ Note:
|
|
|
1426
1494
|
size: abiContent.length
|
|
1427
1495
|
};
|
|
1428
1496
|
console.log(
|
|
1429
|
-
` Including ABI file: ${
|
|
1497
|
+
` Including ABI file: ${path6.basename(abiResolvedPath)}`
|
|
1430
1498
|
);
|
|
1431
1499
|
} catch (error) {
|
|
1432
1500
|
console.error(
|
|
@@ -1450,7 +1518,7 @@ Note:
|
|
|
1450
1518
|
const manifestServices = Array.isArray(
|
|
1451
1519
|
manifestConfig.services
|
|
1452
1520
|
) ? manifestConfig.services : [];
|
|
1453
|
-
const manifestDir = options.manifest ?
|
|
1521
|
+
const manifestDir = options.manifest ? path6.dirname(path6.resolve(options.manifest)) : process.cwd();
|
|
1454
1522
|
const allServiceSources = [
|
|
1455
1523
|
...cliServices.map((src) => ({ src, baseDir: process.cwd() })),
|
|
1456
1524
|
...manifestServices.map((src) => ({ src, baseDir: manifestDir }))
|
|
@@ -1484,7 +1552,7 @@ Note:
|
|
|
1484
1552
|
);
|
|
1485
1553
|
process.exit(1);
|
|
1486
1554
|
}
|
|
1487
|
-
const svcWasmPath =
|
|
1555
|
+
const svcWasmPath = path6.resolve(baseDir, src.wasm);
|
|
1488
1556
|
if (!fs7.existsSync(svcWasmPath)) {
|
|
1489
1557
|
console.error(
|
|
1490
1558
|
`\u274C Service "${src.name}" WASM not found: ${src.wasm}`
|
|
@@ -1508,7 +1576,7 @@ Note:
|
|
|
1508
1576
|
content: svcWasmContent
|
|
1509
1577
|
});
|
|
1510
1578
|
if (src.abi) {
|
|
1511
|
-
const svcAbiPath =
|
|
1579
|
+
const svcAbiPath = path6.resolve(baseDir, src.abi);
|
|
1512
1580
|
if (!fs7.existsSync(svcAbiPath)) {
|
|
1513
1581
|
console.error(
|
|
1514
1582
|
`\u274C Service "${src.name}" ABI not found: ${src.abi}`
|
|
@@ -1542,7 +1610,7 @@ Note:
|
|
|
1542
1610
|
}
|
|
1543
1611
|
serviceArtifacts.push(entry);
|
|
1544
1612
|
console.log(
|
|
1545
|
-
` Including service: ${src.name} (${
|
|
1613
|
+
` Including service: ${src.name} (${path6.basename(svcWasmPath)})`
|
|
1546
1614
|
);
|
|
1547
1615
|
}
|
|
1548
1616
|
const metadata = {
|
|
@@ -1575,29 +1643,29 @@ Note:
|
|
|
1575
1643
|
links: Object.keys(links).length > 0 ? links : void 0,
|
|
1576
1644
|
signature: void 0
|
|
1577
1645
|
};
|
|
1578
|
-
let outputDir = finalOutput ?
|
|
1646
|
+
let outputDir = finalOutput ? path6.resolve(finalOutput) : path6.join(process.cwd(), finalPackage, finalVersion);
|
|
1579
1647
|
if (!fs7.existsSync(outputDir)) {
|
|
1580
1648
|
fs7.mkdirSync(outputDir, { recursive: true });
|
|
1581
1649
|
}
|
|
1582
1650
|
fs7.writeFileSync(
|
|
1583
|
-
|
|
1651
|
+
path6.join(outputDir, "manifest.json"),
|
|
1584
1652
|
JSON.stringify(manifest, null, 2)
|
|
1585
1653
|
);
|
|
1586
|
-
fs7.writeFileSync(
|
|
1654
|
+
fs7.writeFileSync(path6.join(outputDir, "app.wasm"), wasmContent);
|
|
1587
1655
|
if (abiContent) {
|
|
1588
|
-
fs7.writeFileSync(
|
|
1656
|
+
fs7.writeFileSync(path6.join(outputDir, "abi.json"), abiContent);
|
|
1589
1657
|
}
|
|
1590
|
-
const servicesDir =
|
|
1658
|
+
const servicesDir = path6.join(outputDir, "services");
|
|
1591
1659
|
for (const { relPath, content } of serviceFilesToWrite) {
|
|
1592
|
-
const dest =
|
|
1593
|
-
const rel =
|
|
1594
|
-
if (rel.startsWith("..") ||
|
|
1660
|
+
const dest = path6.join(outputDir, relPath);
|
|
1661
|
+
const rel = path6.relative(servicesDir, dest);
|
|
1662
|
+
if (rel.startsWith("..") || path6.isAbsolute(rel)) {
|
|
1595
1663
|
console.error(
|
|
1596
1664
|
`\u274C Refusing to write service file outside services/: ${relPath}`
|
|
1597
1665
|
);
|
|
1598
1666
|
process.exit(1);
|
|
1599
1667
|
}
|
|
1600
|
-
fs7.mkdirSync(
|
|
1668
|
+
fs7.mkdirSync(path6.dirname(dest), { recursive: true });
|
|
1601
1669
|
fs7.writeFileSync(dest, content);
|
|
1602
1670
|
}
|
|
1603
1671
|
console.log(`\u2705 Bundle files written to: ${outputDir}`);
|
|
@@ -1615,7 +1683,7 @@ Note:
|
|
|
1615
1683
|
console.log("");
|
|
1616
1684
|
console.log("Next steps:");
|
|
1617
1685
|
console.log(
|
|
1618
|
-
` 1. Sign the manifest: mero-sign sign ${
|
|
1686
|
+
` 1. Sign the manifest: mero-sign sign ${path6.join(outputDir, "manifest.json")} --key key.json`
|
|
1619
1687
|
);
|
|
1620
1688
|
console.log(
|
|
1621
1689
|
` 2. Push the bundle: calimero-registry bundle push ${outputDir} --remote`
|
|
@@ -1684,15 +1752,15 @@ Note:
|
|
|
1684
1752
|
);
|
|
1685
1753
|
process.exit(1);
|
|
1686
1754
|
}
|
|
1687
|
-
const fullPath =
|
|
1755
|
+
const fullPath = path6.resolve(bundleFile);
|
|
1688
1756
|
if (!fs7.existsSync(fullPath)) {
|
|
1689
1757
|
console.error(`\u274C File not found: ${bundleFile}`);
|
|
1690
1758
|
process.exit(1);
|
|
1691
1759
|
}
|
|
1692
1760
|
mpkPath = fullPath;
|
|
1693
1761
|
if (fs7.statSync(fullPath).isDirectory()) {
|
|
1694
|
-
const manifestInDir =
|
|
1695
|
-
const wasmInDir =
|
|
1762
|
+
const manifestInDir = path6.join(fullPath, "manifest.json");
|
|
1763
|
+
const wasmInDir = path6.join(fullPath, "app.wasm");
|
|
1696
1764
|
if (!fs7.existsSync(manifestInDir)) {
|
|
1697
1765
|
console.error(
|
|
1698
1766
|
`\u274C manifest.json not found in directory: ${fullPath}`
|
|
@@ -1703,7 +1771,7 @@ Note:
|
|
|
1703
1771
|
console.error(`\u274C app.wasm not found in directory: ${fullPath}`);
|
|
1704
1772
|
process.exit(1);
|
|
1705
1773
|
}
|
|
1706
|
-
tempMpk =
|
|
1774
|
+
tempMpk = path6.join(fullPath, `.temp-push-${Date.now()}.mpk`);
|
|
1707
1775
|
let dirManifest;
|
|
1708
1776
|
try {
|
|
1709
1777
|
dirManifest = JSON.parse(
|
|
@@ -1740,7 +1808,7 @@ Note:
|
|
|
1740
1808
|
process.exit(1);
|
|
1741
1809
|
}
|
|
1742
1810
|
for (const f of archiveFiles) {
|
|
1743
|
-
if (!fs7.existsSync(
|
|
1811
|
+
if (!fs7.existsSync(path6.join(fullPath, f))) {
|
|
1744
1812
|
console.error(
|
|
1745
1813
|
`\u274C Bundle file referenced by manifest not found: ${f}`
|
|
1746
1814
|
);
|
|
@@ -1756,7 +1824,7 @@ Note:
|
|
|
1756
1824
|
`\u{1F4E6} Packed directory into temporary bundle (${archiveFiles.length} files)`
|
|
1757
1825
|
);
|
|
1758
1826
|
}
|
|
1759
|
-
console.log(`\u{1F4E6} Processing bundle: ${
|
|
1827
|
+
console.log(`\u{1F4E6} Processing bundle: ${path6.basename(mpkPath)}`);
|
|
1760
1828
|
const manifest = await extractManifest(mpkPath);
|
|
1761
1829
|
if (!manifest) {
|
|
1762
1830
|
console.error("\u274C manifest.json not found in bundle");
|
|
@@ -1872,7 +1940,7 @@ Examples:
|
|
|
1872
1940
|
};
|
|
1873
1941
|
if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
|
|
1874
1942
|
if (options.manifest) {
|
|
1875
|
-
const manifestPath =
|
|
1943
|
+
const manifestPath = path6.resolve(options.manifest);
|
|
1876
1944
|
if (!fs7.existsSync(manifestPath)) {
|
|
1877
1945
|
console.error(`\u274C Manifest file not found: ${options.manifest}`);
|
|
1878
1946
|
process.exit(1);
|
|
@@ -1964,7 +2032,7 @@ Examples:
|
|
|
1964
2032
|
if (!manifest.links) manifest.links = {};
|
|
1965
2033
|
manifest.links.docs = options.docs;
|
|
1966
2034
|
}
|
|
1967
|
-
const outputPath =
|
|
2035
|
+
const outputPath = path6.resolve(options.output || "manifest.json");
|
|
1968
2036
|
fs7.writeFileSync(outputPath, JSON.stringify(manifest, null, 2));
|
|
1969
2037
|
console.log(`\u2705 Wrote modified manifest to: ${outputPath}`);
|
|
1970
2038
|
console.log("");
|
|
@@ -2140,7 +2208,7 @@ async function extractManifest(bundlePath) {
|
|
|
2140
2208
|
if (entry.path === "manifest.json") ;
|
|
2141
2209
|
}
|
|
2142
2210
|
});
|
|
2143
|
-
const extractDir =
|
|
2211
|
+
const extractDir = path6.join(path6.dirname(bundlePath), `.temp-${Date.now()}`);
|
|
2144
2212
|
if (!fs7.existsSync(extractDir)) {
|
|
2145
2213
|
fs7.mkdirSync(extractDir);
|
|
2146
2214
|
}
|
|
@@ -2148,9 +2216,9 @@ async function extractManifest(bundlePath) {
|
|
|
2148
2216
|
await tar.x({
|
|
2149
2217
|
file: bundlePath,
|
|
2150
2218
|
cwd: extractDir,
|
|
2151
|
-
filter: (
|
|
2219
|
+
filter: (path7) => path7 === "manifest.json"
|
|
2152
2220
|
});
|
|
2153
|
-
const manifestPath =
|
|
2221
|
+
const manifestPath = path6.join(extractDir, "manifest.json");
|
|
2154
2222
|
if (fs7.existsSync(manifestPath)) {
|
|
2155
2223
|
const content = fs7.readFileSync(manifestPath, "utf8");
|
|
2156
2224
|
manifestContent = content;
|