solforge 0.2.0 → 0.2.1
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/LICENSE +21 -0
- package/docs/API.md +379 -0
- package/docs/CONFIGURATION.md +407 -0
- package/package.json +56 -45
- package/src/api-server-entry.ts +109 -0
- package/src/commands/add-program.ts +337 -0
- package/src/commands/init.ts +122 -0
- package/src/commands/list.ts +136 -0
- package/src/commands/mint.ts +288 -0
- package/src/commands/start.ts +877 -0
- package/src/commands/status.ts +99 -0
- package/src/commands/stop.ts +406 -0
- package/src/config/manager.ts +157 -0
- package/src/gui/public/build/main.css +1 -0
- package/src/gui/public/build/main.js +303 -0
- package/src/gui/public/build/main.js.txt +231 -0
- package/src/index.ts +188 -0
- package/src/services/api-server.ts +485 -0
- package/src/services/port-manager.ts +177 -0
- package/src/services/process-registry.ts +154 -0
- package/src/services/program-cloner.ts +317 -0
- package/src/services/token-cloner.ts +809 -0
- package/src/services/validator.ts +295 -0
- package/src/types/config.ts +110 -0
- package/src/utils/shell.ts +110 -0
- package/src/utils/token-loader.ts +115 -0
- package/.agi/agi.sqlite +0 -0
- package/.claude/settings.local.json +0 -9
- package/.github/workflows/release-binaries.yml +0 -133
- package/.tmp/.787ebcdbf7b8fde8-00000000.hm +0 -0
- package/.tmp/.bffe6efebdf8aedc-00000000.hm +0 -0
- package/AGENTS.md +0 -271
- package/CLAUDE.md +0 -106
- package/PROJECT_STRUCTURE.md +0 -124
- package/SOLANA_KIT_GUIDE.md +0 -251
- package/SOLFORGE.md +0 -119
- package/biome.json +0 -34
- package/bun.lock +0 -743
- package/drizzle/0000_friendly_millenium_guard.sql +0 -53
- package/drizzle/0001_stale_sentinels.sql +0 -2
- package/drizzle/meta/0000_snapshot.json +0 -329
- package/drizzle/meta/0001_snapshot.json +0 -345
- package/drizzle/meta/_journal.json +0 -20
- package/drizzle.config.ts +0 -12
- package/index.ts +0 -21
- package/mint.sh +0 -47
- package/postcss.config.js +0 -6
- package/rpc-server.ts.backup +0 -519
- package/sf.config.json +0 -38
- package/tailwind.config.js +0 -27
- package/test-client.ts +0 -120
- package/tmp/inspect-html.ts +0 -4
- package/tmp/response-test.ts +0 -5
- package/tmp/test-html.ts +0 -5
- package/tmp/test-server.ts +0 -13
- package/tsconfig.json +0 -29
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
# Configuration Guide
|
|
2
|
+
|
|
3
|
+
This guide covers all configuration options available in SolForge's `sf.config.json` file.
|
|
4
|
+
|
|
5
|
+
## Configuration File Structure
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"name": "string",
|
|
10
|
+
"description": "string (optional)",
|
|
11
|
+
"tokens": [
|
|
12
|
+
/* TokenConfig[] */
|
|
13
|
+
],
|
|
14
|
+
"programs": [
|
|
15
|
+
/* ProgramConfig[] */
|
|
16
|
+
],
|
|
17
|
+
"localnet": {
|
|
18
|
+
/* LocalnetConfig */
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Root Configuration
|
|
24
|
+
|
|
25
|
+
### `name` (required)
|
|
26
|
+
|
|
27
|
+
- **Type**: `string`
|
|
28
|
+
- **Default**: `"solforge-localnet"`
|
|
29
|
+
- **Description**: Name identifier for your localnet configuration
|
|
30
|
+
|
|
31
|
+
### `description` (optional)
|
|
32
|
+
|
|
33
|
+
- **Type**: `string`
|
|
34
|
+
- **Description**: Human-readable description of your setup
|
|
35
|
+
|
|
36
|
+
### `tokens` (optional)
|
|
37
|
+
|
|
38
|
+
- **Type**: `TokenConfig[]`
|
|
39
|
+
- **Default**: `[]`
|
|
40
|
+
- **Description**: Array of tokens to clone from mainnet
|
|
41
|
+
|
|
42
|
+
### `programs` (optional)
|
|
43
|
+
|
|
44
|
+
- **Type**: `ProgramConfig[]`
|
|
45
|
+
- **Default**: `[]`
|
|
46
|
+
- **Description**: Array of programs to clone from mainnet
|
|
47
|
+
|
|
48
|
+
### `localnet` (optional)
|
|
49
|
+
|
|
50
|
+
- **Type**: `LocalnetConfig`
|
|
51
|
+
- **Description**: Validator configuration options
|
|
52
|
+
|
|
53
|
+
## Token Configuration (`TokenConfig`)
|
|
54
|
+
|
|
55
|
+
### `symbol` (required)
|
|
56
|
+
|
|
57
|
+
- **Type**: `string`
|
|
58
|
+
- **Description**: Token symbol (e.g., "USDC", "SOL")
|
|
59
|
+
- **Example**: `"USDC"`
|
|
60
|
+
|
|
61
|
+
### `mainnetMint` (required)
|
|
62
|
+
|
|
63
|
+
- **Type**: `string`
|
|
64
|
+
- **Description**: Mainnet mint address to clone
|
|
65
|
+
- **Example**: `"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"`
|
|
66
|
+
|
|
67
|
+
### `mintAuthority` (optional)
|
|
68
|
+
|
|
69
|
+
- **Type**: `string`
|
|
70
|
+
- **Description**: Path to keypair file for mint authority
|
|
71
|
+
- **Example**: `"./keypairs/mint-authority.json"`
|
|
72
|
+
- **Note**: If not provided, a new keypair will be generated
|
|
73
|
+
|
|
74
|
+
### `mintAmount` (optional)
|
|
75
|
+
|
|
76
|
+
- **Type**: `number`
|
|
77
|
+
- **Default**: `1000000`
|
|
78
|
+
- **Description**: Amount to mint to the mint authority
|
|
79
|
+
- **Note**: Amount is in token's base units (considering decimals)
|
|
80
|
+
|
|
81
|
+
### `cloneMetadata` (optional)
|
|
82
|
+
|
|
83
|
+
- **Type**: `boolean`
|
|
84
|
+
- **Default**: `true`
|
|
85
|
+
- **Description**: Whether to clone token metadata from mainnet
|
|
86
|
+
|
|
87
|
+
### `recipients` (optional)
|
|
88
|
+
|
|
89
|
+
- **Type**: `RecipientConfig[]`
|
|
90
|
+
- **Default**: `[]`
|
|
91
|
+
- **Description**: List of wallets to receive tokens after minting
|
|
92
|
+
|
|
93
|
+
#### `RecipientConfig`
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"wallet": "string (required)",
|
|
98
|
+
"amount": "number (required)"
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
- `wallet`: Public key of recipient wallet
|
|
103
|
+
- `amount`: Amount to transfer (in token's base units)
|
|
104
|
+
|
|
105
|
+
### Example Token Configuration
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"symbol": "USDC",
|
|
110
|
+
"mainnetMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
|
|
111
|
+
"mintAuthority": "./keypairs/usdc-mint.json",
|
|
112
|
+
"mintAmount": 10000000000,
|
|
113
|
+
"cloneMetadata": true,
|
|
114
|
+
"recipients": [
|
|
115
|
+
{
|
|
116
|
+
"wallet": "YourWalletPublicKeyHere",
|
|
117
|
+
"amount": 1000000000
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"wallet": "AnotherWalletPublicKeyHere",
|
|
121
|
+
"amount": 500000000
|
|
122
|
+
}
|
|
123
|
+
]
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Program Configuration (`ProgramConfig`)
|
|
128
|
+
|
|
129
|
+
### `name` (optional)
|
|
130
|
+
|
|
131
|
+
- **Type**: `string`
|
|
132
|
+
- **Description**: Friendly name for the program
|
|
133
|
+
- **Example**: `"Jupiter Aggregator"`
|
|
134
|
+
|
|
135
|
+
### `mainnetProgramId` (required)
|
|
136
|
+
|
|
137
|
+
- **Type**: `string`
|
|
138
|
+
- **Description**: Mainnet program ID to clone
|
|
139
|
+
- **Example**: `"JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"`
|
|
140
|
+
|
|
141
|
+
### `deployPath` (optional)
|
|
142
|
+
|
|
143
|
+
- **Type**: `string`
|
|
144
|
+
- **Description**: Path to local .so file to deploy instead of cloning
|
|
145
|
+
- **Example**: `"./target/deploy/my_program.so"`
|
|
146
|
+
|
|
147
|
+
### `upgradeable` (optional)
|
|
148
|
+
|
|
149
|
+
- **Type**: `boolean`
|
|
150
|
+
- **Default**: `false`
|
|
151
|
+
- **Description**: Whether the program should be deployed as upgradeable
|
|
152
|
+
|
|
153
|
+
### `cluster` (optional)
|
|
154
|
+
|
|
155
|
+
- **Type**: `"mainnet-beta" | "devnet" | "testnet"`
|
|
156
|
+
- **Default**: `"mainnet-beta"`
|
|
157
|
+
- **Description**: Source cluster to clone the program from
|
|
158
|
+
|
|
159
|
+
### `dependencies` (optional)
|
|
160
|
+
|
|
161
|
+
- **Type**: `string[]`
|
|
162
|
+
- **Default**: `[]`
|
|
163
|
+
- **Description**: Array of program IDs this program depends on
|
|
164
|
+
- **Note**: Dependencies will be deployed before this program
|
|
165
|
+
|
|
166
|
+
### Example Program Configuration
|
|
167
|
+
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"name": "Jupiter Aggregator",
|
|
171
|
+
"mainnetProgramId": "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4",
|
|
172
|
+
"cluster": "mainnet-beta",
|
|
173
|
+
"upgradeable": false,
|
|
174
|
+
"dependencies": ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"]
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Localnet Configuration (`LocalnetConfig`)
|
|
179
|
+
|
|
180
|
+
### `airdropAmount` (optional)
|
|
181
|
+
|
|
182
|
+
- **Type**: `number`
|
|
183
|
+
- **Default**: `100`
|
|
184
|
+
- **Description**: SOL amount for initial airdrops
|
|
185
|
+
- **Unit**: SOL
|
|
186
|
+
|
|
187
|
+
### `faucetAccounts` (optional)
|
|
188
|
+
|
|
189
|
+
- **Type**: `string[]`
|
|
190
|
+
- **Default**: `[]`
|
|
191
|
+
- **Description**: Public keys to receive initial SOL airdrops
|
|
192
|
+
|
|
193
|
+
### `port` (optional)
|
|
194
|
+
|
|
195
|
+
- **Type**: `number`
|
|
196
|
+
- **Default**: `8899`
|
|
197
|
+
- **Range**: `1000-65535`
|
|
198
|
+
- **Description**: RPC port for the validator
|
|
199
|
+
|
|
200
|
+
### `faucetPort` (optional)
|
|
201
|
+
|
|
202
|
+
- **Type**: `number`
|
|
203
|
+
- **Default**: `9900`
|
|
204
|
+
- **Range**: `1000-65535`
|
|
205
|
+
- **Description**: Faucet port for the validator
|
|
206
|
+
|
|
207
|
+
### `reset` (optional)
|
|
208
|
+
|
|
209
|
+
- **Type**: `boolean`
|
|
210
|
+
- **Default**: `false`
|
|
211
|
+
- **Description**: Whether to reset the ledger on startup
|
|
212
|
+
|
|
213
|
+
### `logLevel` (optional)
|
|
214
|
+
|
|
215
|
+
- **Type**: `"trace" | "debug" | "info" | "warn" | "error"`
|
|
216
|
+
- **Default**: `"info"`
|
|
217
|
+
- **Description**: Validator log level
|
|
218
|
+
|
|
219
|
+
### `quiet` (optional)
|
|
220
|
+
|
|
221
|
+
- **Type**: `boolean`
|
|
222
|
+
- **Default**: `false`
|
|
223
|
+
- **Description**: Suppress validator output
|
|
224
|
+
|
|
225
|
+
### `ledgerPath` (optional)
|
|
226
|
+
|
|
227
|
+
- **Type**: `string`
|
|
228
|
+
- **Description**: Custom path for ledger data
|
|
229
|
+
- **Note**: If not specified, uses default location
|
|
230
|
+
|
|
231
|
+
### `bindAddress` (optional)
|
|
232
|
+
|
|
233
|
+
- **Type**: `string`
|
|
234
|
+
- **Default**: `"127.0.0.1"`
|
|
235
|
+
- **Description**: IP address to bind the validator to
|
|
236
|
+
|
|
237
|
+
### `limitLedgerSize` (optional)
|
|
238
|
+
|
|
239
|
+
- **Type**: `number`
|
|
240
|
+
- **Default**: `100000`
|
|
241
|
+
- **Description**: Maximum ledger size in slots
|
|
242
|
+
|
|
243
|
+
### `rpc` (optional)
|
|
244
|
+
|
|
245
|
+
- **Type**: `string` (URL)
|
|
246
|
+
- **Default**: `"https://api.mainnet-beta.solana.com"`
|
|
247
|
+
- **Description**: RPC URL for cloning data from mainnet
|
|
248
|
+
|
|
249
|
+
### Example Localnet Configuration
|
|
250
|
+
|
|
251
|
+
```json
|
|
252
|
+
{
|
|
253
|
+
"airdropAmount": 1000,
|
|
254
|
+
"faucetAccounts": ["YourWalletPublicKeyHere", "AnotherWalletPublicKeyHere"],
|
|
255
|
+
"port": 8899,
|
|
256
|
+
"faucetPort": 9900,
|
|
257
|
+
"reset": false,
|
|
258
|
+
"logLevel": "debug",
|
|
259
|
+
"quiet": false,
|
|
260
|
+
"bindAddress": "0.0.0.0",
|
|
261
|
+
"limitLedgerSize": 50000,
|
|
262
|
+
"rpc": "https://mainnet.helius-rpc.com/?api-key=your-key"
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Complete Example Configuration
|
|
267
|
+
|
|
268
|
+
```json
|
|
269
|
+
{
|
|
270
|
+
"name": "defi-development",
|
|
271
|
+
"description": "DeFi development environment with popular tokens and DEX programs",
|
|
272
|
+
"tokens": [
|
|
273
|
+
{
|
|
274
|
+
"symbol": "USDC",
|
|
275
|
+
"mainnetMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
|
|
276
|
+
"mintAmount": 10000000000,
|
|
277
|
+
"cloneMetadata": true,
|
|
278
|
+
"recipients": [
|
|
279
|
+
{
|
|
280
|
+
"wallet": "YourWalletPublicKeyHere",
|
|
281
|
+
"amount": 1000000000
|
|
282
|
+
}
|
|
283
|
+
]
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
"symbol": "USDT",
|
|
287
|
+
"mainnetMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB",
|
|
288
|
+
"mintAmount": 10000000000,
|
|
289
|
+
"cloneMetadata": true,
|
|
290
|
+
"recipients": [
|
|
291
|
+
{
|
|
292
|
+
"wallet": "YourWalletPublicKeyHere",
|
|
293
|
+
"amount": 1000000000
|
|
294
|
+
}
|
|
295
|
+
]
|
|
296
|
+
}
|
|
297
|
+
],
|
|
298
|
+
"programs": [
|
|
299
|
+
{
|
|
300
|
+
"name": "Jupiter Aggregator",
|
|
301
|
+
"mainnetProgramId": "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4",
|
|
302
|
+
"cluster": "mainnet-beta"
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
"name": "Orca",
|
|
306
|
+
"mainnetProgramId": "9W959DqEETiGZocYWCQPaJ6sBmUzgfxXfqGeTEdp3aQP",
|
|
307
|
+
"cluster": "mainnet-beta"
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
"name": "Token Metadata",
|
|
311
|
+
"mainnetProgramId": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s",
|
|
312
|
+
"cluster": "mainnet-beta"
|
|
313
|
+
}
|
|
314
|
+
],
|
|
315
|
+
"localnet": {
|
|
316
|
+
"airdropAmount": 1000,
|
|
317
|
+
"faucetAccounts": ["YourWalletPublicKeyHere"],
|
|
318
|
+
"port": 8899,
|
|
319
|
+
"faucetPort": 9900,
|
|
320
|
+
"reset": false,
|
|
321
|
+
"logLevel": "info",
|
|
322
|
+
"bindAddress": "127.0.0.1",
|
|
323
|
+
"limitLedgerSize": 100000,
|
|
324
|
+
"rpc": "https://api.mainnet-beta.solana.com"
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## Configuration Validation
|
|
330
|
+
|
|
331
|
+
SolForge validates your configuration file using Zod schemas. Common validation errors:
|
|
332
|
+
|
|
333
|
+
### Invalid Token Configuration
|
|
334
|
+
|
|
335
|
+
```
|
|
336
|
+
❌ Token symbol is required
|
|
337
|
+
❌ Mainnet mint address is required
|
|
338
|
+
❌ Mint amount must be positive
|
|
339
|
+
❌ Wallet address is required for recipients
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Invalid Program Configuration
|
|
343
|
+
|
|
344
|
+
```
|
|
345
|
+
❌ Program ID is required
|
|
346
|
+
❌ Invalid cluster (must be mainnet-beta, devnet, or testnet)
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Invalid Localnet Configuration
|
|
350
|
+
|
|
351
|
+
```
|
|
352
|
+
❌ Port must be between 1000 and 65535
|
|
353
|
+
❌ RPC must be a valid URL
|
|
354
|
+
❌ Log level must be one of: trace, debug, info, warn, error
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
## Best Practices
|
|
358
|
+
|
|
359
|
+
1. **Use descriptive names**: Make your configuration name and description clear
|
|
360
|
+
2. **Start small**: Begin with a few tokens/programs and add more as needed
|
|
361
|
+
3. **Use custom RPC**: Consider using a dedicated RPC endpoint for better performance
|
|
362
|
+
4. **Manage keypairs**: Store mint authority keypairs securely
|
|
363
|
+
5. **Port management**: Use different ports for multiple environments
|
|
364
|
+
6. **Reset wisely**: Use `reset: true` for clean starts, `false` for persistent data
|
|
365
|
+
7. **Log levels**: Use `debug` for development, `info` for production
|
|
366
|
+
|
|
367
|
+
## Environment-Specific Configurations
|
|
368
|
+
|
|
369
|
+
### Development Environment
|
|
370
|
+
|
|
371
|
+
```json
|
|
372
|
+
{
|
|
373
|
+
"name": "dev-environment",
|
|
374
|
+
"localnet": {
|
|
375
|
+
"reset": true,
|
|
376
|
+
"logLevel": "debug",
|
|
377
|
+
"airdropAmount": 1000
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### Testing Environment
|
|
383
|
+
|
|
384
|
+
```json
|
|
385
|
+
{
|
|
386
|
+
"name": "test-environment",
|
|
387
|
+
"localnet": {
|
|
388
|
+
"reset": false,
|
|
389
|
+
"logLevel": "warn",
|
|
390
|
+
"quiet": true
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### Production-like Environment
|
|
396
|
+
|
|
397
|
+
```json
|
|
398
|
+
{
|
|
399
|
+
"name": "prod-like-environment",
|
|
400
|
+
"localnet": {
|
|
401
|
+
"reset": false,
|
|
402
|
+
"logLevel": "error",
|
|
403
|
+
"limitLedgerSize": 1000000,
|
|
404
|
+
"rpc": "https://your-premium-rpc-endpoint.com"
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
```
|
package/package.json
CHANGED
|
@@ -1,47 +1,58 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
2
|
+
"name": "solforge",
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"module": "index.ts",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"private": false,
|
|
7
|
+
"bin": {
|
|
8
|
+
"solforge": "dist/solforge"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"src",
|
|
13
|
+
"server",
|
|
14
|
+
"docs",
|
|
15
|
+
"README.md",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"lint": "biome check",
|
|
20
|
+
"cli": "bun src/cli/main.ts",
|
|
21
|
+
"build:gui": "bun build src/gui/src/main.tsx --outdir src/gui/public/build --target=browser --minify",
|
|
22
|
+
"build:css": "bunx tailwindcss -i src/gui/src/index.css -o src/gui/public/app.css --minify",
|
|
23
|
+
"build": "bun run build:bin",
|
|
24
|
+
"build:bin": "bun run build:css && bun run build:gui && bun build --compile src/cli/main.ts --outfile dist/solforge",
|
|
25
|
+
"build:bin:darwin-arm64": "bun run build:css && bun run build:gui && bun build --compile --target=bun-darwin-arm64 src/cli/main.ts --outfile dist/solforge-darwin-arm64",
|
|
26
|
+
"build:bin:darwin-x64": "bun run build:css && bun run build:gui && bun build --compile --target=bun-darwin-x64 src/cli/main.ts --outfile dist/solforge-darwin-x64",
|
|
27
|
+
"build:bin:linux-x64": "bun run build:css && bun run build:gui && bun build --compile --target=bun-linux-x64 src/cli/main.ts --outfile dist/solforge-linux-x64",
|
|
28
|
+
"build:bin:linux-arm64": "bun run build:css && bun run build:gui && bun build --compile --target=bun-linux-arm64 src/cli/main.ts --outfile dist/solforge-linux-arm64",
|
|
29
|
+
"build:bin:windows-x64": "bun run build:css && bun run build:gui && bun build --compile --target=bun-windows-x64 src/cli/main.ts --outfile dist/solforge-windows-x64.exe",
|
|
30
|
+
"build:bin:all": "bun run build:bin:darwin-arm64 && bun run build:bin:darwin-x64 && bun run build:bin:linux-x64 && bun run build:bin:linux-arm64 && bun run build:bin:windows-x64"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@biomejs/biome": "2.2.4",
|
|
34
|
+
"@types/bun": "latest",
|
|
35
|
+
"@types/react": "^19.1.13",
|
|
36
|
+
"@types/react-dom": "^19.1.9",
|
|
37
|
+
"autoprefixer": "^10.4.21",
|
|
38
|
+
"drizzle-kit": "^0.31.4",
|
|
39
|
+
"postcss": "^8.5.6",
|
|
40
|
+
"tailwindcss": "3"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"typescript": "^5"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@clack/prompts": "^0.11.0",
|
|
47
|
+
"@solana-program/compute-budget": "^0.9.0",
|
|
48
|
+
"@solana-program/memo": "^0.8.0",
|
|
49
|
+
"@solana-program/system": "^0.8.0",
|
|
50
|
+
"@solana-program/token": "^0.6.0",
|
|
51
|
+
"@solana/kit": "^3.0.3",
|
|
52
|
+
"@solana/spl-token": "^0.4.14",
|
|
53
|
+
"drizzle-orm": "^0.44.5",
|
|
54
|
+
"litesvm": "^0.3.3",
|
|
55
|
+
"react": "^19.1.1",
|
|
56
|
+
"react-dom": "^19.1.1"
|
|
57
|
+
}
|
|
47
58
|
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { APIServer } from "./services/api-server.js";
|
|
4
|
+
import { configManager } from "./config/manager.js";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
|
|
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");
|
|
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
|
+
}
|
|
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]!;
|
|
43
|
+
|
|
44
|
+
// Load configuration
|
|
45
|
+
await configManager.load(configPath);
|
|
46
|
+
const config = configManager.getConfig();
|
|
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
|
+
});
|
|
57
|
+
|
|
58
|
+
const result = await apiServer.start();
|
|
59
|
+
|
|
60
|
+
if (result.success) {
|
|
61
|
+
console.log(chalk.green(`🚀 API Server started on port ${port}`));
|
|
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
|
+
});
|
|
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
|
+
});
|
|
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
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
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);
|
|
109
|
+
});
|