@shelby-protocol/cli 0.0.15 → 0.0.16

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.
Files changed (2) hide show
  1. package/bin/entry.js +1778 -335
  2. package/package.json +8 -4
package/bin/entry.js CHANGED
@@ -1,15 +1,519 @@
1
1
  #!/usr/bin/env node
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __commonJS = (cb, mod) => function __require() {
9
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+
28
+ // assets/hasura_metadata.txt
29
+ var require_hasura_metadata = __commonJS({
30
+ "assets/hasura_metadata.txt"(exports, module) {
31
+ module.exports = '{\n "resource_version": 15,\n "metadata": {\n "version": 3,\n "sources": [\n {\n "name": "processordb",\n "kind": "postgres",\n "tables": [\n {\n "table": {\n "name": "blob_activities",\n "schema": "public"\n },\n "select_permissions": [\n {\n "role": "anonymous",\n "permission": {\n "columns": [\n "transaction_hash",\n "event_index",\n "transaction_version",\n "blob_name",\n "event_type",\n "timestamp"\n ],\n "filter": {},\n "limit": 100,\n "allow_aggregations": true\n },\n "comment": ""\n }\n ]\n },\n {\n "table": {\n "name": "blobs",\n "schema": "public"\n },\n "array_relationships": [\n {\n "name": "placement_group_slots",\n "using": {\n "manual_configuration": {\n "column_mapping": {\n "placement_group": "placement_group"\n },\n "insertion_order": null,\n "remote_table": {\n "name": "placement_group_slots",\n "schema": "public"\n }\n }\n }\n }\n ],\n "select_permissions": [\n {\n "role": "anonymous",\n "permission": {\n "columns": [\n "owner",\n "placement_group",\n "slice_address",\n "created_at",\n "expires_at",\n "is_deleted",\n "is_written",\n "num_chunksets",\n "size",\n "updated_at",\n "blob_commitment",\n "blob_name"\n ],\n "filter": {},\n "limit": 200,\n "allow_aggregations": true\n },\n "comment": ""\n }\n ]\n },\n {\n "table": {\n "name": "placement_group_slots",\n "schema": "public"\n },\n "select_permissions": [\n {\n "role": "anonymous",\n "permission": {\n "columns": [\n "placement_group",\n "storage_provider",\n "slot_index",\n "updated_at",\n "status"\n ],\n "filter": {}\n },\n "comment": ""\n }\n ]\n },\n {\n "table": {\n "name": "processor_status",\n "schema": "public"\n },\n "select_permissions": [\n {\n "role": "anonymous",\n "permission": {\n "columns": [\n "last_success_version",\n "last_transaction_timestamp",\n "last_updated"\n ],\n "filter": {},\n "limit": 10\n }\n }\n ]\n }\n ],\n "configuration": {\n "connection_info": {\n "database_url": {\n "from_env": "PROCESSOR_DATABASE_URL"\n },\n "isolation_level": "read-committed",\n "pool_settings": {\n "connection_lifetime": 600,\n "max_connections": 120\n },\n "use_prepared_statements": false\n }\n }\n }\n ]\n }\n}';
32
+ }
33
+ });
34
+
35
+ // assets/shelby_internal.txt
36
+ var require_shelby_internal = __commonJS({
37
+ "assets/shelby_internal.txt"(exports, module) {
38
+ module.exports = `# This common_config is designed to work with the localnet setup in ts-cibuild.sh
39
+ common_config:
40
+ health_check_port: 7654
41
+ write_rate_limit_config:
42
+ num_bytes: 500000000
43
+ num_seconds: 300
44
+ transaction_stream_config:
45
+ # The node and its txn stream run on the host. In a Linux Docker environment,
46
+ # docker.host.internal is not normally available and you have to use
47
+ # 172.17.0.1 instead, but we add a hosts entry when running the containers to
48
+ # make it available.
49
+ indexer_grpc_data_service_address: "http://host.docker.internal:50051"
50
+ auth_token: notusedforlocalnet
51
+ request_name_header: "remapping-processor"
52
+ db_config:
53
+ # The domain we use is the name of the database in the localnet Docker network. The
54
+ # remapping processor needs its own database, so we use "postgres" rather than the
55
+ # "local_testnet" database used by the localnet's core processors. We use port 5432
56
+ # because that's the port postgres runs at inside the Docker network, even though we
57
+ # expose it to the outside world at 5433.
58
+ postgres_connection_string: postgresql://postgres:postgres@local-testnet-postgres:5432/postgres
59
+ custom_config:
60
+ db_schema:
61
+ blob_activities:
62
+ blob_name:
63
+ column_type:
64
+ column_type: "string"
65
+ type: "move_type"
66
+ default_value: null
67
+ is_index: false
68
+ is_nullable: false
69
+ is_option: false
70
+ is_primary_key: false
71
+ is_vec: false
72
+ event_index:
73
+ column_type:
74
+ column_type: "event_index"
75
+ type: "event_metadata"
76
+ default_value: null
77
+ is_index: false
78
+ is_nullable: false
79
+ is_option: false
80
+ is_primary_key: true
81
+ is_vec: false
82
+ event_type:
83
+ column_type:
84
+ column_type: "event_type"
85
+ type: "event_metadata"
86
+ default_value: null
87
+ is_index: false
88
+ is_nullable: false
89
+ is_option: false
90
+ is_primary_key: true
91
+ is_vec: false
92
+ timestamp:
93
+ column_type:
94
+ column_type: "timestamp"
95
+ type: "transaction_metadata"
96
+ default_value: null
97
+ is_index: false
98
+ is_nullable: false
99
+ is_option: false
100
+ is_primary_key: false
101
+ is_vec: false
102
+ transaction_hash:
103
+ column_type:
104
+ column_type: "hash"
105
+ type: "transaction_metadata"
106
+ default_value: null
107
+ is_index: false
108
+ is_nullable: false
109
+ is_option: false
110
+ is_primary_key: true
111
+ is_vec: false
112
+ transaction_version:
113
+ column_type:
114
+ column_type: "version"
115
+ type: "transaction_metadata"
116
+ default_value: null
117
+ is_index: false
118
+ is_nullable: false
119
+ is_option: false
120
+ is_primary_key: false
121
+ is_vec: false
122
+ blobs:
123
+ blob_commitment:
124
+ column_type:
125
+ column_type: "string"
126
+ type: "move_type"
127
+ default_value: null
128
+ is_index: false
129
+ is_nullable: false
130
+ is_option: false
131
+ is_primary_key: false
132
+ is_vec: false
133
+ blob_name:
134
+ column_type:
135
+ column_type: "string"
136
+ type: "move_type"
137
+ default_value: null
138
+ is_index: false
139
+ is_nullable: false
140
+ is_option: false
141
+ is_primary_key: true
142
+ is_vec: false
143
+ created_at:
144
+ column_type:
145
+ column_type: "u64"
146
+ type: "move_type"
147
+ default_value: null
148
+ is_index: false
149
+ is_nullable: false
150
+ is_option: false
151
+ is_primary_key: false
152
+ is_vec: false
153
+ expires_at:
154
+ column_type:
155
+ column_type: "u64"
156
+ type: "move_type"
157
+ default_value: null
158
+ is_index: false
159
+ is_nullable: false
160
+ is_option: false
161
+ is_primary_key: false
162
+ is_vec: false
163
+ is_deleted:
164
+ column_type:
165
+ column_type: "u8"
166
+ type: "move_type"
167
+ default_value: null
168
+ is_index: false
169
+ is_nullable: false
170
+ is_option: false
171
+ is_primary_key: false
172
+ is_vec: false
173
+ is_written:
174
+ column_type:
175
+ column_type: "u8"
176
+ type: "move_type"
177
+ default_value: null
178
+ is_index: false
179
+ is_nullable: false
180
+ is_option: false
181
+ is_primary_key: false
182
+ is_vec: false
183
+ num_chunksets:
184
+ column_type:
185
+ column_type: "u32"
186
+ type: "move_type"
187
+ default_value: null
188
+ is_index: false
189
+ is_nullable: false
190
+ is_option: false
191
+ is_primary_key: false
192
+ is_vec: false
193
+ owner:
194
+ column_type:
195
+ column_type: "address"
196
+ type: "move_type"
197
+ default_value: null
198
+ is_index: true
199
+ is_nullable: false
200
+ is_option: false
201
+ is_primary_key: false
202
+ is_vec: false
203
+ placement_group:
204
+ column_type:
205
+ column_type: "address"
206
+ type: "move_type"
207
+ default_value: null
208
+ is_index: false
209
+ is_nullable: false
210
+ is_option: false
211
+ is_primary_key: false
212
+ is_vec: false
213
+ size:
214
+ column_type:
215
+ column_type: "u64"
216
+ type: "move_type"
217
+ default_value: null
218
+ is_index: false
219
+ is_nullable: false
220
+ is_option: false
221
+ is_primary_key: false
222
+ is_vec: false
223
+ slice_address:
224
+ column_type:
225
+ column_type: "address"
226
+ type: "move_type"
227
+ default_value: null
228
+ is_index: false
229
+ is_nullable: false
230
+ is_option: false
231
+ is_primary_key: false
232
+ is_vec: false
233
+ updated_at:
234
+ column_type:
235
+ column_type: "u64"
236
+ type: "move_type"
237
+ default_value: null
238
+ is_index: false
239
+ is_nullable: false
240
+ is_option: false
241
+ is_primary_key: false
242
+ is_vec: false
243
+ placement_group_slots:
244
+ placement_group:
245
+ column_type:
246
+ column_type: "address"
247
+ type: "move_type"
248
+ default_value: null
249
+ is_index: false
250
+ is_nullable: false
251
+ is_option: false
252
+ is_primary_key: true
253
+ is_vec: false
254
+ slot_index:
255
+ column_type:
256
+ column_type: "u64"
257
+ type: "move_type"
258
+ default_value: null
259
+ is_index: false
260
+ is_nullable: false
261
+ is_option: false
262
+ is_primary_key: true
263
+ is_vec: false
264
+ status:
265
+ column_type:
266
+ column_type: "string"
267
+ type: "move_type"
268
+ default_value: null
269
+ is_index: false
270
+ is_nullable: false
271
+ is_option: false
272
+ is_primary_key: false
273
+ is_vec: false
274
+ storage_provider:
275
+ column_type:
276
+ column_type: "address"
277
+ type: "move_type"
278
+ default_value: null
279
+ is_index: false
280
+ is_nullable: false
281
+ is_option: false
282
+ is_primary_key: false
283
+ is_vec: false
284
+ updated_at:
285
+ column_type:
286
+ column_type: "u64"
287
+ type: "move_type"
288
+ default_value: null
289
+ is_index: false
290
+ is_nullable: false
291
+ is_option: false
292
+ is_primary_key: false
293
+ is_vec: false
294
+ events:
295
+ 0xc63d6a5efb0080a6029403131715bd4971e1149f7cc099aac69bb0069b3ddbf5::blob_metadata::BlobDeletedEvent:
296
+ constant_values:
297
+ - column: "is_deleted"
298
+ table: "blobs"
299
+ value: 1
300
+ event_fields:
301
+ $.blob_name:
302
+ - column: "blob_name"
303
+ table: "blobs"
304
+ - column: "blob_name"
305
+ table: "blob_activities"
306
+ $.deleted_at_micros:
307
+ - column: "updated_at"
308
+ table: "blobs"
309
+ event_metadata:
310
+ account_address: []
311
+ creation_number: []
312
+ event_index:
313
+ - column: "event_index"
314
+ table: "blob_activities"
315
+ event_type:
316
+ - column: "event_type"
317
+ table: "blob_activities"
318
+ sequence_number: []
319
+ 0xc63d6a5efb0080a6029403131715bd4971e1149f7cc099aac69bb0069b3ddbf5::blob_metadata::BlobExpirationExtendedEvent:
320
+ constant_values: []
321
+ event_fields:
322
+ $.blob_name:
323
+ - column: "blob_name"
324
+ table: "blobs"
325
+ - column: "blob_name"
326
+ table: "blob_activities"
327
+ $.new_expiration_micros:
328
+ - column: "expires_at"
329
+ table: "blobs"
330
+ $.updated_at_micros:
331
+ - column: "updated_at"
332
+ table: "blobs"
333
+ event_metadata:
334
+ account_address: []
335
+ creation_number: []
336
+ event_index:
337
+ - column: "event_index"
338
+ table: "blob_activities"
339
+ event_type:
340
+ - column: "event_type"
341
+ table: "blob_activities"
342
+ sequence_number: []
343
+ 0xc63d6a5efb0080a6029403131715bd4971e1149f7cc099aac69bb0069b3ddbf5::blob_metadata::BlobRegisteredEvent:
344
+ constant_values:
345
+ - column: "is_deleted"
346
+ table: "blobs"
347
+ value: 0
348
+ - column: "is_written"
349
+ table: "blobs"
350
+ value: 0
351
+ event_fields:
352
+ $.blob_commitment:
353
+ - column: "blob_commitment"
354
+ table: "blobs"
355
+ $.blob_name:
356
+ - column: "blob_name"
357
+ table: "blobs"
358
+ - column: "blob_name"
359
+ table: "blob_activities"
360
+ $.blob_size:
361
+ - column: "size"
362
+ table: "blobs"
363
+ $.chunkset_count:
364
+ - column: "num_chunksets"
365
+ table: "blobs"
366
+ $.creation_micros:
367
+ - column: "created_at"
368
+ table: "blobs"
369
+ - column: "updated_at"
370
+ table: "blobs"
371
+ $.expiration_micros:
372
+ - column: "expires_at"
373
+ table: "blobs"
374
+ $.owner:
375
+ - column: "owner"
376
+ table: "blobs"
377
+ $.placement_group_address:
378
+ - column: "placement_group"
379
+ table: "blobs"
380
+ $.slice_address:
381
+ - column: "slice_address"
382
+ table: "blobs"
383
+ event_metadata:
384
+ account_address: []
385
+ creation_number: []
386
+ event_index:
387
+ - column: "event_index"
388
+ table: "blob_activities"
389
+ event_type:
390
+ - column: "event_type"
391
+ table: "blob_activities"
392
+ sequence_number: []
393
+ 0xc63d6a5efb0080a6029403131715bd4971e1149f7cc099aac69bb0069b3ddbf5::blob_metadata::BlobWrittenEvent:
394
+ constant_values:
395
+ - column: "is_written"
396
+ table: "blobs"
397
+ value: 1
398
+ event_fields:
399
+ $.blob_name:
400
+ - column: "blob_name"
401
+ table: "blobs"
402
+ - column: "blob_name"
403
+ table: "blob_activities"
404
+ $.written_at_micros:
405
+ - column: "updated_at"
406
+ table: "blobs"
407
+ event_metadata:
408
+ account_address: []
409
+ creation_number: []
410
+ event_index:
411
+ - column: "event_index"
412
+ table: "blob_activities"
413
+ event_type:
414
+ - column: "event_type"
415
+ table: "blob_activities"
416
+ sequence_number: []
417
+ 0xc63d6a5efb0080a6029403131715bd4971e1149f7cc099aac69bb0069b3ddbf5::placement_group::StorageProviderActivatedEvent:
418
+ constant_values:
419
+ - column: "status"
420
+ table: "placement_group_slots"
421
+ value: "active"
422
+ event_fields:
423
+ $.activated_at:
424
+ - column: "updated_at"
425
+ table: "placement_group_slots"
426
+ $.placement_group_address:
427
+ - column: "placement_group"
428
+ table: "placement_group_slots"
429
+ $.slot_index:
430
+ - column: "slot_index"
431
+ table: "placement_group_slots"
432
+ $.storage_provider_address:
433
+ - column: "storage_provider"
434
+ table: "placement_group_slots"
435
+ event_metadata:
436
+ account_address: []
437
+ creation_number: []
438
+ event_index: []
439
+ event_type: []
440
+ sequence_number: []
441
+ 0xc63d6a5efb0080a6029403131715bd4971e1149f7cc099aac69bb0069b3ddbf5::placement_group::StorageProviderAssignedEvent:
442
+ constant_values:
443
+ - column: "status"
444
+ table: "placement_group_slots"
445
+ value: "joining"
446
+ event_fields:
447
+ $.assigned_at:
448
+ - column: "updated_at"
449
+ table: "placement_group_slots"
450
+ $.placement_group_address:
451
+ - column: "placement_group"
452
+ table: "placement_group_slots"
453
+ $.slot_index:
454
+ - column: "slot_index"
455
+ table: "placement_group_slots"
456
+ $.storage_provider_address:
457
+ - column: "storage_provider"
458
+ table: "placement_group_slots"
459
+ event_metadata:
460
+ account_address: []
461
+ creation_number: []
462
+ event_index: []
463
+ event_type: []
464
+ sequence_number: []
465
+ 0xc63d6a5efb0080a6029403131715bd4971e1149f7cc099aac69bb0069b3ddbf5::placement_group::StorageProviderLeftEvent:
466
+ constant_values:
467
+ - column: "status"
468
+ table: "placement_group_slots"
469
+ value: "left"
470
+ event_fields:
471
+ $.left_at:
472
+ - column: "updated_at"
473
+ table: "placement_group_slots"
474
+ $.placement_group_address:
475
+ - column: "placement_group"
476
+ table: "placement_group_slots"
477
+ $.slot_index:
478
+ - column: "slot_index"
479
+ table: "placement_group_slots"
480
+ $.storage_provider_address:
481
+ - column: "storage_provider"
482
+ table: "placement_group_slots"
483
+ event_metadata:
484
+ account_address: []
485
+ creation_number: []
486
+ event_index: []
487
+ event_type: []
488
+ sequence_number: []
489
+ payload: {}
490
+ transaction_metadata:
491
+ block_height: []
492
+ epoch: []
493
+ hash:
494
+ - column: "transaction_hash"
495
+ table: "blob_activities"
496
+ timestamp:
497
+ - column: "timestamp"
498
+ table: "blob_activities"
499
+ version:
500
+ - column: "transaction_version"
501
+ table: "blob_activities"
502
+ `;
503
+ }
504
+ });
2
505
 
3
506
  // src/cli.tsx
4
- import { Command } from "commander";
507
+ import { Command } from "@commander-js/extra-typings";
5
508
 
6
509
  // package.json
7
510
  var name = "@shelby-protocol/cli";
8
- var version = "0.0.15";
511
+ var version = "0.0.16";
9
512
 
10
513
  // src/commands/account.tsx
11
514
  import readline from "readline";
12
515
  import { Account as Account3, AptosApiError as AptosApiError2, Ed25519PrivateKey as Ed25519PrivateKey4 } from "@aptos-labs/ts-sdk";
516
+ import { Option } from "@commander-js/extra-typings";
13
517
 
14
518
  // ../../packages/sdk/dist/chunk-RBFWGDMY.mjs
15
519
  import { AptosConfig, Network } from "@aptos-labs/ts-sdk";
@@ -229,10 +733,10 @@ var GraphQLError = class _GraphQLError extends Error {
229
733
  */
230
734
  constructor(message, ...rawArgs) {
231
735
  var _this$nodes, _nodeLocations$, _ref;
232
- const { nodes, source, positions, path: path7, originalError, extensions } = toNormalizedOptions(rawArgs);
736
+ const { nodes, source, positions, path: path10, originalError, extensions } = toNormalizedOptions(rawArgs);
233
737
  super(message);
234
738
  this.name = "GraphQLError";
235
- this.path = path7 !== null && path7 !== void 0 ? path7 : void 0;
739
+ this.path = path10 !== null && path10 !== void 0 ? path10 : void 0;
236
740
  this.originalError = originalError !== null && originalError !== void 0 ? originalError : void 0;
237
741
  this.nodes = undefinedIfEmpty(
238
742
  Array.isArray(nodes) ? nodes : nodes ? [nodes] : void 0
@@ -2800,14 +3304,14 @@ function visit(root, visitor, visitorKeys = QueryDocumentKeys) {
2800
3304
  let node = root;
2801
3305
  let key = void 0;
2802
3306
  let parent = void 0;
2803
- const path7 = [];
3307
+ const path10 = [];
2804
3308
  const ancestors = [];
2805
3309
  do {
2806
3310
  index++;
2807
3311
  const isLeaving = index === keys.length;
2808
3312
  const isEdited = isLeaving && edits.length !== 0;
2809
3313
  if (isLeaving) {
2810
- key = ancestors.length === 0 ? void 0 : path7[path7.length - 1];
3314
+ key = ancestors.length === 0 ? void 0 : path10[path10.length - 1];
2811
3315
  node = parent;
2812
3316
  parent = ancestors.pop();
2813
3317
  if (isEdited) {
@@ -2841,20 +3345,20 @@ function visit(root, visitor, visitorKeys = QueryDocumentKeys) {
2841
3345
  if (node === null || node === void 0) {
2842
3346
  continue;
2843
3347
  }
2844
- path7.push(key);
3348
+ path10.push(key);
2845
3349
  }
2846
3350
  let result;
2847
3351
  if (!Array.isArray(node)) {
2848
3352
  var _enterLeaveMap$get, _enterLeaveMap$get2;
2849
3353
  isNode(node) || devAssert(false, `Invalid AST Node: ${inspect(node)}.`);
2850
3354
  const visitFn = isLeaving ? (_enterLeaveMap$get = enterLeaveMap.get(node.kind)) === null || _enterLeaveMap$get === void 0 ? void 0 : _enterLeaveMap$get.leave : (_enterLeaveMap$get2 = enterLeaveMap.get(node.kind)) === null || _enterLeaveMap$get2 === void 0 ? void 0 : _enterLeaveMap$get2.enter;
2851
- result = visitFn === null || visitFn === void 0 ? void 0 : visitFn.call(visitor, node, key, parent, path7, ancestors);
3355
+ result = visitFn === null || visitFn === void 0 ? void 0 : visitFn.call(visitor, node, key, parent, path10, ancestors);
2852
3356
  if (result === BREAK) {
2853
3357
  break;
2854
3358
  }
2855
3359
  if (result === false) {
2856
3360
  if (!isLeaving) {
2857
- path7.pop();
3361
+ path10.pop();
2858
3362
  continue;
2859
3363
  }
2860
3364
  } else if (result !== void 0) {
@@ -2863,7 +3367,7 @@ function visit(root, visitor, visitorKeys = QueryDocumentKeys) {
2863
3367
  if (isNode(result)) {
2864
3368
  node = result;
2865
3369
  } else {
2866
- path7.pop();
3370
+ path10.pop();
2867
3371
  continue;
2868
3372
  }
2869
3373
  }
@@ -2873,7 +3377,7 @@ function visit(root, visitor, visitorKeys = QueryDocumentKeys) {
2873
3377
  edits.push([key, node]);
2874
3378
  }
2875
3379
  if (isLeaving) {
2876
- path7.pop();
3380
+ path10.pop();
2877
3381
  } else {
2878
3382
  var _node$kind;
2879
3383
  stack = {
@@ -3970,10 +4474,10 @@ function isReadableStream(value) {
3970
4474
  function toUint8Array(view) {
3971
4475
  return view instanceof Uint8Array ? view : new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
3972
4476
  }
3973
- function buildRequestUrl(path7, baseUrl) {
4477
+ function buildRequestUrl(path10, baseUrl) {
3974
4478
  const baseHasSlash = baseUrl.endsWith("/");
3975
4479
  const safeBase = baseHasSlash ? baseUrl : `${baseUrl}/`;
3976
- const safePath = path7.replace(/^\/+/, "");
4480
+ const safePath = path10.replace(/^\/+/, "");
3977
4481
  return new URL(safePath, safeBase);
3978
4482
  }
3979
4483
  function getBlobNameSuffix(blobName) {
@@ -5011,7 +5515,7 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
5011
5515
  }
5012
5516
  };
5013
5517
 
5014
- // ../../packages/sdk/dist/chunk-CQZZRXA6.mjs
5518
+ // ../../packages/sdk/dist/chunk-AUGZMI6U.mjs
5015
5519
  import {
5016
5520
  Aptos as Aptos3
5017
5521
  } from "@aptos-labs/ts-sdk";
@@ -5153,7 +5657,7 @@ function validateConcurrency(concurrency) {
5153
5657
  }
5154
5658
  }
5155
5659
 
5156
- // ../../packages/sdk/dist/chunk-CQZZRXA6.mjs
5660
+ // ../../packages/sdk/dist/chunk-AUGZMI6U.mjs
5157
5661
  var ShelbyClient = class {
5158
5662
  /**
5159
5663
  * The coordination client is used to interact with the Aptos blockchain which handles the commitments
@@ -5386,17 +5890,52 @@ var ShelbyClient = class {
5386
5890
  async download(params) {
5387
5891
  return await this.rpc.getBlob(params);
5388
5892
  }
5893
+ /**
5894
+ *
5895
+ * Funds an account with ShelbyUSD tokens.
5896
+ *
5897
+ * @param params.address - The address to fund.
5898
+ * @param params.amount - The amount to fund.
5899
+ * @returns The transaction hash of the funded account.
5900
+ *
5901
+ * @example
5902
+ * ```typescript
5903
+ * const hash = await client.fundAccount({
5904
+ * address: "0x1",
5905
+ * amount: 100000000,
5906
+ * });
5907
+ * ```
5908
+ */
5909
+ async fundAccount(params) {
5910
+ const { address, amount } = params;
5911
+ try {
5912
+ const faucet = this.config.faucet ?? "https://faucet.shelbynet.shelby.xyz/fund?asset=shelbyusd";
5913
+ const response = await fetch(`${faucet}`, {
5914
+ method: "POST",
5915
+ body: JSON.stringify({ address, amount }),
5916
+ headers: {
5917
+ "Content-Type": "application/json"
5918
+ }
5919
+ });
5920
+ if (!response.ok) {
5921
+ throw new Error("Failed to fund account");
5922
+ }
5923
+ return response.json();
5924
+ } catch (error) {
5925
+ throw new Error("Failed to fund account: " + error);
5926
+ }
5927
+ }
5389
5928
  };
5390
5929
 
5391
- // ../../packages/sdk/dist/chunk-2JMRK5PM.mjs
5930
+ // ../../packages/sdk/dist/chunk-GZJ5IOCG.mjs
5392
5931
  var ShelbyNodeClient = class extends ShelbyClient {
5393
5932
  };
5394
5933
 
5395
5934
  // ../../packages/sdk/dist/chunk-7P6ASYW6.mjs
5396
- var __defProp = Object.defineProperty;
5935
+ var __defProp2 = Object.defineProperty;
5397
5936
  var __export = (target, all) => {
5398
5937
  for (var name2 in all)
5399
- __defProp(target, name2, { get: all[name2], enumerable: true });
5938
+ __defProp2(target, name2, { get: all[name2], enumerable: true });
5400
5939
  };
5401
5940
 
5402
5941
  // ../../packages/sdk/dist/chunk-A4IG6GSE.mjs
@@ -5498,7 +6037,7 @@ var DEFAULT_CHUNK_SIZE_BYTES2 = 2 * 1024 * 1024;
5498
6037
  import chalk2 from "chalk";
5499
6038
  import { filesize } from "filesize";
5500
6039
  import { render } from "ink";
5501
- import { z as z10 } from "zod";
6040
+ import { z as z11 } from "zod";
5502
6041
 
5503
6042
  // src/components/AccountWizard.tsx
5504
6043
  import { Box, Text } from "ink";
@@ -5506,8 +6045,8 @@ import TextInput from "ink-text-input";
5506
6045
  import { useEffect, useState } from "react";
5507
6046
 
5508
6047
  // src/utils/config.ts
5509
- import os from "os";
5510
- import path from "path";
6048
+ import os2 from "os";
6049
+ import path2 from "path";
5511
6050
  import {
5512
6051
  Aptos as Aptos4,
5513
6052
  AptosConfig as AptosConfig3,
@@ -5515,9 +6054,9 @@ import {
5515
6054
  Ed25519PrivateKey,
5516
6055
  NetworkToNetworkName
5517
6056
  } from "@aptos-labs/ts-sdk";
5518
- import fs from "fs-extra";
5519
- import YAML from "yaml";
5520
- import { z as z6 } from "zod";
6057
+ import fs2 from "fs-extra";
6058
+ import YAML2 from "yaml";
6059
+ import { z as z7 } from "zod";
5521
6060
 
5522
6061
  // src/schemas/AptosNetworkSchema.ts
5523
6062
  import { z as z4 } from "zod";
@@ -5548,111 +6087,150 @@ var ShelbyNetworkSchema = z5.object({
5548
6087
  deployer_address: z5.string().optional()
5549
6088
  });
5550
6089
 
5551
- // src/utils/constants.ts
5552
- import { APTOS_COIN, Network as Network7 } from "@aptos-labs/ts-sdk";
5553
-
5554
- // src/utils/context-helpers.ts
5555
- import {
5556
- NetworkToFaucetAPI,
5557
- NetworkToIndexerAPI,
5558
- NetworkToNodeAPI,
5559
- NetworkToPepperAPI,
5560
- NetworkToProverAPI
5561
- } from "@aptos-labs/ts-sdk";
5562
- function createContextForNetwork(network) {
5563
- return {
5564
- aptos_network: {
5565
- name: network,
5566
- fullnode: NetworkToNodeAPI[network],
5567
- faucet: NetworkToFaucetAPI[network],
5568
- indexer: NetworkToIndexerAPI[network],
5569
- pepper: NetworkToPepperAPI[network],
5570
- prover: NetworkToProverAPI[network]
5571
- },
5572
- shelby_network: {
5573
- rpc_endpoint: NetworkToShelbyRPCBaseUrl[network]
5574
- }
5575
- };
5576
- }
5577
-
5578
- // src/utils/constants.ts
5579
- var DEFAULT_CONFIG_PATH = "~/.shelby/config.yaml";
5580
- var DEFAULT_CONFIG = {
5581
- contexts: {
5582
- [Network7.LOCAL]: {
5583
- ...createContextForNetwork(Network7.LOCAL),
5584
- // Override shelby_network for local
5585
- shelby_network: { rpc_endpoint: "http://localhost:9090/" }
5586
- },
5587
- [Network7.SHELBYNET]: createContextForNetwork(Network7.SHELBYNET)
5588
- },
5589
- accounts: {},
5590
- default_context: Network7.SHELBYNET,
5591
- default_account: ""
6090
+ // src/utils/global-config.ts
6091
+ import os from "os";
6092
+ import path from "path";
6093
+ import fs from "fs-extra";
6094
+ import YAML from "yaml";
6095
+ import { z as z6 } from "zod";
6096
+ var GlobalConfigSchema = z6.object({
6097
+ config_location_behavior: z6.enum(["global", "walk"])
6098
+ });
6099
+ var DEFAULT_GLOBAL_CONFIG = {
6100
+ config_location_behavior: "global"
5592
6101
  };
5593
- var STANDARD_CONTEXT_NAMES = Object.keys(DEFAULT_CONFIG.contexts).join(
5594
- ", "
6102
+ var GLOBAL_CONFIG_PATH = path.join(
6103
+ os.homedir(),
6104
+ ".shelby",
6105
+ "global-config.yaml"
5595
6106
  );
5596
- var DEFAULT_DECIMALS = 8;
5597
- var BALANCE_TARGETS = [
5598
- {
5599
- symbol: "APT",
5600
- asset: APTOS_COIN,
5601
- decimals: DEFAULT_DECIMALS
5602
- },
5603
- {
5604
- symbol: SHELBYUSD_TOKEN_NAME,
5605
- asset: SHELBYUSD_FA_METADATA_ADDRESS,
5606
- fallbackDecimals: DEFAULT_DECIMALS
6107
+ function loadGlobalConfig() {
6108
+ if (!fs.existsSync(GLOBAL_CONFIG_PATH)) {
6109
+ return DEFAULT_GLOBAL_CONFIG;
5607
6110
  }
5608
- ];
6111
+ const raw = fs.readFileSync(GLOBAL_CONFIG_PATH, "utf8");
6112
+ let parsed;
6113
+ try {
6114
+ parsed = YAML.parse(raw);
6115
+ } catch {
6116
+ throw new Error("Invalid global config file");
6117
+ }
6118
+ try {
6119
+ return GlobalConfigSchema.parse(parsed);
6120
+ } catch (err) {
6121
+ throw new Error(
6122
+ `Invalid global config file at ${GLOBAL_CONFIG_PATH}: ${err.message}`
6123
+ );
6124
+ }
6125
+ }
6126
+ function saveGlobalConfig(config) {
6127
+ fs.mkdirpSync(path.dirname(GLOBAL_CONFIG_PATH));
6128
+ GlobalConfigSchema.parse(config);
6129
+ fs.writeFileSync(GLOBAL_CONFIG_PATH, YAML.stringify(config), "utf8");
6130
+ }
5609
6131
 
5610
6132
  // src/utils/config.ts
5611
- var ContextSchema = z6.object({
5612
- api_key: z6.string().optional(),
6133
+ var ContextSchema = z7.object({
6134
+ api_key: z7.string().optional(),
5613
6135
  aptos_network: AptosNetworkSchema,
5614
6136
  shelby_network: ShelbyNetworkSchema.optional()
5615
6137
  });
5616
- var AccountNameSchema = z6.string().min(1, "Account name cannot be empty").regex(
6138
+ var AccountNameSchema = z7.string().min(1, "Account name cannot be empty").regex(
5617
6139
  /^[a-zA-Z0-9_-]+$/,
5618
6140
  "Account name must contain only alphanumeric characters, underscores, and hyphens"
5619
6141
  );
5620
- var ConfigSchema = z6.object({
5621
- contexts: z6.record(ContextSchema),
5622
- accounts: z6.record(
6142
+ var ConfigSchema = z7.object({
6143
+ contexts: z7.record(ContextSchema),
6144
+ accounts: z7.record(
5623
6145
  AccountNameSchema,
5624
- z6.object({
5625
- address: z6.string().optional(),
5626
- private_key: z6.string({ message: "private_key must be provided" })
6146
+ z7.object({
6147
+ address: z7.string().optional(),
6148
+ private_key: z7.string({ message: "private_key must be provided" })
5627
6149
  })
5628
6150
  ),
5629
- default_context: z6.string(),
6151
+ default_context: z7.string(),
5630
6152
  // Can be empty string if no account is set up
5631
- default_account: z6.string()
6153
+ default_account: z7.string()
5632
6154
  });
6155
+ function getPathForNewConfig() {
6156
+ const globalConfig = loadGlobalConfig();
6157
+ if (globalConfig.config_location_behavior === "global") {
6158
+ return path2.join(os2.homedir(), ".shelby", "config.yaml");
6159
+ }
6160
+ return path2.join(process.cwd(), ".shelby", "config.yaml");
6161
+ }
6162
+ function loadConfigOrExit(configFile) {
6163
+ let configPath;
6164
+ try {
6165
+ configPath = resolveConfigPath(configFile ?? findExistingConfigPath());
6166
+ if (!fs2.existsSync(configPath)) {
6167
+ console.error("\u274C No configuration file found");
6168
+ console.error(
6169
+ " Please run `shelby init` to create a configuration file."
6170
+ );
6171
+ process.exit(1);
6172
+ }
6173
+ return { configPath, config: loadConfig(configPath) };
6174
+ } catch (err) {
6175
+ console.error("\u274C Failed to load configuration file");
6176
+ if (configPath !== void 0) {
6177
+ console.error(` Path: ${configPath}`);
6178
+ }
6179
+ console.error("");
6180
+ console.error(
6181
+ ` Error: ${err instanceof Error ? err.message : String(err)}`
6182
+ );
6183
+ console.error("");
6184
+ console.error(
6185
+ " Please fix the configuration file or run `shelby init` to recreate it."
6186
+ );
6187
+ process.exit(1);
6188
+ }
6189
+ }
6190
+ function findExistingConfigPath() {
6191
+ const globalConfig = loadGlobalConfig();
6192
+ const homeConfig = path2.join(os2.homedir(), ".shelby", "config.yaml");
6193
+ if (globalConfig.config_location_behavior === "global") {
6194
+ return homeConfig;
6195
+ }
6196
+ const foundPath = walkConfigPath(process.cwd());
6197
+ if (foundPath) {
6198
+ const homeDir = os2.homedir();
6199
+ const displayPath = foundPath.startsWith(homeDir) ? foundPath.replace(homeDir, "~") : path2.relative(process.cwd(), foundPath);
6200
+ console.log(`\u{1F4C1} Using config found by walking up to ${displayPath}`);
6201
+ return foundPath;
6202
+ }
6203
+ console.log(
6204
+ `\u{1F4C1} Could not find config by walking up. Using config file at ${homeConfig.replace(os2.homedir(), "~")}`
6205
+ );
6206
+ return homeConfig;
6207
+ }
6208
+ function walkConfigPath(startDir) {
6209
+ let currentDir = path2.resolve(startDir);
6210
+ while (true) {
6211
+ const candidate = path2.join(currentDir, ".shelby", "config.yaml");
6212
+ if (fs2.existsSync(candidate)) {
6213
+ return candidate;
6214
+ }
6215
+ const parent = path2.dirname(currentDir);
6216
+ if (parent === currentDir) {
6217
+ return null;
6218
+ }
6219
+ currentDir = parent;
6220
+ }
6221
+ }
5633
6222
  function resolveConfigPath(configPath) {
5634
6223
  if (configPath.startsWith("~")) {
5635
- return path.join(os.homedir(), configPath.slice(1));
6224
+ return path2.join(os2.homedir(), configPath.slice(1));
5636
6225
  }
5637
6226
  return configPath;
5638
6227
  }
5639
- function configExists(configPath = DEFAULT_CONFIG_PATH) {
5640
- const resolvedPath = resolveConfigPath(configPath);
5641
- return fs.existsSync(resolvedPath);
5642
- }
5643
- function loadConfig(configPath = DEFAULT_CONFIG_PATH) {
6228
+ function loadConfig(configPath) {
5644
6229
  const resolvedPath = resolveConfigPath(configPath);
5645
- const dir = path.dirname(resolvedPath);
5646
- if (!fs.existsSync(resolvedPath)) {
5647
- fs.mkdirpSync(dir);
5648
- const yamlText = YAML.stringify(DEFAULT_CONFIG);
5649
- fs.writeFileSync(resolvedPath, yamlText, "utf8");
5650
- return DEFAULT_CONFIG;
5651
- }
5652
- const raw = fs.readFileSync(resolvedPath, "utf8");
6230
+ const raw = fs2.readFileSync(resolvedPath, "utf8");
5653
6231
  let parsed;
5654
6232
  try {
5655
- parsed = YAML.parse(raw);
6233
+ parsed = YAML2.parse(raw);
5656
6234
  } catch {
5657
6235
  throw new Error("Invalid config file");
5658
6236
  }
@@ -5662,11 +6240,11 @@ function loadConfig(configPath = DEFAULT_CONFIG_PATH) {
5662
6240
  throw new Error(`Invalid config file: ${err.message}`);
5663
6241
  }
5664
6242
  }
5665
- function saveConfig(config, configPath = "~/.shelby/config.yaml") {
6243
+ function saveConfig(config, configPath) {
5666
6244
  const resolvedPath = resolveConfigPath(configPath);
5667
- fs.mkdirpSync(path.dirname(resolvedPath));
6245
+ fs2.mkdirpSync(path2.dirname(resolvedPath));
5668
6246
  ConfigSchema.parse(config);
5669
- fs.writeFileSync(resolvedPath, YAML.stringify(config), "utf8");
6247
+ fs2.writeFileSync(resolvedPath, YAML2.stringify(config), "utf8");
5670
6248
  }
5671
6249
  function getCurrentContext(config, contextName) {
5672
6250
  const name2 = contextName || config.default_context;
@@ -5683,11 +6261,15 @@ function getCurrentContext(config, contextName) {
5683
6261
  function getCurrentAccount(config, accountName) {
5684
6262
  const name2 = accountName || config.default_account;
5685
6263
  if (!name2) {
5686
- throw new Error(`Account with name '${name2}' not found in config`);
6264
+ throw new Error(
6265
+ `Account with name '${name2}' not found in config. Set --account to a valid account name.`
6266
+ );
5687
6267
  }
5688
6268
  const account = config.accounts[name2];
5689
6269
  if (!account) {
5690
- throw new Error(`Account '${name2}' not found in config`);
6270
+ throw new Error(
6271
+ `Account '${name2}' not found in config. Set --account to a valid account name.`
6272
+ );
5691
6273
  }
5692
6274
  let privateKey;
5693
6275
  if (account.private_key) {
@@ -5737,7 +6319,7 @@ function getCurrentShelbyConfig(config, opts = { context: config.default_context
5737
6319
  const selectedContext = config.contexts[context ?? config.default_context];
5738
6320
  if (!selectedContext) {
5739
6321
  throw new Error(
5740
- `Context '${context ?? config.default_context}' not found in config`
6322
+ `Context '${context ?? config.default_context}' not found in config. Set --context to a valid context name.`
5741
6323
  );
5742
6324
  }
5743
6325
  const shelby = getShelbyConfigFromContext(selectedContext);
@@ -5764,7 +6346,7 @@ import {
5764
6346
  Secp256k1PrivateKey,
5765
6347
  SigningSchemeInput
5766
6348
  } from "@aptos-labs/ts-sdk";
5767
- import { z as z7 } from "zod";
6349
+ import { z as z8 } from "zod";
5768
6350
  function generateEd25519Account() {
5769
6351
  const account = Account.generate({
5770
6352
  scheme: SigningSchemeInput.Ed25519,
@@ -5784,7 +6366,7 @@ function isValidAddress(address) {
5784
6366
  return AccountAddress6.isValid({ input: address }).valid;
5785
6367
  }
5786
6368
  var ED25519_NAME = "ed25519";
5787
- var SignatureSchemeSchema = z7.enum([ED25519_NAME]);
6369
+ var SignatureSchemeSchema = z8.enum([ED25519_NAME]);
5788
6370
 
5789
6371
  // src/components/AccountWizard.tsx
5790
6372
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -5926,11 +6508,11 @@ import { useEffect as useEffect3, useState as useState4 } from "react";
5926
6508
 
5927
6509
  // src/components/ContextReviewWizard.tsx
5928
6510
  import {
5929
- NetworkToFaucetAPI as NetworkToFaucetAPI2,
5930
- NetworkToIndexerAPI as NetworkToIndexerAPI2,
5931
- NetworkToNodeAPI as NetworkToNodeAPI2,
5932
- NetworkToPepperAPI as NetworkToPepperAPI2,
5933
- NetworkToProverAPI as NetworkToProverAPI2
6511
+ NetworkToFaucetAPI,
6512
+ NetworkToIndexerAPI,
6513
+ NetworkToNodeAPI,
6514
+ NetworkToPepperAPI,
6515
+ NetworkToProverAPI
5934
6516
  } from "@aptos-labs/ts-sdk";
5935
6517
  import { Box as Box4, Text as Text4 } from "ink";
5936
6518
  import SelectInput2 from "ink-select-input";
@@ -6012,7 +6594,7 @@ var SHELBY_CONFIG_FIELDS = [
6012
6594
  import { Box as Box3, Text as Text3 } from "ink";
6013
6595
  import TextInput2 from "ink-text-input";
6014
6596
  import { useState as useState2 } from "react";
6015
- import z8 from "zod";
6597
+ import z9 from "zod";
6016
6598
  import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
6017
6599
  function FormTextInput({
6018
6600
  type,
@@ -6042,7 +6624,7 @@ function FormTextInput({
6042
6624
  return;
6043
6625
  }
6044
6626
  if (value2) {
6045
- if (type === "url" && !z8.string().url().safeParse(value2).success) {
6627
+ if (type === "url" && !z9.string().url().safeParse(value2).success) {
6046
6628
  setError("The field must be a valid URL");
6047
6629
  return;
6048
6630
  }
@@ -6103,11 +6685,11 @@ var ContextReviewWizard = ({
6103
6685
  return void 0;
6104
6686
  }
6105
6687
  const fallbackValue = {
6106
- fullnode: NetworkToNodeAPI2[aptosNetwork.name],
6107
- indexer: NetworkToIndexerAPI2[aptosNetwork.name],
6108
- faucet: NetworkToFaucetAPI2[aptosNetwork.name],
6109
- pepper: NetworkToPepperAPI2[aptosNetwork.name],
6110
- prover: NetworkToProverAPI2[aptosNetwork.name]
6688
+ fullnode: NetworkToNodeAPI[aptosNetwork.name],
6689
+ indexer: NetworkToIndexerAPI[aptosNetwork.name],
6690
+ faucet: NetworkToFaucetAPI[aptosNetwork.name],
6691
+ pepper: NetworkToPepperAPI[aptosNetwork.name],
6692
+ prover: NetworkToProverAPI[aptosNetwork.name]
6111
6693
  }[key];
6112
6694
  return fallbackValue ? { value: fallbackValue, source: "default" } : void 0;
6113
6695
  };
@@ -6442,6 +7024,66 @@ import {
6442
7024
  AccountAddress as AccountAddress7,
6443
7025
  AptosApiError
6444
7026
  } from "@aptos-labs/ts-sdk";
7027
+
7028
+ // src/utils/constants.ts
7029
+ import { APTOS_COIN, Network as Network7 } from "@aptos-labs/ts-sdk";
7030
+
7031
+ // src/utils/context-helpers.ts
7032
+ import {
7033
+ NetworkToFaucetAPI as NetworkToFaucetAPI2,
7034
+ NetworkToIndexerAPI as NetworkToIndexerAPI2,
7035
+ NetworkToNodeAPI as NetworkToNodeAPI2,
7036
+ NetworkToPepperAPI as NetworkToPepperAPI2,
7037
+ NetworkToProverAPI as NetworkToProverAPI2
7038
+ } from "@aptos-labs/ts-sdk";
7039
+ function createContextForNetwork(network) {
7040
+ return {
7041
+ aptos_network: {
7042
+ name: network,
7043
+ fullnode: NetworkToNodeAPI2[network],
7044
+ faucet: NetworkToFaucetAPI2[network],
7045
+ indexer: NetworkToIndexerAPI2[network],
7046
+ pepper: NetworkToPepperAPI2[network],
7047
+ prover: NetworkToProverAPI2[network]
7048
+ },
7049
+ shelby_network: {
7050
+ rpc_endpoint: NetworkToShelbyRPCBaseUrl[network]
7051
+ }
7052
+ };
7053
+ }
7054
+
7055
+ // src/utils/constants.ts
7056
+ var DEFAULT_CONFIG = {
7057
+ contexts: {
7058
+ [Network7.LOCAL]: {
7059
+ ...createContextForNetwork(Network7.LOCAL),
7060
+ // Override shelby_network for local
7061
+ shelby_network: { rpc_endpoint: "http://localhost:9090/" }
7062
+ },
7063
+ [Network7.SHELBYNET]: createContextForNetwork(Network7.SHELBYNET)
7064
+ },
7065
+ accounts: {},
7066
+ default_context: Network7.SHELBYNET,
7067
+ default_account: ""
7068
+ };
7069
+ var STANDARD_CONTEXT_NAMES = Object.keys(DEFAULT_CONFIG.contexts).join(
7070
+ ", "
7071
+ );
7072
+ var DEFAULT_DECIMALS = 8;
7073
+ var BALANCE_TARGETS = [
7074
+ {
7075
+ symbol: "APT",
7076
+ asset: APTOS_COIN,
7077
+ decimals: DEFAULT_DECIMALS
7078
+ },
7079
+ {
7080
+ symbol: SHELBYUSD_TOKEN_NAME,
7081
+ asset: SHELBYUSD_FA_METADATA_ADDRESS,
7082
+ fallbackDecimals: DEFAULT_DECIMALS
7083
+ }
7084
+ ];
7085
+
7086
+ // src/utils/balance.ts
6445
7087
  var InvalidAccountAddressError = class extends Error {
6446
7088
  constructor(address) {
6447
7089
  super(
@@ -6599,8 +7241,8 @@ function assetTypeToString(asset) {
6599
7241
  }
6600
7242
 
6601
7243
  // src/utils/cache.ts
6602
- import path2 from "path";
6603
- import fs2 from "fs-extra";
7244
+ import path3 from "path";
7245
+ import fs3 from "fs-extra";
6604
7246
  var Cache = class {
6605
7247
  cachePath;
6606
7248
  schema;
@@ -6614,10 +7256,10 @@ var Cache = class {
6614
7256
  */
6615
7257
  read() {
6616
7258
  try {
6617
- if (!fs2.existsSync(this.cachePath)) {
7259
+ if (!fs3.existsSync(this.cachePath)) {
6618
7260
  return null;
6619
7261
  }
6620
- const data = fs2.readFileSync(this.cachePath, "utf-8");
7262
+ const data = fs3.readFileSync(this.cachePath, "utf-8");
6621
7263
  const parsed = JSON.parse(data);
6622
7264
  const result = this.schema.safeParse(parsed);
6623
7265
  if (!result.success) {
@@ -6635,9 +7277,9 @@ var Cache = class {
6635
7277
  write(data) {
6636
7278
  try {
6637
7279
  const validated = this.schema.parse(data);
6638
- const cacheDir = path2.dirname(this.cachePath);
6639
- fs2.mkdirpSync(cacheDir);
6640
- fs2.writeFileSync(
7280
+ const cacheDir = path3.dirname(this.cachePath);
7281
+ fs3.mkdirpSync(cacheDir);
7282
+ fs3.writeFileSync(
6641
7283
  this.cachePath,
6642
7284
  JSON.stringify(validated, null, 2),
6643
7285
  "utf-8"
@@ -6652,8 +7294,8 @@ var Cache = class {
6652
7294
  */
6653
7295
  clear() {
6654
7296
  try {
6655
- if (fs2.existsSync(this.cachePath)) {
6656
- fs2.unlinkSync(this.cachePath);
7297
+ if (fs3.existsSync(this.cachePath)) {
7298
+ fs3.unlinkSync(this.cachePath);
6657
7299
  }
6658
7300
  return true;
6659
7301
  } catch {
@@ -6664,7 +7306,7 @@ var Cache = class {
6664
7306
  * Check if cache exists
6665
7307
  */
6666
7308
  exists() {
6667
- return fs2.existsSync(this.cachePath);
7309
+ return fs3.existsSync(this.cachePath);
6668
7310
  }
6669
7311
  /**
6670
7312
  * Get the resolved cache file path
@@ -6679,13 +7321,13 @@ import boxen from "boxen";
6679
7321
  import chalk from "chalk";
6680
7322
  import { getLatestVersion } from "fast-npm-meta";
6681
7323
  import * as semver from "semver";
6682
- import { z as z9 } from "zod";
7324
+ import { z as z10 } from "zod";
6683
7325
  var CHECK_INTERVAL = 1e3 * 60 * 60 * 24;
6684
7326
  var NOTIFY_INTERVAL = CHECK_INTERVAL;
6685
- var VersionCacheSchema = z9.object({
6686
- lastChecked: z9.number(),
6687
- latestVersion: z9.string(),
6688
- lastNotified: z9.number().optional()
7327
+ var VersionCacheSchema = z10.object({
7328
+ lastChecked: z10.number(),
7329
+ latestVersion: z10.string(),
7330
+ lastNotified: z10.number().optional()
6689
7331
  });
6690
7332
  var versionCache = new Cache("version-check.json", VersionCacheSchema);
6691
7333
  async function fetchLatestVersion() {
@@ -6760,9 +7402,9 @@ function getErasureCodingProvider() {
6760
7402
  }
6761
7403
 
6762
7404
  // src/utils/paths.ts
6763
- import path3 from "path";
7405
+ import path4 from "path";
6764
7406
  function endsWithDirectorySeparator(filePath) {
6765
- return filePath.endsWith("/") || filePath.endsWith("\\") || filePath.endsWith(path3.sep);
7407
+ return filePath.endsWith("/") || filePath.endsWith("\\") || filePath.endsWith(path4.sep);
6766
7408
  }
6767
7409
  function normBlobName(pathModule, inputDirectoryName, filename, blobPrefix) {
6768
7410
  const blobNameWithoutInputDir = pathModule.relative(
@@ -6775,7 +7417,7 @@ function normBlobName(pathModule, inputDirectoryName, filename, blobPrefix) {
6775
7417
  );
6776
7418
  const blobNameNormalized = pathModule.normalize(blobNameWithPrefix);
6777
7419
  const parts = blobNameNormalized.split(pathModule.sep);
6778
- return path3.posix.join(...parts);
7420
+ return path4.posix.join(...parts);
6779
7421
  }
6780
7422
  function denormBlobName(pathModule, blobPrefix, blobName, outputPrefix) {
6781
7423
  if (!pathModule.isAbsolute(outputPrefix)) {
@@ -7040,8 +7682,8 @@ function getAptosCliVersionInfo(minVersion = MIN_APTOS_CLI_VERSION) {
7040
7682
  // src/components/InitWizard.tsx
7041
7683
  import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
7042
7684
  var InitWizard = ({
7043
- existingConfig,
7044
7685
  configPath,
7686
+ existingConfig,
7045
7687
  onComplete,
7046
7688
  onCancel
7047
7689
  }) => {
@@ -7128,7 +7770,7 @@ var InitWizard = ({
7128
7770
  ] }),
7129
7771
  /* @__PURE__ */ jsxs6(Text6, { color: "cyan", children: [
7130
7772
  " ",
7131
- configPath || DEFAULT_CONFIG_PATH
7773
+ configPath
7132
7774
  ] }),
7133
7775
  /* @__PURE__ */ jsxs6(Text6, { color: "red", children: [
7134
7776
  "\n",
@@ -7515,10 +8157,10 @@ var handleError = (error) => {
7515
8157
 
7516
8158
  // src/commands/account.tsx
7517
8159
  import { jsx as jsx10 } from "react/jsx-runtime";
7518
- var CreateAccountOptionsSchema = z10.object({
7519
- name: z10.string().optional(),
7520
- privateKey: z10.string().optional(),
7521
- address: z10.string().optional(),
8160
+ var CreateAccountOptionsSchema = z11.object({
8161
+ name: z11.string().optional(),
8162
+ privateKey: z11.string().optional(),
8163
+ address: z11.string().optional(),
7522
8164
  scheme: SignatureSchemeSchema.optional()
7523
8165
  });
7524
8166
  var allSchemes = SignatureSchemeSchema.options.join(", ");
@@ -7545,33 +8187,29 @@ async function promptForAccountName(config) {
7545
8187
  return answer;
7546
8188
  }
7547
8189
  }
7548
- var ListAccountOptionsSchema = z10.object({});
7549
- var UseAccountOptionsSchema = z10.object({
7550
- accountName: z10.string()
8190
+ var ListAccountOptionsSchema = z11.object({});
8191
+ var UseAccountOptionsSchema = z11.object({
8192
+ accountName: z11.string()
7551
8193
  });
7552
- var DeleteAccountOptionsSchema = z10.object({
7553
- accountName: z10.string()
8194
+ var DeleteAccountOptionsSchema = z11.object({
8195
+ accountName: z11.string()
7554
8196
  });
7555
8197
  function accountCommand(program) {
7556
8198
  const account = program.command("account").description("Manage signing accounts (addresses & keys)");
7557
- account.command("create").description("Create a new account").option("--name <account-name>", "Name of the account").option(
7558
- `--scheme <signature-scheme: "${SignatureSchemeSchema.Enum.ed25519}">`,
7559
- "Signature scheme of the private key"
8199
+ account.command("create").description("Create a new account").option("--name <account-name>", "Name of the account").addOption(
8200
+ new Option(
8201
+ "--scheme <signature-scheme>",
8202
+ "Signature scheme of the private key"
8203
+ ).choices(Object.values(SignatureSchemeSchema.Enum))
7560
8204
  ).option("--private-key <key>", "Raw private key").option(
7561
8205
  "--address <account-address>",
7562
8206
  "Aptos account address (hex-encoded)"
7563
8207
  ).action(async (options) => {
7564
8208
  CreateAccountOptionsSchema.parse(options);
7565
8209
  const { name: name2, privateKey, address, scheme } = options;
7566
- const configPath = program.opts().configFile;
7567
- let config;
7568
- try {
7569
- config = loadConfig(configPath);
7570
- } catch (err) {
7571
- throw new Error(
7572
- `${err.message}. Please ensure you've first initialized the config by doing \`shelby init\``
7573
- );
7574
- }
8210
+ const { config, configPath } = loadConfigOrExit(
8211
+ program.opts().configFile
8212
+ );
7575
8213
  const targetName = options.name ?? null;
7576
8214
  if (privateKey && !scheme) {
7577
8215
  console.error(
@@ -7579,7 +8217,9 @@ function accountCommand(program) {
7579
8217
  );
7580
8218
  process.exit(1);
7581
8219
  }
7582
- if (scheme && !SignatureSchemeSchema.options.includes(scheme)) {
8220
+ if (scheme && !Object.values(SignatureSchemeSchema.Enum).includes(
8221
+ scheme
8222
+ )) {
7583
8223
  console.error(
7584
8224
  `\u274C Unsupported signature scheme. Only "${allSchemes}" is supported.`
7585
8225
  );
@@ -7647,14 +8287,7 @@ function accountCommand(program) {
7647
8287
  }
7648
8288
  });
7649
8289
  account.command("list").description("List all accounts in a table view").action(() => {
7650
- const configPath = program.opts().configFile;
7651
- let config;
7652
- try {
7653
- config = loadConfig(configPath);
7654
- } catch (err) {
7655
- console.error(`Error listing accounts: ${err.message}`);
7656
- process.exit(1);
7657
- }
8290
+ const { config } = loadConfigOrExit(program.opts().configFile);
7658
8291
  const accounts = Object.entries(config.accounts);
7659
8292
  if (accounts.length === 0) {
7660
8293
  console.log("No accounts found.");
@@ -7680,9 +8313,10 @@ function accountCommand(program) {
7680
8313
  console.log(table.toString());
7681
8314
  });
7682
8315
  account.command("use").description("Set the default account").argument("<account-name>", "Name of the account to use").action((accountName) => {
7683
- const configPath = program.opts().configFile;
7684
8316
  try {
7685
- const config = loadConfig(configPath);
8317
+ const { config, configPath } = loadConfigOrExit(
8318
+ program.opts().configFile
8319
+ );
7686
8320
  if (!config.accounts[accountName]) {
7687
8321
  console.error(`Error: Account '${accountName}' not found`);
7688
8322
  process.exit(1);
@@ -7696,9 +8330,10 @@ function accountCommand(program) {
7696
8330
  }
7697
8331
  });
7698
8332
  account.command("delete").description("Delete an account").argument("<account-name>", "Name of the account to delete").action((accountName) => {
7699
- const configPath = program.opts().configFile;
7700
8333
  try {
7701
- const config = loadConfig(configPath);
8334
+ const { config, configPath } = loadConfigOrExit(
8335
+ program.opts().configFile
8336
+ );
7702
8337
  if (!config.accounts[accountName]) {
7703
8338
  console.error(`Error: Account '${accountName}' not found`);
7704
8339
  process.exit(1);
@@ -7724,8 +8359,7 @@ function accountCommand(program) {
7724
8359
  "-a, --account <account-name>",
7725
8360
  "Name of the account to list blobs for"
7726
8361
  ).action(async () => {
7727
- const configPath = program.opts().configFile;
7728
- const config = loadConfig(configPath);
8362
+ const { config } = loadConfigOrExit(program.opts().configFile);
7729
8363
  try {
7730
8364
  const accountName = program.opts().account || config.default_account;
7731
8365
  const shelbyConfig = getCurrentShelbyConfig(config, {
@@ -7804,8 +8438,7 @@ function accountCommand(program) {
7804
8438
  try {
7805
8439
  const globalOpts = program.opts();
7806
8440
  verbose = Boolean(globalOpts.verbose);
7807
- const configPath = globalOpts.configFile;
7808
- const config = loadConfig(configPath);
8441
+ const { config } = loadConfigOrExit(globalOpts.configFile);
7809
8442
  const contextName = globalOpts.context || config.default_context;
7810
8443
  const context = getCurrentContext(config, contextName);
7811
8444
  const aptos = getAptosFromContext(context);
@@ -7915,21 +8548,21 @@ function accountCommand(program) {
7915
8548
  }
7916
8549
 
7917
8550
  // src/commands/commitment.ts
7918
- import * as fs3 from "fs";
8551
+ import * as fs4 from "fs";
7919
8552
  import * as fsP from "fs/promises";
7920
8553
  import { Readable } from "stream";
7921
- import { z as z11 } from "zod";
7922
- var CommitmentOptionsSchema = z11.object({
7923
- input: z11.string().nonempty("`--input` is required").refine(
7924
- async (path7) => {
7925
- const stat4 = await fsP.stat(path7);
8554
+ import { z as z12 } from "zod";
8555
+ var CommitmentOptionsSchema = z12.object({
8556
+ input: z12.string().nonempty("`--input` is required").refine(
8557
+ async (path10) => {
8558
+ const stat4 = await fsP.stat(path10);
7926
8559
  return stat4.isFile();
7927
8560
  },
7928
8561
  {
7929
8562
  message: "`--input` must be a file"
7930
8563
  }
7931
8564
  ),
7932
- output: z11.string().nonempty("`--output` is required")
8565
+ output: z12.string().nonempty("`--output` is required")
7933
8566
  });
7934
8567
  function commitmentCommand(program) {
7935
8568
  program.command("commitment <input> <output>").description(
@@ -7939,7 +8572,7 @@ function commitmentCommand(program) {
7939
8572
  input,
7940
8573
  output
7941
8574
  });
7942
- const inputFile = fs3.createReadStream(validatedOptions.input);
8575
+ const inputFile = fs4.createReadStream(validatedOptions.input);
7943
8576
  const provider = await getErasureCodingProvider();
7944
8577
  const commitment = await generateCommitments(
7945
8578
  provider,
@@ -7949,31 +8582,110 @@ function commitmentCommand(program) {
7949
8582
  });
7950
8583
  }
7951
8584
 
8585
+ // src/commands/config.tsx
8586
+ import fs5 from "fs-extra";
8587
+ import YAML3 from "yaml";
8588
+ function configCommand(program) {
8589
+ const config = program.command("config").description("Manage CLI configuration");
8590
+ config.command("set-global-config").description(
8591
+ "Set global configuration, such as where to load the .shelby/config.yaml file from"
8592
+ ).requiredOption(
8593
+ "--config-location-behavior <behavior>",
8594
+ "Config location. If set to 'global', the CLI will load the config from ~/.shelby/config.yaml. If set to 'walk', the CLI will try to load the config from .shelby/config.yaml, then its parents, and finally the global ~/.shelby/config.yaml"
8595
+ ).action((options) => {
8596
+ const behavior = options.configLocationBehavior;
8597
+ if (behavior !== "global" && behavior !== "walk") {
8598
+ console.error(
8599
+ "\u274C Error: --config-location-behavior must be either 'global' or 'walk'"
8600
+ );
8601
+ process.exit(1);
8602
+ }
8603
+ const globalConfig = {
8604
+ config_location_behavior: behavior
8605
+ };
8606
+ try {
8607
+ saveGlobalConfig(globalConfig);
8608
+ console.log(
8609
+ `\u2705 Global config updated: config_location_behavior = '${behavior}'`
8610
+ );
8611
+ console.log(
8612
+ behavior === "global" ? " The CLI will now load the config from ~/.shelby/config.yaml" : " The CLI will now try to load the config from .shelby/config.yaml, its parents, and finally the global .shelby/config.yaml"
8613
+ );
8614
+ } catch (err) {
8615
+ console.error(
8616
+ `\u274C Error saving global config: ${err instanceof Error ? err.message : String(err)}`
8617
+ );
8618
+ process.exit(1);
8619
+ }
8620
+ });
8621
+ config.command("describe-global-config").description("Describe the current global configuration").action(() => {
8622
+ try {
8623
+ const globalConfig = loadGlobalConfig();
8624
+ console.log("Global config:");
8625
+ console.log(
8626
+ ` config_location_behavior: ${globalConfig.config_location_behavior}`
8627
+ );
8628
+ console.log(
8629
+ globalConfig.config_location_behavior === "global" ? " Loading config from: ~/.shelby/config.yaml" : " Loading config from: .shelby/config.yaml, its parents, and finally the global .shelby/config.yaml"
8630
+ );
8631
+ } catch (err) {
8632
+ console.error(
8633
+ `\u274C Error loading global config: ${err instanceof Error ? err.message : String(err)}`
8634
+ );
8635
+ process.exit(1);
8636
+ }
8637
+ });
8638
+ config.command("get-global-config").description("Display the global config file content as YAML").action(() => {
8639
+ try {
8640
+ if (!fs5.existsSync(GLOBAL_CONFIG_PATH)) {
8641
+ console.log("No global config file found.");
8642
+ console.log(`Expected location: ${GLOBAL_CONFIG_PATH}`);
8643
+ return;
8644
+ }
8645
+ const content = fs5.readFileSync(GLOBAL_CONFIG_PATH, "utf8");
8646
+ const parsed = YAML3.parse(content);
8647
+ const prettyYaml = YAML3.stringify(parsed, {
8648
+ indent: 2,
8649
+ lineWidth: 0
8650
+ });
8651
+ console.log(`Global config file: ${GLOBAL_CONFIG_PATH}`);
8652
+ console.log("");
8653
+ console.log(prettyYaml.trim());
8654
+ } catch (err) {
8655
+ console.error(
8656
+ `\u274C Error reading global config file: ${err instanceof Error ? err.message : String(err)}`
8657
+ );
8658
+ console.error(` Path: ${GLOBAL_CONFIG_PATH}`);
8659
+ process.exit(1);
8660
+ }
8661
+ });
8662
+ }
8663
+
7952
8664
  // src/commands/context.tsx
7953
8665
  import { render as render2 } from "ink";
7954
- import { z as z13 } from "zod";
8666
+ import { z as z14 } from "zod";
7955
8667
 
7956
8668
  // src/utils/commands.ts
7957
- import z12 from "zod";
7958
- var AptosCommandOptionsSchema = z12.object({
7959
- aptosNetwork: z12.string().optional(),
8669
+ import z13 from "zod";
8670
+ var AptosCommandOptionsSchema = z13.object({
8671
+ aptosNetwork: z13.string().optional(),
7960
8672
  // predefined network name
7961
- aptosFullnode: z12.string().url().optional(),
7962
- aptosFaucet: z12.string().url().optional(),
7963
- aptosIndexer: z12.string().url().optional(),
7964
- aptosPepper: z12.string().url().optional(),
7965
- aptosProver: z12.string().url().optional(),
7966
- aptosApiKey: z12.string().optional()
8673
+ aptosFullnode: z13.string().url().optional(),
8674
+ aptosFaucet: z13.string().url().optional(),
8675
+ aptosIndexer: z13.string().url().optional(),
8676
+ aptosPepper: z13.string().url().optional(),
8677
+ aptosProver: z13.string().url().optional(),
8678
+ aptosApiKey: z13.string().optional()
7967
8679
  });
7968
8680
  var addAptosCommandOptions = (context) => context.option(
7969
8681
  "--aptos-network <network>",
7970
8682
  `Aptos network (${shelbyNetworks.join(", ")})`
7971
8683
  ).option("--aptos-fullnode <url>", "Aptos fullnode URL").option("--aptos-faucet <url>", "Aptos faucet URL").option("--aptos-indexer <url>", "Aptos indexer URL").option("--aptos-pepper <url>", "Aptos pepper URL").option("--aptos-prover <url>", "Aptos prover URL").option("--aptos-api-key <key>", "Aptos API key");
7972
- var ShelbyCommandOptionsSchema = z12.object({
8684
+ var ShelbyCommandOptionsSchema = z13.object({
7973
8685
  shelbyRpcEndpoint: EndpointSchema.optional(),
7974
8686
  shelbyIndexerEndpoint: EndpointSchema.optional(),
7975
- shelbyRpcApiKey: z12.string().optional(),
7976
- shelbyIndexerApiKey: z12.string().optional()
8687
+ shelbyRpcApiKey: z13.string().optional(),
8688
+ shelbyIndexerApiKey: z13.string().optional()
7977
8689
  });
7978
8690
  var addShelbyCommandOptions = (context) => context.option("--shelby-rpc-endpoint <url>", "Shelby RPC endpoint").option("--shelby-indexer-endpoint <url>", "Shelby indexer endpoint").option("--shelby-rpc-api-key <key>", "Shelby RPC API key").option("--shelby-indexer-api-key <key>", "Shelby indexer API key");
7979
8691
 
@@ -8010,8 +8722,8 @@ function getShelbyNetworkFromOptions(options) {
8010
8722
  indexer_api_key: options.shelbyIndexerApiKey
8011
8723
  };
8012
8724
  }
8013
- var CreateContextOptionsSchema = z13.object({ name: z13.string().optional() }).merge(AptosCommandOptionsSchema).merge(ShelbyCommandOptionsSchema);
8014
- var UpdateContextOptionsSchema = z13.object({}).merge(ShelbyCommandOptionsSchema).merge(AptosCommandOptionsSchema);
8725
+ var CreateContextOptionsSchema = z14.object({ name: z14.string().optional() }).merge(AptosCommandOptionsSchema).merge(ShelbyCommandOptionsSchema);
8726
+ var UpdateContextOptionsSchema = z14.object({}).merge(ShelbyCommandOptionsSchema).merge(AptosCommandOptionsSchema);
8015
8727
  function contextCommand(program) {
8016
8728
  const context = program.command("context").description("Manage network contexts (Shelby RPC & Aptos endpoints)");
8017
8729
  addShelbyCommandOptions(addAptosCommandOptions(context.command("create"))).description("Create a new context").option("--name <context-name>", "Name of the context").action((options) => {
@@ -8019,7 +8731,9 @@ function contextCommand(program) {
8019
8731
  const { name: name2 } = options;
8020
8732
  const aptosNetwork = getAptosNetworkFromOptions(options);
8021
8733
  const shelbyNetwork = getShelbyNetworkFromOptions(options);
8022
- const configPath = program.opts().configFile;
8734
+ const configPath = resolveConfigPath(
8735
+ program.opts().configFile ?? findExistingConfigPath()
8736
+ );
8023
8737
  let config;
8024
8738
  try {
8025
8739
  config = loadConfig(configPath);
@@ -8027,8 +8741,8 @@ function contextCommand(program) {
8027
8741
  config = {
8028
8742
  contexts: {},
8029
8743
  accounts: {},
8030
- default_context: name2 || "",
8031
- default_account: "default_account"
8744
+ default_context: name2 || DEFAULT_CONTEXT,
8745
+ default_account: DEFAULT_ACCOUNT
8032
8746
  };
8033
8747
  }
8034
8748
  const hasShelbyNetworkChanges = Object.values(shelbyNetwork).some(
@@ -8083,14 +8797,9 @@ function contextCommand(program) {
8083
8797
  UpdateContextOptionsSchema.parse(options);
8084
8798
  const aptosNetwork = getAptosNetworkFromOptions(options);
8085
8799
  const shelbyNetwork = getShelbyNetworkFromOptions(options);
8086
- const configPath = program.opts().configFile;
8087
- let config;
8088
- try {
8089
- config = loadConfig(configPath);
8090
- } catch (error) {
8091
- console.error(`Error loading config: ${error.message}`);
8092
- process.exit(1);
8093
- }
8800
+ const { config, configPath } = loadConfigOrExit(
8801
+ program.opts().configFile
8802
+ );
8094
8803
  const currentContext = config.contexts[contextName];
8095
8804
  if (!currentContext) {
8096
8805
  console.error(`Error: Context '${contextName}' not found`);
@@ -8153,14 +8862,7 @@ function contextCommand(program) {
8153
8862
  );
8154
8863
  });
8155
8864
  context.command("list").description("List all contexts in a table").action(() => {
8156
- const configPath = program.opts().configFile;
8157
- let config;
8158
- try {
8159
- config = loadConfig(configPath);
8160
- } catch (err) {
8161
- console.error(`Error listing contexts: ${err.message}`);
8162
- process.exit(1);
8163
- }
8865
+ const { config } = loadConfigOrExit(program.opts().configFile);
8164
8866
  if (Object.keys(config.contexts).length === 0) {
8165
8867
  console.log("No contexts found.");
8166
8868
  process.exit(0);
@@ -8237,9 +8939,10 @@ function contextCommand(program) {
8237
8939
  console.log(shelbyConfigTable.toString());
8238
8940
  });
8239
8941
  context.command("use").description("Set the default context").argument("<context-name>", "Name of the context to use").action((contextName) => {
8240
- const configPath = program.opts().configFile;
8942
+ const { config, configPath } = loadConfigOrExit(
8943
+ program.opts().configFile
8944
+ );
8241
8945
  try {
8242
- const config = loadConfig(configPath);
8243
8946
  if (!config.contexts[contextName]) {
8244
8947
  console.error(`Error: Context '${contextName}' not found`);
8245
8948
  process.exit(1);
@@ -8253,9 +8956,10 @@ function contextCommand(program) {
8253
8956
  }
8254
8957
  });
8255
8958
  context.command("delete").description("Delete a context").argument("<context-name>", "Name of the context to delete").action((contextName) => {
8256
- const configPath = program.opts().configFile;
8959
+ const { config, configPath } = loadConfigOrExit(
8960
+ program.opts().configFile
8961
+ );
8257
8962
  try {
8258
- const config = loadConfig(configPath);
8259
8963
  if (!config.contexts[contextName]) {
8260
8964
  console.error(`Error: Context '${contextName}' not found`);
8261
8965
  process.exit(1);
@@ -8281,22 +8985,22 @@ function contextCommand(program) {
8281
8985
 
8282
8986
  // src/commands/download.tsx
8283
8987
  import * as fsS from "fs";
8284
- import * as fs4 from "fs/promises";
8285
- import * as path4 from "path";
8988
+ import * as fs6 from "fs/promises";
8989
+ import * as path5 from "path";
8286
8990
  import { Readable as Readable2, Transform } from "stream";
8287
8991
  import { pipeline } from "stream/promises";
8288
8992
  import ora from "ora";
8289
- import { z as z14 } from "zod";
8290
- var denormBlobName2 = (a, b, c) => denormBlobName(path4, a, b, c);
8291
- var DownloadOptionsSchema = z14.object({
8292
- source: z14.string({
8993
+ import { z as z15 } from "zod";
8994
+ var denormBlobName2 = (a, b, c) => denormBlobName(path5, a, b, c);
8995
+ var DownloadOptionsSchema = z15.object({
8996
+ source: z15.string({
8293
8997
  required_error: "\n\u274C Missing Required Argument\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\u26A0\uFE0F Missing source blob name or prefix (first argument)\n\n\u{1F4A1} Usage:\n shelby download <source-blob-name> <destination-path> [options]\n\n\u{1F4DD} Examples:\n shelby download my-blob.txt ./myfile.txt\n shelby download my-folder/ ./my-folder/ -r\n"
8294
8998
  }).min(1, "Source blob name or directory prefix is required").describe("Blob name or directory prefix to download"),
8295
- destination: z14.string({
8999
+ destination: z15.string({
8296
9000
  required_error: "\n\u274C Missing Required Argument\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\u26A0\uFE0F Missing destination path (second argument)\n\n\u{1F4A1} Usage:\n shelby download <source-blob-name> <destination-path> [options]\n\n\u{1F4DD} Example:\n shelby download my-blob.txt ./myfile.txt\n"
8297
9001
  }).min(1, "`destination` must be a valid filepath").describe("Local path where to save the downloaded content"),
8298
- recursive: z14.boolean().default(false).describe("Download assuming canonical directory layout and recurse"),
8299
- force: z14.boolean().default(false).describe("Overwrite the destination if it already exists")
9002
+ recursive: z15.boolean().default(false).describe("Download assuming canonical directory layout and recurse"),
9003
+ force: z15.boolean().default(false).describe("Overwrite the destination if it already exists")
8300
9004
  }).refine(
8301
9005
  (data) => {
8302
9006
  if (data.recursive) {
@@ -8369,9 +9073,9 @@ var DownloadOptionsSchema = z14.object({
8369
9073
  }
8370
9074
  );
8371
9075
  async function validateOutput(options) {
8372
- const parentDir = path4.dirname(options.destination);
9076
+ const parentDir = path5.dirname(options.destination);
8373
9077
  try {
8374
- const parentStats = await fs4.stat(parentDir);
9078
+ const parentStats = await fs6.stat(parentDir);
8375
9079
  if (!parentStats.isDirectory()) {
8376
9080
  throw new Error(
8377
9081
  `Parent path '${parentDir}' exists but is not a directory. Cannot create destination ${options.recursive ? "directory" : "file"} '${options.destination}'.`
@@ -8388,7 +9092,7 @@ async function validateOutput(options) {
8388
9092
  if (options.force) return;
8389
9093
  let outputStats;
8390
9094
  try {
8391
- outputStats = await fs4.stat(options.destination);
9095
+ outputStats = await fs6.stat(options.destination);
8392
9096
  } catch (error) {
8393
9097
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
8394
9098
  return;
@@ -8407,7 +9111,7 @@ async function validateOutput(options) {
8407
9111
  );
8408
9112
  }
8409
9113
  if (options.recursive) {
8410
- const entries = await fs4.readdir(options.destination);
9114
+ const entries = await fs6.readdir(options.destination);
8411
9115
  if (entries.length > 0) {
8412
9116
  throw new Error(
8413
9117
  `Directory '${options.destination}' exists and is not empty. Use --force to overwrite or choose an empty directory.`
@@ -8474,12 +9178,12 @@ async function createFileList(options, nodeClient, account) {
8474
9178
  async function createOutputDirectories(fileList) {
8475
9179
  const uniqueDirectories = /* @__PURE__ */ new Set();
8476
9180
  for (const fileEntry of fileList) {
8477
- const parentDir = path4.dirname(fileEntry.filename);
9181
+ const parentDir = path5.dirname(fileEntry.filename);
8478
9182
  uniqueDirectories.add(parentDir);
8479
9183
  }
8480
9184
  for (const dir of uniqueDirectories) {
8481
9185
  try {
8482
- await fs4.mkdir(dir, { recursive: true });
9186
+ await fs6.mkdir(dir, { recursive: true });
8483
9187
  } catch (error) {
8484
9188
  throw new Error(
8485
9189
  `Failed to create directory '${dir}': ${error instanceof Error ? error.message : error}`
@@ -8505,8 +9209,9 @@ function createProgressTransform(totalBytes, reporter) {
8505
9209
  function downloadCommand(program) {
8506
9210
  program.command("download").description("Download a file or directory from Shelby RPC").argument("[source]", "Source blob name or prefix").argument("[destination]", "Destination path").option(
8507
9211
  "-r, --recursive",
8508
- "Download assuming canonical directory layout using '/' as separators. Produces a directory."
8509
- ).option("-f, --force", "Overwrite the destination").action(
9212
+ "Download assuming canonical directory layout using '/' as separators. Produces a directory.",
9213
+ false
9214
+ ).option("-f, --force", "Overwrite the destination", false).action(
8510
9215
  async (source, destination, rawOptions) => {
8511
9216
  let options;
8512
9217
  try {
@@ -8516,7 +9221,7 @@ function downloadCommand(program) {
8516
9221
  destination
8517
9222
  });
8518
9223
  } catch (error) {
8519
- if (error instanceof z14.ZodError) {
9224
+ if (error instanceof z15.ZodError) {
8520
9225
  const firstIssue = error.issues[0];
8521
9226
  if (firstIssue) {
8522
9227
  console.log(firstIssue.message);
@@ -8530,7 +9235,7 @@ function downloadCommand(program) {
8530
9235
  }
8531
9236
  process.exit(1);
8532
9237
  }
8533
- options.destination = path4.resolve(options.destination);
9238
+ options.destination = path5.resolve(options.destination);
8534
9239
  let config;
8535
9240
  let spinner;
8536
9241
  const handleSigint = () => {
@@ -8538,8 +9243,7 @@ function downloadCommand(program) {
8538
9243
  process.exit(1);
8539
9244
  };
8540
9245
  try {
8541
- const configPath = program.opts().configFile;
8542
- config = loadConfig(configPath);
9246
+ ({ config } = loadConfigOrExit(program.opts().configFile));
8543
9247
  const shelbyConfig = getCurrentShelbyConfig(config, {
8544
9248
  context: program.opts().context
8545
9249
  });
@@ -8559,13 +9263,13 @@ function downloadCommand(program) {
8559
9263
  console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
8560
9264
  for (let i = 0; i < fileList.length; i++) {
8561
9265
  const fileEntry = fileList[i];
8562
- const blobBaseName = path4.basename(fileEntry.blobname);
9266
+ const blobBaseName = path5.basename(fileEntry.blobname);
8563
9267
  console.log(`${i + 1}. ${blobBaseName} \u2192 ${fileEntry.filename}`);
8564
9268
  }
8565
9269
  console.log();
8566
9270
  if (options.force) {
8567
9271
  console.log(`--force was set, so deleting ${options.destination}`);
8568
- await fs4.rm(options.destination, { recursive: true, force: true });
9272
+ await fs6.rm(options.destination, { recursive: true, force: true });
8569
9273
  }
8570
9274
  process.removeAllListeners("SIGINT");
8571
9275
  process.on("SIGINT", handleSigint);
@@ -8583,7 +9287,7 @@ function downloadCommand(program) {
8583
9287
  const formatProgressPercent = () => totalSize > 0 ? (100 * (amountDownloaded / totalSize)).toFixed(2) : "0.00";
8584
9288
  for (const fileEntry of fileList) {
8585
9289
  const out = fsS.createWriteStream(fileEntry.filename);
8586
- const fileName = path4.basename(fileEntry.blobname);
9290
+ const fileName = path5.basename(fileEntry.blobname);
8587
9291
  const { readable } = await nodeClient.rpc.getBlob({
8588
9292
  account: activeAccount.accountAddress,
8589
9293
  blobName: fileEntry.blobname
@@ -8673,18 +9377,28 @@ function downloadCommand(program) {
8673
9377
 
8674
9378
  // src/commands/faucet.tsx
8675
9379
  import { Network as Network9 } from "@aptos-labs/ts-sdk";
9380
+ import { Option as Option2 } from "@commander-js/extra-typings";
8676
9381
  import { execaSync } from "execa";
8677
- import { z as z15 } from "zod";
8678
- var FaucetOptionsSchema = z15.object({
8679
- network: z15.enum([Network9.SHELBYNET]).optional(),
8680
- open: z15.boolean().optional().default(true)
9382
+ import { z as z16 } from "zod";
9383
+ var FaucetOptionsSchema = z16.object({
9384
+ network: z16.enum([Network9.SHELBYNET]).optional(),
9385
+ open: z16.boolean().optional().default(true)
8681
9386
  });
8682
9387
  function faucetCommand(program) {
8683
- program.command("faucet").description("Open the Shelby faucet web page to request tokens").option("--network <network>", "Network to request tokens for (shelbynet)").option("--no-open", "Don't automatically open browser, just print the URL").action((options) => {
9388
+ program.command("faucet").description("Open the Shelby faucet web page to request tokens").addOption(
9389
+ new Option2(
9390
+ "--network <network>",
9391
+ "Network to request tokens for (shelbynet)"
9392
+ ).choices(Object.values(Network9))
9393
+ ).addOption(
9394
+ new Option2(
9395
+ "--no-open",
9396
+ "Don't automatically open browser, just print the URL"
9397
+ )
9398
+ ).action((options) => {
8684
9399
  try {
8685
9400
  const validatedOptions = FaucetOptionsSchema.parse(options);
8686
- const configPath = program.opts().configFile;
8687
- const config = loadConfig(configPath);
9401
+ const { config } = loadConfigOrExit(program.opts().configFile);
8688
9402
  const accountName = program.opts().account || config.default_account;
8689
9403
  const { account } = getCurrentAccount(config, accountName);
8690
9404
  const network = validatedOptions.network || Network9.SHELBYNET;
@@ -8748,9 +9462,9 @@ function openBrowser(url) {
8748
9462
  }
8749
9463
 
8750
9464
  // src/commands/init.tsx
8751
- import path5 from "path";
9465
+ import path6 from "path";
8752
9466
  import { Network as Network10 } from "@aptos-labs/ts-sdk";
8753
- import fs5 from "fs-extra";
9467
+ import fs7 from "fs-extra";
8754
9468
  import { render as render3 } from "ink";
8755
9469
  import { jsx as jsx12 } from "react/jsx-runtime";
8756
9470
  function initCommand(program) {
@@ -8771,10 +9485,10 @@ function initCommand(program) {
8771
9485
  );
8772
9486
  process.exit(1);
8773
9487
  }
8774
- const configPath = program.opts().configFile || "~/.shelby/config.yaml";
9488
+ const configPath = getPathForNewConfig();
8775
9489
  const resolvedPath = resolveConfigPath(configPath);
8776
9490
  const accountName = program.opts().account;
8777
- const hasExistingConfig = configExists(configPath);
9491
+ const hasExistingConfig = fs7.existsSync(resolvedPath);
8778
9492
  let existingConfigValid = false;
8779
9493
  if (hasExistingConfig) {
8780
9494
  try {
@@ -8791,7 +9505,7 @@ function initCommand(program) {
8791
9505
  }
8792
9506
  }
8793
9507
  if (options.setupDefault) {
8794
- if (configExists(configPath)) {
9508
+ if (fs7.existsSync(resolvedPath)) {
8795
9509
  console.error(
8796
9510
  `\u274C Refusing to overwrite existing config at ${resolvedPath}. Remove it first or run 'shelby init' interactively.`
8797
9511
  );
@@ -8879,12 +9593,12 @@ function cloneContexts(contexts) {
8879
9593
  return JSON.parse(JSON.stringify(contexts));
8880
9594
  }
8881
9595
  function ensureConfigDir(resolvedPath) {
8882
- fs5.mkdirpSync(path5.dirname(resolvedPath));
9596
+ fs7.mkdirpSync(path6.dirname(resolvedPath));
8883
9597
  }
8884
9598
 
8885
9599
  // src/commands/upload.tsx
8886
- import * as fs6 from "fs/promises";
8887
- import * as path6 from "path";
9600
+ import * as fs8 from "fs/promises";
9601
+ import * as path7 from "path";
8888
9602
  import { Aptos as Aptos5, AptosConfig as AptosConfig4 } from "@aptos-labs/ts-sdk";
8889
9603
  import * as chrono from "chrono-node";
8890
9604
  import { glob } from "glob";
@@ -8892,7 +9606,7 @@ import ignore from "ignore";
8892
9606
  import { Box as Box7, render as render4, Text as Text7 } from "ink";
8893
9607
  import SelectInput4 from "ink-select-input";
8894
9608
  import ora2 from "ora";
8895
- import { z as z16 } from "zod";
9609
+ import { z as z17 } from "zod";
8896
9610
 
8897
9611
  // src/utils/commander-helpers.ts
8898
9612
  function createExitOverrideHandler(commandName, requiredArgs, requiredOptions, exampleUsage, warningMessage) {
@@ -8943,8 +9657,8 @@ function createExitOverrideHandler(commandName, requiredArgs, requiredOptions, e
8943
9657
 
8944
9658
  // src/commands/upload.tsx
8945
9659
  import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
8946
- var normBlobName2 = (i, f, b) => normBlobName(path6, i, f, b);
8947
- var flexibleDateSchema = z16.string().transform((val, ctx) => {
9660
+ var normBlobName2 = (i, f, b) => normBlobName(path7, i, f, b);
9661
+ var flexibleDateSchema = z17.string().transform((val, ctx) => {
8948
9662
  const now = /* @__PURE__ */ new Date();
8949
9663
  let parsedDate = null;
8950
9664
  if (/^\d+$/.test(val)) {
@@ -8967,7 +9681,7 @@ var flexibleDateSchema = z16.string().transform((val, ctx) => {
8967
9681
  }
8968
9682
  if (!parsedDate || Number.isNaN(parsedDate.getTime())) {
8969
9683
  ctx.addIssue({
8970
- code: z16.ZodIssueCode.custom,
9684
+ code: z17.ZodIssueCode.custom,
8971
9685
  message: `
8972
9686
  \u274C Upload Failed
8973
9687
  \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
@@ -8981,11 +9695,11 @@ var flexibleDateSchema = z16.string().transform((val, ctx) => {
8981
9695
 
8982
9696
  \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`
8983
9697
  });
8984
- return z16.NEVER;
9698
+ return z17.NEVER;
8985
9699
  }
8986
9700
  if (parsedDate.getTime() <= now.getTime()) {
8987
9701
  ctx.addIssue({
8988
- code: z16.ZodIssueCode.custom,
9702
+ code: z17.ZodIssueCode.custom,
8989
9703
  message: `
8990
9704
  \u274C Upload Failed
8991
9705
  \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
@@ -8997,26 +9711,26 @@ var flexibleDateSchema = z16.string().transform((val, ctx) => {
8997
9711
 
8998
9712
  \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`
8999
9713
  });
9000
- return z16.NEVER;
9714
+ return z17.NEVER;
9001
9715
  }
9002
9716
  return parsedDate;
9003
9717
  });
9004
- var UploadOptionsSchema = z16.object({
9005
- source: z16.string({
9718
+ var UploadOptionsSchema = z17.object({
9719
+ source: z17.string({
9006
9720
  required_error: '\n\u274C Missing Required Argument\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\u26A0\uFE0F Missing source file or directory path (first argument)\n\n\u{1F4A1} Usage:\n shelby upload <source-file-or-directory> <destination-blob-name> [options]\n\n\u{1F4DD} Examples:\n shelby upload ./myfile.txt my-blob.txt -e tomorrow\n shelby upload ./my-folder/ my-folder/ -r -e "next week"\n\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
9007
9721
  }).min(1, "Source file or directory path is required"),
9008
- destination: z16.string({
9722
+ destination: z17.string({
9009
9723
  required_error: "\n\u274C Missing Required Argument\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\u26A0\uFE0F Missing destination blob name (second argument)\n\n\u{1F4A1} Usage:\n shelby upload <source-file-or-directory> <destination-blob-name> [options]\n\n\u{1F4DD} Example:\n shelby upload ./myfile.txt files/my-blob.txt -e tomorrow\n\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
9010
9724
  }).min(1, "Destination blob name is required"),
9011
9725
  expiration: flexibleDateSchema,
9012
- recursive: z16.boolean().optional().default(false),
9013
- assumeYes: z16.boolean().optional().default(false),
9014
- outputCommitments: z16.string().optional()
9726
+ recursive: z17.boolean().optional().default(false),
9727
+ assumeYes: z17.boolean().optional().default(false),
9728
+ outputCommitments: z17.string().optional()
9015
9729
  }).superRefine(async (data, ctx) => {
9016
- const stats = await fs6.stat(data.source);
9730
+ const stats = await fs8.stat(data.source);
9017
9731
  if (!stats.isFile() && !stats.isDirectory()) {
9018
9732
  ctx.addIssue({
9019
- code: z16.ZodIssueCode.custom,
9733
+ code: z17.ZodIssueCode.custom,
9020
9734
  message: "\n\u274C Upload Failed\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\u26A0\uFE0F Source path must be a file or directory\n\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
9021
9735
  path: ["source"]
9022
9736
  });
@@ -9025,7 +9739,7 @@ var UploadOptionsSchema = z16.object({
9025
9739
  if (stats.isDirectory()) {
9026
9740
  if (!data.destination.endsWith("/")) {
9027
9741
  ctx.addIssue({
9028
- code: z16.ZodIssueCode.custom,
9742
+ code: z17.ZodIssueCode.custom,
9029
9743
  message: `
9030
9744
  \u274C Upload Failed
9031
9745
  \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
@@ -9043,7 +9757,7 @@ var UploadOptionsSchema = z16.object({
9043
9757
  const blobNameResult = BlobNameSchema.safeParse(data.destination);
9044
9758
  if (!blobNameResult.success) {
9045
9759
  ctx.addIssue({
9046
- code: z16.ZodIssueCode.custom,
9760
+ code: z17.ZodIssueCode.custom,
9047
9761
  message: `
9048
9762
  \u274C Upload Failed
9049
9763
  \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
@@ -9060,7 +9774,7 @@ var UploadOptionsSchema = z16.object({
9060
9774
  }
9061
9775
  });
9062
9776
  async function buildGitignoreMap(root) {
9063
- const resolvedRoot = path6.resolve(root);
9777
+ const resolvedRoot = path7.resolve(root);
9064
9778
  const gitignoreMap = /* @__PURE__ */ new Map();
9065
9779
  const ensureMatcher = (dir) => {
9066
9780
  const existing = gitignoreMap.get(dir);
@@ -9080,8 +9794,8 @@ async function buildGitignoreMap(root) {
9080
9794
  });
9081
9795
  for (const gitignorePath of gitignoreFiles) {
9082
9796
  try {
9083
- const contents = await fs6.readFile(gitignorePath, "utf8");
9084
- const directory = path6.dirname(gitignorePath);
9797
+ const contents = await fs8.readFile(gitignorePath, "utf8");
9798
+ const directory = path7.dirname(gitignorePath);
9085
9799
  ensureMatcher(directory).add(contents);
9086
9800
  } catch (error) {
9087
9801
  if (error instanceof Error && Object.hasOwn(error, "code") && // biome-ignore lint/suspicious/noExplicitAny: node fs error type
@@ -9095,13 +9809,13 @@ async function buildGitignoreMap(root) {
9095
9809
  }
9096
9810
  function collectDirectoriesFromRoot(root, filePath) {
9097
9811
  const directories = [];
9098
- let current = path6.dirname(filePath);
9812
+ let current = path7.dirname(filePath);
9099
9813
  while (true) {
9100
9814
  directories.push(current);
9101
9815
  if (current === root) {
9102
9816
  break;
9103
9817
  }
9104
- const parent = path6.dirname(current);
9818
+ const parent = path7.dirname(current);
9105
9819
  if (parent === current) {
9106
9820
  break;
9107
9821
  }
@@ -9117,7 +9831,7 @@ function shouldIgnorePath(gitignoreMap, root, filePath) {
9117
9831
  if (!matcher) {
9118
9832
  continue;
9119
9833
  }
9120
- const relative2 = path6.relative(directory, filePath).split(path6.sep).join("/");
9834
+ const relative2 = path7.relative(directory, filePath).split(path7.sep).join("/");
9121
9835
  const result = matcher.test(relative2);
9122
9836
  if (result.ignored) {
9123
9837
  ignored = true;
@@ -9129,7 +9843,7 @@ function shouldIgnorePath(gitignoreMap, root, filePath) {
9129
9843
  return ignored;
9130
9844
  }
9131
9845
  async function createFilelist(options) {
9132
- const stats = await fs6.stat(options.source);
9846
+ const stats = await fs8.stat(options.source);
9133
9847
  if (stats.isFile()) {
9134
9848
  const blobname = normBlobName2(
9135
9849
  options.source,
@@ -9149,7 +9863,7 @@ async function createFilelist(options) {
9149
9863
  `${options.source} is a directory. Use --recursive to upload directories.`
9150
9864
  );
9151
9865
  }
9152
- const sourceRoot = path6.resolve(options.source);
9866
+ const sourceRoot = path7.resolve(options.source);
9153
9867
  const gitignoreMap = await buildGitignoreMap(sourceRoot);
9154
9868
  const fileList = [];
9155
9869
  const result = await glob("**/*", {
@@ -9162,7 +9876,7 @@ async function createFilelist(options) {
9162
9876
  if (shouldIgnorePath(gitignoreMap, sourceRoot, file)) {
9163
9877
  continue;
9164
9878
  }
9165
- const stats2 = await fs6.stat(file);
9879
+ const stats2 = await fs8.stat(file);
9166
9880
  if (!stats2.isFile()) {
9167
9881
  continue;
9168
9882
  }
@@ -9185,9 +9899,10 @@ function uploadCommand(program) {
9185
9899
  const uploadCmd = program.command("upload").description("Upload a file or directory to the shelby RPC in the config.").argument("[source]", "Source file or directory path").argument("[destination]", "Destination blob name").requiredOption(
9186
9900
  "-e, --expiration <datetime>",
9187
9901
  'Expiration date/time (required). Examples: "tomorrow", "in 2 days", "next Friday", "2025-12-31", UNIX timestamp'
9188
- ).option("-r, --recursive", "If uploading a directory, recurse").option(
9902
+ ).option("-r, --recursive", "If uploading a directory, recurse", false).option(
9189
9903
  "--assume-yes",
9190
- "Do not prompt interactively, assume yes for any questions"
9904
+ "Do not prompt interactively, assume yes for any questions",
9905
+ false
9191
9906
  ).option(
9192
9907
  "--output-commitments <filename>",
9193
9908
  "Location to store commitments computed as as part of the upload"
@@ -9205,16 +9920,16 @@ function uploadCommand(program) {
9205
9920
  )
9206
9921
  );
9207
9922
  uploadCmd.action(
9208
- async (source, destination, options) => {
9209
- let validatedOptions;
9923
+ async (source, destination, rawOptions) => {
9924
+ let options;
9210
9925
  try {
9211
- validatedOptions = await UploadOptionsSchema.parseAsync({
9212
- ...options,
9926
+ options = await UploadOptionsSchema.parseAsync({
9927
+ ...rawOptions,
9213
9928
  source,
9214
9929
  destination
9215
9930
  });
9216
9931
  } catch (error) {
9217
- if (error instanceof z16.ZodError) {
9932
+ if (error instanceof z17.ZodError) {
9218
9933
  const firstIssue = error.issues[0];
9219
9934
  if (firstIssue) {
9220
9935
  console.log(firstIssue.message);
@@ -9227,16 +9942,9 @@ function uploadCommand(program) {
9227
9942
  }
9228
9943
  process.exit(1);
9229
9944
  }
9230
- const configPath = program.opts().configFile;
9231
- let config;
9232
- try {
9233
- config = loadConfig(configPath);
9234
- } catch (error) {
9235
- console.error(`Error: ${error.message}`);
9236
- process.exit(1);
9237
- }
9945
+ const { config } = loadConfigOrExit(program.opts().configFile);
9238
9946
  const start = performance.now();
9239
- const filelist = await createFilelist(validatedOptions);
9947
+ const filelist = await createFilelist(options);
9240
9948
  const timeToCreateFilelist = ((performance.now() - start) / 1e3).toFixed(
9241
9949
  5
9242
9950
  );
@@ -9253,10 +9961,10 @@ function uploadCommand(program) {
9253
9961
  `\u{1F9EE} Filelist created (${filelist.length} ${filelist.length === 1 ? "entry" : "entries"})`
9254
9962
  );
9255
9963
  console.log(`\u23F1\uFE0F Took: ${timeToCreateFilelist}s`);
9256
- if (validatedOptions.assumeYes) {
9964
+ if (options.assumeYes) {
9257
9965
  console.log("\u2699\uFE0F Flag: --assume-yes (auto-confirmed)");
9258
9966
  }
9259
- if (!validatedOptions.assumeYes) {
9967
+ if (!options.assumeYes) {
9260
9968
  const shouldContinue = await new Promise((resolve3) => {
9261
9969
  const { unmount } = render4(
9262
9970
  /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
@@ -9297,7 +10005,7 @@ function uploadCommand(program) {
9297
10005
  };
9298
10006
  process.removeAllListeners("SIGINT");
9299
10007
  process.on("SIGINT", handleSigint);
9300
- const expireUsec = validatedOptions.expiration.getTime() * 1e3;
10008
+ const expireUsec = options.expiration.getTime() * 1e3;
9301
10009
  const expirationDate = new Date(expireUsec / 1e3);
9302
10010
  const formattedExpiration = expirationDate.toLocaleDateString("en-US", {
9303
10011
  year: "numeric",
@@ -9326,11 +10034,11 @@ function uploadCommand(program) {
9326
10034
  const formatProgressPercent = () => totalSize > 0 ? (100 * (amountUploaded / totalSize)).toFixed(2) : "0.00";
9327
10035
  let filesProcessed = 0;
9328
10036
  for (const entry of filelist) {
9329
- const fileName = path6.basename(entry.filename);
10037
+ const fileName = path7.basename(entry.filename);
9330
10038
  const fileProgress = isSingleFile ? `(${formatProgressPercent()}%)` : `(${filesProcessed}/${filelist.length} files, ${formatProgressPercent()}%)`;
9331
10039
  spinner.text = `\u{1F4D6} Reading ${fileName}... ${fileProgress}`;
9332
10040
  try {
9333
- const blobData = await fs6.readFile(entry.filename);
10041
+ const blobData = await fs8.readFile(entry.filename);
9334
10042
  if (blobData.length !== entry.sizeBytes) {
9335
10043
  throw new Error(
9336
10044
  `Size of file ${entry.filename} changed after initial scan. Original size was ${entry.sizeBytes} but it is now ${blobData.length}`
@@ -9350,7 +10058,7 @@ function uploadCommand(program) {
9350
10058
  spinner.text = `\u{1F517} Generating commitments for ${fileName}... ${fileProgress}`;
9351
10059
  const provider = await getErasureCodingProvider();
9352
10060
  const blobCommitments = await generateCommitments(provider, blobData);
9353
- if (validatedOptions.outputCommitments) {
10061
+ if (options.outputCommitments) {
9354
10062
  outputCommitments[entry.filename] = blobCommitments;
9355
10063
  }
9356
10064
  spinner.text = `\u{1F517} Registering ${fileName} on L1... ${fileProgress}`;
@@ -9359,7 +10067,7 @@ function uploadCommand(program) {
9359
10067
  blobName: entry.blobname,
9360
10068
  blobMerkleRoot: blobCommitments.blob_merkle_root,
9361
10069
  size: blobData.length,
9362
- expirationMicros: validatedOptions.expiration.getTime() * 1e3
10070
+ expirationMicros: options.expiration.getTime() * 1e3
9363
10071
  });
9364
10072
  const registerTransactionHash = pendingRegisterBlobTransaction.hash;
9365
10073
  if (!firstTransactionHash) {
@@ -9382,9 +10090,9 @@ function uploadCommand(program) {
9382
10090
  process.exit(1);
9383
10091
  }
9384
10092
  }
9385
- if (validatedOptions.outputCommitments) {
9386
- await fs6.writeFile(
9387
- validatedOptions.outputCommitments,
10093
+ if (options.outputCommitments) {
10094
+ await fs8.writeFile(
10095
+ options.outputCommitments,
9388
10096
  JSON.stringify(outputCommitments)
9389
10097
  );
9390
10098
  }
@@ -9414,37 +10122,772 @@ function uploadCommand(program) {
9414
10122
  );
9415
10123
  }
9416
10124
 
9417
- // src/cli.tsx
9418
- function createProgram() {
9419
- let config;
9420
- if (configExists()) {
10125
+ // src/commands/localnet/start.tsx
10126
+ import fs10 from "fs";
10127
+ import path9 from "path";
10128
+ import Dockerode from "dockerode";
10129
+ import { execa } from "execa";
10130
+ import ora3 from "ora";
10131
+ import { parse as parse2, stringify } from "yaml";
10132
+
10133
+ // src/commands/localnet/assets.ts
10134
+ import "fs";
10135
+ import "path";
10136
+ import "url";
10137
+ var hasuraMetadataContent;
10138
+ var nciConfigContent;
10139
+ if (true) {
10140
+ hasuraMetadataContent = (await Promise.resolve().then(() => __toESM(require_hasura_metadata(), 1))).default;
10141
+ nciConfigContent = (await Promise.resolve().then(() => __toESM(require_shelby_internal(), 1))).default;
10142
+ } else {
10143
+ const __filename = fileURLToPath(import.meta.url);
10144
+ const __dirname = path8.dirname(__filename);
10145
+ const assetsDir = path8.resolve(__dirname, "../../../assets");
10146
+ hasuraMetadataContent = fs9.readFileSync(
10147
+ path8.join(assetsDir, "hasura_metadata.txt"),
10148
+ "utf-8"
10149
+ );
10150
+ nciConfigContent = fs9.readFileSync(
10151
+ path8.join(assetsDir, "shelby_internal.txt"),
10152
+ "utf-8"
10153
+ );
10154
+ }
10155
+
10156
+ // src/commands/localnet/common.ts
10157
+ var LOCALNET_NAME = "shelby-localnet";
10158
+ var MOUNT_DIR = "/mounted";
10159
+ var debugEnabled = false;
10160
+ function setDebugEnabled(enabled) {
10161
+ debugEnabled = enabled;
10162
+ }
10163
+ function debug(message) {
10164
+ if (debugEnabled) {
10165
+ console.log(`\u{1F50D} ${message}`);
10166
+ }
10167
+ }
10168
+
10169
+ // src/commands/localnet/docker.ts
10170
+ var SHELBY_LOCALNET_NETWORK = "shelby-localnet-network";
10171
+ var restart = "no";
10172
+ var shelbyPostgres = "shelby-postgres";
10173
+ var shelbyAptosLocalnetIndexerApi = "shelby-aptos-localnet-indexer-api";
10174
+ var shelbyAptosLocalnet = "shelby-aptos-localnet";
10175
+ var shelbyNciProcessor = "shelby-nci-processor";
10176
+ var shelbyNciApi = "shelby-nci-api";
10177
+ var shelbyRpc = "shelby-rpc";
10178
+ var corePostgresDatabase = "shelby_aptos_localnet";
10179
+ var nciPostgresDatabase = "postgres";
10180
+ var aptosNodePort = 8080;
10181
+ var mountDirEnvVar = {
10182
+ MOUNT_DIR
10183
+ };
10184
+ function createDockerCompose({
10185
+ hostDataPath,
10186
+ shelbyRepoWithSlash,
10187
+ tags,
10188
+ skipNci,
10189
+ skipRpc,
10190
+ ports,
10191
+ additionalAptosLocalnetArgs
10192
+ }) {
10193
+ const coreHasuraDbString = `postgresql://postgres:postgres@${shelbyPostgres}:${ports.postgres}/${corePostgresDatabase}`;
10194
+ const nciHasuraDbString = `postgresql://postgres:postgres@${shelbyPostgres}:${ports.postgres}/postgres`;
10195
+ const services = {
10196
+ [shelbyPostgres]: {
10197
+ image: "postgres:17",
10198
+ container_name: shelbyPostgres,
10199
+ networks: [SHELBY_LOCALNET_NETWORK],
10200
+ environment: {
10201
+ POSTGRES_HOST_AUTH_METHOD: "trust",
10202
+ PGPORT: ports.postgres.toString(),
10203
+ POSTGRES_DB: corePostgresDatabase
10204
+ },
10205
+ healthcheck: {
10206
+ test: [
10207
+ "CMD",
10208
+ "pg_isready",
10209
+ "-U",
10210
+ "postgres",
10211
+ "-d",
10212
+ corePostgresDatabase
10213
+ ],
10214
+ interval: "1s",
10215
+ timeout: "2s",
10216
+ retries: 30,
10217
+ start_period: "30s"
10218
+ },
10219
+ ports: [`${ports.postgres}:${ports.postgres}`],
10220
+ restart,
10221
+ volumes: [`${hostDataPath}/postgres:/var/lib/postgresql/data`]
10222
+ },
10223
+ // Hasura GraphQL API for the core Aptos localnet indexer.
10224
+ [shelbyAptosLocalnetIndexerApi]: createHasuraService(
10225
+ shelbyAptosLocalnetIndexerApi,
10226
+ coreHasuraDbString,
10227
+ ports.coreIndexerApi,
10228
+ {
10229
+ [shelbyPostgres]: {
10230
+ condition: "service_healthy"
10231
+ }
10232
+ },
10233
+ {
10234
+ INDEXER_V2_POSTGRES_URL: coreHasuraDbString
10235
+ },
10236
+ tags.hasura
10237
+ ),
10238
+ // Aptos localnet with pre-deployed Shelby contracts.
10239
+ [shelbyAptosLocalnet]: {
10240
+ command: [
10241
+ "--bind-to",
10242
+ "0.0.0.0",
10243
+ // This flag is what causes the CLI to run the processors and apply the Hasura
10244
+ // metadata. It won't run postgres or Hasura itself like normal because of the
10245
+ // --use-host-postgres and --existing-hasura-url flags.
10246
+ "--with-indexer-api",
10247
+ "--use-host-postgres",
10248
+ "--host-postgres-host",
10249
+ // We route via the Docker network, not the host (host.docker.internal).
10250
+ shelbyPostgres,
10251
+ "--host-postgres-port",
10252
+ ports.postgres.toString(),
10253
+ "--postgres-database",
10254
+ corePostgresDatabase,
10255
+ "--existing-hasura-url",
10256
+ `http://${shelbyAptosLocalnetIndexerApi}:${ports.coreIndexerApi}`,
10257
+ "--faucet-port",
10258
+ ports.faucet.toString(),
10259
+ "--txn-stream-port",
10260
+ ports.txnStream.toString(),
10261
+ "--indexer-api-port",
10262
+ ports.coreIndexerApi.toString(),
10263
+ "--ready-server-listen-port",
10264
+ ports.localnetReadiness.toString(),
10265
+ ...additionalAptosLocalnetArgs
10266
+ ],
10267
+ container_name: shelbyAptosLocalnet,
10268
+ depends_on: {
10269
+ [shelbyAptosLocalnetIndexerApi]: {
10270
+ condition: "service_healthy"
10271
+ },
10272
+ [shelbyPostgres]: {
10273
+ condition: "service_healthy"
10274
+ }
10275
+ },
10276
+ environment: { ...mountDirEnvVar },
10277
+ healthcheck: {
10278
+ test: [
10279
+ "CMD",
10280
+ "curl",
10281
+ "-f",
10282
+ `http://localhost:${ports.localnetReadiness}/`
10283
+ ],
10284
+ interval: "1s",
10285
+ timeout: "3s",
10286
+ retries: 60,
10287
+ start_period: "10s"
10288
+ },
10289
+ image: `${shelbyRepoWithSlash}shelby/aptos-localnet:${tags.aptosLocalnet}`,
10290
+ networks: [SHELBY_LOCALNET_NETWORK],
10291
+ ports: [
10292
+ `${aptosNodePort}:${aptosNodePort}`,
10293
+ `${ports.localnetReadiness}:${ports.localnetReadiness}`,
10294
+ `${ports.faucet}:${ports.faucet}`,
10295
+ `${ports.txnStream}:${ports.txnStream}`
10296
+ ],
10297
+ restart,
10298
+ volumes: [`${hostDataPath}:${MOUNT_DIR}`]
10299
+ }
10300
+ };
10301
+ if (!skipNci) {
10302
+ services[shelbyNciProcessor] = {
10303
+ command: [
10304
+ "/usr/local/bin/remapping-processor",
10305
+ "--config-path",
10306
+ `${MOUNT_DIR}/nci/shelby_internal.yaml`
10307
+ ],
10308
+ container_name: shelbyNciProcessor,
10309
+ depends_on: {
10310
+ [shelbyPostgres]: {
10311
+ condition: "service_healthy"
10312
+ },
10313
+ [shelbyAptosLocalnet]: {
10314
+ condition: "service_healthy"
10315
+ }
10316
+ },
10317
+ environment: { ...mountDirEnvVar },
10318
+ healthcheck: {
10319
+ test: [
10320
+ "CMD-SHELL",
10321
+ `timeout 1 bash -c 'echo > /dev/tcp/localhost/${ports.nciProcessorMetrics}'`
10322
+ ],
10323
+ interval: "2s",
10324
+ timeout: "4s",
10325
+ retries: 10,
10326
+ start_period: "10s"
10327
+ },
10328
+ image: `aptoslabs/aptos-nocode-processors:${tags.nciProcessor}`,
10329
+ networks: [SHELBY_LOCALNET_NETWORK],
10330
+ // We don't build the image for arm at the moment, so we force amd64.
10331
+ platform: "linux/amd64",
10332
+ ports: [`${ports.nciProcessorMetrics}:${ports.nciProcessorMetrics}`],
10333
+ restart,
10334
+ volumes: [`${hostDataPath}:${MOUNT_DIR}`]
10335
+ };
10336
+ services[shelbyNciApi] = createHasuraService(
10337
+ shelbyNciApi,
10338
+ nciHasuraDbString,
10339
+ ports.nciIndexerApi,
10340
+ {
10341
+ [shelbyPostgres]: {
10342
+ condition: "service_healthy"
10343
+ },
10344
+ [shelbyAptosLocalnet]: {
10345
+ condition: "service_healthy"
10346
+ },
10347
+ [shelbyNciProcessor]: {
10348
+ condition: "service_healthy"
10349
+ }
10350
+ },
10351
+ {
10352
+ // This corresponds to from_env in the Hasura metadata.
10353
+ PROCESSOR_DATABASE_URL: nciHasuraDbString
10354
+ },
10355
+ tags.hasura
10356
+ );
10357
+ }
10358
+ if (!skipRpc) {
10359
+ services[shelbyRpc] = {
10360
+ container_name: shelbyRpc,
10361
+ depends_on: {
10362
+ // For now this uses its own sqlite database.
10363
+ [shelbyAptosLocalnet]: {
10364
+ condition: "service_healthy"
10365
+ }
10366
+ },
10367
+ environment: {
10368
+ PORT: ports.rpc.toString(),
10369
+ APTOS_LOCAL_NODE_API_URL: `http://${shelbyAptosLocalnet}:${aptosNodePort}/v1`,
10370
+ ...mountDirEnvVar
10371
+ },
10372
+ healthcheck: {
10373
+ // TODO: Do a better healthcheck when one is available.
10374
+ test: ["CMD", "curl", "-f", `http://localhost:${ports.rpc}/metrics`],
10375
+ interval: "1s"
10376
+ },
10377
+ image: `${shelbyRepoWithSlash}shelby/rpc:${tags.rpc}`,
10378
+ networks: [SHELBY_LOCALNET_NETWORK],
10379
+ ports: [`${ports.rpc}:${ports.rpc}`],
10380
+ restart,
10381
+ volumes: [`${hostDataPath}/rpc:${MOUNT_DIR}`]
10382
+ };
10383
+ }
10384
+ return {
10385
+ services,
10386
+ networks: {
10387
+ [SHELBY_LOCALNET_NETWORK]: {
10388
+ name: SHELBY_LOCALNET_NETWORK,
10389
+ driver: "bridge"
10390
+ }
10391
+ }
10392
+ };
10393
+ }
10394
+ async function cleanupLocalnet(dockerode) {
10395
+ const labelKey = "com.docker.compose.project";
10396
+ const labelValue = LOCALNET_NAME;
10397
+ const labelFilter = `${labelKey}=${labelValue}`;
10398
+ const filters = JSON.stringify({ label: [labelFilter] });
10399
+ const deletedItems = [];
10400
+ const containers = await dockerode.listContainers({ all: true, filters });
10401
+ for (const info of containers) {
10402
+ debug(`Deleting container ${info.Names.join(",")}...`);
10403
+ const container = await dockerode.getContainer(info.Id);
10404
+ await container.remove({ force: true });
10405
+ debug(`Deleted container ${info.Names.join(",")}`);
10406
+ deletedItems.push(...info.Names);
10407
+ }
10408
+ const networks = await dockerode.listNetworks({ filters });
10409
+ for (const info of networks) {
10410
+ debug(`Deleting network ${info.Name}...`);
10411
+ const network = await dockerode.getNetwork(info.Id);
10412
+ await network.remove();
10413
+ debug(`Deleted network ${info.Name}`);
10414
+ deletedItems.push(info.Name);
10415
+ }
10416
+ return deletedItems;
10417
+ }
10418
+ function createHasuraService(containerName, dbString, port, dependsOn, extraEnvironment, hasuraTag) {
10419
+ return {
10420
+ container_name: containerName,
10421
+ depends_on: dependsOn,
10422
+ environment: {
10423
+ HASURA_GRAPHQL_CONSOLE_ASSETS_DIR: "/srv/console-assets",
10424
+ HASURA_GRAPHQL_DEV_MODE: "true",
10425
+ HASURA_GRAPHQL_ENABLE_CONSOLE: "true",
10426
+ HASURA_GRAPHQL_METADATA_DATABASE_URL: dbString,
10427
+ PG_DATABASE_URL: dbString,
10428
+ HASURA_GRAPHQL_SERVER_PORT: port.toString(),
10429
+ ...extraEnvironment
10430
+ },
10431
+ healthcheck: {
10432
+ interval: "1s",
10433
+ retries: 30,
10434
+ start_period: "10s",
10435
+ test: ["CMD", "curl", "-f", `http://localhost:${port}/healthz`],
10436
+ timeout: "3s"
10437
+ },
10438
+ image: `hasura/graphql-engine:${hasuraTag}`,
10439
+ networks: [SHELBY_LOCALNET_NETWORK],
10440
+ ports: [`${port}:${port}`],
10441
+ restart
10442
+ };
10443
+ }
10444
+
10445
+ // src/commands/localnet/hasura.ts
10446
+ async function makeHasuraMetadataRequest(url, type, args) {
10447
+ const metadataUrl = new URL("/v1/metadata", url);
10448
+ const payload = {
10449
+ type,
10450
+ args: args || {}
10451
+ };
10452
+ const response = await fetch(metadataUrl.toString(), {
10453
+ method: "POST",
10454
+ headers: {
10455
+ "Content-Type": "application/json"
10456
+ },
10457
+ body: JSON.stringify(payload)
10458
+ });
10459
+ if (!response.ok) {
10460
+ const responseBody = await response.text();
10461
+ throw new Error(
10462
+ `Hasura metadata request failed: ${response.status} ${response.statusText}
10463
+ Response body: ${responseBody}`
10464
+ );
10465
+ }
10466
+ return await response.json();
10467
+ }
10468
+ async function applyHasuraMetadata(url, metadataContent) {
10469
+ const metadataJson = JSON.parse(metadataContent);
10470
+ const response = await makeHasuraMetadataRequest(
10471
+ url,
10472
+ "replace_metadata",
10473
+ metadataJson
10474
+ );
10475
+ if (response.is_consistent === true) {
10476
+ return;
10477
+ }
10478
+ throw new Error(
10479
+ `Failed to apply Hasura metadata consistently. Response: ${JSON.stringify(response, null, 2)}`
10480
+ );
10481
+ }
10482
+ async function confirmHasuraMetadataApplied(url) {
10483
+ const response = await makeHasuraMetadataRequest(url, "export_metadata");
10484
+ if (response.sources && Array.isArray(response.sources) && response.sources.length > 0) {
10485
+ return;
10486
+ }
10487
+ throw new Error(
10488
+ `Hasura metadata has not been applied yet. Response: ${JSON.stringify(response, null, 2)}`
10489
+ );
10490
+ }
10491
+ async function applyAndConfirmHasuraMetadata(url, metadataContent, maxRetries = 6, retryDelayMs = 2500) {
10492
+ let lastError = null;
10493
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
9421
10494
  try {
9422
- config = loadConfig();
9423
- } catch (_err) {
9424
- config = void 0;
10495
+ await applyHasuraMetadata(url, metadataContent);
10496
+ await confirmHasuraMetadataApplied(url);
10497
+ return;
10498
+ } catch (error) {
10499
+ lastError = error;
10500
+ if (attempt < maxRetries) {
10501
+ await new Promise((resolve3) => setTimeout(resolve3, retryDelayMs));
10502
+ }
9425
10503
  }
9426
10504
  }
9427
- const program = new Command();
9428
- program.name("shelby").description(
10505
+ throw new Error(
10506
+ `Failed to apply Hasura metadata after ${maxRetries} attempts: ${lastError?.message}`
10507
+ );
10508
+ }
10509
+
10510
+ // src/commands/localnet/start.tsx
10511
+ function parsePort(value) {
10512
+ const port = Number.parseInt(value.trim(), 10);
10513
+ if (Number.isNaN(port)) {
10514
+ console.error(`Invalid port: ${value}`);
10515
+ process.exit(1);
10516
+ }
10517
+ if (port === 0) {
10518
+ console.error("We cannot handle port = 0 right now, sorry!");
10519
+ process.exit(1);
10520
+ }
10521
+ return port;
10522
+ }
10523
+ function localnetStartCommand(program) {
10524
+ program.command("start").description("Start a Shelby localnet (without SPs at the moment)").option("-d, --debug", "Enable debug logging", false).option("-f", "Follow logs after starting", false).option(
10525
+ "--additional-aptos-localnet-args <args>",
10526
+ "Additional arguments to pass to Aptos localnet",
10527
+ ""
10528
+ ).option(
10529
+ "--data-path <path>",
10530
+ "Directory where localnet data will be stored (default: .shelby location based on global config)",
10531
+ path9.join(path9.dirname(findExistingConfigPath()), "localnet")
10532
+ ).option("--reset", "Wipe all existing localnet data before starting", false).option(
10533
+ "--docker-repo <registry>",
10534
+ "Docker registry to use for Shelby images",
10535
+ "ghcr.io"
10536
+ ).option(
10537
+ "--aptos-localnet-tag <tag>",
10538
+ "Tag to use for Aptos localnet image (e.g., latest, <commit-hash>)",
10539
+ "latest"
10540
+ ).option("--rpc-tag <tag>", "Tag to use for RPC image", "latest").option("--sp-tag <tag>", "Tag to use for Storage Provider image", "latest").option(
10541
+ "--nci-processor-tag <tag>",
10542
+ "Tag to use for No-Code Indexer Processor image",
10543
+ "02b51d2cf5a0609eb04771adfc906457ffad95be"
10544
+ ).option("--hasura-tag <tag>", "Tag to use for Hasura image", "v2.48.5-ce").option(
10545
+ "--postgres-port <port>",
10546
+ "Port to use for postgres",
10547
+ parsePort,
10548
+ 5433
10549
+ ).option(
10550
+ "--faucet-port <port>",
10551
+ "Port to use for Aptos faucet",
10552
+ parsePort,
10553
+ 8081
10554
+ ).option(
10555
+ "--txn-stream-port <port>",
10556
+ "Port to use for Aptos localnet transaction stream",
10557
+ parsePort,
10558
+ 50051
10559
+ ).option(
10560
+ "--core-indexer-api-port <port>",
10561
+ "Port to use for Aptos indexer API",
10562
+ parsePort,
10563
+ 8090
10564
+ ).option(
10565
+ "--localnet-readiness-port <port>",
10566
+ "Port to use for Aptos localnet readiness",
10567
+ parsePort,
10568
+ 8070
10569
+ ).option(
10570
+ "--nci-processor-metrics-port <port>",
10571
+ "Port to use for no-code indexer processor metrics",
10572
+ parsePort,
10573
+ 7654
10574
+ ).option(
10575
+ "--nci-indexer-api-port <port>",
10576
+ "Port to use for no-code indexer API",
10577
+ parsePort,
10578
+ 8091
10579
+ ).option(
10580
+ "--rpc-port <port>",
10581
+ "Port to use for the Shelby RPC",
10582
+ parsePort,
10583
+ 8093
10584
+ ).option(
10585
+ "--skip-nci",
10586
+ "Skip running the no-code indexer processor + API",
10587
+ false
10588
+ ).option("--skip-rpc", "Skip running the Shelby RPC", false).action(async (options) => {
10589
+ const dataPath = path9.resolve(options.dataPath);
10590
+ const shelbyRepo = options.dockerRepo || "";
10591
+ const shelbyRepoWithSlash = shelbyRepo ? `${shelbyRepo}/` : "";
10592
+ setDebugEnabled(options.debug);
10593
+ const spinner = ora3();
10594
+ console.log("\u{1F680} Starting Shelby localnet...\n");
10595
+ console.log(`\u{1F5C2}\uFE0F Data path: ${dataPath}`);
10596
+ if (options.reset) {
10597
+ console.log("\u{1F5D1}\uFE0F Reset flag set - wiping data before starting");
10598
+ }
10599
+ if (shelbyRepo) {
10600
+ console.log(
10601
+ `\u{1F433} Using Docker registry for Shelby images: ${shelbyRepo}`
10602
+ );
10603
+ }
10604
+ console.log("");
10605
+ if (options.reset && fs10.existsSync(dataPath)) {
10606
+ const spinner2 = ora3("Removing existing data...").start();
10607
+ fs10.rmSync(dataPath, { recursive: true, force: true });
10608
+ spinner2.succeed("Data path wiped");
10609
+ }
10610
+ debug(`Creating localnet data in ${dataPath}...`);
10611
+ fs10.mkdirSync(dataPath, { recursive: true });
10612
+ fs10.mkdirSync(path9.join(dataPath, "postgres"), { recursive: true });
10613
+ fs10.mkdirSync(path9.join(dataPath, "nci"), { recursive: true });
10614
+ fs10.mkdirSync(path9.join(dataPath, "rpc", "blobs"), { recursive: true });
10615
+ debug("Directory structure created");
10616
+ const nciConfigPath = path9.join(dataPath, "nci", "shelby_internal.yaml");
10617
+ fs10.writeFileSync(nciConfigPath, nciConfigContent);
10618
+ fs10.writeFileSync(
10619
+ path9.join(dataPath, "nci", "hasura_metadata.json"),
10620
+ hasuraMetadataContent
10621
+ );
10622
+ const nciConfig = parse2(nciConfigContent);
10623
+ nciConfig.common_config.transaction_stream_config.indexer_grpc_data_service_address = `http://${shelbyAptosLocalnet}:${options.txnStreamPort}`;
10624
+ nciConfig.common_config.db_config.postgres_connection_string = `postgresql://postgres:postgres@${shelbyPostgres}:${options.postgresPort}/${nciPostgresDatabase}`;
10625
+ nciConfig.common_config.health_check_port = options.nciProcessorMetricsPort;
10626
+ fs10.writeFileSync(nciConfigPath, stringify(nciConfig, { indent: 2 }));
10627
+ debug("Generating docker-compose.yml...");
10628
+ const additionalAptosLocalnetArgs = options.additionalAptosLocalnetArgs ? options.additionalAptosLocalnetArgs.split(" ") : [];
10629
+ const composeConfig = createDockerCompose({
10630
+ shelbyRepoWithSlash,
10631
+ tags: {
10632
+ aptosLocalnet: options.aptosLocalnetTag,
10633
+ nciProcessor: options.nciProcessorTag,
10634
+ hasura: options.hasuraTag,
10635
+ rpc: options.rpcTag
10636
+ },
10637
+ skipNci: options.skipNci,
10638
+ skipRpc: options.skipRpc,
10639
+ ports: {
10640
+ postgres: options.postgresPort,
10641
+ faucet: options.faucetPort,
10642
+ txnStream: options.txnStreamPort,
10643
+ coreIndexerApi: options.coreIndexerApiPort,
10644
+ localnetReadiness: options.localnetReadinessPort,
10645
+ nciProcessorMetrics: options.nciProcessorMetricsPort,
10646
+ nciIndexerApi: options.nciIndexerApiPort,
10647
+ rpc: options.rpcPort
10648
+ },
10649
+ hostDataPath: dataPath,
10650
+ additionalAptosLocalnetArgs
10651
+ });
10652
+ const dockerComposePath = path9.join(dataPath, "docker-compose.yml");
10653
+ fs10.writeFileSync(
10654
+ dockerComposePath,
10655
+ stringify(composeConfig, { indent: 2 })
10656
+ );
10657
+ debug("docker-compose.yml generated");
10658
+ let dockerode;
10659
+ try {
10660
+ dockerode = new Dockerode();
10661
+ } catch (error) {
10662
+ console.error("Failed to connect to Docker, is it running?");
10663
+ throw error;
10664
+ }
10665
+ try {
10666
+ const deletedItems = await cleanupLocalnet(dockerode);
10667
+ if (deletedItems.length > 0) {
10668
+ debug(
10669
+ `Cleaned up leftover Docker resources from previous localnet: ${deletedItems.join(", ")}`
10670
+ );
10671
+ } else {
10672
+ debug("No leftover Docker resources found");
10673
+ }
10674
+ } catch (error) {
10675
+ console.error("Failed to clean up leftover Docker resources");
10676
+ throw error;
10677
+ }
10678
+ console.log("\nStarting services...");
10679
+ let logsProcess = null;
10680
+ let isShuttingDown = false;
10681
+ const shutdownHandler = async (signal) => {
10682
+ if (isShuttingDown) {
10683
+ console.log("\n\u26A0\uFE0F Second interrupt received, forcing exit...");
10684
+ process.exit(1);
10685
+ }
10686
+ isShuttingDown = true;
10687
+ console.log(`
10688
+
10689
+ \u{1F6D1} Received ${signal}, shutting down gracefully...`);
10690
+ console.log(" (Press Ctrl+C again to force exit)\n");
10691
+ try {
10692
+ if (logsProcess && !logsProcess.killed) {
10693
+ logsProcess.kill("SIGTERM");
10694
+ }
10695
+ await execa(
10696
+ "docker",
10697
+ ["compose", "-f", dockerComposePath, "-p", LOCALNET_NAME, "down"],
10698
+ {
10699
+ stdio: "inherit"
10700
+ }
10701
+ );
10702
+ console.log("\n\u2705 Localnet shut down gracefully");
10703
+ process.exit(0);
10704
+ } catch (error) {
10705
+ console.error("\n\u274C Error during shutdown:", error);
10706
+ process.exit(1);
10707
+ }
10708
+ };
10709
+ process.on("SIGINT", () => {
10710
+ if (!isShuttingDown) {
10711
+ shutdownHandler("SIGINT");
10712
+ }
10713
+ });
10714
+ try {
10715
+ await execa(
10716
+ "docker",
10717
+ ["compose", "-f", dockerComposePath, "-p", LOCALNET_NAME, "up", "-d"],
10718
+ {
10719
+ stdio: "inherit"
10720
+ }
10721
+ );
10722
+ console.log("\u2714 Services spawned");
10723
+ spinner.start("Waiting up to 2 minutes for services to be healthy...");
10724
+ await execa(
10725
+ "docker",
10726
+ [
10727
+ "compose",
10728
+ "-f",
10729
+ dockerComposePath,
10730
+ "-p",
10731
+ LOCALNET_NAME,
10732
+ "up",
10733
+ "--wait",
10734
+ "--wait-timeout",
10735
+ "120"
10736
+ ],
10737
+ {
10738
+ stdio: "pipe"
10739
+ }
10740
+ );
10741
+ spinner.succeed("All services are healthy");
10742
+ } catch (error) {
10743
+ spinner.fail(
10744
+ `Failed to start services, try running: docker compose -p ${LOCALNET_NAME} logs -f`
10745
+ );
10746
+ throw error;
10747
+ }
10748
+ console.log();
10749
+ spinner.start("Running post-startup steps...");
10750
+ if (!options.skipNci) {
10751
+ try {
10752
+ await applyAndConfirmHasuraMetadata(
10753
+ `http://127.0.0.1:${options.nciIndexerApiPort}`,
10754
+ hasuraMetadataContent
10755
+ );
10756
+ } catch (error) {
10757
+ spinner.fail(`Failed to apply Hasura metadata: ${error}`);
10758
+ throw error;
10759
+ }
10760
+ }
10761
+ spinner.succeed("Post-startup steps complete");
10762
+ console.log("\n\u2705 Shelby localnet is running!\n");
10763
+ console.log("\u{1F4CD} Service Endpoints:");
10764
+ console.log(` Aptos REST API: http://127.0.0.1:${aptosNodePort}`);
10765
+ console.log(
10766
+ ` Aptos Faucet: http://127.0.0.1:${options.faucetPort}`
10767
+ );
10768
+ if (!options.skipRpc) {
10769
+ console.log(
10770
+ ` Shelby RPC Server: http://127.0.0.1:${options.rpcPort}`
10771
+ );
10772
+ }
10773
+ console.log(
10774
+ ` Transaction Stream: http://127.0.0.1:${options.txnStreamPort}`
10775
+ );
10776
+ console.log(
10777
+ ` Core Indexer API: http://127.0.0.1:${options.coreIndexerApiPort}`
10778
+ );
10779
+ if (!options.skipNci) {
10780
+ console.log(
10781
+ ` No-Code Indexer API: http://127.0.0.1:${options.nciIndexerApiPort}`
10782
+ );
10783
+ }
10784
+ console.log(
10785
+ ` Postgres: postgresql://postgres:postgres@127.0.0.1:${options.postgresPort}/${corePostgresDatabase}`
10786
+ );
10787
+ console.log("");
10788
+ if (options.f) {
10789
+ console.log("\u{1F4DA} Following logs (press Ctrl+C to stop)...");
10790
+ console.log("");
10791
+ try {
10792
+ logsProcess = execa(
10793
+ "docker",
10794
+ [
10795
+ "compose",
10796
+ "-f",
10797
+ dockerComposePath,
10798
+ "-p",
10799
+ LOCALNET_NAME,
10800
+ "logs",
10801
+ "-f"
10802
+ ],
10803
+ {
10804
+ stdio: "inherit",
10805
+ reject: false
10806
+ }
10807
+ );
10808
+ await logsProcess;
10809
+ } catch (error) {
10810
+ console.error("Error while following logs:", error);
10811
+ throw error;
10812
+ }
10813
+ } else {
10814
+ console.log(
10815
+ [
10816
+ "\u{1F4DA} To view logs:",
10817
+ ` docker compose -p ${LOCALNET_NAME} logs -f`,
10818
+ "",
10819
+ "\u{1F52C} To check the status:",
10820
+ ` docker compose -p ${LOCALNET_NAME} ps --format 'table {{.Name}}\\t{{.State}}'`,
10821
+ "",
10822
+ "\u{1F6D1} To stop:",
10823
+ ` docker compose -p ${LOCALNET_NAME} down`,
10824
+ ""
10825
+ ].join("\n")
10826
+ );
10827
+ }
10828
+ });
10829
+ }
10830
+
10831
+ // src/commands/localnet/index.tsx
10832
+ function localnetCommand(program) {
10833
+ const localnetCmd = program.command("localnet").description("Manage Shelby localnet");
10834
+ localnetStartCommand(localnetCmd);
10835
+ }
10836
+
10837
+ // src/cli.tsx
10838
+ var DEFAULT_CONTEXT = "default_context";
10839
+ var DEFAULT_ACCOUNT = "default_account";
10840
+ function getBaseCommand(defaultContext, defaultAccount) {
10841
+ return new Command().name("shelby").description(
9429
10842
  "CLI tool for preparing, uploading, and reading video content on Shelby"
9430
10843
  ).version(version).option("-v, --verbose", "Enable verbose logging", false).option(
9431
10844
  "-C, --config-file <path>",
9432
- "Path to your Shelby CLI config",
9433
- "~/.shelby/config.yaml"
10845
+ "Path to your Shelby CLI config (defaults to ~/.shelby/config.yaml unless config_location_behavior in global config is set to 'walk')"
9434
10846
  ).option(
9435
10847
  "-c, --context <name>",
9436
- "Load endpoints from contexts.<name>",
9437
- config?.default_context || "default_context"
10848
+ "Load endpoints from contexts.<name> (defaults to default_context in config)",
10849
+ defaultContext || "default_context"
9438
10850
  ).option(
9439
10851
  "-a, --account <name>",
9440
- "Load signing credentials from accounts.<name>",
9441
- config?.default_account || "default_account"
10852
+ "Load signing credentials from accounts.<name> (defaults to default_account in config)",
10853
+ defaultAccount || "default_account"
10854
+ );
10855
+ }
10856
+ function parseConfigFileArg() {
10857
+ const args = process.argv;
10858
+ for (let i = 0; i < args.length; i++) {
10859
+ if (args[i] === "--config-file" || args[i] === "-C") {
10860
+ if (i + 1 >= args.length || args[i + 1].startsWith("-")) {
10861
+ console.error(
10862
+ `\u274C Missing required value for ${args[i]} argument. Please provide a config file path after ${args[i]}.`
10863
+ );
10864
+ process.exit(1);
10865
+ }
10866
+ return args[i + 1];
10867
+ }
10868
+ }
10869
+ return void 0;
10870
+ }
10871
+ function createProgram() {
10872
+ const explicitConfigPath = parseConfigFileArg();
10873
+ let config;
10874
+ try {
10875
+ const configPath = explicitConfigPath || findExistingConfigPath();
10876
+ config = loadConfig(configPath);
10877
+ } catch (_err) {
10878
+ config = void 0;
10879
+ }
10880
+ const program = getBaseCommand(
10881
+ config?.default_context,
10882
+ config?.default_account
9442
10883
  );
9443
10884
  initCommand(program);
9444
10885
  accountCommand(program);
10886
+ configCommand(program);
9445
10887
  contextCommand(program);
9446
10888
  downloadCommand(program);
9447
10889
  faucetCommand(program);
10890
+ localnetCommand(program);
9448
10891
  uploadCommand(program);
9449
10892
  commitmentCommand(program);
9450
10893
  return program;