neozip-cli 0.75.0-beta → 0.75.2-beta

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.
@@ -0,0 +1,455 @@
1
+ "use strict";
2
+ /**
3
+ * ConfigSetup - Interactive setup wizard for NeoZip configuration
4
+ * Provides CLI interface for configuring wallet, network, RPC, gas, and debug settings
5
+ * This is the presentation layer - handles user interaction and uses ConfigStore for data operations
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ exports.ConfigSetup = void 0;
42
+ const readline = __importStar(require("readline"));
43
+ const ConfigStore_1 = require("./ConfigStore");
44
+ const blockchain_1 = require("neozipkit/blockchain");
45
+ class ConfigSetup {
46
+ constructor() {
47
+ this.rl = readline.createInterface({
48
+ input: process.stdin,
49
+ output: process.stdout,
50
+ });
51
+ }
52
+ /**
53
+ * Prompt for selection from a numbered list
54
+ */
55
+ async promptSelection(title, options, defaultValue) {
56
+ console.log(` ${title}`);
57
+ // Display options with numbers
58
+ options.forEach((opt, index) => {
59
+ const isDefault = opt.value === defaultValue;
60
+ const defaultTag = isDefault ? ' [DEFAULT]' : '';
61
+ const description = opt.description ? ` - ${opt.description}` : '';
62
+ console.log(` ${index + 1}. ${opt.label}${description}${defaultTag}`);
63
+ });
64
+ // Get default index
65
+ const defaultIndex = defaultValue
66
+ ? options.findIndex(opt => opt.value === defaultValue) + 1
67
+ : 1;
68
+ const answer = await this.prompt(' Enter choice', defaultIndex.toString());
69
+ const choice = parseInt(answer);
70
+ if (isNaN(choice) || choice < 1 || choice > options.length) {
71
+ console.error(` āŒ Invalid choice. Please select 1-${options.length}`);
72
+ return defaultValue || options[0].value;
73
+ }
74
+ return options[choice - 1].value;
75
+ }
76
+ /**
77
+ * Prompt for a value with validation
78
+ */
79
+ async prompt(question, defaultValue, isPassword = false) {
80
+ return new Promise((resolve) => {
81
+ const displayQuestion = defaultValue
82
+ ? `${question} (${defaultValue}): `
83
+ : `${question}: `;
84
+ if (isPassword) {
85
+ // For password input, use readline with line clearing for security
86
+ this.rl.question(displayQuestion, (answer) => {
87
+ // Clear the line to hide the password from terminal history
88
+ readline.clearLine(process.stdout, 0);
89
+ readline.cursorTo(process.stdout, 0);
90
+ process.stdout.write(question.split(':')[0] + ': ********\n');
91
+ resolve(answer.trim() || defaultValue || '');
92
+ });
93
+ }
94
+ else {
95
+ this.rl.question(displayQuestion, (answer) => {
96
+ resolve(answer.trim() || defaultValue || '');
97
+ });
98
+ }
99
+ });
100
+ }
101
+ /**
102
+ * Run the interactive setup wizard
103
+ */
104
+ async run() {
105
+ console.log('\nšŸ”§ NeoZip Wallet Configuration Setup\n');
106
+ console.log('This wizard will help you configure your blockchain wallet settings.');
107
+ console.log('Press Ctrl+C at any time to cancel.\n');
108
+ try {
109
+ // Load existing config if available
110
+ const existingConfig = ConfigStore_1.ConfigStore.load();
111
+ const isUpdate = existingConfig !== null;
112
+ if (isUpdate) {
113
+ console.log('šŸ“ Existing configuration found. You can update individual settings.\n');
114
+ }
115
+ // 1. Wallet Private Key
116
+ console.log('1ļøāƒ£ Wallet Configuration');
117
+ console.log(' Your private key is required for blockchain operations (minting, OTS).');
118
+ let privateKey;
119
+ if (isUpdate && existingConfig?.wallet?.privateKey) {
120
+ const masked = `${existingConfig.wallet.privateKey.substring(0, 6)}...${existingConfig.wallet.privateKey.substring(existingConfig.wallet.privateKey.length - 4)}`;
121
+ const keep = await this.promptSelection(`Keep existing private key (${masked})?`, [
122
+ { value: 'y', label: 'Yes', description: 'Keep current key' },
123
+ { value: 'n', label: 'No', description: 'Enter new key' }
124
+ ], 'y');
125
+ if (keep === 'y') {
126
+ privateKey = existingConfig.wallet.privateKey;
127
+ }
128
+ else {
129
+ privateKey = await this.prompt(' Enter wallet private key', '', true);
130
+ }
131
+ }
132
+ else {
133
+ privateKey = await this.prompt(' Enter wallet private key', '', true);
134
+ }
135
+ // Validate private key
136
+ if (privateKey && !ConfigStore_1.ConfigStore.validatePrivateKey(privateKey)) {
137
+ console.error('\nāŒ Invalid private key format. Must be 64 hex characters (with or without 0x prefix).');
138
+ this.rl.close();
139
+ return false;
140
+ }
141
+ // Ensure 0x prefix
142
+ if (privateKey && !privateKey.startsWith('0x')) {
143
+ privateKey = `0x${privateKey}`;
144
+ }
145
+ // 2. Network Selection
146
+ console.log('\n2ļøāƒ£ Network Selection');
147
+ const currentNetwork = existingConfig?.wallet?.network || 'base-sepolia';
148
+ // Dynamically build network options from CONTRACT_CONFIGS
149
+ // CONTRACT_CONFIGS is already ordered correctly: Base (testnet/mainnet), Arbitrum (testnet/mainnet), Ethereum
150
+ const networkOptions = [];
151
+ const networkConfigs = Object.values(blockchain_1.CONTRACT_CONFIGS);
152
+ // Verify we're loading networks
153
+ if (networkConfigs.length === 0) {
154
+ console.error('āŒ Error: No networks found in CONTRACT_CONFIGS');
155
+ console.error(' This should not happen. Please check the contracts configuration.');
156
+ process.exit(1);
157
+ }
158
+ // Networks are already in the correct order from CONTRACT_CONFIGS (preserved by Object.values())
159
+ for (const config of networkConfigs) {
160
+ // Use the primary alias (first nameAlias) or network name as value
161
+ const primaryAlias = config.nameAliases && config.nameAliases.length > 0
162
+ ? config.nameAliases[0]
163
+ : (0, blockchain_1.normalizeNetworkName)(config.network);
164
+ // Determine description based on network type
165
+ const isTestnet = config.network.toLowerCase().includes('testnet') ||
166
+ config.network.toLowerCase().includes('sepolia');
167
+ const description = isTestnet
168
+ ? `Testnet (Chain ID: ${config.chainId})`
169
+ : `Mainnet (Chain ID: ${config.chainId}) - Real ETH required`;
170
+ networkOptions.push({
171
+ value: primaryAlias,
172
+ label: config.network,
173
+ description: description
174
+ });
175
+ }
176
+ const network = await this.promptSelection('Choose your blockchain network:', networkOptions, currentNetwork);
177
+ // 3. Custom RPC (optional)
178
+ console.log('\n3ļøāƒ£ RPC Configuration (optional)');
179
+ const useCustomRpc = await this.promptSelection('Configure custom RPC endpoints?', [
180
+ { value: 'n', label: 'No', description: 'Use default public RPC endpoints' },
181
+ { value: 'y', label: 'Yes', description: 'Configure custom RPC URLs' }
182
+ ], 'n');
183
+ // Build RPC config dynamically from available networks
184
+ const rpcConfig = {};
185
+ // Preserve existing RPC config (for backward compatibility)
186
+ if (existingConfig?.rpc) {
187
+ Object.assign(rpcConfig, existingConfig.rpc);
188
+ }
189
+ if (useCustomRpc === 'y') {
190
+ // Get the selected network config to show default RPC
191
+ const selectedNetworkConfig = (0, blockchain_1.getNetworkByName)(network);
192
+ // Prompt for RPC URL for the selected network
193
+ if (selectedNetworkConfig) {
194
+ const defaultRpc = selectedNetworkConfig.rpcUrls && selectedNetworkConfig.rpcUrls.length > 0
195
+ ? selectedNetworkConfig.rpcUrls[0]
196
+ : '';
197
+ // Use primary alias as RPC key for consistency (or normalized network name as fallback)
198
+ const rpcKey = (selectedNetworkConfig.nameAliases && selectedNetworkConfig.nameAliases.length > 0)
199
+ ? selectedNetworkConfig.nameAliases[0]
200
+ : (0, blockchain_1.normalizeNetworkName)(selectedNetworkConfig.network);
201
+ // Check both new format and legacy format for backward compatibility
202
+ const existingRpc = rpcConfig[rpcKey]
203
+ || rpcConfig[(0, blockchain_1.normalizeNetworkName)(selectedNetworkConfig.network).replace(/\s+/g, '')]
204
+ || existingConfig?.rpc?.[rpcKey]
205
+ || existingConfig?.rpc?.[(0, blockchain_1.normalizeNetworkName)(selectedNetworkConfig.network).replace(/\s+/g, '')];
206
+ const customRpc = await this.prompt(` ${selectedNetworkConfig.network} RPC URL`, existingRpc || defaultRpc);
207
+ if (customRpc) {
208
+ rpcConfig[rpcKey] = customRpc;
209
+ }
210
+ }
211
+ // Optionally configure RPC for other networks
212
+ const configureMore = await this.promptSelection('Configure RPC for additional networks?', [
213
+ { value: 'n', label: 'No', description: 'Only configure selected network' },
214
+ { value: 'y', label: 'Yes', description: 'Configure all networks' }
215
+ ], 'n');
216
+ if (configureMore === 'y') {
217
+ for (const config of networkConfigs) {
218
+ // Skip the already configured network
219
+ const configAlias = config.nameAliases && config.nameAliases.length > 0
220
+ ? config.nameAliases[0]
221
+ : (0, blockchain_1.normalizeNetworkName)(config.network);
222
+ if (configAlias === network)
223
+ continue;
224
+ // Use primary alias as RPC key for consistency (or normalized network name as fallback)
225
+ const rpcKey = (config.nameAliases && config.nameAliases.length > 0)
226
+ ? config.nameAliases[0]
227
+ : (0, blockchain_1.normalizeNetworkName)(config.network);
228
+ const defaultRpc = config.rpcUrls && config.rpcUrls.length > 0
229
+ ? config.rpcUrls[0]
230
+ : '';
231
+ // Check both new format and legacy format for backward compatibility
232
+ const existingRpc = rpcConfig[rpcKey]
233
+ || rpcConfig[(0, blockchain_1.normalizeNetworkName)(config.network).replace(/\s+/g, '')]
234
+ || existingConfig?.rpc?.[rpcKey]
235
+ || existingConfig?.rpc?.[(0, blockchain_1.normalizeNetworkName)(config.network).replace(/\s+/g, '')];
236
+ const customRpc = await this.prompt(` ${config.network} RPC URL`, existingRpc || defaultRpc);
237
+ if (customRpc) {
238
+ rpcConfig[rpcKey] = customRpc;
239
+ }
240
+ }
241
+ }
242
+ }
243
+ // 4. Gas Configuration (optional)
244
+ console.log('\n4ļøāƒ£ Gas Configuration (optional)');
245
+ const configureGas = await this.promptSelection('Configure gas settings?', [
246
+ { value: 'n', label: 'No', description: 'Use default gas settings' },
247
+ { value: 'y', label: 'Yes', description: 'Configure custom gas limits' }
248
+ ], 'n');
249
+ let gasMultiplier = existingConfig?.gas?.multiplier;
250
+ let maxGasPrice = existingConfig?.gas?.maxPriceGwei;
251
+ if (configureGas === 'y') {
252
+ const multiplierStr = await this.prompt(' Gas price multiplier', gasMultiplier?.toString() || '1.0');
253
+ const maxPriceStr = await this.prompt(' Max gas price (gwei)', maxGasPrice?.toString() || '100');
254
+ gasMultiplier = parseFloat(multiplierStr);
255
+ maxGasPrice = parseInt(maxPriceStr);
256
+ }
257
+ // 5. Debug Settings (optional)
258
+ console.log('\n5ļøāƒ£ Debug Configuration (optional)');
259
+ const configureDebug = await this.promptSelection('Enable debug/verbose mode?', [
260
+ { value: 'n', label: 'No', description: 'Standard logging only' },
261
+ { value: 'y', label: 'Yes', description: 'Enable verbose and debug output' }
262
+ ], 'n');
263
+ let verbose = existingConfig?.debug?.verbose || false;
264
+ let debugEnabled = existingConfig?.debug?.enabled || false;
265
+ if (configureDebug === 'y') {
266
+ const verboseStr = await this.promptSelection('Enable verbose logging?', [
267
+ { value: 'n', label: 'No' },
268
+ { value: 'y', label: 'Yes' }
269
+ ], verbose ? 'y' : 'n');
270
+ const debugStr = await this.promptSelection('Enable debug mode?', [
271
+ { value: 'n', label: 'No' },
272
+ { value: 'y', label: 'Yes' }
273
+ ], debugEnabled ? 'y' : 'n');
274
+ verbose = verboseStr === 'y';
275
+ debugEnabled = debugStr === 'y';
276
+ }
277
+ // Build configuration object
278
+ const config = {
279
+ wallet: {
280
+ privateKey,
281
+ network,
282
+ },
283
+ rpc: Object.keys(rpcConfig).length > 0 ? rpcConfig : undefined,
284
+ gas: gasMultiplier || maxGasPrice ? {
285
+ multiplier: gasMultiplier,
286
+ maxPriceGwei: maxGasPrice,
287
+ } : undefined,
288
+ debug: verbose || debugEnabled ? {
289
+ verbose,
290
+ enabled: debugEnabled,
291
+ } : undefined,
292
+ };
293
+ // Save configuration
294
+ console.log('\nšŸ’¾ Saving configuration...');
295
+ const saved = ConfigStore_1.ConfigStore.save(config);
296
+ if (saved) {
297
+ console.log(`āœ… Configuration saved to: ${ConfigStore_1.ConfigStore.getConfigPath()}\n`);
298
+ console.log('šŸ“‹ Configuration summary:');
299
+ console.log(` Wallet: ${privateKey ? `${privateKey.substring(0, 6)}...${privateKey.substring(privateKey.length - 4)}` : '(not set)'}`);
300
+ console.log(` Network: ${network}`);
301
+ if (Object.keys(rpcConfig).length > 0) {
302
+ console.log(` RPC URLs: Custom (${Object.keys(rpcConfig).length} network(s))`);
303
+ }
304
+ if (gasMultiplier || maxGasPrice) {
305
+ console.log(` Gas: Custom (${gasMultiplier}x, max ${maxGasPrice} gwei)`);
306
+ }
307
+ if (verbose || debugEnabled) {
308
+ console.log(` Debug: ${verbose ? 'verbose' : ''} ${debugEnabled ? 'enabled' : ''}`);
309
+ }
310
+ console.log('\nšŸ’” You can now use blockchain features: neozip -b <archive> <files>');
311
+ console.log('šŸ’” To update config: neozip config show | set | reset\n');
312
+ }
313
+ this.rl.close();
314
+ return saved;
315
+ }
316
+ catch (error) {
317
+ console.error(`\nāŒ Setup failed: ${error}`);
318
+ this.rl.close();
319
+ return false;
320
+ }
321
+ }
322
+ /**
323
+ * Show configuration and offer options to modify or reset
324
+ */
325
+ static async showAndManage() {
326
+ if (!ConfigStore_1.ConfigStore.exists()) {
327
+ console.log('\nāš ļø No wallet.json configuration found.');
328
+ console.log('šŸ’” Run "neozip init" to create your configuration.\n');
329
+ process.exit(0);
330
+ }
331
+ console.log('\nšŸ“‹ Current NeoZip Configuration:');
332
+ console.log(`šŸ“ Location: ${ConfigStore_1.ConfigStore.getConfigPath()}\n`);
333
+ console.log(ConfigStore_1.ConfigStore.getMaskedConfig());
334
+ console.log('');
335
+ // Create readline interface for menu
336
+ const rl = require('readline').createInterface({
337
+ input: process.stdin,
338
+ output: process.stdout
339
+ });
340
+ return new Promise((resolve) => {
341
+ const showMenu = () => {
342
+ const config = ConfigStore_1.ConfigStore.getConfig();
343
+ const hasPrivateKey = config.walletKey !== null;
344
+ console.log('What would you like to do?');
345
+ console.log(' 1. Modify configuration (update settings)');
346
+ if (hasPrivateKey) {
347
+ console.log(' 2. Delete private key (remove wallet key from configuration)');
348
+ console.log(' 3. Reset to defaults (delete entire configuration)');
349
+ console.log(' 4. Exit');
350
+ }
351
+ else {
352
+ console.log(' 2. Reset to defaults (delete entire configuration)');
353
+ console.log(' 3. Exit');
354
+ }
355
+ const maxChoice = hasPrivateKey ? 4 : 3;
356
+ rl.question(`\nEnter choice (1-${maxChoice}): `, async (answer) => {
357
+ const choice = parseInt(answer);
358
+ switch (choice) {
359
+ case 1:
360
+ rl.close();
361
+ const wizard = new ConfigSetup();
362
+ const success = await wizard.run();
363
+ process.exit(success ? 0 : 1);
364
+ break;
365
+ case 2:
366
+ if (hasPrivateKey) {
367
+ // Delete private key only
368
+ rl.question('\nāš ļø Are you sure you want to delete your private key? (y/n): ', (confirm) => {
369
+ if (confirm.toLowerCase() === 'y') {
370
+ const success = ConfigStore_1.ConfigStore.delete('wallet.privateKey');
371
+ if (success) {
372
+ console.log('āœ… Private key deleted successfully.\n');
373
+ }
374
+ else {
375
+ console.log('āŒ Failed to delete private key.\n');
376
+ }
377
+ rl.close();
378
+ process.exit(success ? 0 : 1);
379
+ }
380
+ else {
381
+ console.log('āŒ Deletion cancelled.\n');
382
+ rl.close();
383
+ process.exit(0);
384
+ }
385
+ });
386
+ }
387
+ else {
388
+ // Reset entire config
389
+ rl.question('\nāš ļø Are you sure you want to delete your wallet configuration? (y/n): ', (confirm) => {
390
+ if (confirm.toLowerCase() === 'y') {
391
+ const success = ConfigStore_1.ConfigStore.reset();
392
+ if (success) {
393
+ console.log('āœ… Configuration deleted successfully.\n');
394
+ }
395
+ rl.close();
396
+ process.exit(success ? 0 : 1);
397
+ }
398
+ else {
399
+ console.log('āŒ Reset cancelled.\n');
400
+ rl.close();
401
+ process.exit(0);
402
+ }
403
+ });
404
+ }
405
+ break;
406
+ case 3:
407
+ if (hasPrivateKey) {
408
+ // Reset entire config
409
+ rl.question('\nāš ļø Are you sure you want to delete your wallet configuration? (y/n): ', (confirm) => {
410
+ if (confirm.toLowerCase() === 'y') {
411
+ const success = ConfigStore_1.ConfigStore.reset();
412
+ if (success) {
413
+ console.log('āœ… Configuration deleted successfully.\n');
414
+ }
415
+ rl.close();
416
+ process.exit(success ? 0 : 1);
417
+ }
418
+ else {
419
+ console.log('āŒ Reset cancelled.\n');
420
+ rl.close();
421
+ process.exit(0);
422
+ }
423
+ });
424
+ }
425
+ else {
426
+ // Exit
427
+ console.log('');
428
+ rl.close();
429
+ process.exit(0);
430
+ }
431
+ break;
432
+ case 4:
433
+ if (hasPrivateKey) {
434
+ // Exit
435
+ console.log('');
436
+ rl.close();
437
+ process.exit(0);
438
+ }
439
+ else {
440
+ console.log(`\nāŒ Invalid choice. Please select 1-${maxChoice}.\n`);
441
+ showMenu();
442
+ }
443
+ break;
444
+ default:
445
+ console.log(`\nāŒ Invalid choice. Please select 1-${maxChoice}.\n`);
446
+ showMenu();
447
+ }
448
+ });
449
+ };
450
+ showMenu();
451
+ });
452
+ }
453
+ }
454
+ exports.ConfigSetup = ConfigSetup;
455
+ //# sourceMappingURL=ConfigSetup.js.map