neozip-cli 0.70.0-alpha

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 (43) hide show
  1. package/CHANGELOG.md +72 -0
  2. package/DOCUMENTATION.md +194 -0
  3. package/LICENSE +22 -0
  4. package/README.md +504 -0
  5. package/WHY_NEOZIP.md +212 -0
  6. package/bin/neolist +16 -0
  7. package/bin/neounzip +16 -0
  8. package/bin/neozip +15 -0
  9. package/dist/neozipkit-bundles/blockchain.js +13091 -0
  10. package/dist/neozipkit-bundles/browser.js +5733 -0
  11. package/dist/neozipkit-bundles/core.js +3766 -0
  12. package/dist/neozipkit-bundles/server.js +14996 -0
  13. package/dist/neozipkit-wrappers/blockchain/core/contracts.js +16 -0
  14. package/dist/neozipkit-wrappers/blockchain/index.js +2 -0
  15. package/dist/neozipkit-wrappers/core/ZipDecompress.js +2 -0
  16. package/dist/neozipkit-wrappers/core/components/HashCalculator.js +2 -0
  17. package/dist/neozipkit-wrappers/core/components/Logger.js +2 -0
  18. package/dist/neozipkit-wrappers/core/constants/Errors.js +2 -0
  19. package/dist/neozipkit-wrappers/core/constants/Headers.js +2 -0
  20. package/dist/neozipkit-wrappers/core/encryption/ZipCrypto.js +7 -0
  21. package/dist/neozipkit-wrappers/core/index.js +3 -0
  22. package/dist/neozipkit-wrappers/index.js +13 -0
  23. package/dist/neozipkit-wrappers/server/index.js +2 -0
  24. package/dist/src/config/ConfigSetup.js +455 -0
  25. package/dist/src/config/ConfigStore.js +373 -0
  26. package/dist/src/config/ConfigWizard.js +453 -0
  27. package/dist/src/config/WalletConfig.js +372 -0
  28. package/dist/src/exit-codes.js +210 -0
  29. package/dist/src/index.js +141 -0
  30. package/dist/src/neolist.js +1194 -0
  31. package/dist/src/neounzip.js +2177 -0
  32. package/dist/src/neozip/CommentManager.js +240 -0
  33. package/dist/src/neozip/blockchain.js +383 -0
  34. package/dist/src/neozip/createZip.js +2273 -0
  35. package/dist/src/neozip/file-operations.js +920 -0
  36. package/dist/src/neozip/types.js +6 -0
  37. package/dist/src/neozip/user-interaction.js +256 -0
  38. package/dist/src/neozip/utils.js +96 -0
  39. package/dist/src/neozip.js +785 -0
  40. package/dist/src/server/CommentManager.js +240 -0
  41. package/dist/src/version.js +59 -0
  42. package/env.example +101 -0
  43. package/package.json +175 -0
@@ -0,0 +1,240 @@
1
+ "use strict";
2
+ /**
3
+ * CommentManager - Handles archive and file comments for ZIP files
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.CommentManager = void 0;
40
+ const fs = __importStar(require("fs"));
41
+ const readline = __importStar(require("readline"));
42
+ class CommentManager {
43
+ static setArchiveComment(zip, comment) {
44
+ try {
45
+ if (zip && typeof zip.setZipComment === 'function') {
46
+ zip.setZipComment(comment);
47
+ return true;
48
+ }
49
+ return false;
50
+ }
51
+ catch (error) {
52
+ console.error('Error setting archive comment:', error);
53
+ return false;
54
+ }
55
+ }
56
+ static getArchiveComment(zip) {
57
+ try {
58
+ if (zip && typeof zip.getZipComment === 'function') {
59
+ return zip.getZipComment();
60
+ }
61
+ return null;
62
+ }
63
+ catch (error) {
64
+ console.error('Error getting archive comment:', error);
65
+ return null;
66
+ }
67
+ }
68
+ static setFileComment(entry, comment) {
69
+ try {
70
+ if (entry && typeof entry.comment !== 'undefined') {
71
+ entry.comment = comment;
72
+ return true;
73
+ }
74
+ return false;
75
+ }
76
+ catch (error) {
77
+ console.error('Error setting file comment:', error);
78
+ return false;
79
+ }
80
+ }
81
+ static getFileComment(entry) {
82
+ try {
83
+ if (entry && typeof entry.comment !== 'undefined') {
84
+ return entry.comment || null;
85
+ }
86
+ return null;
87
+ }
88
+ catch (error) {
89
+ console.error('Error getting file comment:', error);
90
+ return null;
91
+ }
92
+ }
93
+ static async readCommentsFromFile(filePath) {
94
+ try {
95
+ if (!fs.existsSync(filePath)) {
96
+ return { success: false, error: `Comment file not found: ${filePath}` };
97
+ }
98
+ const content = fs.readFileSync(filePath, 'utf8');
99
+ const lines = content.split('\n');
100
+ let archiveComment = '';
101
+ const fileComments = {};
102
+ let currentFile = '';
103
+ let currentComment = '';
104
+ for (const line of lines) {
105
+ const trimmedLine = line.trim();
106
+ if (!trimmedLine) {
107
+ if (currentFile && currentComment) {
108
+ fileComments[currentFile] = currentComment.trim();
109
+ currentFile = '';
110
+ currentComment = '';
111
+ }
112
+ continue;
113
+ }
114
+ if (trimmedLine.includes(':')) {
115
+ if (currentFile && currentComment) {
116
+ fileComments[currentFile] = currentComment.trim();
117
+ }
118
+ const colonIndex = trimmedLine.indexOf(':');
119
+ currentFile = trimmedLine.substring(0, colonIndex).trim();
120
+ currentComment = trimmedLine.substring(colonIndex + 1).trim();
121
+ }
122
+ else {
123
+ if (currentFile) {
124
+ currentComment += (currentComment ? '\n' : '') + trimmedLine;
125
+ }
126
+ else {
127
+ archiveComment += (archiveComment ? '\n' : '') + trimmedLine;
128
+ }
129
+ }
130
+ }
131
+ if (currentFile && currentComment) {
132
+ fileComments[currentFile] = currentComment.trim();
133
+ }
134
+ return {
135
+ success: true,
136
+ archiveComment: archiveComment || undefined,
137
+ fileComments: Object.keys(fileComments).length > 0 ? fileComments : undefined
138
+ };
139
+ }
140
+ catch (error) {
141
+ return {
142
+ success: false,
143
+ error: `Error reading comment file: ${error instanceof Error ? error.message : String(error)}`
144
+ };
145
+ }
146
+ }
147
+ static async promptForArchiveComment() {
148
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
149
+ return new Promise((resolve) => {
150
+ rl.question('Enter archive comment (press Enter twice to finish):\n', (comment) => {
151
+ const lines = [comment];
152
+ const readLine = () => {
153
+ rl.question('', (line) => {
154
+ if (line.trim() === '') {
155
+ rl.close();
156
+ resolve(lines.join('\n').trim());
157
+ }
158
+ else {
159
+ lines.push(line);
160
+ readLine();
161
+ }
162
+ });
163
+ };
164
+ readLine();
165
+ });
166
+ });
167
+ }
168
+ static async promptForFileComments(filenames) {
169
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
170
+ const fileComments = {};
171
+ for (const filename of filenames) {
172
+ const comment = await new Promise((resolve) => {
173
+ rl.question(`Enter comment for ${filename}: `, (input) => resolve(input.trim()));
174
+ });
175
+ if (comment)
176
+ fileComments[filename] = comment;
177
+ }
178
+ rl.close();
179
+ return fileComments;
180
+ }
181
+ static async promptForFileCommentsOnly(filenames) {
182
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
183
+ const fileComments = {};
184
+ for (const filename of filenames) {
185
+ const comment = await new Promise((resolve) => {
186
+ rl.question(`Enter comment for ${filename}: `, (input) => resolve(input.trim()));
187
+ });
188
+ if (comment)
189
+ fileComments[filename] = comment;
190
+ }
191
+ rl.close();
192
+ return fileComments;
193
+ }
194
+ static applyComments(zip, entries, options) {
195
+ try {
196
+ let success = true;
197
+ const errors = [];
198
+ if (options.archiveComment) {
199
+ if (!this.setArchiveComment(zip, options.archiveComment)) {
200
+ success = false;
201
+ errors.push('Failed to set archive comment');
202
+ }
203
+ }
204
+ if (options.fileComments) {
205
+ for (const [filename, comment] of Object.entries(options.fileComments)) {
206
+ const entry = entries.find((e) => e.filename === filename);
207
+ if (entry) {
208
+ if (!this.setFileComment(entry, comment)) {
209
+ success = false;
210
+ errors.push(`Failed to set comment for ${filename}`);
211
+ }
212
+ }
213
+ else {
214
+ success = false;
215
+ errors.push(`File not found: ${filename}`);
216
+ }
217
+ }
218
+ }
219
+ return { success, archiveComment: options.archiveComment, fileComments: options.fileComments, error: errors.length > 0 ? errors.join('; ') : undefined };
220
+ }
221
+ catch (error) {
222
+ return { success: false, error: `Error applying comments: ${error instanceof Error ? error.message : String(error)}` };
223
+ }
224
+ }
225
+ static applyFileCommentToEntry(entry, filename, fileComments) {
226
+ try {
227
+ if (fileComments[filename]) {
228
+ return this.setFileComment(entry, fileComments[filename]);
229
+ }
230
+ return true;
231
+ }
232
+ catch (error) {
233
+ console.error(`Error applying file comment to ${filename}:`, error);
234
+ return false;
235
+ }
236
+ }
237
+ }
238
+ exports.CommentManager = CommentManager;
239
+ exports.default = CommentManager;
240
+ //# sourceMappingURL=CommentManager.js.map
@@ -0,0 +1,383 @@
1
+ "use strict";
2
+ /**
3
+ * Blockchain-related functions for NeoZip CLI
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.isSupportedNetwork = isSupportedNetwork;
40
+ exports.getWalletPasskey = getWalletPasskey;
41
+ exports.addTokenMetaToZip = addTokenMetaToZip;
42
+ exports.handleTokenMinting = handleTokenMinting;
43
+ const src_1 = require('../../neozipkit-wrappers');
44
+ const blockchain_1 = require('../../neozipkit-wrappers/blockchain');
45
+ const contracts_1 = require('../../neozipkit-wrappers/blockchain/core/contracts');
46
+ const ConfigStore_1 = require("../config/ConfigStore");
47
+ const readline = __importStar(require("readline"));
48
+ /**
49
+ * Check if the network is supported (uses nameAliases from CONTRACT_CONFIGS)
50
+ */
51
+ function isSupportedNetwork(network) {
52
+ return (0, contracts_1.getChainIdByName)(network) !== null;
53
+ }
54
+ /**
55
+ * Check if the required wallet passkey is available and valid
56
+ * Priority: CLI arg > wallet.json > ENV var
57
+ * @param cliWalletKey - Optional wallet key from CLI
58
+ * @param showError - Whether to show error messages (default: true)
59
+ */
60
+ function getWalletPasskey(cliWalletKey, showError = true) {
61
+ // Get config with CLI wallet key taking precedence
62
+ const config = ConfigStore_1.ConfigStore.getConfig(cliWalletKey);
63
+ const passkey = config.walletKey;
64
+ if (!passkey) {
65
+ if (showError) {
66
+ console.error('āŒ Error: Wallet private key is required for blockchain operations');
67
+ console.error('');
68
+ console.error(' Option 1 (Recommended): Run interactive setup');
69
+ console.error(' $ neozip init');
70
+ console.error('');
71
+ console.error(' Option 2: Use command-line flag');
72
+ console.error(' $ neozip -b -w 0x... <archive> <files>');
73
+ console.error('');
74
+ console.error(' Option 3: Set environment variable');
75
+ console.error(' $ export NEOZIP_WALLET_PASSKEY="0x..."');
76
+ console.error('');
77
+ console.error(' Get testnet ETH from: https://www.coinbase.com/faucets/base-ethereum-sepolia-faucet');
78
+ }
79
+ return null;
80
+ }
81
+ // Validate the private key format
82
+ if (!(0, blockchain_1.validatePrivateKey)(passkey)) {
83
+ if (showError) {
84
+ console.error('āŒ Error: Invalid private key format');
85
+ console.error(' Private key should be a 64-character hex string starting with 0x');
86
+ console.error(' Example: 0x1234567890abcdef...');
87
+ }
88
+ return null;
89
+ }
90
+ return passkey;
91
+ }
92
+ /**
93
+ * Add token metadata to ZIP file using the constant
94
+ */
95
+ async function addTokenMetaToZip(zip, tokenMeta) {
96
+ const tokenContent = JSON.stringify(tokenMeta, null, 2);
97
+ const tokenBuffer = Buffer.from(tokenContent, 'utf8');
98
+ const tokenPath = src_1.TOKENIZED_METADATA;
99
+ // Create new token entry
100
+ const tokenEntry = zip.createZipEntry(tokenPath);
101
+ tokenEntry.timeDateDOS = tokenEntry.setDateTime(new Date());
102
+ tokenEntry.compressedSize = tokenBuffer.length;
103
+ tokenEntry.uncompressedSize = tokenBuffer.length;
104
+ tokenEntry.cmpMethod = 0; // STORED
105
+ tokenEntry.crc = (0, src_1.crc32)(tokenBuffer);
106
+ tokenEntry.fileBuffer = tokenBuffer;
107
+ tokenEntry.isUpdated = true;
108
+ console.log('āœ… Token metadata prepared for ZIP');
109
+ console.log(`šŸ“„ Token content:\n${tokenContent}`);
110
+ return tokenEntry;
111
+ }
112
+ /**
113
+ * Prompt user for action when minting timeout/error occurs
114
+ */
115
+ async function promptForMintingTimeoutAction(networkConfig, currentRpcIndex, nonInteractive) {
116
+ if (nonInteractive) {
117
+ return 'exit';
118
+ }
119
+ const rpcUrls = networkConfig.rpcUrls || [];
120
+ const hasMoreRpcs = currentRpcIndex + 1 < rpcUrls.length;
121
+ console.log('\nā±ļø Minting timeout/error occurred');
122
+ console.log(` Current RPC: ${rpcUrls[currentRpcIndex] || 'unknown'}`);
123
+ if (hasMoreRpcs) {
124
+ console.log(` ${rpcUrls.length - currentRpcIndex - 1} more RPC URL(s) available`);
125
+ }
126
+ const rl = readline.createInterface({
127
+ input: process.stdin,
128
+ output: process.stdout
129
+ });
130
+ return new Promise((resolve) => {
131
+ console.log('\nChoose an option:');
132
+ console.log(' 1. Retry minting with same RPC');
133
+ if (hasMoreRpcs) {
134
+ console.log(' 2. Try next RPC URL');
135
+ }
136
+ console.log(' 3. Exit (continue without token metadata)');
137
+ rl.question('Enter your choice (1-3): ', (answer) => {
138
+ rl.close();
139
+ const choice = answer.trim();
140
+ if (choice === '1') {
141
+ resolve('retry');
142
+ }
143
+ else if (choice === '2' && hasMoreRpcs) {
144
+ resolve('next-rpc');
145
+ }
146
+ else if (choice === '3') {
147
+ resolve('exit');
148
+ }
149
+ else {
150
+ // Invalid choice, default to exit
151
+ console.log('Invalid choice, exiting...');
152
+ resolve('exit');
153
+ }
154
+ });
155
+ });
156
+ }
157
+ /**
158
+ * Handle token minting process with retry logic and RPC switching
159
+ */
160
+ async function handleTokenMinting(initialMinter, zip, nonInteractive = false, initialRpcUrlIndex = 0) {
161
+ // Get network config from minter
162
+ const networkConfig = initialMinter.networkConfig;
163
+ const network = initialMinter.networkConfig?.network || 'unknown';
164
+ const merkleRoot = initialMinter.merkleRoot;
165
+ const walletPrivateKey = initialMinter.wallet?.privateKey;
166
+ const debug = initialMinter.debug;
167
+ const verbose = process.env.NEOZIP_VERBOSE === 'true';
168
+ let currentRpcIndex = initialRpcUrlIndex;
169
+ let maxRetries = 3; // Maximum retries per RPC
170
+ let retryCount = 0;
171
+ let minter = null;
172
+ // Cleanup helper
173
+ const cleanup = () => {
174
+ if (minter) {
175
+ try {
176
+ minter.destroy();
177
+ }
178
+ catch (error) {
179
+ // Ignore cleanup errors
180
+ }
181
+ }
182
+ };
183
+ try {
184
+ while (true) {
185
+ try {
186
+ // Cleanup previous minter if switching RPCs
187
+ if (minter && minter !== initialMinter) {
188
+ cleanup();
189
+ }
190
+ // Create new minter with current RPC index (or reuse initial if first attempt)
191
+ if (currentRpcIndex === initialRpcUrlIndex && retryCount === 0) {
192
+ minter = initialMinter;
193
+ }
194
+ else {
195
+ // ZipkitMinter uses getChainIdByName internally which handles all nameAliases
196
+ // So we can pass the original network name directly
197
+ minter = new src_1.ZipkitMinter(merkleRoot, {
198
+ network: network,
199
+ walletPrivateKey: walletPrivateKey,
200
+ verbose: verbose,
201
+ debug: debug,
202
+ rpcUrlIndex: currentRpcIndex
203
+ });
204
+ }
205
+ console.log('\nā³ Minting token on blockchain...');
206
+ // Enable debug logging
207
+ const debugMode = debug || process.env.NEOZIP_DEBUG === 'true' || process.env.NEOZIP_VERBOSE === 'true';
208
+ if (debugMode) {
209
+ console.log('[DEBUG] Starting completeMinting()...');
210
+ if (networkConfig) {
211
+ console.log('[DEBUG] Network:', networkConfig.network || 'unknown');
212
+ console.log('[DEBUG] Chain ID:', networkConfig.chainId || 'unknown');
213
+ console.log('[DEBUG] Contract Address:', networkConfig.address || 'unknown');
214
+ console.log('[DEBUG] RPC URL:', networkConfig.rpcUrls?.[currentRpcIndex] || 'unknown');
215
+ console.log('[DEBUG] Explorer URL:', networkConfig.explorerUrl || 'unknown');
216
+ }
217
+ }
218
+ // Complete the minting process
219
+ const mintResult = await minter.completeMinting();
220
+ if (mintResult.mintingResult.success) {
221
+ console.log(`āœ… Token minted successfully!`);
222
+ console.log(` Token ID: ${mintResult.tokenMetadata?.tokenId}`);
223
+ console.log(` Transaction: ${mintResult.tokenMetadata?.transactionHash}`);
224
+ console.log(` Contract: ${mintResult.tokenMetadata?.contractAddress}`);
225
+ // Create TokenMetadata from minting result
226
+ if (mintResult.tokenMetadata) {
227
+ const tokenMeta = {
228
+ version: '1.0',
229
+ tokenId: mintResult.tokenMetadata.tokenId,
230
+ contractAddress: mintResult.tokenMetadata.contractAddress,
231
+ network: mintResult.tokenMetadata.network,
232
+ networkChainId: mintResult.tokenMetadata.networkChainId || networkConfig?.chainId || 84532,
233
+ transactionHash: mintResult.tokenMetadata.transactionHash,
234
+ merkleRoot: mintResult.tokenMetadata.merkleRoot,
235
+ mintedAt: mintResult.tokenMetadata.mintDate
236
+ };
237
+ // Cleanup before returning
238
+ if (minter !== initialMinter) {
239
+ cleanup();
240
+ }
241
+ return { success: true, tokenInfo: tokenMeta, entry: null };
242
+ }
243
+ }
244
+ else {
245
+ // Minting failed - check if it's a retryable error
246
+ const errorMessage = mintResult.mintingResult.message ||
247
+ mintResult.mintingResult.error ||
248
+ 'Unknown minting error';
249
+ // Check if this is a timeout or retryable error
250
+ const isTimeout = errorMessage.toLowerCase().includes('timeout');
251
+ const isNetworkError = errorMessage.toLowerCase().includes('network') ||
252
+ errorMessage.toLowerCase().includes('connection') ||
253
+ errorMessage.toLowerCase().includes('rpc') ||
254
+ errorMessage.toLowerCase().includes('failed to connect');
255
+ const isRetryable = isTimeout || isNetworkError;
256
+ if (isRetryable && !nonInteractive && networkConfig) {
257
+ // Display the error first
258
+ console.log(`āŒ ${errorMessage}`);
259
+ console.log(` Network: ${networkConfig.network}`);
260
+ console.log(` RPC URL: ${networkConfig.rpcUrls[currentRpcIndex] || 'unknown'}`);
261
+ console.log(` Contract: ${networkConfig.address}`);
262
+ // Prompt user for action
263
+ const action = await promptForMintingTimeoutAction(networkConfig, currentRpcIndex, nonInteractive);
264
+ if (action === 'exit') {
265
+ // User chose to exit - continue without token metadata
266
+ if (minter !== initialMinter) {
267
+ cleanup();
268
+ }
269
+ return { success: false };
270
+ }
271
+ else if (action === 'retry') {
272
+ // Retry with same RPC
273
+ retryCount++;
274
+ if (retryCount >= maxRetries) {
275
+ console.log(`\nāŒ Maximum retries (${maxRetries}) reached for current RPC`);
276
+ if (minter !== initialMinter) {
277
+ cleanup();
278
+ }
279
+ return { success: false };
280
+ }
281
+ console.log(`\nšŸ”„ Retrying minting (attempt ${retryCount + 1}/${maxRetries})...`);
282
+ continue;
283
+ }
284
+ else if (action === 'next-rpc') {
285
+ // Try next RPC URL
286
+ currentRpcIndex++;
287
+ retryCount = 0; // Reset retry count for new RPC
288
+ if (currentRpcIndex >= networkConfig.rpcUrls.length) {
289
+ console.log('\nāŒ No more RPC URLs available');
290
+ if (minter !== initialMinter) {
291
+ cleanup();
292
+ }
293
+ return { success: false };
294
+ }
295
+ console.log(`\nšŸ”„ Trying next RPC URL (${currentRpcIndex + 1}/${networkConfig.rpcUrls.length})...`);
296
+ continue;
297
+ }
298
+ }
299
+ else {
300
+ // Not retryable or non-interactive - show error and return
301
+ console.error(`āŒ Token minting failed!`);
302
+ if (mintResult.mintingResult.error) {
303
+ console.error(` Error: ${mintResult.mintingResult.error}`);
304
+ }
305
+ if (mintResult.mintingResult.message) {
306
+ console.error(` Message: ${mintResult.mintingResult.message}`);
307
+ }
308
+ if (minter !== initialMinter) {
309
+ cleanup();
310
+ }
311
+ return { success: false };
312
+ }
313
+ }
314
+ }
315
+ catch (error) {
316
+ // Handle unexpected errors
317
+ const errorMessage = error instanceof Error ? error.message : String(error);
318
+ const isTimeout = errorMessage.toLowerCase().includes('timeout');
319
+ const isNetworkError = errorMessage.toLowerCase().includes('network') ||
320
+ errorMessage.toLowerCase().includes('connection') ||
321
+ errorMessage.toLowerCase().includes('rpc') ||
322
+ errorMessage.toLowerCase().includes('failed to connect');
323
+ const isRetryable = isTimeout || isNetworkError;
324
+ if (isRetryable && !nonInteractive && networkConfig) {
325
+ // Display the error first
326
+ console.log(`āŒ Minting error: ${errorMessage}`);
327
+ console.log(` Network: ${networkConfig.network}`);
328
+ console.log(` RPC URL: ${networkConfig.rpcUrls[currentRpcIndex] || 'unknown'}`);
329
+ console.log(` Contract: ${networkConfig.address}`);
330
+ const action = await promptForMintingTimeoutAction(networkConfig, currentRpcIndex, nonInteractive);
331
+ if (action === 'exit') {
332
+ if (minter && minter !== initialMinter) {
333
+ cleanup();
334
+ }
335
+ return { success: false };
336
+ }
337
+ else if (action === 'retry') {
338
+ retryCount++;
339
+ if (retryCount >= maxRetries) {
340
+ if (minter && minter !== initialMinter) {
341
+ cleanup();
342
+ }
343
+ return { success: false };
344
+ }
345
+ console.log(`\nšŸ”„ Retrying minting (attempt ${retryCount + 1}/${maxRetries})...`);
346
+ continue;
347
+ }
348
+ else if (action === 'next-rpc') {
349
+ currentRpcIndex++;
350
+ retryCount = 0;
351
+ if (currentRpcIndex >= networkConfig.rpcUrls.length) {
352
+ if (minter && minter !== initialMinter) {
353
+ cleanup();
354
+ }
355
+ return { success: false };
356
+ }
357
+ console.log(`\nšŸ”„ Trying next RPC URL (${currentRpcIndex + 1}/${networkConfig.rpcUrls.length})...`);
358
+ continue;
359
+ }
360
+ }
361
+ else {
362
+ // Not retryable or non-interactive - show error and return
363
+ console.error(`āŒ Token minting error: ${errorMessage}`);
364
+ if (error instanceof Error && error.stack && debug) {
365
+ console.error(` Stack trace: ${error.stack}`);
366
+ }
367
+ if (minter && minter !== initialMinter) {
368
+ cleanup();
369
+ }
370
+ return { success: false };
371
+ }
372
+ }
373
+ }
374
+ }
375
+ finally {
376
+ // Ensure cleanup of any minter we created (but not the initial one)
377
+ if (minter && minter !== initialMinter) {
378
+ cleanup();
379
+ }
380
+ }
381
+ return { success: false };
382
+ }
383
+ //# sourceMappingURL=blockchain.js.map