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.
- package/CHANGELOG.md +72 -0
- package/DOCUMENTATION.md +194 -0
- package/LICENSE +22 -0
- package/README.md +504 -0
- package/WHY_NEOZIP.md +212 -0
- package/bin/neolist +16 -0
- package/bin/neounzip +16 -0
- package/bin/neozip +15 -0
- package/dist/neozipkit-bundles/blockchain.js +13091 -0
- package/dist/neozipkit-bundles/browser.js +5733 -0
- package/dist/neozipkit-bundles/core.js +3766 -0
- package/dist/neozipkit-bundles/server.js +14996 -0
- package/dist/neozipkit-wrappers/blockchain/core/contracts.js +16 -0
- package/dist/neozipkit-wrappers/blockchain/index.js +2 -0
- package/dist/neozipkit-wrappers/core/ZipDecompress.js +2 -0
- package/dist/neozipkit-wrappers/core/components/HashCalculator.js +2 -0
- package/dist/neozipkit-wrappers/core/components/Logger.js +2 -0
- package/dist/neozipkit-wrappers/core/constants/Errors.js +2 -0
- package/dist/neozipkit-wrappers/core/constants/Headers.js +2 -0
- package/dist/neozipkit-wrappers/core/encryption/ZipCrypto.js +7 -0
- package/dist/neozipkit-wrappers/core/index.js +3 -0
- package/dist/neozipkit-wrappers/index.js +13 -0
- package/dist/neozipkit-wrappers/server/index.js +2 -0
- package/dist/src/config/ConfigSetup.js +455 -0
- package/dist/src/config/ConfigStore.js +373 -0
- package/dist/src/config/ConfigWizard.js +453 -0
- package/dist/src/config/WalletConfig.js +372 -0
- package/dist/src/exit-codes.js +210 -0
- package/dist/src/index.js +141 -0
- package/dist/src/neolist.js +1194 -0
- package/dist/src/neounzip.js +2177 -0
- package/dist/src/neozip/CommentManager.js +240 -0
- package/dist/src/neozip/blockchain.js +383 -0
- package/dist/src/neozip/createZip.js +2273 -0
- package/dist/src/neozip/file-operations.js +920 -0
- package/dist/src/neozip/types.js +6 -0
- package/dist/src/neozip/user-interaction.js +256 -0
- package/dist/src/neozip/utils.js +96 -0
- package/dist/src/neozip.js +785 -0
- package/dist/src/server/CommentManager.js +240 -0
- package/dist/src/version.js +59 -0
- package/env.example +101 -0
- 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
|