@bitsocial/bitsocial-cli 0.19.59 → 0.19.60

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 CHANGED
@@ -344,7 +344,7 @@ EXAMPLES
344
344
  $ bitsocial challenge install ./my-local-challenge
345
345
  ```
346
346
 
347
- _See code: [src/cli/commands/challenge/install.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.59/src/cli/commands/challenge/install.ts)_
347
+ _See code: [src/cli/commands/challenge/install.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.60/src/cli/commands/challenge/install.ts)_
348
348
 
349
349
  ## `bitsocial challenge list`
350
350
 
@@ -367,7 +367,7 @@ EXAMPLES
367
367
  $ bitsocial challenge list -q
368
368
  ```
369
369
 
370
- _See code: [src/cli/commands/challenge/list.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.59/src/cli/commands/challenge/list.ts)_
370
+ _See code: [src/cli/commands/challenge/list.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.60/src/cli/commands/challenge/list.ts)_
371
371
 
372
372
  ## `bitsocial challenge remove NAME`
373
373
 
@@ -392,7 +392,7 @@ EXAMPLES
392
392
  $ bitsocial challenge remove @scope/my-challenge
393
393
  ```
394
394
 
395
- _See code: [src/cli/commands/challenge/remove.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.59/src/cli/commands/challenge/remove.ts)_
395
+ _See code: [src/cli/commands/challenge/remove.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.60/src/cli/commands/challenge/remove.ts)_
396
396
 
397
397
  ## `bitsocial community create`
398
398
 
@@ -422,7 +422,7 @@ EXAMPLES
422
422
  $ bitsocial community create --jsonFile ./create-options.json
423
423
  ```
424
424
 
425
- _See code: [src/cli/commands/community/create.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.59/src/cli/commands/community/create.ts)_
425
+ _See code: [src/cli/commands/community/create.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.60/src/cli/commands/community/create.ts)_
426
426
 
427
427
  ## `bitsocial community delete ADDRESSES`
428
428
 
@@ -447,7 +447,7 @@ EXAMPLES
447
447
  $ bitsocial community delete 12D3KooWG3XbzoVyAE6Y9vHZKF64Yuuu4TjdgQKedk14iYmTEPWu
448
448
  ```
449
449
 
450
- _See code: [src/cli/commands/community/delete.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.59/src/cli/commands/community/delete.ts)_
450
+ _See code: [src/cli/commands/community/delete.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.60/src/cli/commands/community/delete.ts)_
451
451
 
452
452
  ## `bitsocial community edit ADDRESS`
453
453
 
@@ -517,7 +517,7 @@ EXAMPLES
517
517
  $ bitsocial community edit bitsocial.bso --jsonFile ./edit-options.json
518
518
  ```
519
519
 
520
- _See code: [src/cli/commands/community/edit.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.59/src/cli/commands/community/edit.ts)_
520
+ _See code: [src/cli/commands/community/edit.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.60/src/cli/commands/community/edit.ts)_
521
521
 
522
522
  ## `bitsocial community get [ADDRESS]`
523
523
 
@@ -548,7 +548,7 @@ EXAMPLES
548
548
  $ bitsocial community get --publicKey 12D3KooWG3XbzoVyAE6Y9vHZKF64Yuuu4TjdgQKedk14iYmTEPWu
549
549
  ```
550
550
 
551
- _See code: [src/cli/commands/community/get.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.59/src/cli/commands/community/get.ts)_
551
+ _See code: [src/cli/commands/community/get.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.60/src/cli/commands/community/get.ts)_
552
552
 
553
553
  ## `bitsocial community list`
554
554
 
@@ -571,7 +571,7 @@ EXAMPLES
571
571
  $ bitsocial community list
572
572
  ```
573
573
 
574
- _See code: [src/cli/commands/community/list.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.59/src/cli/commands/community/list.ts)_
574
+ _See code: [src/cli/commands/community/list.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.60/src/cli/commands/community/list.ts)_
575
575
 
576
576
  ## `bitsocial community start ADDRESSES`
577
577
 
@@ -605,7 +605,7 @@ EXAMPLES
605
605
  $ bitsocial community start $(bitsocial community list -q) --concurrency 1
606
606
  ```
607
607
 
608
- _See code: [src/cli/commands/community/start.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.59/src/cli/commands/community/start.ts)_
608
+ _See code: [src/cli/commands/community/start.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.60/src/cli/commands/community/start.ts)_
609
609
 
610
610
  ## `bitsocial community stop ADDRESSES`
611
611
 
@@ -630,7 +630,7 @@ EXAMPLES
630
630
  $ bitsocial community stop Qmb99crTbSUfKXamXwZBe829Vf6w5w5TktPkb6WstC9RFW
631
631
  ```
632
632
 
633
- _See code: [src/cli/commands/community/stop.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.59/src/cli/commands/community/stop.ts)_
633
+ _See code: [src/cli/commands/community/stop.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.60/src/cli/commands/community/stop.ts)_
634
634
 
635
635
  ## `bitsocial daemon`
636
636
 
@@ -671,7 +671,7 @@ EXAMPLES
671
671
  $ bitsocial daemon --chainProviderUrls https://mainnet.infura.io/v3/YOUR_KEY
672
672
  ```
673
673
 
674
- _See code: [src/cli/commands/daemon.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.59/src/cli/commands/daemon.ts)_
674
+ _See code: [src/cli/commands/daemon.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.60/src/cli/commands/daemon.ts)_
675
675
 
676
676
  ## `bitsocial help [COMMAND]`
677
677
 
@@ -737,7 +737,7 @@ EXAMPLES
737
737
  $ bitsocial logs --stdout -f
738
738
  ```
739
739
 
740
- _See code: [src/cli/commands/logs.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.59/src/cli/commands/logs.ts)_
740
+ _See code: [src/cli/commands/logs.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.60/src/cli/commands/logs.ts)_
741
741
 
742
742
  ## `bitsocial update check`
743
743
 
@@ -754,7 +754,7 @@ EXAMPLES
754
754
  $ bitsocial update check
755
755
  ```
756
756
 
757
- _See code: [src/cli/commands/update/check.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.59/src/cli/commands/update/check.ts)_
757
+ _See code: [src/cli/commands/update/check.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.60/src/cli/commands/update/check.ts)_
758
758
 
759
759
  ## `bitsocial update install [VERSION]`
760
760
 
@@ -786,7 +786,7 @@ EXAMPLES
786
786
  $ bitsocial update install --no-restart-daemons
787
787
  ```
788
788
 
789
- _See code: [src/cli/commands/update/install.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.59/src/cli/commands/update/install.ts)_
789
+ _See code: [src/cli/commands/update/install.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.60/src/cli/commands/update/install.ts)_
790
790
 
791
791
  ## `bitsocial update versions`
792
792
 
@@ -808,7 +808,7 @@ EXAMPLES
808
808
  $ bitsocial update versions --limit 5
809
809
  ```
810
810
 
811
- _See code: [src/cli/commands/update/versions.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.59/src/cli/commands/update/versions.ts)_
811
+ _See code: [src/cli/commands/update/versions.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.60/src/cli/commands/update/versions.ts)_
812
812
  <!-- commandsstop -->
813
813
 
814
814
  ## Contribution
@@ -5,7 +5,6 @@ export interface KeepKuboUpTickDeps {
5
5
  pkcOptionsFromFlag: {
6
6
  kuboRpcClientsOptions?: unknown;
7
7
  } | undefined;
8
- usingDifferentProcessRpc: boolean;
9
8
  hasKuboProcess: boolean;
10
9
  hasPendingKuboStart: boolean;
11
10
  keepKuboUp: () => Promise<void>;
@@ -44,13 +44,13 @@ const defaultPkcOptions = {
44
44
  export async function runKeepKuboUpTick(deps) {
45
45
  let isRpcPortTaken = false;
46
46
  try {
47
- isRpcPortTaken = await deps.tcpPortUsedCheck(Number(deps.pkcRpcUrl.port), deps.pkcRpcUrl.hostname);
48
- if (!deps.pkcOptionsFromFlag?.kuboRpcClientsOptions && !isRpcPortTaken && !deps.usingDifferentProcessRpc)
47
+ isRpcPortTaken = await deps.tcpPortUsedCheck(Number(deps.pkcRpcUrl.port), toConnectableHostname(deps.pkcRpcUrl.hostname));
48
+ if (!deps.pkcOptionsFromFlag?.kuboRpcClientsOptions && !isRpcPortTaken)
49
49
  await deps.keepKuboUp();
50
- else if (deps.pkcOptionsFromFlag?.kuboRpcClientsOptions && !deps.usingDifferentProcessRpc)
50
+ else if (deps.pkcOptionsFromFlag?.kuboRpcClientsOptions)
51
51
  await deps.keepKuboUp();
52
52
  // Retry if kubo died and onKuboExit's restart attempt failed (e.g. transient port conflict)
53
- else if (!deps.hasKuboProcess && !deps.hasPendingKuboStart && !deps.usingDifferentProcessRpc)
53
+ else if (!deps.hasKuboProcess && !deps.hasPendingKuboStart)
54
54
  await deps.keepKuboUp();
55
55
  }
56
56
  catch (error) {
@@ -225,6 +225,14 @@ export default class Daemon extends Command {
225
225
  this.error("Can't provide pkcOptions.kuboRpcClientsOptions as an array with more than 1 element, or as a non array");
226
226
  if (pkcOptionsFromFlag?.ipfsGatewayUrls && pkcOptionsFromFlag.ipfsGatewayUrls.length !== 1)
227
227
  this.error("Can't provide pkcOptions.ipfsGatewayUrls as an array with more than 1 element, or as a non array");
228
+ const rpcConnectHostname = toConnectableHostname(pkcRpcUrl.hostname);
229
+ const isRpcPortAlreadyTaken = await tcpPortUsed.check(Number(pkcRpcUrl.port), rpcConnectHostname);
230
+ if (isRpcPortAlreadyTaken) {
231
+ this.error(`PKC RPC port is already in use at ${pkcRpcUrl} (another bitsocial daemon is likely running). ` +
232
+ `To talk to the running daemon, use other bitsocial commands with --pkcRpcUrl ${pkcRpcUrl} ` +
233
+ `(e.g. 'bitsocial community list --pkcRpcUrl ${pkcRpcUrl}'). ` +
234
+ `To run a second daemon, restart with a different port, e.g. --pkcRpcUrl ws://${pkcRpcUrl.hostname}:${Number(pkcRpcUrl.port) + 1}.`);
235
+ }
228
236
  const ipfsConfig = await loadKuboConfigFile(pkcOptionsFromFlag?.dataPath || defaultPkcOptions.dataPath);
229
237
  const kuboRpcEndpoint = pkcOptionsFromFlag?.kuboRpcClientsOptions
230
238
  ? new URL(pkcOptionsFromFlag.kuboRpcClientsOptions[0].toString())
@@ -264,7 +272,7 @@ export default class Daemon extends Command {
264
272
  if (mainProcessExited)
265
273
  return;
266
274
  const kuboApiPort = Number(kuboRpcEndpoint.port);
267
- if (kuboProcess || pendingKuboStart || usingDifferentProcessRpc)
275
+ if (kuboProcess || pendingKuboStart)
268
276
  return; // already started, no need to intervene
269
277
  const connectHostname = toConnectableHostname(kuboRpcEndpoint.hostname);
270
278
  const isKuboApiPortTaken = await tcpPortUsed.check(kuboApiPort, connectHostname);
@@ -353,34 +361,24 @@ export default class Daemon extends Command {
353
361
  currentProcess.once("exit", onKuboExit);
354
362
  };
355
363
  let startedOwnRpc = false;
356
- let usingDifferentProcessRpc = false;
357
364
  let daemonServer;
358
365
  const createOrConnectRpc = async () => {
359
366
  if (mainProcessExited)
360
367
  return;
361
368
  if (startedOwnRpc)
362
369
  return;
363
- const isRpcPortTaken = await tcpPortUsed.check(Number(pkcRpcUrl.port), pkcRpcUrl.hostname);
364
- if (isRpcPortTaken && usingDifferentProcessRpc)
365
- return;
370
+ // Re-check the port: the early fail-fast at startup is a few ms before this runs,
371
+ // so a TOCTOU race could let another process grab the port in between. If that
372
+ // happens we must fail rather than silently leaving the daemon without an RPC.
373
+ const isRpcPortTaken = await tcpPortUsed.check(Number(pkcRpcUrl.port), rpcConnectHostname);
366
374
  if (isRpcPortTaken) {
367
- log(`PKC RPC is already running (${pkcRpcUrl}) by another program. bitsocial-cli will use the running RPC server, and if shuts down, bitsocial-cli will start a new RPC instance`);
368
- console.log("Using the already started RPC server at:", pkcRpcUrl);
369
- console.log("bitsocial-cli daemon will monitor the PKC RPC and kubo ipfs API to make sure they're always up");
370
- const PKC = await import("@pkcprotocol/pkc-js");
371
- const pkc = await PKC.default({ pkcRpcClientsOptions: [pkcRpcUrl.toString()] });
372
- await new Promise((resolve) => pkc.once("communitieschange", resolve));
373
- pkc.on("error", (error) => console.error("Error from pkc instance", error));
374
- console.log(`Communities in data path: `, pkc.communities);
375
- usingDifferentProcessRpc = true;
376
- return;
375
+ throw new Error(`PKC RPC port ${pkcRpcUrl.hostname}:${pkcRpcUrl.port} (${pkcRpcUrl}) became occupied before the daemon could bind it.`);
377
376
  }
378
377
  // Load installed challenge packages before starting the RPC server
379
378
  const loadedChallenges = await loadChallengesIntoPKC(mergedPkcOptions.dataPath);
380
379
  if (loadedChallenges.length > 0)
381
380
  console.log(`Loaded challenge packages: ${loadedChallenges.join(", ")}`);
382
381
  daemonServer = await startDaemonServer(pkcRpcUrl, ipfsGatewayEndpoint, mergedPkcOptions);
383
- usingDifferentProcessRpc = false;
384
382
  startedOwnRpc = true;
385
383
  console.log(`pkc rpc: listening on ${pkcRpcUrl} (local connections only)`);
386
384
  console.log(`pkc rpc: listening on ${pkcRpcUrl}${daemonServer.rpcAuthKey} (secret auth key for remote connections)`);
@@ -401,8 +399,8 @@ export default class Daemon extends Command {
401
399
  console.log(`WebUI (${webui.name}${desc}): http://${remoteIpAddress}:${rpcPort}${webui.endpointRemote}`);
402
400
  }
403
401
  };
404
- const isRpcPortTaken = await tcpPortUsed.check(Number(pkcRpcUrl.port), pkcRpcUrl.hostname);
405
- if (!pkcOptionsFromFlag?.kuboRpcClientsOptions && !isRpcPortTaken && !usingDifferentProcessRpc)
402
+ // RPC port was already verified free above (fail-fast); only the kuboRpcClientsOptions branch skips local kubo.
403
+ if (!pkcOptionsFromFlag?.kuboRpcClientsOptions)
406
404
  await keepKuboUp();
407
405
  await createOrConnectRpc();
408
406
  let keepKuboUpInterval;
@@ -503,7 +501,6 @@ export default class Daemon extends Command {
503
501
  pkcRpcUrl,
504
502
  tcpPortUsedCheck: (port, host) => tcpPortUsed.check(port, host),
505
503
  pkcOptionsFromFlag,
506
- usingDifferentProcessRpc,
507
504
  hasKuboProcess: !!kuboProcess,
508
505
  hasPendingKuboStart: !!pendingKuboStart,
509
506
  keepKuboUp,
@@ -1,3 +1,4 @@
1
1
  import { ChildProcessWithoutNullStreams } from "child_process";
2
2
  export declare function mergeCliDefaultsIntoIpfsConfig(log: any, ipfsConfigPath: string, apiUrl: URL, gatewayUrl: URL): Promise<void>;
3
+ export declare function _gatherChildOutput(log: any, child: ChildProcessWithoutNullStreams): Promise<null>;
3
4
  export declare function startKuboNode(apiUrl: URL, gatewayUrl: URL, dataPath: string, onSpawn?: (process: ChildProcessWithoutNullStreams) => void): Promise<ChildProcessWithoutNullStreams>;
@@ -64,32 +64,37 @@ export async function mergeCliDefaultsIntoIpfsConfig(log, ipfsConfigPath, apiUrl
64
64
  }
65
65
  // use this custom function instead of spawnSync for better logging
66
66
  // also spawnSync might have been causing crash on start on windows
67
- function _spawnAsync(log, ...args) {
67
+ // Listens on 'close' (not 'exit') so all stderr 'data' events have been delivered
68
+ // before we read errorMessage — otherwise on macOS a fast-exiting child can deliver
69
+ // its exit signal before its stderr drains, producing a rejection with an empty
70
+ // message and breaking the "configuration file already exists" suppression upstream.
71
+ export function _gatherChildOutput(log, child) {
68
72
  return new Promise((resolve, reject) => {
69
- //@ts-ignore
70
- const spawedProcess = spawn(...args);
71
73
  let errorMessage = "";
72
- spawedProcess.on("exit", (exitCode, signal) => {
74
+ child.on("close", (exitCode, signal) => {
73
75
  if (exitCode === 0)
74
- resolve(null);
75
- else {
76
- const error = new Error(errorMessage);
77
- Object.assign(error, { exitCode, pid: spawedProcess.pid, signal });
78
- reject(error);
79
- }
76
+ return resolve(null);
77
+ const error = new Error(errorMessage);
78
+ Object.assign(error, { exitCode, pid: child.pid, signal });
79
+ reject(error);
80
80
  });
81
- spawedProcess.stderr.on("data", (data) => {
81
+ child.stderr.on("data", (data) => {
82
82
  log.trace(data.toString());
83
83
  errorMessage += data.toString();
84
84
  });
85
- spawedProcess.stdin.on("data", (data) => log.trace(data.toString()));
86
- spawedProcess.stdout.on("data", (data) => log.trace(data.toString()));
87
- spawedProcess.on("error", (data) => {
85
+ child.stdin.on("data", (data) => log.trace(data.toString()));
86
+ child.stdout.on("data", (data) => log.trace(data.toString()));
87
+ child.on("error", (data) => {
88
88
  errorMessage += data.toString();
89
89
  log.error(data.toString());
90
90
  });
91
91
  });
92
92
  }
93
+ function _spawnAsync(log, ...args) {
94
+ //@ts-ignore
95
+ const child = spawn(...args);
96
+ return _gatherChildOutput(log, child);
97
+ }
93
98
  let cachedMultiaddrFactory;
94
99
  async function getMultiaddrFactory() {
95
100
  if (!cachedMultiaddrFactory) {
@@ -770,5 +770,5 @@
770
770
  ]
771
771
  }
772
772
  },
773
- "version": "0.19.59"
773
+ "version": "0.19.60"
774
774
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitsocial/bitsocial-cli",
3
- "version": "0.19.59",
3
+ "version": "0.19.60",
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",