@bitsocial/bitsocial-cli 0.19.64 → 0.19.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -15
- package/dist/cli/ascii-banner.d.ts +8 -1
- package/dist/cli/ascii-banner.js +31 -24
- package/dist/cli/commands/community/export.d.ts +22 -0
- package/dist/cli/commands/community/export.js +198 -0
- package/dist/cli/commands/daemon.d.ts +1 -0
- package/dist/cli/commands/daemon.js +15 -6
- package/dist/cli/commands/update/install.js +1 -0
- package/dist/webui/daemon-server.d.ts +3 -1
- package/dist/webui/daemon-server.js +16 -2
- package/oclif.manifest.json +94 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -304,6 +304,7 @@ $ bitsocial community edit mysub.bso '--roles["author-address.bso"]' null
|
|
|
304
304
|
* [`bitsocial community create`](#bitsocial-community-create)
|
|
305
305
|
* [`bitsocial community delete ADDRESSES`](#bitsocial-community-delete-addresses)
|
|
306
306
|
* [`bitsocial community edit ADDRESS`](#bitsocial-community-edit-address)
|
|
307
|
+
* [`bitsocial community export [ADDRESS]`](#bitsocial-community-export-address)
|
|
307
308
|
* [`bitsocial community get [ADDRESS]`](#bitsocial-community-get-address)
|
|
308
309
|
* [`bitsocial community list`](#bitsocial-community-list)
|
|
309
310
|
* [`bitsocial community start ADDRESSES`](#bitsocial-community-start-addresses)
|
|
@@ -344,7 +345,7 @@ EXAMPLES
|
|
|
344
345
|
$ bitsocial challenge install ./my-local-challenge
|
|
345
346
|
```
|
|
346
347
|
|
|
347
|
-
_See code: [src/cli/commands/challenge/install.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.
|
|
348
|
+
_See code: [src/cli/commands/challenge/install.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.65/src/cli/commands/challenge/install.ts)_
|
|
348
349
|
|
|
349
350
|
## `bitsocial challenge list`
|
|
350
351
|
|
|
@@ -367,7 +368,7 @@ EXAMPLES
|
|
|
367
368
|
$ bitsocial challenge list -q
|
|
368
369
|
```
|
|
369
370
|
|
|
370
|
-
_See code: [src/cli/commands/challenge/list.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.
|
|
371
|
+
_See code: [src/cli/commands/challenge/list.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.65/src/cli/commands/challenge/list.ts)_
|
|
371
372
|
|
|
372
373
|
## `bitsocial challenge remove NAME`
|
|
373
374
|
|
|
@@ -392,7 +393,7 @@ EXAMPLES
|
|
|
392
393
|
$ bitsocial challenge remove @scope/my-challenge
|
|
393
394
|
```
|
|
394
395
|
|
|
395
|
-
_See code: [src/cli/commands/challenge/remove.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.
|
|
396
|
+
_See code: [src/cli/commands/challenge/remove.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.65/src/cli/commands/challenge/remove.ts)_
|
|
396
397
|
|
|
397
398
|
## `bitsocial community create`
|
|
398
399
|
|
|
@@ -422,7 +423,7 @@ EXAMPLES
|
|
|
422
423
|
$ bitsocial community create --jsonFile ./create-options.json
|
|
423
424
|
```
|
|
424
425
|
|
|
425
|
-
_See code: [src/cli/commands/community/create.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.
|
|
426
|
+
_See code: [src/cli/commands/community/create.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.65/src/cli/commands/community/create.ts)_
|
|
426
427
|
|
|
427
428
|
## `bitsocial community delete ADDRESSES`
|
|
428
429
|
|
|
@@ -447,7 +448,7 @@ EXAMPLES
|
|
|
447
448
|
$ bitsocial community delete 12D3KooWG3XbzoVyAE6Y9vHZKF64Yuuu4TjdgQKedk14iYmTEPWu
|
|
448
449
|
```
|
|
449
450
|
|
|
450
|
-
_See code: [src/cli/commands/community/delete.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.
|
|
451
|
+
_See code: [src/cli/commands/community/delete.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.65/src/cli/commands/community/delete.ts)_
|
|
451
452
|
|
|
452
453
|
## `bitsocial community edit ADDRESS`
|
|
453
454
|
|
|
@@ -517,7 +518,48 @@ EXAMPLES
|
|
|
517
518
|
$ bitsocial community edit bitsocial.bso --jsonFile ./edit-options.json
|
|
518
519
|
```
|
|
519
520
|
|
|
520
|
-
_See code: [src/cli/commands/community/edit.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.
|
|
521
|
+
_See code: [src/cli/commands/community/edit.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.65/src/cli/commands/community/edit.ts)_
|
|
522
|
+
|
|
523
|
+
## `bitsocial community export [ADDRESS]`
|
|
524
|
+
|
|
525
|
+
Export a local community to a SQLite snapshot file. The export runs on the RPC server (daemon); once finished the snapshot is downloaded and its sha256 checksum is verified. Pass --includePrivateKey to produce a restorable backup that keeps the community's address.
|
|
526
|
+
|
|
527
|
+
```
|
|
528
|
+
USAGE
|
|
529
|
+
$ bitsocial community export [ADDRESS] --pkcRpcUrl <value> [--name <value>] [--publicKey <value>] [-o <value>]
|
|
530
|
+
[--includePrivateKey] [--force] [-q]
|
|
531
|
+
|
|
532
|
+
ARGUMENTS
|
|
533
|
+
[ADDRESS] Address of the community to export
|
|
534
|
+
|
|
535
|
+
FLAGS
|
|
536
|
+
-o, --path=<value> Destination file for the downloaded snapshot (default:
|
|
537
|
+
<dataPath>/exports/<address>_<datetime>.sqlite)
|
|
538
|
+
-q, --quiet Suppress progress output; only print the path of the downloaded snapshot
|
|
539
|
+
--force Overwrite the destination file if it already exists
|
|
540
|
+
--includePrivateKey Ask the RPC server to include the community signer's private key in the export. Required for
|
|
541
|
+
a restorable backup that keeps the same community address. The daemon may refuse (see
|
|
542
|
+
`bitsocial daemon --no-allowPrivateKeyExport`)
|
|
543
|
+
--name=<value> Name of the community to export
|
|
544
|
+
--pkcRpcUrl=<value> (required) [default: ws://localhost:9138/] URL to PKC RPC
|
|
545
|
+
--publicKey=<value> Public key of the community to export
|
|
546
|
+
|
|
547
|
+
DESCRIPTION
|
|
548
|
+
Export a local community to a SQLite snapshot file. The export runs on the RPC server (daemon); once finished the
|
|
549
|
+
snapshot is downloaded and its sha256 checksum is verified. Pass --includePrivateKey to produce a restorable backup
|
|
550
|
+
that keeps the community's address.
|
|
551
|
+
|
|
552
|
+
EXAMPLES
|
|
553
|
+
$ bitsocial community export plebmusic.bso
|
|
554
|
+
|
|
555
|
+
$ bitsocial community export plebmusic.bso --includePrivateKey -o ./backups/plebmusic.sqlite
|
|
556
|
+
|
|
557
|
+
$ bitsocial community export --name my-community
|
|
558
|
+
|
|
559
|
+
$ bitsocial community export --publicKey 12D3KooWG3XbzoVyAE6Y9vHZKF64Yuuu4TjdgQKedk14iYmTEPWu
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
_See code: [src/cli/commands/community/export.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.65/src/cli/commands/community/export.ts)_
|
|
521
563
|
|
|
522
564
|
## `bitsocial community get [ADDRESS]`
|
|
523
565
|
|
|
@@ -548,7 +590,7 @@ EXAMPLES
|
|
|
548
590
|
$ bitsocial community get --publicKey 12D3KooWG3XbzoVyAE6Y9vHZKF64Yuuu4TjdgQKedk14iYmTEPWu
|
|
549
591
|
```
|
|
550
592
|
|
|
551
|
-
_See code: [src/cli/commands/community/get.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.
|
|
593
|
+
_See code: [src/cli/commands/community/get.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.65/src/cli/commands/community/get.ts)_
|
|
552
594
|
|
|
553
595
|
## `bitsocial community list`
|
|
554
596
|
|
|
@@ -571,7 +613,7 @@ EXAMPLES
|
|
|
571
613
|
$ bitsocial community list
|
|
572
614
|
```
|
|
573
615
|
|
|
574
|
-
_See code: [src/cli/commands/community/list.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.
|
|
616
|
+
_See code: [src/cli/commands/community/list.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.65/src/cli/commands/community/list.ts)_
|
|
575
617
|
|
|
576
618
|
## `bitsocial community start ADDRESSES`
|
|
577
619
|
|
|
@@ -605,7 +647,7 @@ EXAMPLES
|
|
|
605
647
|
$ bitsocial community start $(bitsocial community list -q) --concurrency 1
|
|
606
648
|
```
|
|
607
649
|
|
|
608
|
-
_See code: [src/cli/commands/community/start.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.
|
|
650
|
+
_See code: [src/cli/commands/community/start.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.65/src/cli/commands/community/start.ts)_
|
|
609
651
|
|
|
610
652
|
## `bitsocial community stop ADDRESSES`
|
|
611
653
|
|
|
@@ -630,7 +672,7 @@ EXAMPLES
|
|
|
630
672
|
$ bitsocial community stop Qmb99crTbSUfKXamXwZBe829Vf6w5w5TktPkb6WstC9RFW
|
|
631
673
|
```
|
|
632
674
|
|
|
633
|
-
_See code: [src/cli/commands/community/stop.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.
|
|
675
|
+
_See code: [src/cli/commands/community/stop.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.65/src/cli/commands/community/stop.ts)_
|
|
634
676
|
|
|
635
677
|
## `bitsocial daemon`
|
|
636
678
|
|
|
@@ -639,8 +681,12 @@ Run a network-connected Bitsocial node. Once the daemon is running you can creat
|
|
|
639
681
|
```
|
|
640
682
|
USAGE
|
|
641
683
|
$ bitsocial daemon --pkcRpcUrl <value> --logPath <value> [--chainProviderUrls <value>...]
|
|
684
|
+
[--allowPrivateKeyExport]
|
|
642
685
|
|
|
643
686
|
FLAGS
|
|
687
|
+
--[no-]allowPrivateKeyExport Allow RPC clients to request community exports that include the community signer's
|
|
688
|
+
private key (`bitsocial community export --includePrivateKey`). Disable with
|
|
689
|
+
--no-allowPrivateKeyExport when exposing the RPC to untrusted clients
|
|
644
690
|
--chainProviderUrls=<value>... [default:
|
|
645
691
|
https://eth.drpc.org,https://ethereum.publicnode.com,https://ethereum-rpc.publicnode.c
|
|
646
692
|
om,https://rpc.mevblocker.io,https://1rpc.io/eth,https://eth-pokt.nodies.app] RPC
|
|
@@ -669,9 +715,11 @@ EXAMPLES
|
|
|
669
715
|
$ bitsocial daemon --pkcOptions.kuboRpcClientsOptions[0] https://remoteipfsnode.com
|
|
670
716
|
|
|
671
717
|
$ bitsocial daemon --chainProviderUrls https://mainnet.infura.io/v3/YOUR_KEY
|
|
718
|
+
|
|
719
|
+
$ bitsocial daemon --no-allowPrivateKeyExport
|
|
672
720
|
```
|
|
673
721
|
|
|
674
|
-
_See code: [src/cli/commands/daemon.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.
|
|
722
|
+
_See code: [src/cli/commands/daemon.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.65/src/cli/commands/daemon.ts)_
|
|
675
723
|
|
|
676
724
|
## `bitsocial help [COMMAND]`
|
|
677
725
|
|
|
@@ -737,7 +785,7 @@ EXAMPLES
|
|
|
737
785
|
$ bitsocial logs --stdout -f
|
|
738
786
|
```
|
|
739
787
|
|
|
740
|
-
_See code: [src/cli/commands/logs.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.
|
|
788
|
+
_See code: [src/cli/commands/logs.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.65/src/cli/commands/logs.ts)_
|
|
741
789
|
|
|
742
790
|
## `bitsocial update check`
|
|
743
791
|
|
|
@@ -754,7 +802,7 @@ EXAMPLES
|
|
|
754
802
|
$ bitsocial update check
|
|
755
803
|
```
|
|
756
804
|
|
|
757
|
-
_See code: [src/cli/commands/update/check.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.
|
|
805
|
+
_See code: [src/cli/commands/update/check.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.65/src/cli/commands/update/check.ts)_
|
|
758
806
|
|
|
759
807
|
## `bitsocial update install [VERSION]`
|
|
760
808
|
|
|
@@ -786,7 +834,7 @@ EXAMPLES
|
|
|
786
834
|
$ bitsocial update install --no-restart-daemons
|
|
787
835
|
```
|
|
788
836
|
|
|
789
|
-
_See code: [src/cli/commands/update/install.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.
|
|
837
|
+
_See code: [src/cli/commands/update/install.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.65/src/cli/commands/update/install.ts)_
|
|
790
838
|
|
|
791
839
|
## `bitsocial update versions`
|
|
792
840
|
|
|
@@ -808,7 +856,7 @@ EXAMPLES
|
|
|
808
856
|
$ bitsocial update versions --limit 5
|
|
809
857
|
```
|
|
810
858
|
|
|
811
|
-
_See code: [src/cli/commands/update/versions.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.
|
|
859
|
+
_See code: [src/cli/commands/update/versions.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.65/src/cli/commands/update/versions.ts)_
|
|
812
860
|
<!-- commandsstop -->
|
|
813
861
|
|
|
814
862
|
## Contribution
|
|
@@ -1 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
interface RenderBannerOptions {
|
|
2
|
+
env?: Record<string, string | undefined>;
|
|
3
|
+
forceColor?: boolean;
|
|
4
|
+
stdoutIsTTY?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare function renderBanner(options?: RenderBannerOptions): string;
|
|
7
|
+
export declare function printBanner(options?: RenderBannerOptions): void;
|
|
8
|
+
export {};
|
package/dist/cli/ascii-banner.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
//
|
|
6
6
|
// COLORS is the paint map. Each character corresponds 1:1 to the character
|
|
7
7
|
// at the same position in SHAPE:
|
|
8
|
-
// B = blue
|
|
9
|
-
// S =
|
|
8
|
+
// B = blue accent — the sphere
|
|
9
|
+
// S = default foreground — the rings and the "Bitsocial" text
|
|
10
10
|
// . = no color (pass the glyph through as-is; use this for spaces)
|
|
11
11
|
//
|
|
12
12
|
// To retouch the art, find a glyph in SHAPE, then flip the character at the
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
//
|
|
16
16
|
// Both grids MUST have the same number of rows. Each row in COLORS must be at
|
|
17
17
|
// least as wide as the corresponding SHAPE row (extra chars are ignored).
|
|
18
|
-
//
|
|
18
|
+
// Use the terminal's default foreground for the wordmark/rings so the banner
|
|
19
|
+
// stays readable on both light and dark terminal themes.
|
|
19
20
|
const SHAPE = [
|
|
20
21
|
" ⢀⣴⣿⣿⣦⡀ ",
|
|
21
22
|
" ⣾⣿⠁⠈⣿⣷⡀ ",
|
|
@@ -56,39 +57,45 @@ const COLORS = [
|
|
|
56
57
|
"...............SSSSSSSS......................................................................................",
|
|
57
58
|
"................SSSSSS......................................................................................."
|
|
58
59
|
];
|
|
59
|
-
const BLUE = "\x1b[
|
|
60
|
-
const
|
|
61
|
-
const RESET = "\x1b[0m";
|
|
60
|
+
const BLUE = "\x1b[94m";
|
|
61
|
+
const DEFAULT_FOREGROUND = "\x1b[39m";
|
|
62
62
|
function paint(shape, colors) {
|
|
63
63
|
let out = "";
|
|
64
|
-
let
|
|
64
|
+
let blueActive = false;
|
|
65
65
|
for (let i = 0; i < shape.length; i++) {
|
|
66
66
|
const glyph = shape[i];
|
|
67
67
|
const want = colors[i] ?? ".";
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
out += BLUE;
|
|
73
|
-
else if (want === "S")
|
|
74
|
-
out += SILVER;
|
|
75
|
-
current = want;
|
|
68
|
+
const wantBlue = want === "B";
|
|
69
|
+
if (wantBlue !== blueActive) {
|
|
70
|
+
out += wantBlue ? BLUE : DEFAULT_FOREGROUND;
|
|
71
|
+
blueActive = wantBlue;
|
|
76
72
|
}
|
|
77
73
|
out += glyph;
|
|
78
74
|
}
|
|
79
|
-
if (
|
|
80
|
-
out +=
|
|
75
|
+
if (blueActive)
|
|
76
|
+
out += DEFAULT_FOREGROUND;
|
|
81
77
|
return out;
|
|
82
78
|
}
|
|
83
|
-
function
|
|
84
|
-
if (
|
|
79
|
+
function envForcesColor(value) {
|
|
80
|
+
if (value === undefined)
|
|
85
81
|
return false;
|
|
86
|
-
|
|
82
|
+
return value !== "0" && value.toLowerCase() !== "false";
|
|
83
|
+
}
|
|
84
|
+
function supportsColor(options = {}) {
|
|
85
|
+
const env = options.env ?? process.env;
|
|
86
|
+
if (env["NO_COLOR"] !== undefined)
|
|
87
|
+
return false;
|
|
88
|
+
if (options.forceColor)
|
|
87
89
|
return true;
|
|
88
|
-
|
|
90
|
+
if (env["FORCE_COLOR"] !== undefined)
|
|
91
|
+
return envForcesColor(env["FORCE_COLOR"]);
|
|
92
|
+
return Boolean(options.stdoutIsTTY ?? process.stdout.isTTY);
|
|
89
93
|
}
|
|
90
|
-
export function
|
|
91
|
-
const useColor = supportsColor();
|
|
94
|
+
export function renderBanner(options = {}) {
|
|
95
|
+
const useColor = supportsColor(options);
|
|
92
96
|
const lines = SHAPE.map((row, i) => (useColor ? paint(row, COLORS[i] ?? "") : row));
|
|
93
|
-
|
|
97
|
+
return lines.join("\n") + "\n\n";
|
|
98
|
+
}
|
|
99
|
+
export function printBanner(options = {}) {
|
|
100
|
+
process.stdout.write(renderBanner(options));
|
|
94
101
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { BaseCommand } from "../../base-command.js";
|
|
2
|
+
export default class Export extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
address: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
static flags: {
|
|
9
|
+
name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
publicKey: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
path: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
includePrivateKey: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
|
+
quiet: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
|
+
};
|
|
16
|
+
private _printProgress;
|
|
17
|
+
run(): Promise<void>;
|
|
18
|
+
/** Start the export on the RPC server and resolve with the terminal record (progress === 1). */
|
|
19
|
+
private _runExport;
|
|
20
|
+
/** Download the finished snapshot to destPath, verifying its sha256 against the export record. */
|
|
21
|
+
private _downloadAndVerify;
|
|
22
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { Args, Flags } from "@oclif/core";
|
|
2
|
+
import { BaseCommand } from "../../base-command.js";
|
|
3
|
+
import defaults from "../../../common-utils/defaults.js";
|
|
4
|
+
import { PKCLogger } from "../../../util.js";
|
|
5
|
+
import { createHash } from "node:crypto";
|
|
6
|
+
import { createWriteStream } from "node:fs";
|
|
7
|
+
import fs from "node:fs/promises";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import { Readable } from "node:stream";
|
|
10
|
+
import { pipeline } from "node:stream/promises";
|
|
11
|
+
export default class Export extends BaseCommand {
|
|
12
|
+
static description = "Export a local community to a SQLite snapshot file. The export runs on the RPC server (daemon); once finished the snapshot is downloaded and its sha256 checksum is verified. Pass --includePrivateKey to produce a restorable backup that keeps the community's address.";
|
|
13
|
+
static examples = [
|
|
14
|
+
"bitsocial community export plebmusic.bso",
|
|
15
|
+
"bitsocial community export plebmusic.bso --includePrivateKey -o ./backups/plebmusic.sqlite",
|
|
16
|
+
"bitsocial community export --name my-community",
|
|
17
|
+
"bitsocial community export --publicKey 12D3KooWG3XbzoVyAE6Y9vHZKF64Yuuu4TjdgQKedk14iYmTEPWu"
|
|
18
|
+
];
|
|
19
|
+
static args = {
|
|
20
|
+
address: Args.string({
|
|
21
|
+
name: "address",
|
|
22
|
+
required: false,
|
|
23
|
+
description: "Address of the community to export"
|
|
24
|
+
})
|
|
25
|
+
};
|
|
26
|
+
static flags = {
|
|
27
|
+
name: Flags.string({
|
|
28
|
+
description: "Name of the community to export"
|
|
29
|
+
}),
|
|
30
|
+
publicKey: Flags.string({
|
|
31
|
+
description: "Public key of the community to export"
|
|
32
|
+
}),
|
|
33
|
+
path: Flags.string({
|
|
34
|
+
char: "o",
|
|
35
|
+
description: "Destination file for the downloaded snapshot (default: <dataPath>/exports/<address>_<datetime>.sqlite)"
|
|
36
|
+
}),
|
|
37
|
+
includePrivateKey: Flags.boolean({
|
|
38
|
+
default: false,
|
|
39
|
+
description: "Ask the RPC server to include the community signer's private key in the export. Required for a restorable backup that keeps the same community address. The daemon may refuse (see `bitsocial daemon --no-allowPrivateKeyExport`)"
|
|
40
|
+
}),
|
|
41
|
+
force: Flags.boolean({
|
|
42
|
+
default: false,
|
|
43
|
+
description: "Overwrite the destination file if it already exists"
|
|
44
|
+
}),
|
|
45
|
+
quiet: Flags.boolean({
|
|
46
|
+
char: "q",
|
|
47
|
+
default: false,
|
|
48
|
+
description: "Suppress progress output; only print the path of the downloaded snapshot"
|
|
49
|
+
})
|
|
50
|
+
};
|
|
51
|
+
_printProgress(quiet, message) {
|
|
52
|
+
if (!quiet)
|
|
53
|
+
process.stderr.write(message);
|
|
54
|
+
}
|
|
55
|
+
async run() {
|
|
56
|
+
const { args, flags } = await this.parse(Export);
|
|
57
|
+
const log = PKCLogger("bitsocial-cli:commands:community:export");
|
|
58
|
+
log(`args: `, args);
|
|
59
|
+
log(`flags: `, flags);
|
|
60
|
+
const lookupParam = {};
|
|
61
|
+
if (args.address)
|
|
62
|
+
lookupParam.address = args.address;
|
|
63
|
+
if (flags.name)
|
|
64
|
+
lookupParam.name = flags.name;
|
|
65
|
+
if (flags.publicKey)
|
|
66
|
+
lookupParam.publicKey = flags.publicKey;
|
|
67
|
+
if (Object.keys(lookupParam).length === 0) {
|
|
68
|
+
this.error("At least one of address argument, --name, or --publicKey must be provided");
|
|
69
|
+
}
|
|
70
|
+
const pkc = await this._connectToPkcRpc(flags.pkcRpcUrl.toString());
|
|
71
|
+
// Cancel the in-flight export server-side on Ctrl+C. A second Ctrl+C force-exits
|
|
72
|
+
// (the handler is registered with `once`, so the default SIGINT behavior is restored).
|
|
73
|
+
const abortController = new AbortController();
|
|
74
|
+
const onSigint = () => {
|
|
75
|
+
this._printProgress(flags.quiet, "\nCancelling export... (Ctrl+C again to force exit)\n");
|
|
76
|
+
abortController.abort();
|
|
77
|
+
};
|
|
78
|
+
process.once("SIGINT", onSigint);
|
|
79
|
+
try {
|
|
80
|
+
const community = (await pkc.createCommunity(lookupParam));
|
|
81
|
+
if (typeof community.export !== "function") {
|
|
82
|
+
this.error(`Community is not local to the RPC server at ${flags.pkcRpcUrl}. Only communities created on this daemon can be exported`);
|
|
83
|
+
}
|
|
84
|
+
const exportableCommunity = community;
|
|
85
|
+
// Datetime in the filename matches the daemon log convention (ISO 8601 with ':' → '-')
|
|
86
|
+
// so repeated exports never collide and snapshots sort chronologically
|
|
87
|
+
const defaultFilename = `${exportableCommunity.address}_${new Date().toISOString().replace(/:/g, "-")}.sqlite`;
|
|
88
|
+
const destPath = path.resolve(flags.path ?? path.join(defaults.PKC_DATA_PATH, "exports", defaultFilename));
|
|
89
|
+
const destExists = await fs
|
|
90
|
+
.stat(destPath)
|
|
91
|
+
.then(() => true)
|
|
92
|
+
.catch(() => false);
|
|
93
|
+
if (destExists && !flags.force) {
|
|
94
|
+
this.error(`Destination file already exists: ${destPath}. Use --force to overwrite it`);
|
|
95
|
+
}
|
|
96
|
+
const finishedRecord = await this._runExport(exportableCommunity, flags.includePrivateKey, abortController.signal, flags.quiet);
|
|
97
|
+
log("Export finished on the RPC server", finishedRecord);
|
|
98
|
+
if (!finishedRecord.url) {
|
|
99
|
+
this.error(`Export ${finishedRecord.exportId} finished but the RPC server did not provide a download URL`);
|
|
100
|
+
}
|
|
101
|
+
// Mirrors pkc-js's rpcHttpOrigin: the ws[s]:// RPC URL with the protocol swapped to http[s]://
|
|
102
|
+
const parsedRpcUrl = new URL(flags.pkcRpcUrl.toString());
|
|
103
|
+
const expectedDownloadOrigin = `${parsedRpcUrl.protocol === "wss:" ? "https:" : "http:"}//${parsedRpcUrl.host}`;
|
|
104
|
+
await this._downloadAndVerify(finishedRecord, destPath, abortController.signal, flags.quiet, expectedDownloadOrigin);
|
|
105
|
+
this.log(destPath);
|
|
106
|
+
}
|
|
107
|
+
catch (e) {
|
|
108
|
+
console.error(e);
|
|
109
|
+
await pkc.destroy();
|
|
110
|
+
this.exit(1);
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
process.removeListener("SIGINT", onSigint);
|
|
114
|
+
}
|
|
115
|
+
await pkc.destroy();
|
|
116
|
+
}
|
|
117
|
+
/** Start the export on the RPC server and resolve with the terminal record (progress === 1). */
|
|
118
|
+
async _runExport(community, includePrivateKey, signal, quiet) {
|
|
119
|
+
const { exportId } = await community.export({ includePrivateKey, signal });
|
|
120
|
+
return new Promise((resolve, reject) => {
|
|
121
|
+
let lastPrintedPercent = -1;
|
|
122
|
+
const cleanup = () => {
|
|
123
|
+
community.removeListener("exportschange", checkRecords);
|
|
124
|
+
signal.removeEventListener("abort", onAbort);
|
|
125
|
+
};
|
|
126
|
+
// Don't wait for the server's terminal ERR_EXPORT_CANCELLED record — it never arrives if the
|
|
127
|
+
// daemon died or the connection dropped. pkc-js's own abort listener (registered inside
|
|
128
|
+
// community.export(), before this one) already dispatched cancelExport() to the server.
|
|
129
|
+
const onAbort = () => {
|
|
130
|
+
cleanup();
|
|
131
|
+
reject(new Error("Export cancelled"));
|
|
132
|
+
};
|
|
133
|
+
const checkRecords = (records) => {
|
|
134
|
+
const record = records.find((rec) => rec.exportId === exportId);
|
|
135
|
+
if (!record)
|
|
136
|
+
return;
|
|
137
|
+
if (record.error) {
|
|
138
|
+
cleanup();
|
|
139
|
+
reject(new Error(`Export failed (${record.error.code}): ${record.error.message}`));
|
|
140
|
+
}
|
|
141
|
+
else if (record.progress === 1) {
|
|
142
|
+
cleanup();
|
|
143
|
+
this._printProgress(quiet, `\rExporting ${community.address}: 100%\n`);
|
|
144
|
+
resolve(record);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
const percent = Math.floor(record.progress * 100);
|
|
148
|
+
if (percent !== lastPrintedPercent) {
|
|
149
|
+
lastPrintedPercent = percent;
|
|
150
|
+
this._printProgress(quiet, `\rExporting ${community.address}: ${percent}%`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
community.on("exportschange", checkRecords);
|
|
155
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
156
|
+
if (signal.aborted)
|
|
157
|
+
return onAbort();
|
|
158
|
+
// The terminal notification may have arrived before the listener was attached
|
|
159
|
+
checkRecords(community.exports);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
/** Download the finished snapshot to destPath, verifying its sha256 against the export record. */
|
|
163
|
+
async _downloadAndVerify(record, destPath, signal, quiet, expectedOrigin) {
|
|
164
|
+
// The export download contract is GET <rpc-http-origin>/exports/<exportId> — refuse anything else
|
|
165
|
+
// so a misconfigured/compromised RPC server can't use the CLI to fetch arbitrary URLs
|
|
166
|
+
const downloadUrl = new URL(record.url);
|
|
167
|
+
if (downloadUrl.origin !== expectedOrigin || !downloadUrl.pathname.startsWith("/exports/")) {
|
|
168
|
+
this.error(`Refusing to download export from unexpected URL ${record.url} (expected ${expectedOrigin}/exports/<exportId>)`);
|
|
169
|
+
}
|
|
170
|
+
this._printProgress(quiet, `Downloading snapshot from ${downloadUrl}\n`);
|
|
171
|
+
const response = await fetch(downloadUrl, { signal });
|
|
172
|
+
if (!response.ok || !response.body) {
|
|
173
|
+
this.error(`Failed to download export from ${record.url}: HTTP ${response.status}`);
|
|
174
|
+
}
|
|
175
|
+
await fs.mkdir(path.dirname(destPath), { recursive: true });
|
|
176
|
+
// Download to a .partial file so an interrupted/corrupted download never clobbers destPath
|
|
177
|
+
const partialPath = destPath + ".partial";
|
|
178
|
+
const hash = createHash("sha256");
|
|
179
|
+
try {
|
|
180
|
+
await pipeline(Readable.fromWeb(response.body), async function* (source) {
|
|
181
|
+
for await (const chunk of source) {
|
|
182
|
+
hash.update(chunk);
|
|
183
|
+
yield chunk;
|
|
184
|
+
}
|
|
185
|
+
}, createWriteStream(partialPath));
|
|
186
|
+
const downloadedSha256 = hash.digest("hex");
|
|
187
|
+
if (record.sha256 && downloadedSha256 !== record.sha256) {
|
|
188
|
+
throw new Error(`sha256 mismatch for downloaded export: expected ${record.sha256} but downloaded file hashes to ${downloadedSha256}`);
|
|
189
|
+
}
|
|
190
|
+
await fs.rename(partialPath, destPath);
|
|
191
|
+
}
|
|
192
|
+
catch (e) {
|
|
193
|
+
await fs.rm(partialPath, { force: true }).catch(() => { });
|
|
194
|
+
throw e;
|
|
195
|
+
}
|
|
196
|
+
this._printProgress(quiet, `Verified sha256 (${record.sha256}) and saved snapshot${record.size ? ` (${record.size} bytes)` : ""}\n`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
@@ -26,6 +26,7 @@ export default class Daemon extends Command {
|
|
|
26
26
|
pkcRpcUrl: import("@oclif/core/interfaces").OptionFlag<import("url").URL, import("@oclif/core/interfaces").CustomOptions>;
|
|
27
27
|
logPath: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
28
28
|
chainProviderUrls: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
|
|
29
|
+
allowPrivateKeyExport: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
29
30
|
};
|
|
30
31
|
static examples: string[];
|
|
31
32
|
private _setupLogger;
|
|
@@ -83,6 +83,11 @@ export default class Daemon extends Command {
|
|
|
83
83
|
description: "RPC URL(s) for .bso name resolution. Can be specified multiple times.",
|
|
84
84
|
multiple: true,
|
|
85
85
|
default: DEFAULT_PROVIDERS
|
|
86
|
+
}),
|
|
87
|
+
allowPrivateKeyExport: Flags.boolean({
|
|
88
|
+
description: "Allow RPC clients to request community exports that include the community signer's private key (`bitsocial community export --includePrivateKey`). Disable with --no-allowPrivateKeyExport when exposing the RPC to untrusted clients",
|
|
89
|
+
allowNo: true,
|
|
90
|
+
default: true
|
|
86
91
|
})
|
|
87
92
|
};
|
|
88
93
|
static examples = [
|
|
@@ -91,6 +96,7 @@ export default class Daemon extends Command {
|
|
|
91
96
|
"bitsocial daemon --pkcOptions.dataPath /tmp/bitsocial-datapath/",
|
|
92
97
|
"bitsocial daemon --pkcOptions.kuboRpcClientsOptions[0] https://remoteipfsnode.com",
|
|
93
98
|
"bitsocial daemon --chainProviderUrls https://mainnet.infura.io/v3/YOUR_KEY",
|
|
99
|
+
"bitsocial daemon --no-allowPrivateKeyExport",
|
|
94
100
|
];
|
|
95
101
|
_setupLogger(Logger) {
|
|
96
102
|
setupDebugLogger(Logger, { enableDefaultNamespace: true });
|
|
@@ -187,7 +193,8 @@ export default class Daemon extends Command {
|
|
|
187
193
|
return { logFilePath, stdoutWrite, fileLogger };
|
|
188
194
|
}
|
|
189
195
|
async run() {
|
|
190
|
-
|
|
196
|
+
// Daemon output is often viewed through Docker/systemd logs where stdout is not a TTY.
|
|
197
|
+
printBanner({ forceColor: true });
|
|
191
198
|
// Non-blocking update check — fire-and-forget, won't delay startup
|
|
192
199
|
import("../../update/npm-registry.js")
|
|
193
200
|
.then(({ fetchLatestVersion }) => fetchLatestVersion().then(async (latest) => {
|
|
@@ -378,7 +385,9 @@ export default class Daemon extends Command {
|
|
|
378
385
|
const loadedChallenges = await loadChallengesIntoPKC(mergedPkcOptions.dataPath);
|
|
379
386
|
if (loadedChallenges.length > 0)
|
|
380
387
|
console.log(`Loaded challenge packages: ${loadedChallenges.join(", ")}`);
|
|
381
|
-
daemonServer = await startDaemonServer(pkcRpcUrl, ipfsGatewayEndpoint, mergedPkcOptions
|
|
388
|
+
daemonServer = await startDaemonServer(pkcRpcUrl, ipfsGatewayEndpoint, mergedPkcOptions, {
|
|
389
|
+
allowPrivateKeyExport: flags.allowPrivateKeyExport
|
|
390
|
+
});
|
|
382
391
|
startedOwnRpc = true;
|
|
383
392
|
console.log(`pkc rpc: listening on ${pkcRpcUrl} (local connections only)`);
|
|
384
393
|
console.log(`pkc rpc: listening on ${pkcRpcUrl}${daemonServer.rpcAuthKey} (secret auth key for remote connections)`);
|
|
@@ -399,10 +408,6 @@ export default class Daemon extends Command {
|
|
|
399
408
|
console.log(`WebUI (${webui.name}${desc}): http://${remoteIpAddress}:${rpcPort}${webui.endpointRemote}`);
|
|
400
409
|
}
|
|
401
410
|
};
|
|
402
|
-
// RPC port was already verified free above (fail-fast); only the kuboRpcClientsOptions branch skips local kubo.
|
|
403
|
-
if (!pkcOptionsFromFlag?.kuboRpcClientsOptions)
|
|
404
|
-
await keepKuboUp();
|
|
405
|
-
await createOrConnectRpc();
|
|
406
411
|
let keepKuboUpInterval;
|
|
407
412
|
const { asyncExitHook } = await import("exit-hook");
|
|
408
413
|
const killKuboProcessGroup = (pid, signal) => {
|
|
@@ -494,6 +499,10 @@ export default class Daemon extends Command {
|
|
|
494
499
|
killKuboProcessGroup(kuboProcess.pid, "SIGKILL");
|
|
495
500
|
}
|
|
496
501
|
});
|
|
502
|
+
// RPC port was already verified free above (fail-fast); only the kuboRpcClientsOptions branch skips local kubo.
|
|
503
|
+
if (!pkcOptionsFromFlag?.kuboRpcClientsOptions)
|
|
504
|
+
await keepKuboUp();
|
|
505
|
+
await createOrConnectRpc();
|
|
497
506
|
keepKuboUpInterval = setInterval(async () => {
|
|
498
507
|
if (mainProcessExited)
|
|
499
508
|
return;
|
|
@@ -115,6 +115,7 @@ export default class Install extends Command {
|
|
|
115
115
|
// Restart daemons with the new binary
|
|
116
116
|
if (aliveDaemons.length > 0 && flags["restart-daemons"]) {
|
|
117
117
|
await this._restartDaemons(aliveDaemons);
|
|
118
|
+
this.log("To see the daemon logs run `bitsocial logs --stdout`");
|
|
118
119
|
}
|
|
119
120
|
}
|
|
120
121
|
async _restartDaemons(daemons) {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
export declare function startDaemonServer(rpcUrl: URL, ipfsGatewayUrl: URL, pkcOptions: any
|
|
1
|
+
export declare function startDaemonServer(rpcUrl: URL, ipfsGatewayUrl: URL, pkcOptions: any, rpcServerOptions?: {
|
|
2
|
+
allowPrivateKeyExport?: boolean;
|
|
3
|
+
}): Promise<{
|
|
2
4
|
rpcAuthKey: string;
|
|
3
5
|
listedSub: string[];
|
|
4
6
|
webuis: {
|
|
@@ -39,10 +39,23 @@ async function _generateRpcAuthKeyIfNotExisting(pkcDataPath) {
|
|
|
39
39
|
return pkcRpcAuthKey;
|
|
40
40
|
}
|
|
41
41
|
// The daemon server will host both RPC and webui on the same port
|
|
42
|
-
export async function startDaemonServer(rpcUrl, ipfsGatewayUrl, pkcOptions) {
|
|
42
|
+
export async function startDaemonServer(rpcUrl, ipfsGatewayUrl, pkcOptions, rpcServerOptions) {
|
|
43
43
|
// Start pkc-js RPC
|
|
44
44
|
const log = PKCLogger("bitsocial-cli:daemon:startDaemonServer");
|
|
45
45
|
const webuiExpressApp = express();
|
|
46
|
+
// GET /exports/<exportId> is streamed by pkc-js's own request listener, attached to this same
|
|
47
|
+
// http.Server inside PKCWsServer. Express must stay silent for those paths — its catch-all 404
|
|
48
|
+
// races the async pkc-js handler and clobbers the download (the CLI's `community export` would
|
|
49
|
+
// see HTTP 404). Other /exports/ paths fall through to express's 404 because pkc-js ignores
|
|
50
|
+
// them on a caller-supplied server and the request would otherwise hang unanswered.
|
|
51
|
+
// NOT mounted at "/exports": a mounted middleware strips the mount prefix from the shared
|
|
52
|
+
// req.url while the request is held, so pkc-js's listener would no longer recognize it.
|
|
53
|
+
webuiExpressApp.use((req, res, next) => {
|
|
54
|
+
const isExportDownload = /^\/exports\/[0-9a-fA-F-]{36}$/.test(req.path);
|
|
55
|
+
if (!isExportDownload)
|
|
56
|
+
return next();
|
|
57
|
+
// intentionally neither responds nor calls next(): pkc-js's listener owns this request
|
|
58
|
+
});
|
|
46
59
|
// Wait for bind to actually complete before returning. Calling express.listen() without
|
|
47
60
|
// awaiting 'listening' lets startup proceed before the port is accepting connections,
|
|
48
61
|
// and without an 'error' handler a bind failure becomes an uncaughtException that kills
|
|
@@ -68,7 +81,8 @@ export async function startDaemonServer(rpcUrl, ipfsGatewayUrl, pkcOptions) {
|
|
|
68
81
|
const rpcServer = await PKCRpc.default.PKCWsServer({
|
|
69
82
|
server: httpServer,
|
|
70
83
|
pkcOptions: pkcOptions,
|
|
71
|
-
authKey: rpcAuthKey
|
|
84
|
+
authKey: rpcAuthKey,
|
|
85
|
+
allowPrivateKeyExport: rpcServerOptions?.allowPrivateKeyExport
|
|
72
86
|
});
|
|
73
87
|
const webuisDir = path.join(__dirname, "..", "..", "dist", "webuis");
|
|
74
88
|
const webUiNames = (await fs.readdir(webuisDir, { withFileTypes: true })).filter((file) => file.isDirectory()).map((file) => file.name);
|
package/oclif.manifest.json
CHANGED
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"bitsocial daemon --pkcRpcUrl ws://localhost:53812",
|
|
10
10
|
"bitsocial daemon --pkcOptions.dataPath /tmp/bitsocial-datapath/",
|
|
11
11
|
"bitsocial daemon --pkcOptions.kuboRpcClientsOptions[0] https://remoteipfsnode.com",
|
|
12
|
-
"bitsocial daemon --chainProviderUrls https://mainnet.infura.io/v3/YOUR_KEY"
|
|
12
|
+
"bitsocial daemon --chainProviderUrls https://mainnet.infura.io/v3/YOUR_KEY",
|
|
13
|
+
"bitsocial daemon --no-allowPrivateKeyExport"
|
|
13
14
|
],
|
|
14
15
|
"flags": {
|
|
15
16
|
"pkcRpcUrl": {
|
|
@@ -44,6 +45,12 @@
|
|
|
44
45
|
"hasDynamicHelp": false,
|
|
45
46
|
"multiple": true,
|
|
46
47
|
"type": "option"
|
|
48
|
+
},
|
|
49
|
+
"allowPrivateKeyExport": {
|
|
50
|
+
"description": "Allow RPC clients to request community exports that include the community signer's private key (`bitsocial community export --includePrivateKey`). Disable with --no-allowPrivateKeyExport when exposing the RPC to untrusted clients",
|
|
51
|
+
"name": "allowPrivateKeyExport",
|
|
52
|
+
"allowNo": true,
|
|
53
|
+
"type": "boolean"
|
|
47
54
|
}
|
|
48
55
|
},
|
|
49
56
|
"hasDynamicHelp": false,
|
|
@@ -459,6 +466,91 @@
|
|
|
459
466
|
"edit.js"
|
|
460
467
|
]
|
|
461
468
|
},
|
|
469
|
+
"community:export": {
|
|
470
|
+
"aliases": [],
|
|
471
|
+
"args": {
|
|
472
|
+
"address": {
|
|
473
|
+
"description": "Address of the community to export",
|
|
474
|
+
"name": "address",
|
|
475
|
+
"required": false
|
|
476
|
+
}
|
|
477
|
+
},
|
|
478
|
+
"description": "Export a local community to a SQLite snapshot file. The export runs on the RPC server (daemon); once finished the snapshot is downloaded and its sha256 checksum is verified. Pass --includePrivateKey to produce a restorable backup that keeps the community's address.",
|
|
479
|
+
"examples": [
|
|
480
|
+
"bitsocial community export plebmusic.bso",
|
|
481
|
+
"bitsocial community export plebmusic.bso --includePrivateKey -o ./backups/plebmusic.sqlite",
|
|
482
|
+
"bitsocial community export --name my-community",
|
|
483
|
+
"bitsocial community export --publicKey 12D3KooWG3XbzoVyAE6Y9vHZKF64Yuuu4TjdgQKedk14iYmTEPWu"
|
|
484
|
+
],
|
|
485
|
+
"flags": {
|
|
486
|
+
"pkcRpcUrl": {
|
|
487
|
+
"name": "pkcRpcUrl",
|
|
488
|
+
"required": true,
|
|
489
|
+
"summary": "URL to PKC RPC",
|
|
490
|
+
"default": "ws://localhost:9138/",
|
|
491
|
+
"hasDynamicHelp": false,
|
|
492
|
+
"multiple": false,
|
|
493
|
+
"type": "option"
|
|
494
|
+
},
|
|
495
|
+
"name": {
|
|
496
|
+
"description": "Name of the community to export",
|
|
497
|
+
"name": "name",
|
|
498
|
+
"hasDynamicHelp": false,
|
|
499
|
+
"multiple": false,
|
|
500
|
+
"type": "option"
|
|
501
|
+
},
|
|
502
|
+
"publicKey": {
|
|
503
|
+
"description": "Public key of the community to export",
|
|
504
|
+
"name": "publicKey",
|
|
505
|
+
"hasDynamicHelp": false,
|
|
506
|
+
"multiple": false,
|
|
507
|
+
"type": "option"
|
|
508
|
+
},
|
|
509
|
+
"path": {
|
|
510
|
+
"char": "o",
|
|
511
|
+
"description": "Destination file for the downloaded snapshot (default: <dataPath>/exports/<address>_<datetime>.sqlite)",
|
|
512
|
+
"name": "path",
|
|
513
|
+
"hasDynamicHelp": false,
|
|
514
|
+
"multiple": false,
|
|
515
|
+
"type": "option"
|
|
516
|
+
},
|
|
517
|
+
"includePrivateKey": {
|
|
518
|
+
"description": "Ask the RPC server to include the community signer's private key in the export. Required for a restorable backup that keeps the same community address. The daemon may refuse (see `bitsocial daemon --no-allowPrivateKeyExport`)",
|
|
519
|
+
"name": "includePrivateKey",
|
|
520
|
+
"allowNo": false,
|
|
521
|
+
"type": "boolean"
|
|
522
|
+
},
|
|
523
|
+
"force": {
|
|
524
|
+
"description": "Overwrite the destination file if it already exists",
|
|
525
|
+
"name": "force",
|
|
526
|
+
"allowNo": false,
|
|
527
|
+
"type": "boolean"
|
|
528
|
+
},
|
|
529
|
+
"quiet": {
|
|
530
|
+
"char": "q",
|
|
531
|
+
"description": "Suppress progress output; only print the path of the downloaded snapshot",
|
|
532
|
+
"name": "quiet",
|
|
533
|
+
"allowNo": false,
|
|
534
|
+
"type": "boolean"
|
|
535
|
+
}
|
|
536
|
+
},
|
|
537
|
+
"hasDynamicHelp": false,
|
|
538
|
+
"hiddenAliases": [],
|
|
539
|
+
"id": "community:export",
|
|
540
|
+
"pluginAlias": "@bitsocial/bitsocial-cli",
|
|
541
|
+
"pluginName": "@bitsocial/bitsocial-cli",
|
|
542
|
+
"pluginType": "core",
|
|
543
|
+
"strict": true,
|
|
544
|
+
"enableJsonFlag": false,
|
|
545
|
+
"isESM": true,
|
|
546
|
+
"relativePath": [
|
|
547
|
+
"dist",
|
|
548
|
+
"cli",
|
|
549
|
+
"commands",
|
|
550
|
+
"community",
|
|
551
|
+
"export.js"
|
|
552
|
+
]
|
|
553
|
+
},
|
|
462
554
|
"community:get": {
|
|
463
555
|
"aliases": [],
|
|
464
556
|
"args": {
|
|
@@ -770,5 +862,5 @@
|
|
|
770
862
|
]
|
|
771
863
|
}
|
|
772
864
|
},
|
|
773
|
-
"version": "0.19.
|
|
865
|
+
"version": "0.19.65"
|
|
774
866
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bitsocial/bitsocial-cli",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.65",
|
|
4
4
|
"description": "Command line interface to Bitsocial API",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"homepage": "https://github.com/bitsocialnet/bitsocial-cli",
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
"@oclif/plugin-help": "6.2.36",
|
|
120
120
|
"@oclif/plugin-not-found": "3.2.73",
|
|
121
121
|
"@oclif/table": "0.5.1",
|
|
122
|
-
"@pkcprotocol/pkc-js": "0.0.
|
|
122
|
+
"@pkcprotocol/pkc-js": "0.0.41",
|
|
123
123
|
"dataobject-parser": "1.2.22",
|
|
124
124
|
"decompress": "4.2.1",
|
|
125
125
|
"env-paths": "2.2.1",
|