trac-peer 0.3.0 → 0.4.0

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 (61) hide show
  1. package/.github/workflows/publish.yml +10 -1
  2. package/DOCS.md +2 -4
  3. package/README.md +2 -2
  4. package/{src/dev → dev}/pokemonContract.js +3 -3
  5. package/{src/dev → dev}/pokemonProtocol.js +17 -12
  6. package/package.json +9 -5
  7. package/rpc/services.js +13 -12
  8. package/scripts/run-peer.mjs +40 -21
  9. package/src/api.js +65 -65
  10. package/src/{contract.js → artifacts/contract.js} +14 -58
  11. package/src/{feature.js → artifacts/feature.js} +3 -4
  12. package/src/{protocol.js → artifacts/protocol.js} +18 -35
  13. package/src/base/check.js +115 -0
  14. package/src/config/config.js +149 -0
  15. package/src/config/env.js +63 -0
  16. package/src/contractCheck.js +90 -0
  17. package/src/index.js +124 -759
  18. package/src/msbClient.js +62 -38
  19. package/src/operations/addAdmin/index.js +44 -0
  20. package/src/operations/addIndexer/index.js +64 -0
  21. package/src/operations/addWriter/index.js +64 -0
  22. package/src/operations/autoAddWriter/index.js +48 -0
  23. package/src/operations/deleteMessage/index.js +83 -0
  24. package/src/operations/enableTransactions/index.js +58 -0
  25. package/src/operations/enableWhitelist/index.js +59 -0
  26. package/src/operations/feature/index.js +64 -0
  27. package/src/operations/index.js +52 -0
  28. package/src/operations/msg/index.js +108 -0
  29. package/src/operations/muteStatus/index.js +72 -0
  30. package/src/operations/pinMessage/index.js +82 -0
  31. package/src/operations/removeWriter/index.js +64 -0
  32. package/src/operations/setAutoAddWriters/index.js +65 -0
  33. package/src/operations/setChatStatus/index.js +62 -0
  34. package/src/operations/setMod/index.js +60 -0
  35. package/src/operations/setNick/index.js +89 -0
  36. package/src/operations/setWhitelistStatus/index.js +60 -0
  37. package/src/operations/tx/index.js +142 -0
  38. package/src/operations/unpinMessage/index.js +73 -0
  39. package/src/operations/updateAdmin/index.js +63 -0
  40. package/src/tasks/transactionObserver.js +91 -0
  41. package/src/tasks/updater.js +57 -0
  42. package/src/terminal/handlers.js +494 -0
  43. package/src/terminal/index.js +123 -0
  44. package/src/transaction/transactionPool.js +38 -0
  45. package/src/utils/scheduler.js +118 -0
  46. package/src/utils/types.js +81 -0
  47. package/src/wallet.js +2 -1
  48. package/tests/acceptance/acceptance.test.js +4 -1
  49. package/tests/acceptance/rpc.test.js +37 -82
  50. package/tests/helpers/tmpdir.js +58 -0
  51. package/tests/unit/applyGuards.test.js +23 -26
  52. package/tests/unit/baseContractProtocol.test.js +10 -9
  53. package/tests/unit/cliTx.test.js +113 -0
  54. package/tests/unit/operations.test.js +560 -0
  55. package/tests/unit/unit.test.js +2 -0
  56. package/src/check.js +0 -565
  57. package/src/cli.js +0 -275
  58. package/src/dev/HyperMallConctract.js +0 -990
  59. package/src/dev/HyperMallProtocol.js +0 -689
  60. package/src/functions.js +0 -495
  61. package/src/permissions.js +0 -63
@@ -22,7 +22,16 @@ jobs:
22
22
  node-version: 22
23
23
  cache: 'npm'
24
24
  - run: npm ci
25
- - run: npm run test:all
25
+ - name: Install bare
26
+ run: npm i -g bare
27
+ - name: Verify bare install
28
+ run: |
29
+ which bare
30
+ bare --version
31
+ - name: Unit tests (node + bare)
32
+ run: npm run test:unit:all
33
+ - name: Acceptance tests (node + bare)
34
+ run: npm run test:acceptance:all
26
35
  release:
27
36
  needs: test
28
37
  if: startsWith(github.ref, 'refs/tags/')
package/DOCS.md CHANGED
@@ -74,7 +74,7 @@ npm run peer:run -- --msb-bootstrap=<hex32> --msb-channel=<channel>
74
74
  /deploy_subnet
75
75
  /add_admin --address <your-peer-publicKey-hex>
76
76
  /tx --command "ping hello"
77
- /get --key app/ping/<tx-hash>
77
+ /get --key app/ping/<tx-hash> --confirmed false
78
78
  ```
79
79
 
80
80
  ---
@@ -422,11 +422,9 @@ npm run peer:pear-rpc -- \
422
422
  - `POST /v1/contract/tx` body: `{ "tx": "<hex32>", "prepared_command": { ... }, "address": "<pubkey-hex32>", "signature": "<hex64>", "nonce": "<hex32>", "sim": true|false }`
423
423
 
424
424
  Notes:
425
- - To allow wallet tx submission, start the peer with `--api-tx-exposed` (or env `PEER_API_TX_EXPOSED=1`).
425
+ - To allow wallet tx submission, start the peer with `--rpc` and `--api-tx-exposed` (or env `PEER_API_TX_EXPOSED=1` + `PEER_RPC=1`).
426
426
  - The peer must be subnet-writable (writer) to broadcast a tx.
427
427
 
428
- ---
429
-
430
428
  ## Building your own app (Protocol + Contract)
431
429
 
432
430
  The runner uses demo protocol/contract files under `src/dev/` (wired in `scripts/run-peer.mjs`) so you can test quickly.
package/README.md CHANGED
@@ -68,7 +68,7 @@ npm run peer:run -- \
68
68
  The runner prints the Peer MSB address. Fund that address on MSB (so the node entry exists and fee checks pass), then in the peer console run:
69
69
  - `/deploy_subnet`
70
70
  - `/tx --command "ping hello"` (dev protocol)
71
- - If you want to use admin-only commands (writer/indexer management, chat moderation), run `/add_admin --address "<peer-publicKey-hex>"` and verify with `/get --key admin`.
71
+ - If you want to use admin-only commands (writer/indexer management, chat moderation), run `/add_admin --address "<peer-publicKey-hex>"` and verify with `/get --key admin --confirmed false`.
72
72
 
73
73
  Notes:
74
74
  - The subnet bootstrap key is auto-generated the first time and persisted to `stores/<peer-store>/subnet-bootstrap.hex`.
@@ -115,5 +115,5 @@ Endpoints (all JSON):
115
115
  - `POST /v1/contract/tx` body: `{ "tx": "<hex32>", "prepared_command": { ... }, "address": "<pubkey-hex32>", "signature": "<hex64>", "nonce": "<hex32>", "sim": true|false }`
116
116
 
117
117
  Notes:
118
- - To allow wallet tx submission, start the peer with `--api-tx-exposed` (or env `PEER_API_TX_EXPOSED=1`).
118
+ - To allow wallet tx submission, start the peer with `--rpc` and `--api-tx-exposed` (or env `PEER_API_TX_EXPOSED=1` + `PEER_RPC=1`).
119
119
  - RPC request bodies are limited to `1_000_000` bytes by default (override with `--rpc-max-body-bytes`).
@@ -1,4 +1,4 @@
1
- import BaseContract from "../contract.js";
1
+ import BaseContract from "../src/artifacts/contract.js";
2
2
 
3
3
  export const GEN1_POKEMON = [
4
4
  { id: 1, name: "Bulbasaur" },
@@ -155,8 +155,8 @@ export const GEN1_POKEMON = [
155
155
  ];
156
156
 
157
157
  class PokemonContract extends BaseContract {
158
- constructor(protocol) {
159
- super(protocol);
158
+ constructor(protocol, config) {
159
+ super(protocol, config);
160
160
  this.addFunction("catch");
161
161
  }
162
162
 
@@ -1,4 +1,4 @@
1
- import BaseProtocol from "../protocol.js";
1
+ import BaseProtocol from "../src/artifacts/protocol.js";
2
2
  import { bufferToBigInt, bigIntToDecimalString } from "trac-msb/src/utils/amountSerialization.js";
3
3
 
4
4
  class PokemonProtocol extends BaseProtocol {
@@ -30,31 +30,37 @@ class PokemonProtocol extends BaseProtocol {
30
30
 
31
31
  async customCommand(input) {
32
32
  if (typeof input !== "string") return;
33
+
33
34
  if (input.startsWith("/get")) {
34
- const m = input.match(/(?:^|\s)--key(?:=|\s+)(.+)$/);
35
+ const m = input.match(/(?:^|\s)--key(?:=|\s+)(\"[^\"]+\"|'[^']+'|\S+)/);
35
36
  const raw = m ? m[1].trim() : null;
36
37
  if (!raw) {
37
- console.log('Usage: /get --key "<hyperbee-key>"');
38
+ console.log('Usage: /get --key "<hyperbee-key>" [--confirmed true|false] [--unconfirmed 1]');
38
39
  return;
39
40
  }
40
41
  const key = raw.replace(/^\"(.*)\"$/, "$1").replace(/^'(.*)'$/, "$1");
41
- const v = await this.getSigned(key);
42
+ const confirmedMatch = input.match(/(?:^|\s)--confirmed(?:=|\s+)(\S+)/);
43
+ const unconfirmedMatch = input.match(/(?:^|\s)--unconfirmed(?:=|\s+)?(\S+)?/);
44
+ const confirmed = unconfirmedMatch ? false : confirmedMatch ? confirmedMatch[1] === "true" || confirmedMatch[1] === "1" : true;
45
+ const v = confirmed ? await this.getSigned(key) : await this.get(key);
42
46
  console.log(v);
43
47
  return;
44
48
  }
49
+
45
50
  if (input.startsWith("/msb")) {
46
51
  const txv = await this.peer.msbClient.getTxvHex();
47
52
  const peerMsbAddress = this.peer.msbClient.pubKeyHexToAddress(this.peer.wallet.publicKey);
48
- const entry = peerMsbAddress ? await this.peer.msb.state.getNodeEntryUnsigned(peerMsbAddress) : null;
49
- const balance = entry?.balance ? bigIntToDecimalString(bufferToBigInt(entry.balance)) : null;
50
- const fee = bigIntToDecimalString(bufferToBigInt(this.peer.msb.state.getFee()));
51
- const validators = this.peer.msb.network?.validatorConnectionManager?.connectionCount?.() ?? 0;
53
+ const entry = await this.peer.msbClient.getNodeEntryUnsigned(peerMsbAddress);
54
+ const balance = entry?.balance ? bigIntToDecimalString(bufferToBigInt(entry.balance)) : 0;
55
+ const feeBuf = this.peer.msbClient.getFee();
56
+ const fee = feeBuf ? bigIntToDecimalString(bufferToBigInt(feeBuf)) : 0;
57
+ const validators = this.peer.msbClient.getConnectedValidatorsCount();
52
58
  console.log({
53
59
  networkId: this.peer.msbClient.networkId,
54
60
  msbBootstrap: this.peer.msbClient.bootstrapHex,
55
61
  txv,
56
- msbSignedLength: this.peer.msb.state.getSignedLength(),
57
- msbUnsignedLength: this.peer.msb.state.getUnsignedLength(),
62
+ msbSignedLength: this.peer.msbClient.getSignedLength(),
63
+ msbUnsignedLength: this.peer.msbClient.getUnsignedLength(),
58
64
  connectedValidators: validators,
59
65
  peerMsbAddress,
60
66
  peerMsbBalance: balance,
@@ -68,7 +74,7 @@ class PokemonProtocol extends BaseProtocol {
68
74
  console.log("");
69
75
  console.log("- Dev commands:");
70
76
  console.log('- /msb | prints MSB txv + lengths (local MSB node view).');
71
- console.log('- /get --key "<key>" | reads signed subnet state key.');
77
+ console.log('- /get --key "<key>" [--confirmed true|false] | reads subnet state key (confirmed defaults to true).');
72
78
  console.log("");
73
79
  console.log("- Dev TX examples:");
74
80
  console.log('- /tx --command "ping hello"');
@@ -78,4 +84,3 @@ class PokemonProtocol extends BaseProtocol {
78
84
  }
79
85
 
80
86
  export default PokemonProtocol;
81
-
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "trac-peer",
3
3
  "main": "src/index.js",
4
- "version": "0.3.0",
4
+ "version": "0.4.0",
5
5
  "type": "module",
6
6
  "pear": {
7
7
  "name": "trac-peer",
@@ -24,9 +24,13 @@
24
24
  "peer:smoke": "node scripts/smoke-msb-sync.mjs",
25
25
  "peer:pear": "pear run -d scripts/run-peer.mjs",
26
26
  "peer:pear-rpc": "pear run -d scripts/run-peer.mjs --rpc",
27
- "test:unit:node": "node tests/unit/unit.test.js",
28
- "test:acceptance:node": "node tests/acceptance/acceptance.test.js",
29
- "test:all": "npm run test:unit:node && npm run test:acceptance:node"
27
+ "test:unit:node": "brittle-node -t 60000 tests/unit/unit.test.js",
28
+ "test:unit:bare": "brittle-bare -t 60000 tests/unit/unit.test.js",
29
+ "test:unit:all": "(npm run test:unit:node && npm run test:unit:bare) || exit 1",
30
+ "test:acceptance:node": "brittle-node -t 120000 tests/acceptance/acceptance.test.js",
31
+ "test:acceptance:bare": "brittle-bare -t 120000 tests/acceptance/acceptance.test.js",
32
+ "test:acceptance:all": "(npm run test:acceptance:node && npm run test:acceptance:bare) || exit 1",
33
+ "test:all": "npm run test:unit:all && npm run test:acceptance:all"
30
34
  },
31
35
  "dependencies": {
32
36
  "@tracsystems/blake3": "^0.0.15",
@@ -96,7 +100,7 @@
96
100
  "timers": "npm:bare-node-timers",
97
101
  "tls": "npm:bare-node-tls",
98
102
  "trac-crypto-api": "^0.1.3",
99
- "trac-msb": "^0.2.8",
103
+ "trac-msb": "^0.2.9",
100
104
  "trac-wallet": "^0.0.43-msb-r2.9",
101
105
  "tty": "npm:bare-node-tty",
102
106
  "url": "npm:bare-node-url",
package/rpc/services.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import b4a from "b4a";
2
2
  import { fastestToJsonSchema } from "./utils/schemaToJson.js";
3
+ import { createHash } from "../src/utils/types.js";
3
4
 
4
5
  const asHex32 = (value, field) => {
5
6
  const hex = String(value ?? "").trim().toLowerCase();
@@ -10,7 +11,7 @@ const asHex32 = (value, field) => {
10
11
  const isObject = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
11
12
 
12
13
  const requireApi = (peer) => {
13
- const api = peer?.protocol_instance?.api;
14
+ const api = peer?.protocol.instance?.api;
14
15
  if (!api) throw new Error("Protocol API not initialized.");
15
16
  return api;
16
17
  };
@@ -22,7 +23,7 @@ export async function getStatus(peer) {
22
23
  ? String(peer.bootstrap)
23
24
  : null;
24
25
 
25
- const peerMsbAddress = peer.msbClient?.isReady() ? peer.msbClient.pubKeyHexToAddress(peer.wallet.publicKey) : null;
26
+ const peerMsbAddress = peer.msbClient.pubKeyHexToAddress(peer.wallet.publicKey);
26
27
 
27
28
  const admin = peer.base?.view ? await peer.base.view.get("admin") : null;
28
29
  const chatStatus = peer.base?.view ? await peer.base.view.get("chat_status") : null;
@@ -43,10 +44,10 @@ export async function getStatus(peer) {
43
44
  chatStatus: chatStatus?.value ?? null,
44
45
  },
45
46
  msb: {
46
- ready: peer.msbClient?.isReady?.() ?? false,
47
- bootstrapHex: peer.msbClient?.bootstrapHex ?? null,
48
- networkId: peer.msbClient?.networkId ?? null,
49
- signedLength: peer.msbClient?.isReady?.() ? peer.msbClient.getSignedLength() : null,
47
+ ready: true,
48
+ bootstrapHex: peer.msbClient.bootstrapHex,
49
+ networkId: peer.msbClient.networkId,
50
+ signedLength: peer.msbClient.getSignedLength()
50
51
  },
51
52
  };
52
53
  }
@@ -78,7 +79,7 @@ const convertContractOpSchema = (fv) => {
78
79
  };
79
80
 
80
81
  export async function getContractSchema(peer) {
81
- const contract = peer?.contract_instance;
82
+ const contract = peer?.contract?.instance;
82
83
  if (!contract) throw new Error("Contract instance not initialized.");
83
84
 
84
85
  const registrations = contract.metadata ?? {};
@@ -106,11 +107,11 @@ export async function getContractSchema(peer) {
106
107
  schemaFormat: "json-schema",
107
108
  contract: {
108
109
  contractClass: contract.constructor?.name ?? null,
109
- protocolClass: peer.protocol_instance?.constructor?.name ?? null,
110
+ protocolClass: peer.protocol.instance?.constructor?.name ?? null,
110
111
  txTypes,
111
112
  ops,
112
113
  },
113
- api: peer.protocol_instance?.getApiSchema ? peer.protocol_instance.getApiSchema() : { methods: {} },
114
+ api: peer.protocol.instance?.getApiSchema ? peer.protocol.instance.getApiSchema() : { methods: {} },
114
115
  };
115
116
  }
116
117
 
@@ -125,14 +126,14 @@ export async function contractPrepareTx(peer, { prepared_command, address, nonce
125
126
  const addr = asHex32(address, "address");
126
127
  const n = asHex32(nonce, "nonce");
127
128
 
128
- if (peer?.protocol_instance?.safeJsonStringify == null) {
129
+ if (peer?.protocol.instance?.safeJsonStringify == null) {
129
130
  throw new Error("safeJsonStringify is not available on protocol instance.");
130
131
  }
131
132
 
132
- const json = peer.protocol_instance.safeJsonStringify(prepared_command);
133
+ const json = peer.protocol.instance.safeJsonStringify(prepared_command);
133
134
  if (json == null) throw new Error("Failed to stringify prepared_command.");
134
135
 
135
- const command_hash = await peer.createHash("blake3", json);
136
+ const command_hash = await createHash(json);
136
137
  const tx = await api.generateTx(addr, command_hash, n);
137
138
  return { tx, command_hash };
138
139
  }
@@ -2,15 +2,15 @@ import b4a from "b4a";
2
2
  import path from "path";
3
3
  import fs from "fs";
4
4
  import PeerWallet from "trac-wallet";
5
- import { Peer, Wallet } from "../src/index.js";
5
+ import { Peer, Wallet, createConfig as createPeerConfig, ENV as PEER_ENV } from "../src/index.js";
6
6
  import { MainSettlementBus } from "trac-msb/src/index.js";
7
- import { createConfig, ENV } from "trac-msb/src/config/env.js"
7
+ import { createConfig as createMsbConfig, ENV as MSB_ENV } from "trac-msb/src/config/env.js"
8
8
  import { startRpcServer } from "../rpc/rpc_server.js";
9
9
  import { DEFAULT_RPC_HOST, DEFAULT_RPC_PORT, DEFAULT_MAX_BODY_BYTES } from "../rpc/constants.js";
10
- import { startInteractiveCli } from "../src/cli.js";
10
+ import { Terminal } from "../src/terminal/index.js";
11
11
  import { ensureTextCodecs } from "../src/textCodec.js";
12
- import PokemonProtocol from "../src/dev/pokemonProtocol.js";
13
- import PokemonContract from "../src/dev/pokemonContract.js";
12
+ import PokemonProtocol from "../dev/pokemonProtocol.js";
13
+ import PokemonContract from "../dev/pokemonContract.js";
14
14
 
15
15
  let process = globalThis.process;
16
16
  if (globalThis.Pear !== undefined) {
@@ -18,8 +18,13 @@ if (globalThis.Pear !== undefined) {
18
18
  process = bareProcess;
19
19
  }
20
20
 
21
+ const pearApp = typeof Pear !== "undefined" ? (Pear.app ?? Pear.config) : undefined;
22
+ const runtimeArgs = typeof process !== "undefined" ? process.argv.slice(2) : [];
23
+ const argv = pearApp?.args ?? runtimeArgs;
24
+ const positionalStoreName = argv.find((a) => a !== undefined && !String(a).startsWith("--")) ?? null;
25
+
21
26
  const createMsb = (options) => {
22
- const config = createConfig(ENV.MAINNET, options)
27
+ const config = createMsbConfig(MSB_ENV.MAINNET, options)
23
28
  return new MainSettlementBus(config);
24
29
  }
25
30
 
@@ -72,7 +77,7 @@ const readHexFile = (filePath, byteLength) => {
72
77
  return null;
73
78
  };
74
79
 
75
- const args = toArgMap(process.argv.slice(2));
80
+ const args = toArgMap(argv);
76
81
 
77
82
  const rpcEnabled =
78
83
  args["rpc"] === true || args["rpc"] === "true" || process.env.PEER_RPC === "true" || process.env.PEER_RPC === "1";
@@ -102,6 +107,11 @@ const apiTxExposed =
102
107
  process.env.PEER_API_TX_EXPOSED === "true" ||
103
108
  process.env.PEER_API_TX_EXPOSED === "1";
104
109
 
110
+ const apiTxExposedEffective = rpcEnabled ? apiTxExposed : false;
111
+ if (!rpcEnabled && apiTxExposed) {
112
+ console.warn("Ignoring --api-tx-exposed because RPC is not enabled (use --rpc).");
113
+ }
114
+
105
115
  const msbStoresDirectory =
106
116
  (args["msb-stores-directory"] && String(args["msb-stores-directory"])) ||
107
117
  process.env.MSB_STORES_DIRECTORY ||
@@ -110,7 +120,7 @@ const msbStoresDirectory =
110
120
  const msbStoreName =
111
121
  (args["msb-store-name"] && String(args["msb-store-name"])) ||
112
122
  process.env.MSB_STORE_NAME ||
113
- "peer-msb";
123
+ null;
114
124
 
115
125
  const msbBootstrap =
116
126
  (args["msb-bootstrap"] && String(args["msb-bootstrap"])) ||
@@ -130,8 +140,8 @@ const peerStoresDirectory =
130
140
  const peerStoreNameRaw =
131
141
  (args["peer-store-name"] && String(args["peer-store-name"])) ||
132
142
  process.env.PEER_STORE_NAME ||
143
+ (positionalStoreName ? String(positionalStoreName) : null) ||
133
144
  "peer";
134
- const peerStoreName = ensureTrailingSlash(peerStoreNameRaw);
135
145
 
136
146
  const subnetBootstrapHex =
137
147
  (args["subnet-bootstrap"] && String(args["subnet-bootstrap"])) ||
@@ -161,13 +171,14 @@ if (!msbBootstrapHex || !msbChannel) {
161
171
  // Important: this starts a *local MSB node* (its own store) that joins your already-running MSB network.
162
172
  // trac-peer currently requires an MSB instance to broadcast and to observe confirmed state.
163
173
 
164
- const msbStoresFullPath = `${ensureTrailingSlash(msbStoresDirectory)}/${msbStoreName}`;
165
- const msbKeyPairPath = `${msbStoresFullPath}/db/keypair.json`;
174
+ const effectiveMsbStoreName = msbStoreName ?? `${peerStoreNameRaw}-msb`;
175
+ const msbStoresFullPath = path.join(ensureTrailingSlash(msbStoresDirectory), effectiveMsbStoreName);
176
+ const msbKeyPairPath = path.join(msbStoresFullPath, "db", "keypair.json");
166
177
  await ensureKeypairFile(msbKeyPairPath);
167
178
 
168
179
  const peerKeyPairPath = path.join(
169
180
  peerStoresDirectory,
170
- peerStoreName,
181
+ peerStoreNameRaw,
171
182
  "db",
172
183
  "keypair.json"
173
184
  );
@@ -197,22 +208,25 @@ if (subnetBootstrap) {
197
208
  }
198
209
  }
199
210
 
200
- const msb = createMsb({ bootstrap: msbBootstrap, channel: msbChannel, storeName: msbStoreName, storesDirectory: msbStoresDirectory})
211
+ const msb = createMsb({ bootstrap: msbBootstrap, channel: msbChannel, storeName: effectiveMsbStoreName, storesDirectory: msbStoresDirectory})
201
212
  await msb.ready();
202
213
 
203
214
  // DevProtocol and DevContract moved to shared src files
215
+ const peerConfig = createPeerConfig(PEER_ENV.MAINNET, {
216
+ storesDirectory: ensureTrailingSlash(peerStoresDirectory),
217
+ storeName: peerStoreNameRaw,
218
+ bootstrap: subnetBootstrap ? b4a.from(subnetBootstrap, "hex") : null,
219
+ channel: subnetChannel,
220
+ enableInteractiveMode: rpcEnabled ? false : true,
221
+ apiTxExposed: apiTxExposedEffective,
222
+ });
204
223
 
205
224
  const peer = new Peer({
206
- stores_directory: ensureTrailingSlash(peerStoresDirectory),
207
- store_name: peerStoreName,
225
+ config: peerConfig,
208
226
  msb,
209
227
  wallet: new Wallet(),
210
228
  protocol: PokemonProtocol,
211
229
  contract: PokemonContract,
212
- bootstrap: subnetBootstrap ? b4a.from(subnetBootstrap, "hex") : null,
213
- channel: subnetChannel,
214
- enable_interactive_mode: true,
215
- api_tx_exposed: apiTxExposed,
216
230
  });
217
231
  await peer.ready();
218
232
 
@@ -222,7 +236,7 @@ if (rpcEnabled) {
222
236
  }
223
237
 
224
238
  const peerMsbAddress = peer.msbClient.pubKeyHexToAddress(peer.wallet.publicKey);
225
- const effectiveSubnetBootstrapHex = peer.base?.key ? b4a.toString(peer.base.key, "hex") : (b4a.isBuffer(peer.bootstrap) ? b4a.toString(peer.bootstrap, "hex") : String(peer.bootstrap));
239
+ const effectiveSubnetBootstrapHex = peer.base?.key ? b4a.toString(peer.base.key, "hex") : (b4a.isBuffer(peer.config.bootstrap) ? b4a.toString(peer.config.bootstrap, "hex") : String(peer.config.bootstrap));
226
240
  if (!subnetBootstrap) {
227
241
  fs.mkdirSync(path.dirname(subnetBootstrapFile), { recursive: true });
228
242
  fs.writeFileSync(subnetBootstrapFile, `${effectiveSubnetBootstrapHex}\n`);
@@ -256,7 +270,12 @@ console.log(' - /get --key "txl"');
256
270
  console.log("==========================================================");
257
271
  console.log("");
258
272
 
259
- await startInteractiveCli(peer);
273
+ if (peer.config.enableInteractiveMode) {
274
+ const terminal = new Terminal(peer);
275
+ await terminal.start();
276
+ } else {
277
+ console.log("Interactive CLI disabled.");
278
+ }
260
279
 
261
280
  process.on("SIGINT", async () => {
262
281
  if (rpcServer) await new Promise((resolve) => rpcServer.close(resolve));