solforge 0.2.4 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +471 -79
  2. package/cli.cjs +106 -78
  3. package/package.json +1 -1
  4. package/scripts/install.sh +1 -1
  5. package/scripts/postinstall.cjs +69 -61
  6. package/server/lib/base58.ts +1 -1
  7. package/server/methods/account/get-account-info.ts +3 -7
  8. package/server/methods/account/get-balance.ts +3 -7
  9. package/server/methods/account/get-multiple-accounts.ts +2 -1
  10. package/server/methods/account/get-parsed-account-info.ts +3 -7
  11. package/server/methods/account/parsers/index.ts +2 -2
  12. package/server/methods/account/parsers/loader-upgradeable.ts +14 -1
  13. package/server/methods/account/parsers/spl-token.ts +29 -10
  14. package/server/methods/account/request-airdrop.ts +44 -31
  15. package/server/methods/block/get-block.ts +3 -7
  16. package/server/methods/block/get-blocks-with-limit.ts +3 -7
  17. package/server/methods/block/is-blockhash-valid.ts +3 -7
  18. package/server/methods/get-address-lookup-table.ts +3 -7
  19. package/server/methods/program/get-program-accounts.ts +9 -9
  20. package/server/methods/program/get-token-account-balance.ts +3 -7
  21. package/server/methods/program/get-token-accounts-by-delegate.ts +4 -3
  22. package/server/methods/program/get-token-accounts-by-owner.ts +61 -35
  23. package/server/methods/program/get-token-largest-accounts.ts +3 -2
  24. package/server/methods/program/get-token-supply.ts +3 -2
  25. package/server/methods/solforge/index.ts +9 -6
  26. package/server/methods/transaction/get-parsed-transaction.ts +3 -7
  27. package/server/methods/transaction/get-signature-statuses.ts +14 -7
  28. package/server/methods/transaction/get-signatures-for-address.ts +3 -7
  29. package/server/methods/transaction/get-transaction.ts +167 -81
  30. package/server/methods/transaction/send-transaction.ts +29 -16
  31. package/server/methods/transaction/simulate-transaction.ts +3 -2
  32. package/server/rpc-server.ts +47 -34
  33. package/server/types.ts +9 -6
  34. package/server/ws-server.ts +15 -8
  35. package/src/api-server-entry.ts +91 -91
  36. package/src/cli/commands/airdrop.ts +2 -2
  37. package/src/cli/commands/config.ts +2 -2
  38. package/src/cli/commands/mint.ts +3 -3
  39. package/src/cli/commands/program-clone.ts +9 -11
  40. package/src/cli/commands/program-load.ts +3 -3
  41. package/src/cli/commands/rpc-start.ts +8 -5
  42. package/src/cli/commands/token-adopt-authority.ts +1 -1
  43. package/src/cli/commands/token-clone.ts +5 -6
  44. package/src/cli/commands/token-create.ts +5 -5
  45. package/src/cli/main.ts +38 -37
  46. package/src/cli/run-solforge.ts +20 -6
  47. package/src/cli/setup-wizard.ts +8 -6
  48. package/src/commands/add-program.ts +324 -328
  49. package/src/commands/init.ts +106 -106
  50. package/src/commands/list.ts +125 -125
  51. package/src/commands/mint.ts +247 -248
  52. package/src/commands/start.ts +837 -833
  53. package/src/commands/status.ts +80 -80
  54. package/src/commands/stop.ts +381 -382
  55. package/src/config/index.ts +33 -17
  56. package/src/config/manager.ts +150 -150
  57. package/src/db/index.ts +2 -2
  58. package/src/db/tx-store.ts +12 -8
  59. package/src/gui/public/app.css +1556 -1
  60. package/src/gui/public/build/main.css +1569 -1
  61. package/src/gui/server.ts +21 -22
  62. package/src/gui/src/api.ts +1 -1
  63. package/src/gui/src/app.tsx +96 -45
  64. package/src/gui/src/components/airdrop-mint-form.tsx +49 -19
  65. package/src/gui/src/components/clone-program-modal.tsx +31 -12
  66. package/src/gui/src/components/clone-token-modal.tsx +32 -13
  67. package/src/gui/src/components/modal.tsx +18 -11
  68. package/src/gui/src/components/programs-panel.tsx +27 -15
  69. package/src/gui/src/components/status-panel.tsx +32 -18
  70. package/src/gui/src/components/tokens-panel.tsx +25 -19
  71. package/src/gui/src/index.css +491 -463
  72. package/src/index.ts +177 -149
  73. package/src/rpc/start.ts +1 -1
  74. package/src/services/api-server.ts +494 -475
  75. package/src/services/port-manager.ts +164 -167
  76. package/src/services/process-registry.ts +144 -145
  77. package/src/services/program-cloner.ts +312 -312
  78. package/src/services/token-cloner.ts +799 -797
  79. package/src/services/validator.ts +288 -290
  80. package/src/types/config.ts +72 -72
  81. package/src/utils/shell.ts +75 -75
  82. package/src/utils/token-loader.ts +78 -78
@@ -35,8 +35,8 @@ export class LiteSVMRpcServer {
35
35
  blockTime?: number;
36
36
  preBalances?: number[];
37
37
  postBalances?: number[];
38
- preTokenBalances?: any[];
39
- postTokenBalances?: any[];
38
+ preTokenBalances?: unknown[];
39
+ postTokenBalances?: unknown[];
40
40
  }
41
41
  > = new Map();
42
42
  private store: TxStore;
@@ -95,7 +95,7 @@ export class LiteSVMRpcServer {
95
95
 
96
96
  private createSuccessResponse(
97
97
  id: string | number,
98
- result: any,
98
+ result: unknown,
99
99
  ): JsonRpcResponse {
100
100
  return {
101
101
  jsonrpc: "2.0",
@@ -108,7 +108,7 @@ export class LiteSVMRpcServer {
108
108
  id: string | number,
109
109
  code: number,
110
110
  message: string,
111
- data?: any,
111
+ data?: unknown,
112
112
  ): JsonRpcResponse {
113
113
  return {
114
114
  jsonrpc: "2.0",
@@ -132,7 +132,7 @@ export class LiteSVMRpcServer {
132
132
  },
133
133
  getFaucet: () => this.faucet,
134
134
  getTxCount: () => this.txCount,
135
- registerMint: (mint: any) => {
135
+ registerMint: (mint: PublicKey | string) => {
136
136
  try {
137
137
  const pk =
138
138
  typeof mint === "string" ? mint : new PublicKey(mint).toBase58();
@@ -140,7 +140,7 @@ export class LiteSVMRpcServer {
140
140
  } catch {}
141
141
  },
142
142
  listMints: () => Array.from(this.knownMints),
143
- registerProgram: (program: any) => {
143
+ registerProgram: (program: PublicKey | string) => {
144
144
  try {
145
145
  const pk =
146
146
  typeof program === "string"
@@ -160,19 +160,30 @@ export class LiteSVMRpcServer {
160
160
  blockTime: meta?.blockTime,
161
161
  preBalances: meta?.preBalances,
162
162
  postBalances: meta?.postBalances,
163
- preTokenBalances: (meta as any)?.preTokenBalances,
164
- postTokenBalances: (meta as any)?.postTokenBalances,
163
+ preTokenBalances: (
164
+ meta as { preTokenBalances?: unknown[] } | undefined
165
+ )?.preTokenBalances,
166
+ postTokenBalances: (
167
+ meta as { postTokenBalances?: unknown[] } | undefined
168
+ )?.postTokenBalances,
165
169
  });
166
170
 
167
171
  // Persist to SQLite for durability and history queries
168
172
  try {
169
- const msg: any = tx.message as any;
170
- const rawKeys: any[] = Array.isArray(msg.staticAccountKeys)
173
+ const msg = tx.message as unknown as {
174
+ staticAccountKeys?: unknown[];
175
+ accountKeys?: unknown[];
176
+ header?: unknown;
177
+ isAccountSigner?: (i: number) => boolean;
178
+ isAccountWritable?: (i: number) => boolean;
179
+ version?: number;
180
+ };
181
+ const rawKeys: unknown[] = Array.isArray(msg.staticAccountKeys)
171
182
  ? msg.staticAccountKeys
172
183
  : Array.isArray(msg.accountKeys)
173
184
  ? msg.accountKeys
174
185
  : [];
175
- const keys: string[] = rawKeys.map((k: any) => {
186
+ const keys: string[] = rawKeys.map((k) => {
176
187
  try {
177
188
  return typeof k === "string" ? k : (k as PublicKey).toBase58();
178
189
  } catch {
@@ -226,18 +237,24 @@ export class LiteSVMRpcServer {
226
237
  err: meta?.err ?? null,
227
238
  rawBase64,
228
239
  preBalances: Array.isArray(meta?.preBalances)
229
- ? meta!.preBalances!
240
+ ? (meta?.preBalances as number[])
230
241
  : [],
231
242
  postBalances: Array.isArray(meta?.postBalances)
232
- ? meta!.postBalances!
233
- : [],
234
- logs: Array.isArray(meta?.logs) ? meta!.logs! : [],
235
- preTokenBalances: Array.isArray((meta as any)?.preTokenBalances)
236
- ? (meta as any).preTokenBalances
237
- : [],
238
- postTokenBalances: Array.isArray((meta as any)?.postTokenBalances)
239
- ? (meta as any).postTokenBalances
243
+ ? (meta?.postBalances as number[])
240
244
  : [],
245
+ logs: Array.isArray(meta?.logs) ? (meta?.logs as string[]) : [],
246
+ preTokenBalances: (() => {
247
+ const arr = (
248
+ meta as { preTokenBalances?: unknown[] } | undefined
249
+ )?.preTokenBalances;
250
+ return Array.isArray(arr) ? arr : [];
251
+ })(),
252
+ postTokenBalances: (() => {
253
+ const arr = (
254
+ meta as { postTokenBalances?: unknown[] } | undefined
255
+ )?.postTokenBalances;
256
+ return Array.isArray(arr) ? arr : [];
257
+ })(),
241
258
  accounts,
242
259
  })
243
260
  .catch(() => {});
@@ -262,7 +279,7 @@ export class LiteSVMRpcServer {
262
279
  return null;
263
280
  }
264
281
  })
265
- .filter(Boolean) as any[];
282
+ .filter(Boolean) as import("../src/db/tx-store").AccountSnapshot[];
266
283
  if (snapshots.length > 0)
267
284
  this.store.upsertAccounts(snapshots).catch(() => {});
268
285
  } catch {}
@@ -302,7 +319,7 @@ export class LiteSVMRpcServer {
302
319
 
303
320
  getSignatureStatus(
304
321
  signature: string,
305
- ): { slot: number; err: any | null } | null {
322
+ ): { slot: number; err: unknown | null } | null {
306
323
  // Prefer local record for reliability
307
324
  const rec = this.txRecords.get(signature);
308
325
  if (rec) {
@@ -312,10 +329,10 @@ export class LiteSVMRpcServer {
312
329
  const sigBytes = decodeBase58(signature);
313
330
  const tx = this.svm.getTransaction(sigBytes);
314
331
  if (!tx) return null;
315
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
316
- let errVal: any = null;
332
+ let errVal: unknown = null;
317
333
  try {
318
- errVal = "err" in tx ? (tx as any).err() : null;
334
+ const raw = (tx as { err?: unknown }).err;
335
+ errVal = typeof raw === "function" ? (raw as () => unknown)() : raw;
319
336
  } catch {
320
337
  errVal = null;
321
338
  }
@@ -350,13 +367,9 @@ export class LiteSVMRpcServer {
350
367
  }
351
368
 
352
369
  return result;
353
- } catch (error: any) {
354
- return this.createErrorResponse(
355
- id,
356
- -32603,
357
- "Internal error",
358
- error.message,
359
- );
370
+ } catch (error: unknown) {
371
+ const message = error instanceof Error ? error.message : String(error);
372
+ return this.createErrorResponse(id, -32603, "Internal error", message);
360
373
  }
361
374
  }
362
375
  }
@@ -406,7 +419,7 @@ export function createLiteSVMRpcServer(port: number = 8899, host?: string) {
406
419
  try {
407
420
  console.log(
408
421
  "RPC batch:",
409
- body.map((b: any) => b.method),
422
+ body.map((b: { method?: string }) => b.method),
410
423
  );
411
424
  } catch {}
412
425
  }
@@ -432,7 +445,7 @@ export function createLiteSVMRpcServer(port: number = 8899, host?: string) {
432
445
  headers: { "Content-Type": "application/json", ...corsHeaders },
433
446
  });
434
447
  }
435
- } catch (error) {
448
+ } catch (_error) {
436
449
  return new Response(
437
450
  JSON.stringify({
438
451
  jsonrpc: "2.0",
package/server/types.ts CHANGED
@@ -6,17 +6,17 @@ export interface JsonRpcRequest {
6
6
  jsonrpc: "2.0";
7
7
  id: string | number;
8
8
  method: string;
9
- params?: any;
9
+ params?: unknown;
10
10
  }
11
11
 
12
12
  export interface JsonRpcResponse {
13
13
  jsonrpc: "2.0";
14
14
  id: string | number;
15
- result?: any;
15
+ result?: unknown;
16
16
  error?: {
17
17
  code: number;
18
18
  message: string;
19
- data?: any;
19
+ data?: unknown;
20
20
  };
21
21
  }
22
22
 
@@ -27,12 +27,15 @@ export interface RpcMethodContext {
27
27
  store?: TxStore;
28
28
  encodeBase58: (bytes: Uint8Array) => string;
29
29
  decodeBase58: (str: string) => Uint8Array;
30
- createSuccessResponse: (id: string | number, result: any) => JsonRpcResponse;
30
+ createSuccessResponse: (
31
+ id: string | number,
32
+ result: unknown,
33
+ ) => JsonRpcResponse;
31
34
  createErrorResponse: (
32
35
  id: string | number,
33
36
  code: number,
34
37
  message: string,
35
- data?: any,
38
+ data?: unknown,
36
39
  ) => JsonRpcResponse;
37
40
  notifySignature: (signature: string) => void;
38
41
  getFaucet: () => Keypair;
@@ -69,6 +72,6 @@ export interface RpcMethodContext {
69
72
 
70
73
  export type RpcMethodHandler = (
71
74
  id: string | number,
72
- params: any,
75
+ params: unknown[] | undefined,
73
76
  context: RpcMethodContext,
74
77
  ) => JsonRpcResponse | Promise<JsonRpcResponse>;
@@ -6,6 +6,7 @@ type Sub = { id: number; type: "signature"; signature: string };
6
6
  export function createLiteSVMWebSocketServer(
7
7
  rpcServer: LiteSVMRpcServer,
8
8
  port: number = 8900,
9
+ host?: string,
9
10
  ) {
10
11
  let nextSubId = 1;
11
12
  const subs = new Map<number, Sub>();
@@ -13,7 +14,11 @@ export function createLiteSVMWebSocketServer(
13
14
  const sockets = new Set<WebSocket>();
14
15
  const pendingChecks = new Map<string, number>();
15
16
 
16
- const sendSignatureNotification = (sig: string, slot: number, err: any) => {
17
+ const sendSignatureNotification = (
18
+ sig: string,
19
+ slot: number,
20
+ err: unknown,
21
+ ) => {
17
22
  const payload = {
18
23
  jsonrpc: "2.0",
19
24
  method: "signatureNotification",
@@ -24,14 +29,14 @@ export function createLiteSVMWebSocketServer(
24
29
  for (const [id, sub] of subs.entries()) {
25
30
  if (sub.type === "signature" && sub.signature === sig) {
26
31
  try {
27
- sockets.forEach((s) =>
32
+ for (const s of sockets) {
28
33
  s.send(
29
34
  JSON.stringify({
30
35
  ...payload,
31
36
  params: { ...payload.params, subscription: id },
32
37
  }),
33
- ),
34
- );
38
+ );
39
+ }
35
40
  } catch {}
36
41
  subs.delete(id);
37
42
  }
@@ -67,8 +72,9 @@ export function createLiteSVMWebSocketServer(
67
72
 
68
73
  const server: Server = Bun.serve({
69
74
  port,
75
+ hostname: host || process.env.RPC_HOST || "127.0.0.1",
70
76
  fetch(req, srv) {
71
- if (srv.upgrade(req)) return undefined as any;
77
+ if (srv.upgrade(req)) return undefined as unknown as Response;
72
78
  return new Response("Not a websocket", { status: 400 });
73
79
  },
74
80
  websocket: {
@@ -89,7 +95,7 @@ export function createLiteSVMWebSocketServer(
89
95
  id,
90
96
  method,
91
97
  params = [],
92
- } = msg as { id: number; method: string; params?: any[] };
98
+ } = msg as { id: number; method: string; params?: unknown[] };
93
99
  if (method === "signatureSubscribe") {
94
100
  const [signature] = params;
95
101
  const subId = nextSubId++;
@@ -145,7 +151,7 @@ export function createLiteSVMWebSocketServer(
145
151
  error: { code: -32601, message: `Method not found: ${method}` },
146
152
  }),
147
153
  );
148
- } catch (e) {
154
+ } catch (_e) {
149
155
  try {
150
156
  ws.send(
151
157
  JSON.stringify({
@@ -160,7 +166,8 @@ export function createLiteSVMWebSocketServer(
160
166
  },
161
167
  });
162
168
 
163
- console.log(`📣 LiteSVM RPC PubSub running on ws://localhost:${port}`);
169
+ const hostname = (host || process.env.RPC_HOST || "127.0.0.1").toString();
170
+ console.log(`📣 LiteSVM RPC PubSub running on ws://${hostname}:${port}`);
164
171
  return {
165
172
  wsServer: server,
166
173
  stop: () => {
@@ -1,109 +1,109 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { APIServer } from "./services/api-server.js";
4
- import { configManager } from "./config/manager.js";
5
3
  import chalk from "chalk";
4
+ import { configManager } from "./config/manager.js";
5
+ import { APIServer } from "./services/api-server.js";
6
6
 
7
7
  async function main() {
8
- try {
9
- // Parse command line arguments
10
- const args = process.argv.slice(2);
11
- const portIndex = args.indexOf("--port");
12
- const hostIndex = args.indexOf("--host");
13
- const configIndex = args.indexOf("--config");
14
- const rpcIndex = args.indexOf("--rpc-url");
15
- const faucetIndex = args.indexOf("--faucet-url");
16
- const workDirIndex = args.indexOf("--work-dir");
8
+ try {
9
+ // Parse command line arguments
10
+ const args = process.argv.slice(2);
11
+ const portIndex = args.indexOf("--port");
12
+ const hostIndex = args.indexOf("--host");
13
+ const configIndex = args.indexOf("--config");
14
+ const rpcIndex = args.indexOf("--rpc-url");
15
+ const faucetIndex = args.indexOf("--faucet-url");
16
+ const workDirIndex = args.indexOf("--work-dir");
17
17
 
18
- if (
19
- portIndex === -1 ||
20
- configIndex === -1 ||
21
- rpcIndex === -1 ||
22
- faucetIndex === -1 ||
23
- workDirIndex === -1 ||
24
- !args[portIndex + 1] ||
25
- !args[configIndex + 1] ||
26
- !args[rpcIndex + 1] ||
27
- !args[faucetIndex + 1] ||
28
- !args[workDirIndex + 1]
29
- ) {
30
- console.error(
31
- "Usage: api-server-entry --port <port> --config <config-path> --rpc-url <url> --faucet-url <url> --work-dir <dir> [--host <host>]"
32
- );
33
- process.exit(1);
34
- }
18
+ if (
19
+ portIndex === -1 ||
20
+ configIndex === -1 ||
21
+ rpcIndex === -1 ||
22
+ faucetIndex === -1 ||
23
+ workDirIndex === -1 ||
24
+ !args[portIndex + 1] ||
25
+ !args[configIndex + 1] ||
26
+ !args[rpcIndex + 1] ||
27
+ !args[faucetIndex + 1] ||
28
+ !args[workDirIndex + 1]
29
+ ) {
30
+ console.error(
31
+ "Usage: api-server-entry --port <port> --config <config-path> --rpc-url <url> --faucet-url <url> --work-dir <dir> [--host <host>]",
32
+ );
33
+ process.exit(1);
34
+ }
35
35
 
36
- const port = parseInt(args[portIndex + 1]!);
37
- const host =
38
- hostIndex !== -1 && args[hostIndex + 1] ? args[hostIndex + 1] : undefined;
39
- const configPath = args[configIndex + 1]!;
40
- const rpcUrl = args[rpcIndex + 1]!;
41
- const faucetUrl = args[faucetIndex + 1]!;
42
- const workDir = args[workDirIndex + 1]!;
36
+ const port = parseInt(String(args[portIndex + 1]), 10);
37
+ const host =
38
+ hostIndex !== -1 && args[hostIndex + 1] ? args[hostIndex + 1] : undefined;
39
+ const configPath = String(args[configIndex + 1]);
40
+ const rpcUrl = String(args[rpcIndex + 1]);
41
+ const faucetUrl = String(args[faucetIndex + 1]);
42
+ const workDir = String(args[workDirIndex + 1]);
43
43
 
44
- // Load configuration
45
- await configManager.load(configPath);
46
- const config = configManager.getConfig();
44
+ // Load configuration
45
+ await configManager.load(configPath);
46
+ const config = configManager.getConfig();
47
47
 
48
- // Create and start API server
49
- const apiServer = new APIServer({
50
- port,
51
- host,
52
- validatorRpcUrl: rpcUrl,
53
- validatorFaucetUrl: faucetUrl,
54
- config,
55
- workDir,
56
- });
48
+ // Create and start API server
49
+ const apiServer = new APIServer({
50
+ port,
51
+ host,
52
+ validatorRpcUrl: rpcUrl,
53
+ validatorFaucetUrl: faucetUrl,
54
+ config,
55
+ workDir,
56
+ });
57
57
 
58
- const result = await apiServer.start();
58
+ const result = await apiServer.start();
59
59
 
60
- if (result.success) {
61
- console.log(chalk.green(`🚀 API Server started on port ${port}`));
60
+ if (result.success) {
61
+ console.log(chalk.green(`🚀 API Server started on port ${port}`));
62
62
 
63
- // Keep the process alive
64
- process.on("SIGTERM", async () => {
65
- console.log(
66
- chalk.yellow("📡 API Server received SIGTERM, shutting down...")
67
- );
68
- await apiServer.stop();
69
- process.exit(0);
70
- });
63
+ // Keep the process alive
64
+ process.on("SIGTERM", async () => {
65
+ console.log(
66
+ chalk.yellow("📡 API Server received SIGTERM, shutting down..."),
67
+ );
68
+ await apiServer.stop();
69
+ process.exit(0);
70
+ });
71
71
 
72
- process.on("SIGINT", async () => {
73
- console.log(
74
- chalk.yellow("📡 API Server received SIGINT, shutting down...")
75
- );
76
- await apiServer.stop();
77
- process.exit(0);
78
- });
72
+ process.on("SIGINT", async () => {
73
+ console.log(
74
+ chalk.yellow("📡 API Server received SIGINT, shutting down..."),
75
+ );
76
+ await apiServer.stop();
77
+ process.exit(0);
78
+ });
79
79
 
80
- // Keep process alive
81
- setInterval(() => {}, 1000);
82
- } else {
83
- console.error(
84
- chalk.red(`❌ Failed to start API server: ${result.error}`)
85
- );
86
- process.exit(1);
87
- }
88
- } catch (error) {
89
- console.error(
90
- chalk.red(
91
- `❌ API Server error: ${
92
- error instanceof Error ? error.message : String(error)
93
- }`
94
- )
95
- );
96
- process.exit(1);
97
- }
80
+ // Keep process alive
81
+ setInterval(() => {}, 1000);
82
+ } else {
83
+ console.error(
84
+ chalk.red(`❌ Failed to start API server: ${result.error}`),
85
+ );
86
+ process.exit(1);
87
+ }
88
+ } catch (error) {
89
+ console.error(
90
+ chalk.red(
91
+ `❌ API Server error: ${
92
+ error instanceof Error ? error.message : String(error)
93
+ }`,
94
+ ),
95
+ );
96
+ process.exit(1);
97
+ }
98
98
  }
99
99
 
100
100
  main().catch((error) => {
101
- console.error(
102
- chalk.red(
103
- `❌ Fatal error: ${
104
- error instanceof Error ? error.message : String(error)
105
- }`
106
- )
107
- );
108
- process.exit(1);
101
+ console.error(
102
+ chalk.red(
103
+ `❌ Fatal error: ${
104
+ error instanceof Error ? error.message : String(error)
105
+ }`,
106
+ ),
107
+ );
108
+ process.exit(1);
109
109
  });
@@ -4,8 +4,8 @@ import { parseFlags } from "../utils/args";
4
4
 
5
5
  export async function airdropCommand(args: string[]) {
6
6
  const { flags } = parseFlags(args);
7
- const to = String(flags["to"] || "");
8
- const sol = Number(flags["sol"] || 0);
7
+ const to = String(flags.to || "");
8
+ const sol = Number(flags.sol || 0);
9
9
  const cfg = await readConfig();
10
10
  const url = `http://localhost:${cfg.server.rpcPort}`;
11
11
  if (!to || !sol) {
@@ -11,7 +11,7 @@ export async function configCommand(sub: string | undefined, args: string[]) {
11
11
  switch (sub) {
12
12
  case "init": {
13
13
  const { flags } = parseFlags(args);
14
- const force = !!flags["force"];
14
+ const force = !!flags.force;
15
15
  await writeDefaultConfig({ force });
16
16
  p.log.success("Wrote sf.config.json");
17
17
  return;
@@ -28,7 +28,7 @@ export async function configCommand(sub: string | undefined, args: string[]) {
28
28
  const updated = setConfigValue(cfg, key, value);
29
29
  await Bun.write(
30
30
  "sf.config.json",
31
- JSON.stringify(updated, null, 2) + "\n",
31
+ `${JSON.stringify(updated, null, 2)}\n`,
32
32
  );
33
33
  p.log.success(`Updated ${key}`);
34
34
  return;
@@ -7,9 +7,9 @@ import { parseFlags } from "../utils/args";
7
7
  // Usage: solforge mint --mint <mint> --to <owner> --amount <amount>
8
8
  export async function mintCommand(args: string[]) {
9
9
  const { flags } = parseFlags(args);
10
- let mint = flags["mint"] as string | undefined;
11
- let receiver = flags["to"] as string | undefined; // required: receiver address (ATA owner)
12
- let amountBase = flags["amount"] as string | undefined; // optional direct base-units
10
+ let mint = flags.mint as string | undefined;
11
+ let receiver = flags.to as string | undefined; // required: receiver address (ATA owner)
12
+ let amountBase = flags.amount as string | undefined; // optional direct base-units
13
13
  let uiAmount = flags["ui-amount"] as string | undefined; // preferred UI units
14
14
 
15
15
  const cfg = await readConfig();
@@ -6,12 +6,12 @@ export async function programCloneCommand(args: string[]) {
6
6
  const { flags, rest } = parseFlags(args);
7
7
  const programId = (
8
8
  (rest[0] as string) ||
9
- (flags["program"] as string) ||
9
+ (flags.program as string) ||
10
10
  ""
11
11
  ).trim();
12
- const configPath = flags["config"] as string | undefined;
12
+ const configPath = flags.config as string | undefined;
13
13
  const cfg = await readConfig(configPath);
14
- const endpoint = (flags["endpoint"] as string) || cfg.clone.endpoint;
14
+ const endpoint = (flags.endpoint as string) || cfg.clone.endpoint;
15
15
  const withAccounts = !!flags["with-accounts"];
16
16
  const accountsLimit = flags["accounts-limit"]
17
17
  ? Number(flags["accounts-limit"])
@@ -56,16 +56,14 @@ export async function programAccountsCloneCommand(args: string[]) {
56
56
  const { flags, rest } = parseFlags(args);
57
57
  const programId = (
58
58
  (rest[0] as string) ||
59
- (flags["program"] as string) ||
59
+ (flags.program as string) ||
60
60
  ""
61
61
  ).trim();
62
- const configPath = flags["config"] as string | undefined;
62
+ const configPath = flags.config as string | undefined;
63
63
  const cfg = await readConfig(configPath);
64
- const endpoint = (flags["endpoint"] as string) || cfg.clone.endpoint;
65
- const limit = flags["limit"] ? Number(flags["limit"]) : undefined;
66
- const filters = flags["filters"]
67
- ? safeJson(flags["filters"] as string)
68
- : undefined;
64
+ const endpoint = (flags.endpoint as string) || cfg.clone.endpoint;
65
+ const limit = flags.limit ? Number(flags.limit) : undefined;
66
+ const filters = flags.filters ? safeJson(flags.filters as string) : undefined;
69
67
  if (!programId) {
70
68
  p.log.error(
71
69
  "Usage: solforge program accounts clone <programId> [--endpoint URL] [--limit N] [--filters JSON]",
@@ -97,7 +95,7 @@ export async function programAccountsCloneCommand(args: string[]) {
97
95
  }
98
96
  }
99
97
 
100
- function safeJson(s: string): any {
98
+ function safeJson(s: string): unknown {
101
99
  try {
102
100
  return JSON.parse(s);
103
101
  } catch {
@@ -5,9 +5,9 @@ import { parseFlags } from "../utils/args";
5
5
 
6
6
  export async function programLoadCommand(args: string[]) {
7
7
  const { flags, rest } = parseFlags(args);
8
- const programId = (rest[0] as string) || (flags["program"] as string);
9
- const fromFile = flags["file"] as string | undefined;
10
- const endpoint = flags["endpoint"] as string | undefined;
8
+ const programId = (rest[0] as string) || (flags.program as string);
9
+ const fromFile = flags.file as string | undefined;
10
+ const endpoint = flags.endpoint as string | undefined;
11
11
  if (!programId) {
12
12
  p.log.error(
13
13
  "Usage: solforge program load <programId> [--file PATH | --endpoint URL]",
@@ -5,10 +5,11 @@ import { parseFlags } from "../utils/args";
5
5
 
6
6
  export async function rpcStartCommand(args: string[]) {
7
7
  const { flags } = parseFlags(args);
8
- const cfg = await readConfig(flags["config"] as string | undefined);
9
- const rpcPort = Number(flags["port"] ?? cfg.server.rpcPort ?? 8899);
8
+ const cfg = await readConfig(flags.config as string | undefined);
9
+ const rpcPort = Number(flags.port ?? cfg.server.rpcPort ?? 8899);
10
10
  const wsPort = Number(flags["ws-port"] ?? cfg.server.wsPort ?? rpcPort + 1);
11
- const host = (flags["host"] as string) || "127.0.0.1";
11
+ const host =
12
+ flags.network === true ? "0.0.0.0" : (flags.host as string) || "127.0.0.1";
12
13
  const dbMode =
13
14
  (flags["db-mode"] as string) || cfg.server.db.mode || "ephemeral";
14
15
  const dbPath =
@@ -17,7 +18,7 @@ export async function rpcStartCommand(args: string[]) {
17
18
  const guiEnabled =
18
19
  flags["no-gui"] === true
19
20
  ? false
20
- : flags["gui"] === true
21
+ : flags.gui === true
21
22
  ? true
22
23
  : cfg.gui.enabled !== false;
23
24
 
@@ -25,10 +26,12 @@ export async function rpcStartCommand(args: string[]) {
25
26
  const guiMsg = guiEnabled ? `, GUI on ${guiPort}` : "";
26
27
  s.start(`Starting RPC on ${host}:${rpcPort}, WS on ${wsPort}${guiMsg}...`);
27
28
  try {
29
+ const mode: "ephemeral" | "persistent" =
30
+ dbMode === "persistent" ? "persistent" : "ephemeral";
28
31
  const started = startRpcServers({
29
32
  rpcPort,
30
33
  wsPort,
31
- dbMode: dbMode as any,
34
+ dbMode: mode,
32
35
  dbPath,
33
36
  host,
34
37
  guiEnabled,
@@ -5,7 +5,7 @@ import { parseFlags } from "../utils/args";
5
5
  // Set the faucet as mint authority for an existing mint in LiteSVM (local-only)
6
6
  export async function tokenAdoptAuthorityCommand(args: string[]) {
7
7
  const { flags, rest } = parseFlags(args);
8
- const mint = (rest[0] as string) || (flags["mint"] as string);
8
+ const mint = (rest[0] as string) || (flags.mint as string);
9
9
  if (!mint) {
10
10
  p.log.error("Usage: solforge token adopt-authority <mint>");
11
11
  return;