@shelby-protocol/cli 0.0.4 → 0.0.6
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 +2 -15
- package/bin/entry.js +403 -111
- package/package.json +2 -4
package/README.md
CHANGED
|
@@ -33,18 +33,5 @@ shelby <command> [options]
|
|
|
33
33
|
|
|
34
34
|
## Binary Release
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
On homebrew, you can do:
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
brew tap oven-sh/bun
|
|
42
|
-
|
|
43
|
-
brew install bun
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
If you don't have homebrew, see https://bun.sh/get
|
|
47
|
-
|
|
48
|
-
### Run `scripts/bun-release.sh`
|
|
49
|
-
|
|
50
|
-
From `apps/cli` run `bash scripts/bun-release.sh`
|
|
36
|
+
1. Bump version
|
|
37
|
+
2. Run `npm publish`
|
package/bin/entry.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { Command } from "commander";
|
|
5
5
|
|
|
6
6
|
// package.json
|
|
7
|
-
var version = "0.0.
|
|
7
|
+
var version = "0.0.6";
|
|
8
8
|
|
|
9
9
|
// src/commands/init.tsx
|
|
10
10
|
import { render } from "ink";
|
|
@@ -444,6 +444,135 @@ var ContextWizard = ({ onComplete }) => {
|
|
|
444
444
|
return null;
|
|
445
445
|
};
|
|
446
446
|
|
|
447
|
+
// src/components/UpdateContextWizard.tsx
|
|
448
|
+
import { Box as Box4, Text as Text4 } from "ink";
|
|
449
|
+
import TextInput4 from "ink-text-input";
|
|
450
|
+
import { useEffect as useEffect4, useState as useState4 } from "react";
|
|
451
|
+
|
|
452
|
+
// src/schemas/AptosNetworkSchema.ts
|
|
453
|
+
import { z } from "zod";
|
|
454
|
+
var AptosNetworkSchema = z.enum([
|
|
455
|
+
"mainnet",
|
|
456
|
+
"testnet",
|
|
457
|
+
"devnet",
|
|
458
|
+
"local"
|
|
459
|
+
]);
|
|
460
|
+
|
|
461
|
+
// src/schemas/EndpointSchema.ts
|
|
462
|
+
import { z as z2 } from "zod";
|
|
463
|
+
var EndpointSchema = z2.string().url("Must be a valid URL");
|
|
464
|
+
|
|
465
|
+
// src/components/UpdateContextWizard.tsx
|
|
466
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
467
|
+
var UpdateContextWizard = ({
|
|
468
|
+
contextName,
|
|
469
|
+
currentShelbyRpc,
|
|
470
|
+
currentAptosNetwork,
|
|
471
|
+
onComplete
|
|
472
|
+
}) => {
|
|
473
|
+
const [step, setStep] = useState4("shelbyRpc");
|
|
474
|
+
const [shelbyRpcEndpoint, setShelbyRpcEndpoint] = useState4(currentShelbyRpc);
|
|
475
|
+
const [aptosNetwork, setAptosNetwork] = useState4(currentAptosNetwork);
|
|
476
|
+
const [error, setError] = useState4("");
|
|
477
|
+
useEffect4(() => {
|
|
478
|
+
if (step === "done") {
|
|
479
|
+
const updates = {};
|
|
480
|
+
if (shelbyRpcEndpoint !== currentShelbyRpc) {
|
|
481
|
+
updates.shelbyRpcEndpoint = shelbyRpcEndpoint;
|
|
482
|
+
}
|
|
483
|
+
if (aptosNetwork !== currentAptosNetwork) {
|
|
484
|
+
updates.aptosNetwork = aptosNetwork;
|
|
485
|
+
}
|
|
486
|
+
onComplete(updates);
|
|
487
|
+
}
|
|
488
|
+
}, [
|
|
489
|
+
step,
|
|
490
|
+
shelbyRpcEndpoint,
|
|
491
|
+
aptosNetwork,
|
|
492
|
+
currentShelbyRpc,
|
|
493
|
+
currentAptosNetwork,
|
|
494
|
+
onComplete
|
|
495
|
+
]);
|
|
496
|
+
if (step === "shelbyRpc") {
|
|
497
|
+
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
498
|
+
/* @__PURE__ */ jsxs4(Text4, { children: [
|
|
499
|
+
"Updating context: ",
|
|
500
|
+
contextName
|
|
501
|
+
] }),
|
|
502
|
+
/* @__PURE__ */ jsxs4(Text4, { children: [
|
|
503
|
+
"Shelby RPC endpoint? (current: ",
|
|
504
|
+
currentShelbyRpc,
|
|
505
|
+
")"
|
|
506
|
+
] }),
|
|
507
|
+
error && /* @__PURE__ */ jsxs4(Text4, { color: "red", children: [
|
|
508
|
+
"Error: ",
|
|
509
|
+
error
|
|
510
|
+
] }),
|
|
511
|
+
/* @__PURE__ */ jsx4(
|
|
512
|
+
TextInput4,
|
|
513
|
+
{
|
|
514
|
+
value: shelbyRpcEndpoint,
|
|
515
|
+
placeholder: currentShelbyRpc,
|
|
516
|
+
onChange: (value) => {
|
|
517
|
+
setShelbyRpcEndpoint(value);
|
|
518
|
+
setError("");
|
|
519
|
+
},
|
|
520
|
+
onSubmit: () => {
|
|
521
|
+
if (shelbyRpcEndpoint && shelbyRpcEndpoint !== currentShelbyRpc) {
|
|
522
|
+
const result = EndpointSchema.safeParse(shelbyRpcEndpoint);
|
|
523
|
+
if (!result.success) {
|
|
524
|
+
setError(result.error.errors[0].message);
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
setError("");
|
|
529
|
+
setStep("aptosApi");
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
),
|
|
533
|
+
/* @__PURE__ */ jsx4(Text4, { color: "gray", children: "Press Enter to continue" })
|
|
534
|
+
] });
|
|
535
|
+
}
|
|
536
|
+
if (step === "aptosApi") {
|
|
537
|
+
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
538
|
+
/* @__PURE__ */ jsxs4(Text4, { children: [
|
|
539
|
+
"Aptos network? (current: ",
|
|
540
|
+
currentAptosNetwork,
|
|
541
|
+
")"
|
|
542
|
+
] }),
|
|
543
|
+
error && /* @__PURE__ */ jsxs4(Text4, { color: "red", children: [
|
|
544
|
+
"Error: ",
|
|
545
|
+
error
|
|
546
|
+
] }),
|
|
547
|
+
/* @__PURE__ */ jsx4(
|
|
548
|
+
TextInput4,
|
|
549
|
+
{
|
|
550
|
+
value: aptosNetwork,
|
|
551
|
+
placeholder: currentAptosNetwork,
|
|
552
|
+
onChange: (value) => {
|
|
553
|
+
setAptosNetwork(value);
|
|
554
|
+
setError("");
|
|
555
|
+
},
|
|
556
|
+
onSubmit: () => {
|
|
557
|
+
if (aptosNetwork && aptosNetwork !== currentAptosNetwork) {
|
|
558
|
+
const result = AptosNetworkSchema.safeParse(aptosNetwork);
|
|
559
|
+
if (!result.success) {
|
|
560
|
+
setError("Must be one of: mainnet, testnet, devnet, local");
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
setError("");
|
|
565
|
+
setStep("done");
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
),
|
|
569
|
+
/* @__PURE__ */ jsx4(Text4, { color: "gray", children: "Valid options: mainnet, testnet, devnet, local" }),
|
|
570
|
+
/* @__PURE__ */ jsx4(Text4, { color: "gray", children: "Press Enter to save changes" })
|
|
571
|
+
] });
|
|
572
|
+
}
|
|
573
|
+
return null;
|
|
574
|
+
};
|
|
575
|
+
|
|
447
576
|
// src/utils/config.ts
|
|
448
577
|
import os from "os";
|
|
449
578
|
import path from "path";
|
|
@@ -455,7 +584,7 @@ import {
|
|
|
455
584
|
} from "@aptos-labs/ts-sdk";
|
|
456
585
|
import fs from "fs-extra";
|
|
457
586
|
import YAML from "yaml";
|
|
458
|
-
import { z } from "zod";
|
|
587
|
+
import { z as z3 } from "zod";
|
|
459
588
|
|
|
460
589
|
// tests/utils/mockConfig.ts
|
|
461
590
|
var mockAccountAlice = generateEd25519Account();
|
|
@@ -493,20 +622,20 @@ var mockConfig = {
|
|
|
493
622
|
var DEFAULT_CONFIG_PATH = "~/.shelby/config.yaml";
|
|
494
623
|
|
|
495
624
|
// src/utils/config.ts
|
|
496
|
-
var ContextSchema =
|
|
497
|
-
aptos_network:
|
|
498
|
-
shelby_rpc_endpoint:
|
|
625
|
+
var ContextSchema = z3.object({
|
|
626
|
+
aptos_network: AptosNetworkSchema,
|
|
627
|
+
shelby_rpc_endpoint: EndpointSchema
|
|
499
628
|
});
|
|
500
|
-
var ConfigSchema =
|
|
501
|
-
contexts:
|
|
502
|
-
accounts:
|
|
503
|
-
|
|
504
|
-
address:
|
|
505
|
-
private_key:
|
|
629
|
+
var ConfigSchema = z3.object({
|
|
630
|
+
contexts: z3.record(ContextSchema),
|
|
631
|
+
accounts: z3.record(
|
|
632
|
+
z3.object({
|
|
633
|
+
address: z3.string().optional(),
|
|
634
|
+
private_key: z3.string({ message: "private_key must be provided" })
|
|
506
635
|
})
|
|
507
636
|
),
|
|
508
|
-
default_context:
|
|
509
|
-
default_account:
|
|
637
|
+
default_context: z3.string(),
|
|
638
|
+
default_account: z3.string()
|
|
510
639
|
});
|
|
511
640
|
function resolveConfigPath(configPath) {
|
|
512
641
|
if (configPath.startsWith("~")) {
|
|
@@ -618,7 +747,7 @@ function denormBlobName(pathModule, blobPrefix, blobName, outputPrefix) {
|
|
|
618
747
|
}
|
|
619
748
|
|
|
620
749
|
// src/commands/init.tsx
|
|
621
|
-
import { jsx as
|
|
750
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
622
751
|
function initCommand(program) {
|
|
623
752
|
program.command("init").description(
|
|
624
753
|
"Bootstrap your Shelby config via an interactive wizard or flags"
|
|
@@ -690,7 +819,7 @@ function initCommand(program) {
|
|
|
690
819
|
);
|
|
691
820
|
} else {
|
|
692
821
|
const { unmount } = render(
|
|
693
|
-
/* @__PURE__ */
|
|
822
|
+
/* @__PURE__ */ jsx5(
|
|
694
823
|
InitWizard,
|
|
695
824
|
{
|
|
696
825
|
onComplete: (config) => {
|
|
@@ -753,8 +882,8 @@ function getChunksetSizeBytes() {
|
|
|
753
882
|
|
|
754
883
|
// ../../packages/sdk/dist/chunk-LATCKOZE.mjs
|
|
755
884
|
import { AccountAddress as AccountAddress2 } from "@aptos-labs/ts-sdk";
|
|
756
|
-
import { z as
|
|
757
|
-
var BlobNameSchema =
|
|
885
|
+
import { z as z4 } from "zod";
|
|
886
|
+
var BlobNameSchema = z4.string().min(1, "Blob name path parameter cannot be empty.").max(1024, "Blob name cannot exceed 1024 characters.").refine((name2) => !name2.endsWith("/"), {
|
|
758
887
|
message: "Blob name cannot end with a slash"
|
|
759
888
|
});
|
|
760
889
|
function roundSize(size) {
|
|
@@ -1335,12 +1464,12 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1335
1464
|
};
|
|
1336
1465
|
|
|
1337
1466
|
// ../../packages/sdk/dist/chunk-OG3JQI44.mjs
|
|
1338
|
-
import { z as
|
|
1339
|
-
var ChunksetCommitmentSchema =
|
|
1467
|
+
import { z as z5 } from "zod";
|
|
1468
|
+
var ChunksetCommitmentSchema = z5.object({
|
|
1340
1469
|
// Chunkset root (vector commitment of child chunks)
|
|
1341
|
-
chunkset_root:
|
|
1470
|
+
chunkset_root: z5.string().nullable(),
|
|
1342
1471
|
// the size is known statically from the current configuration
|
|
1343
|
-
chunk_commitments:
|
|
1472
|
+
chunk_commitments: z5.array(z5.string())
|
|
1344
1473
|
}).refine(
|
|
1345
1474
|
(data) => {
|
|
1346
1475
|
return data.chunk_commitments.length === ERASURE_K + ERASURE_M;
|
|
@@ -1353,13 +1482,13 @@ var ChunksetCommitmentSchema = z3.object({
|
|
|
1353
1482
|
function expectedTotalChunksets(rawSize) {
|
|
1354
1483
|
return roundSize(rawSize) / getChunksetSizeBytes();
|
|
1355
1484
|
}
|
|
1356
|
-
var BlobCommitmentsSchema =
|
|
1357
|
-
schema_version:
|
|
1358
|
-
raw_data_size:
|
|
1485
|
+
var BlobCommitmentsSchema = z5.object({
|
|
1486
|
+
schema_version: z5.string(),
|
|
1487
|
+
raw_data_size: z5.number(),
|
|
1359
1488
|
// FIXME I am not sure about this being here, or if it should be somewhere else
|
|
1360
1489
|
// I deleted the blob_commitment. What's the difference?
|
|
1361
|
-
blob_merkle_root:
|
|
1362
|
-
chunkset_commitments:
|
|
1490
|
+
blob_merkle_root: z5.string(),
|
|
1491
|
+
chunkset_commitments: z5.array(ChunksetCommitmentSchema)
|
|
1363
1492
|
}).refine(
|
|
1364
1493
|
(data) => {
|
|
1365
1494
|
return expectedTotalChunksets(data.raw_data_size) === data.chunkset_commitments.length;
|
|
@@ -1377,20 +1506,20 @@ import { hashValues } from "@aptos-labs/ts-sdk";
|
|
|
1377
1506
|
// src/commands/account.tsx
|
|
1378
1507
|
import Table from "cli-table3";
|
|
1379
1508
|
import { render as render2 } from "ink";
|
|
1380
|
-
import { z as
|
|
1381
|
-
import { jsx as
|
|
1382
|
-
var CreateAccountOptionsSchema =
|
|
1383
|
-
name:
|
|
1384
|
-
privateKey:
|
|
1385
|
-
address:
|
|
1386
|
-
scheme:
|
|
1509
|
+
import { z as z6 } from "zod";
|
|
1510
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
1511
|
+
var CreateAccountOptionsSchema = z6.object({
|
|
1512
|
+
name: z6.string().optional(),
|
|
1513
|
+
privateKey: z6.string().optional(),
|
|
1514
|
+
address: z6.string().optional(),
|
|
1515
|
+
scheme: z6.union([z6.literal(ED25519_NAME), z6.literal(SECP256K1_NAME)]).optional()
|
|
1387
1516
|
});
|
|
1388
|
-
var ListAccountOptionsSchema =
|
|
1389
|
-
var UseAccountOptionsSchema =
|
|
1390
|
-
accountName:
|
|
1517
|
+
var ListAccountOptionsSchema = z6.object({});
|
|
1518
|
+
var UseAccountOptionsSchema = z6.object({
|
|
1519
|
+
accountName: z6.string()
|
|
1391
1520
|
});
|
|
1392
|
-
var DeleteAccountOptionsSchema =
|
|
1393
|
-
accountName:
|
|
1521
|
+
var DeleteAccountOptionsSchema = z6.object({
|
|
1522
|
+
accountName: z6.string()
|
|
1394
1523
|
});
|
|
1395
1524
|
function accountCommand(program) {
|
|
1396
1525
|
const account = program.command("account").description("Manage signing accounts (addresses & keys)");
|
|
@@ -1428,7 +1557,7 @@ function accountCommand(program) {
|
|
|
1428
1557
|
} else {
|
|
1429
1558
|
try {
|
|
1430
1559
|
const { unmount } = render2(
|
|
1431
|
-
/* @__PURE__ */
|
|
1560
|
+
/* @__PURE__ */ jsx6(
|
|
1432
1561
|
AccountWizard,
|
|
1433
1562
|
{
|
|
1434
1563
|
onComplete: ({
|
|
@@ -1533,23 +1662,21 @@ function accountCommand(program) {
|
|
|
1533
1662
|
const configPath = program.opts().configFile;
|
|
1534
1663
|
try {
|
|
1535
1664
|
const config = loadConfig(configPath);
|
|
1665
|
+
const accountName = program.opts().account || config.default_account;
|
|
1536
1666
|
const shelbyConfig = getCurrentShelbyConfig(config, {
|
|
1537
1667
|
context: program.opts().context
|
|
1538
1668
|
});
|
|
1539
|
-
const activeAccount = getCurrentAccount(
|
|
1540
|
-
config,
|
|
1541
|
-
program.opts().account
|
|
1542
|
-
).account;
|
|
1669
|
+
const activeAccount = getCurrentAccount(config, accountName).account;
|
|
1543
1670
|
const aptos = new Aptos3(shelbyConfig.aptos.config);
|
|
1544
1671
|
const blobClient = new ShelbyBlobClient({ aptos });
|
|
1545
1672
|
console.log(
|
|
1546
|
-
`\u{1F50D} Retrieving blobs for ${
|
|
1673
|
+
`\u{1F50D} Retrieving blobs for ${accountName} (${activeAccount.accountAddress.toString()})`
|
|
1547
1674
|
);
|
|
1548
1675
|
const blobs = await blobClient.getAccountBlobs({
|
|
1549
1676
|
account: activeAccount.accountAddress
|
|
1550
1677
|
});
|
|
1551
1678
|
console.log(
|
|
1552
|
-
`\u2705 Retrieved ${blobs.length} blobs for ${activeAccount.toString()}`
|
|
1679
|
+
`\u2705 Retrieved ${blobs.length} blobs for ${accountName} (${activeAccount.accountAddress.toString()})`
|
|
1553
1680
|
);
|
|
1554
1681
|
const table = new Table({
|
|
1555
1682
|
head: [
|
|
@@ -1594,13 +1721,18 @@ function accountCommand(program) {
|
|
|
1594
1721
|
// src/commands/context.tsx
|
|
1595
1722
|
import Table2 from "cli-table3";
|
|
1596
1723
|
import { render as render3 } from "ink";
|
|
1597
|
-
import { z as
|
|
1598
|
-
import { jsx as
|
|
1599
|
-
var CreateContextOptionsSchema =
|
|
1600
|
-
name:
|
|
1601
|
-
shelbyRpcEndpoint:
|
|
1602
|
-
aptosNetwork:
|
|
1603
|
-
// TODO
|
|
1724
|
+
import { z as z7 } from "zod";
|
|
1725
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
1726
|
+
var CreateContextOptionsSchema = z7.object({
|
|
1727
|
+
name: z7.string().optional(),
|
|
1728
|
+
shelbyRpcEndpoint: EndpointSchema.optional(),
|
|
1729
|
+
aptosNetwork: AptosNetworkSchema.optional()
|
|
1730
|
+
// TODO: Add support for custom endpoints objects
|
|
1731
|
+
});
|
|
1732
|
+
var UpdateContextOptionsSchema = z7.object({
|
|
1733
|
+
shelbyRpcEndpoint: EndpointSchema.optional(),
|
|
1734
|
+
aptosNetwork: AptosNetworkSchema.optional()
|
|
1735
|
+
// TODO: Add support for custom endpoints objects
|
|
1604
1736
|
});
|
|
1605
1737
|
function contextCommand(program) {
|
|
1606
1738
|
const context = program.command("context").description("Manage network contexts (Shelby RPC & Aptos endpoints)");
|
|
@@ -1629,7 +1761,7 @@ function contextCommand(program) {
|
|
|
1629
1761
|
return;
|
|
1630
1762
|
}
|
|
1631
1763
|
const { unmount } = render3(
|
|
1632
|
-
/* @__PURE__ */
|
|
1764
|
+
/* @__PURE__ */ jsx7(
|
|
1633
1765
|
ContextWizard,
|
|
1634
1766
|
{
|
|
1635
1767
|
onComplete: ({
|
|
@@ -1650,6 +1782,59 @@ function contextCommand(program) {
|
|
|
1650
1782
|
)
|
|
1651
1783
|
);
|
|
1652
1784
|
});
|
|
1785
|
+
context.command("update").description("Update an existing context").argument("<context-name>", "Name of the context to update").option("--shelby-rpc-endpoint <url>", "URL of the Shelby RPC service").option("--aptos-network <network>", "Aptos network").action((contextName, options) => {
|
|
1786
|
+
UpdateContextOptionsSchema.parse(options);
|
|
1787
|
+
const { shelbyRpcEndpoint, aptosNetwork } = options;
|
|
1788
|
+
const configPath = program.opts().configFile;
|
|
1789
|
+
let config;
|
|
1790
|
+
try {
|
|
1791
|
+
config = loadConfig(configPath);
|
|
1792
|
+
} catch (error) {
|
|
1793
|
+
console.error(`Error loading config: ${error.message}`);
|
|
1794
|
+
process.exit(1);
|
|
1795
|
+
}
|
|
1796
|
+
if (!config.contexts[contextName]) {
|
|
1797
|
+
console.error(`Error: Context '${contextName}' not found`);
|
|
1798
|
+
process.exit(1);
|
|
1799
|
+
}
|
|
1800
|
+
const currentContext = config.contexts[contextName];
|
|
1801
|
+
if (shelbyRpcEndpoint || aptosNetwork) {
|
|
1802
|
+
if (shelbyRpcEndpoint) {
|
|
1803
|
+
config.contexts[contextName].shelby_rpc_endpoint = shelbyRpcEndpoint;
|
|
1804
|
+
}
|
|
1805
|
+
if (aptosNetwork) {
|
|
1806
|
+
config.contexts[contextName].aptos_network = aptosNetwork;
|
|
1807
|
+
}
|
|
1808
|
+
saveConfig(config, configPath);
|
|
1809
|
+
console.log(`\u2705 Context '${contextName}' updated successfully`);
|
|
1810
|
+
return;
|
|
1811
|
+
}
|
|
1812
|
+
const { unmount } = render3(
|
|
1813
|
+
/* @__PURE__ */ jsx7(
|
|
1814
|
+
UpdateContextWizard,
|
|
1815
|
+
{
|
|
1816
|
+
contextName,
|
|
1817
|
+
currentShelbyRpc: currentContext.shelby_rpc_endpoint,
|
|
1818
|
+
currentAptosNetwork: currentContext.aptos_network,
|
|
1819
|
+
onComplete: ({
|
|
1820
|
+
shelbyRpcEndpoint: shelbyRpcEndpoint2,
|
|
1821
|
+
aptosNetwork: aptosNetwork2
|
|
1822
|
+
}) => {
|
|
1823
|
+
if (shelbyRpcEndpoint2) {
|
|
1824
|
+
config.contexts[contextName].shelby_rpc_endpoint = shelbyRpcEndpoint2;
|
|
1825
|
+
}
|
|
1826
|
+
if (aptosNetwork2) {
|
|
1827
|
+
config.contexts[contextName].aptos_network = aptosNetwork2;
|
|
1828
|
+
}
|
|
1829
|
+
saveConfig(config, configPath);
|
|
1830
|
+
console.log(`\u2705 Context '${contextName}' updated successfully`);
|
|
1831
|
+
unmount();
|
|
1832
|
+
process.exit(0);
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
)
|
|
1836
|
+
);
|
|
1837
|
+
});
|
|
1653
1838
|
context.command("list").description("List all contexts in a table").action(() => {
|
|
1654
1839
|
const configPath = program.opts().configFile;
|
|
1655
1840
|
let config;
|
|
@@ -1729,16 +1914,16 @@ import { Transform as Transform2 } from "stream";
|
|
|
1729
1914
|
import { pipeline } from "stream/promises";
|
|
1730
1915
|
import { Aptos as Aptos4 } from "@aptos-labs/ts-sdk";
|
|
1731
1916
|
import ora from "ora";
|
|
1732
|
-
import { z as
|
|
1917
|
+
import { z as z8 } from "zod";
|
|
1733
1918
|
var denormBlobName2 = (a, b, c) => denormBlobName(path3, a, b, c);
|
|
1734
1919
|
var endsWithDirectorySeparator = (filePath) => {
|
|
1735
1920
|
return filePath.endsWith("/") || filePath.endsWith("\\") || filePath.endsWith(path3.sep);
|
|
1736
1921
|
};
|
|
1737
|
-
var DownloadOptionsSchema =
|
|
1738
|
-
input:
|
|
1739
|
-
output:
|
|
1740
|
-
recursive:
|
|
1741
|
-
force:
|
|
1922
|
+
var DownloadOptionsSchema = z8.object({
|
|
1923
|
+
input: z8.string().min(1, "Input must be a valid blob name or directory prefix").describe("Blob name or directory prefix to download"),
|
|
1924
|
+
output: z8.string().min(1, "Output must be a valid filepath").describe("Local path where to save the downloaded content"),
|
|
1925
|
+
recursive: z8.boolean().default(false).describe("Download assuming canonical directory layout and recurse"),
|
|
1926
|
+
force: z8.boolean().default(false).describe("Overwrite the output if it already exists")
|
|
1742
1927
|
}).refine(
|
|
1743
1928
|
(data) => {
|
|
1744
1929
|
if (data.recursive) {
|
|
@@ -1982,15 +2167,86 @@ function downloadCommand(program) {
|
|
|
1982
2167
|
// src/commands/upload.tsx
|
|
1983
2168
|
import * as fs3 from "fs/promises";
|
|
1984
2169
|
import * as path4 from "path";
|
|
2170
|
+
import { Readable as Readable4 } from "stream";
|
|
1985
2171
|
import { Aptos as Aptos5 } from "@aptos-labs/ts-sdk";
|
|
1986
2172
|
import { glob } from "glob";
|
|
1987
|
-
import { Box as
|
|
2173
|
+
import { Box as Box5, Text as Text5, render as render4 } from "ink";
|
|
1988
2174
|
import SelectInput2 from "ink-select-input";
|
|
1989
2175
|
import ora2 from "ora";
|
|
1990
|
-
import { z as
|
|
1991
|
-
|
|
2176
|
+
import { z as z9 } from "zod";
|
|
2177
|
+
|
|
2178
|
+
// src/utils/errors.ts
|
|
2179
|
+
var ERROR_CODES = {
|
|
2180
|
+
UNKNOWN_ERROR: "UNKNOWN_ERROR",
|
|
2181
|
+
EBLOB_WRITE_INSUFFICIENT_FUNDS: "EBLOB_WRITE_INSUFFICIENT_FUNDS",
|
|
2182
|
+
EBLOB_WRITE_CHUNKSET_ALREADY_EXISTS: "EBLOB_WRITE_CHUNKSET_ALREADY_EXISTS",
|
|
2183
|
+
ECONNREFUSED: "ECONNREFUSED",
|
|
2184
|
+
ENOTFOUND: "ENOTFOUND"
|
|
2185
|
+
};
|
|
2186
|
+
var DEFAULT_ERROR_RESPONSE = {
|
|
2187
|
+
displayMessage: "An unknown error occurred",
|
|
2188
|
+
code: ERROR_CODES.UNKNOWN_ERROR
|
|
2189
|
+
};
|
|
2190
|
+
var formatHostInfo = (error) => {
|
|
2191
|
+
if (error instanceof Error) {
|
|
2192
|
+
if ("hostname" in error) {
|
|
2193
|
+
return `(${error.hostname})`;
|
|
2194
|
+
}
|
|
2195
|
+
if ("address" in error && "port" in error) {
|
|
2196
|
+
return `(${error.address}:${error.port})`;
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
return void 0;
|
|
2200
|
+
};
|
|
2201
|
+
var handleError = (error) => {
|
|
2202
|
+
if (error instanceof Error) {
|
|
2203
|
+
if (error.message.includes(ERROR_CODES.EBLOB_WRITE_INSUFFICIENT_FUNDS)) {
|
|
2204
|
+
return {
|
|
2205
|
+
displayMessage: "Insufficient Shelby tokens. Please fund your account with Shelby tokens to continue.",
|
|
2206
|
+
code: ERROR_CODES.EBLOB_WRITE_INSUFFICIENT_FUNDS
|
|
2207
|
+
};
|
|
2208
|
+
}
|
|
2209
|
+
if (error.message.includes(ERROR_CODES.EBLOB_WRITE_CHUNKSET_ALREADY_EXISTS)) {
|
|
2210
|
+
return {
|
|
2211
|
+
displayMessage: "The blob already exists on L1.",
|
|
2212
|
+
code: ERROR_CODES.EBLOB_WRITE_CHUNKSET_ALREADY_EXISTS
|
|
2213
|
+
};
|
|
2214
|
+
}
|
|
2215
|
+
if ("code" in error) {
|
|
2216
|
+
if (error.code === ERROR_CODES.ECONNREFUSED) {
|
|
2217
|
+
return {
|
|
2218
|
+
displayMessage: `Could not connect to the Shelby RPC endpoint. Please check that the endpoint you are using is correct ${formatHostInfo(error) ?? ""}.`,
|
|
2219
|
+
code: ERROR_CODES.ECONNREFUSED
|
|
2220
|
+
};
|
|
2221
|
+
}
|
|
2222
|
+
if (error.code === ERROR_CODES.ENOTFOUND) {
|
|
2223
|
+
return {
|
|
2224
|
+
displayMessage: `Could not connect to the Shelby RPC endpoint. Please check that the endpoint you are using is correct ${formatHostInfo(error) ?? ""}.`,
|
|
2225
|
+
code: ERROR_CODES.ENOTFOUND
|
|
2226
|
+
};
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
if (error.cause instanceof AggregateError) {
|
|
2230
|
+
const firstKnownError = error.cause.errors.find((error2) => {
|
|
2231
|
+
const handledError = handleError(error2);
|
|
2232
|
+
return handledError.code !== ERROR_CODES.UNKNOWN_ERROR;
|
|
2233
|
+
});
|
|
2234
|
+
if (firstKnownError) return handleError(firstKnownError);
|
|
2235
|
+
}
|
|
2236
|
+
if (error.cause instanceof Error) {
|
|
2237
|
+
return handleError(error.cause);
|
|
2238
|
+
}
|
|
2239
|
+
}
|
|
2240
|
+
return {
|
|
2241
|
+
displayMessage: `An unknown error occurred ${error instanceof Error ? `: ${error.message}` : ""}`,
|
|
2242
|
+
code: ERROR_CODES.UNKNOWN_ERROR
|
|
2243
|
+
};
|
|
2244
|
+
};
|
|
2245
|
+
|
|
2246
|
+
// src/commands/upload.tsx
|
|
2247
|
+
import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1992
2248
|
var normBlobName2 = (i, f, b) => normBlobName(path4, i, f, b);
|
|
1993
|
-
var flexibleDateSchema =
|
|
2249
|
+
var flexibleDateSchema = z9.string().transform((val) => {
|
|
1994
2250
|
if (/^\d+$/.test(val)) {
|
|
1995
2251
|
const timestamp = Number.parseInt(val, 10);
|
|
1996
2252
|
if (timestamp > 0 && timestamp < 4102444800) {
|
|
@@ -2003,18 +2259,18 @@ var flexibleDateSchema = z7.string().transform((val) => {
|
|
|
2003
2259
|
}
|
|
2004
2260
|
return ret;
|
|
2005
2261
|
});
|
|
2006
|
-
var UploadOptionsSchema =
|
|
2007
|
-
input:
|
|
2008
|
-
output:
|
|
2262
|
+
var UploadOptionsSchema = z9.object({
|
|
2263
|
+
input: z9.string().nonempty("`--input` is required"),
|
|
2264
|
+
output: z9.string().nonempty("`output` is required"),
|
|
2009
2265
|
expiration: flexibleDateSchema,
|
|
2010
|
-
recursive:
|
|
2011
|
-
assumeYes:
|
|
2012
|
-
outputCommitments:
|
|
2266
|
+
recursive: z9.boolean().optional().default(false),
|
|
2267
|
+
assumeYes: z9.boolean().optional().default(false),
|
|
2268
|
+
outputCommitments: z9.string().optional()
|
|
2013
2269
|
}).superRefine(async (data, ctx) => {
|
|
2014
2270
|
const stats = await fs3.stat(data.input);
|
|
2015
2271
|
if (!stats.isFile() && !stats.isDirectory()) {
|
|
2016
2272
|
ctx.addIssue({
|
|
2017
|
-
code:
|
|
2273
|
+
code: z9.ZodIssueCode.custom,
|
|
2018
2274
|
message: "`--input` must be a file or a directory",
|
|
2019
2275
|
path: ["input"]
|
|
2020
2276
|
});
|
|
@@ -2023,7 +2279,7 @@ var UploadOptionsSchema = z7.object({
|
|
|
2023
2279
|
if (stats.isDirectory()) {
|
|
2024
2280
|
if (!data.output.endsWith("/")) {
|
|
2025
2281
|
ctx.addIssue({
|
|
2026
|
-
code:
|
|
2282
|
+
code: z9.ZodIssueCode.custom,
|
|
2027
2283
|
message: "When input is a directory, output must end with '/'",
|
|
2028
2284
|
path: ["output"]
|
|
2029
2285
|
});
|
|
@@ -2032,7 +2288,7 @@ var UploadOptionsSchema = z7.object({
|
|
|
2032
2288
|
const blobNameResult = BlobNameSchema.safeParse(data.output);
|
|
2033
2289
|
if (!blobNameResult.success) {
|
|
2034
2290
|
ctx.addIssue({
|
|
2035
|
-
code:
|
|
2291
|
+
code: z9.ZodIssueCode.custom,
|
|
2036
2292
|
message: "When input is a file, output must be a valid blob name (cannot end with '/')",
|
|
2037
2293
|
path: ["output"]
|
|
2038
2294
|
});
|
|
@@ -2081,9 +2337,9 @@ function computeCost(filelist) {
|
|
|
2081
2337
|
return 1e8 * filelist.length;
|
|
2082
2338
|
}
|
|
2083
2339
|
function uploadCommand(program) {
|
|
2084
|
-
program.command("upload <input> <output>").description("Upload a file or directory to the shelby RPC in the config.").
|
|
2340
|
+
program.command("upload <input> <output>").description("Upload a file or directory to the shelby RPC in the config.").requiredOption(
|
|
2085
2341
|
"-e, --expiration <datetime>",
|
|
2086
|
-
"
|
|
2342
|
+
"UNIX Timestamp at which this blob will expire"
|
|
2087
2343
|
).option("-r, --recursive", "If uploading a directory, recurse").option(
|
|
2088
2344
|
"--assume-yes",
|
|
2089
2345
|
"Do not prompt interactively, assume yes for any questions"
|
|
@@ -2117,13 +2373,13 @@ function uploadCommand(program) {
|
|
|
2117
2373
|
if (!validatedOptions.assumeYes) {
|
|
2118
2374
|
const shouldContinue = await new Promise((resolve2) => {
|
|
2119
2375
|
const { unmount } = render4(
|
|
2120
|
-
/* @__PURE__ */
|
|
2121
|
-
/* @__PURE__ */
|
|
2376
|
+
/* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
2377
|
+
/* @__PURE__ */ jsxs5(Text5, { children: [
|
|
2122
2378
|
"Upload will cost ",
|
|
2123
2379
|
cost,
|
|
2124
2380
|
". Continue?"
|
|
2125
2381
|
] }),
|
|
2126
|
-
/* @__PURE__ */
|
|
2382
|
+
/* @__PURE__ */ jsx8(
|
|
2127
2383
|
SelectInput2,
|
|
2128
2384
|
{
|
|
2129
2385
|
items: [
|
|
@@ -2185,37 +2441,69 @@ function uploadCommand(program) {
|
|
|
2185
2441
|
for (const entry of filelist) {
|
|
2186
2442
|
totalSize += entry.sizeBytes;
|
|
2187
2443
|
}
|
|
2444
|
+
let hasUploadedBlob = false;
|
|
2188
2445
|
for (const entry of filelist) {
|
|
2189
2446
|
spinner.text = `Reading ${entry.filename}.. (Overall: ${formatProgressPercent()}%, ${formatProgressRate()} MiB/s)`;
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2447
|
+
try {
|
|
2448
|
+
const blobData = await fs3.readFile(entry.filename);
|
|
2449
|
+
if (blobData.length !== entry.sizeBytes) {
|
|
2450
|
+
throw new Error(
|
|
2451
|
+
`Size of file ${entry.filename} changed after initial scan. Original size was ${entry.sizeBytes} but it is now ${blobData.length}`
|
|
2452
|
+
);
|
|
2453
|
+
}
|
|
2454
|
+
spinner.text = `Committing ${entry.filename} to L1.. (Overall: ${formatProgressPercent()}%, ${formatProgressRate()} MiB/s)`;
|
|
2455
|
+
const existingBlobMetadata = await shelbyBlobClient.getBlobMetadata({
|
|
2456
|
+
account: activeAccount.accountAddress,
|
|
2457
|
+
name: entry.blobname
|
|
2458
|
+
});
|
|
2459
|
+
const blobCommitments = await generateCommitments(
|
|
2460
|
+
Readable4.from(blobData)
|
|
2194
2461
|
);
|
|
2462
|
+
if (!existingBlobMetadata) {
|
|
2463
|
+
const { transaction: pendingWriteBlobCommitmentsTransaction } = await shelbyBlobClient.writeBlobCommitments({
|
|
2464
|
+
account: activeAccount,
|
|
2465
|
+
blobName: entry.blobname,
|
|
2466
|
+
lifetime: validatedOptions.expiration.getTime() * 1e3,
|
|
2467
|
+
blobCommitments
|
|
2468
|
+
});
|
|
2469
|
+
await aptos.waitForTransaction({
|
|
2470
|
+
transactionHash: pendingWriteBlobCommitmentsTransaction.hash
|
|
2471
|
+
});
|
|
2472
|
+
} else {
|
|
2473
|
+
spinner.text = `Blob ${entry.blobname} already exists on L1, skipping commitments and uploading to Shelby RPC...`;
|
|
2474
|
+
}
|
|
2475
|
+
if (validatedOptions.outputCommitments) {
|
|
2476
|
+
outputCommitments[entry.filename] = blobCommitments;
|
|
2477
|
+
}
|
|
2478
|
+
const existingBlobChunks = await shelbyBlobClient.getBlobChunks({
|
|
2479
|
+
account: activeAccount.accountAddress,
|
|
2480
|
+
name: entry.blobname
|
|
2481
|
+
});
|
|
2482
|
+
if (existingBlobChunks.length === 0) {
|
|
2483
|
+
console.error(
|
|
2484
|
+
`Blob ${entry.blobname} does not exist on L1, an error occurred when uploading commitments...`
|
|
2485
|
+
);
|
|
2486
|
+
process.exit(1);
|
|
2487
|
+
}
|
|
2488
|
+
if (!existingBlobChunks.every(
|
|
2489
|
+
(chunk) => chunk.location.variant === "stored"
|
|
2490
|
+
)) {
|
|
2491
|
+
spinner.text = `Uploading ${entry.filename} to Shelby RPC.. (Overall: ${formatProgressPercent()}%, ${formatProgressRate()} MiB/s)`;
|
|
2492
|
+
await shelbyNodeClient.putBlob(
|
|
2493
|
+
activeAccount.accountAddress,
|
|
2494
|
+
entry.blobname,
|
|
2495
|
+
blobData
|
|
2496
|
+
);
|
|
2497
|
+
hasUploadedBlob = true;
|
|
2498
|
+
} else {
|
|
2499
|
+
spinner.text = "All blob chunks have been stored on L1, skipping upload to Shelby RPC...";
|
|
2500
|
+
}
|
|
2501
|
+
amountUploaded += blobData.length;
|
|
2502
|
+
} catch (error) {
|
|
2503
|
+
const { displayMessage } = handleError(error);
|
|
2504
|
+
spinner.fail(displayMessage);
|
|
2505
|
+
process.exit(1);
|
|
2195
2506
|
}
|
|
2196
|
-
spinner.text = `Committing ${entry.filename} to L1.. (Overall: ${formatProgressPercent()}%, ${formatProgressRate()} MiB/s)`;
|
|
2197
|
-
const {
|
|
2198
|
-
blobCommitments,
|
|
2199
|
-
transaction: pendingWriteBlobCommitmentsTransaction
|
|
2200
|
-
} = await shelbyBlobClient.writeBlobCommitments({
|
|
2201
|
-
account: activeAccount,
|
|
2202
|
-
blobName: entry.blobname,
|
|
2203
|
-
lifetime: validatedOptions.expiration.getTime() * 1e3,
|
|
2204
|
-
data: blobData
|
|
2205
|
-
});
|
|
2206
|
-
if (validatedOptions.outputCommitments) {
|
|
2207
|
-
outputCommitments[entry.filename] = blobCommitments;
|
|
2208
|
-
}
|
|
2209
|
-
await aptos.waitForTransaction({
|
|
2210
|
-
transactionHash: pendingWriteBlobCommitmentsTransaction.hash
|
|
2211
|
-
});
|
|
2212
|
-
spinner.text = `Uploading ${entry.filename} to Shelby RPC.. (Overall: ${formatProgressPercent()}%, ${formatProgressRate()} MiB/s)`;
|
|
2213
|
-
await shelbyNodeClient.putBlob(
|
|
2214
|
-
activeAccount.accountAddress,
|
|
2215
|
-
entry.blobname,
|
|
2216
|
-
blobData
|
|
2217
|
-
);
|
|
2218
|
-
amountUploaded += blobData.length;
|
|
2219
2507
|
}
|
|
2220
2508
|
if (validatedOptions.outputCommitments) {
|
|
2221
2509
|
await fs3.writeFile(
|
|
@@ -2223,18 +2511,22 @@ function uploadCommand(program) {
|
|
|
2223
2511
|
JSON.stringify(outputCommitments)
|
|
2224
2512
|
);
|
|
2225
2513
|
}
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2514
|
+
if (hasUploadedBlob) {
|
|
2515
|
+
spinner.succeed(
|
|
2516
|
+
`Uploaded complete, ran at ${formatProgressRate()} MiB/s`
|
|
2517
|
+
);
|
|
2518
|
+
} else {
|
|
2519
|
+
spinner.succeed("Skipped upload, blob has already been uploaded.");
|
|
2520
|
+
}
|
|
2229
2521
|
});
|
|
2230
2522
|
}
|
|
2231
2523
|
|
|
2232
2524
|
// src/commands/commitment.ts
|
|
2233
2525
|
import * as fs4 from "fs";
|
|
2234
2526
|
import * as fsP from "fs/promises";
|
|
2235
|
-
import { z as
|
|
2236
|
-
var CommitmentOptionsSchema =
|
|
2237
|
-
input:
|
|
2527
|
+
import { z as z10 } from "zod";
|
|
2528
|
+
var CommitmentOptionsSchema = z10.object({
|
|
2529
|
+
input: z10.string().nonempty("`--input` is required").refine(
|
|
2238
2530
|
async (path5) => {
|
|
2239
2531
|
const stat4 = await fsP.stat(path5);
|
|
2240
2532
|
return stat4.isFile();
|
|
@@ -2243,7 +2535,7 @@ var CommitmentOptionsSchema = z8.object({
|
|
|
2243
2535
|
message: "`--input` must be a file"
|
|
2244
2536
|
}
|
|
2245
2537
|
),
|
|
2246
|
-
output:
|
|
2538
|
+
output: z10.string().nonempty("`--output` is required")
|
|
2247
2539
|
});
|
|
2248
2540
|
function commitmentCommand(program) {
|
|
2249
2541
|
program.command("commitment").description(
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shelby-protocol/cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.6",
|
|
5
5
|
"private": false,
|
|
6
6
|
"bin": {
|
|
7
7
|
"shelby": "bin/entry.js"
|
|
@@ -9,9 +9,7 @@
|
|
|
9
9
|
"publishConfig": {
|
|
10
10
|
"access": "public"
|
|
11
11
|
},
|
|
12
|
-
"files": [
|
|
13
|
-
"bin/entry.js"
|
|
14
|
-
],
|
|
12
|
+
"files": ["bin/entry.js"],
|
|
15
13
|
"scripts": {
|
|
16
14
|
"prepublishOnly": "pnpm run build",
|
|
17
15
|
"lint": "biome check .",
|