neozip-cli 0.75.2-beta → 0.90.0
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 +78 -0
- package/DOCUMENTATION.md +20 -9
- package/README.md +55 -31
- package/dist/src/commands/mintTimestampProof.js +335 -0
- package/dist/src/commands/verifyEmail.js +146 -0
- package/dist/src/config/ConfigSetup.js +50 -20
- package/dist/src/config/ConfigStore.js +36 -3
- package/dist/src/index.js +1 -1
- package/dist/src/neolist.js +25 -11
- package/dist/src/neounzip.js +324 -66
- package/dist/src/neozip/blockchain.js +5 -5
- package/dist/src/neozip/createZip.js +211 -44
- package/dist/src/neozip/upgradeZip.js +182 -0
- package/dist/src/neozip.js +160 -24
- package/env.example +10 -0
- package/package.json +97 -82
- package/dist/neozipkit-bundles/blockchain.js +0 -13725
- package/dist/neozipkit-bundles/browser.js +0 -6186
- package/dist/neozipkit-bundles/core.js +0 -3839
- package/dist/neozipkit-bundles/node.js +0 -17730
- package/dist/neozipkit-wrappers/blockchain/core/contracts.js +0 -16
- package/dist/neozipkit-wrappers/blockchain/index.js +0 -2
- package/dist/neozipkit-wrappers/core/ZipDecompress.js +0 -2
- package/dist/neozipkit-wrappers/core/components/HashCalculator.js +0 -2
- package/dist/neozipkit-wrappers/core/components/Logger.js +0 -2
- package/dist/neozipkit-wrappers/core/constants/Errors.js +0 -2
- package/dist/neozipkit-wrappers/core/constants/Headers.js +0 -2
- package/dist/neozipkit-wrappers/core/encryption/ZipCrypto.js +0 -7
- package/dist/neozipkit-wrappers/core/index.js +0 -3
- package/dist/neozipkit-wrappers/index.js +0 -13
- package/dist/neozipkit-wrappers/node/index.js +0 -2
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Upgrade Zipstamp timestamp from pending (TS-SUBMIT.NZIP) to confirmed (TIMESTAMP.NZIP)
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
|
+
};
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.upgradeZipForTimestamp = upgradeZipForTimestamp;
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const os = __importStar(require("os"));
|
|
46
|
+
const node_1 = __importDefault(require("neozipkit/node"));
|
|
47
|
+
const node_2 = require("neozipkit/node");
|
|
48
|
+
const zipstamp_server_1 = require("neozip-blockchain/zipstamp-server");
|
|
49
|
+
const exit_codes_1 = require("../exit-codes");
|
|
50
|
+
/**
|
|
51
|
+
* Extract timestamp metadata from a ZIP entry.
|
|
52
|
+
* Tries the library's extractTimestampData first; if it fails (e.g. file-based ZIP),
|
|
53
|
+
* fall back to extracting to a temp file and parsing JSON.
|
|
54
|
+
*/
|
|
55
|
+
async function extractTimestampMetadata(zip, entry) {
|
|
56
|
+
let metadata = await (0, zipstamp_server_1.extractTimestampData)(zip, entry);
|
|
57
|
+
if (metadata)
|
|
58
|
+
return metadata;
|
|
59
|
+
// Fallback for file-based ZIPs where zip.extract() may not work
|
|
60
|
+
try {
|
|
61
|
+
const tmpPath = path.join(os.tmpdir(), `neozip-upgrade-meta-${Date.now()}.json`);
|
|
62
|
+
await zip.extractToFile(entry, tmpPath, { skipHashCheck: true });
|
|
63
|
+
try {
|
|
64
|
+
const buf = fs.readFileSync(tmpPath);
|
|
65
|
+
return JSON.parse(buf.toString('utf-8'));
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
if (fs.existsSync(tmpPath))
|
|
69
|
+
fs.unlinkSync(tmpPath);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Upgrade a ZIP file with pending Zipstamp timestamp to confirmed status.
|
|
78
|
+
* Replaces TS-SUBMIT.NZIP with TIMESTAMP.NZIP when the batch is confirmed on the blockchain.
|
|
79
|
+
*/
|
|
80
|
+
async function upgradeZipForTimestamp(inputPath, outputPath, options = {}) {
|
|
81
|
+
const { wait = false, verbose = false, debug = false } = options;
|
|
82
|
+
if (!fs.existsSync(inputPath)) {
|
|
83
|
+
(0, exit_codes_1.exitZip)(exit_codes_1.ZIP_EXIT_CODES.CANT_FIND_ARCHIVE, `Error: ZIP file not found: ${inputPath}`);
|
|
84
|
+
}
|
|
85
|
+
const zip = new node_1.default();
|
|
86
|
+
await zip.loadZipFile(inputPath);
|
|
87
|
+
const entries = zip.getDirectory() || [];
|
|
88
|
+
const metadataResult = (0, zipstamp_server_1.findMetadataEntry)(entries);
|
|
89
|
+
if (!metadataResult) {
|
|
90
|
+
console.log('No Zipstamp timestamp found in ZIP file');
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (metadataResult.type === 'confirmed') {
|
|
94
|
+
console.log('✓ Timestamp already confirmed - no upgrade needed');
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const metadata = await extractTimestampMetadata(zip, metadataResult.entry);
|
|
98
|
+
if (!metadata || !metadata.digest) {
|
|
99
|
+
(0, exit_codes_1.exitZip)(exit_codes_1.ZIP_EXIT_CODES.BAD_ARCHIVE_FORMAT, 'Error: Failed to extract timestamp metadata');
|
|
100
|
+
}
|
|
101
|
+
if (!(0, zipstamp_server_1.shouldUpgrade)(metadata, metadataResult.type)) {
|
|
102
|
+
console.log('✓ Timestamp does not need upgrade');
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const digest = metadata.digest;
|
|
106
|
+
const chainId = metadata.chainId && metadata.chainId > 0 ? metadata.chainId : undefined;
|
|
107
|
+
const batchId = metadata.batchId ?? undefined;
|
|
108
|
+
let verified = null;
|
|
109
|
+
if (wait) {
|
|
110
|
+
if (verbose || debug)
|
|
111
|
+
console.log('Polling for confirmation (--wait)...');
|
|
112
|
+
verified = await (0, zipstamp_server_1.pollForConfirmation)(digest, chainId, batchId, 300000, 5000, { debug });
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
const verifyRes = await (0, zipstamp_server_1.verifyDigest)(digest, chainId, batchId, undefined, { debug });
|
|
116
|
+
if (verifyRes.verified) {
|
|
117
|
+
verified = verifyRes;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (!verified || !verified.verified) {
|
|
121
|
+
console.log('⏳ Timestamp not yet confirmed on blockchain');
|
|
122
|
+
console.log(' Run with --wait to poll until confirmed, or try again later');
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
console.log('✓ Timestamp confirmed on blockchain');
|
|
126
|
+
if (verified.transactionHash && (verbose || debug)) {
|
|
127
|
+
console.log(` Transaction: ${verified.transactionHash}`);
|
|
128
|
+
}
|
|
129
|
+
const confirmedMetadata = {
|
|
130
|
+
...metadata,
|
|
131
|
+
status: 'confirmed',
|
|
132
|
+
merkleProof: verified.merkleProof ?? metadata.merkleProof,
|
|
133
|
+
merkleRoot: verified.merkleRoot ?? metadata.merkleRoot,
|
|
134
|
+
transactionHash: verified.transactionHash ?? metadata.transactionHash,
|
|
135
|
+
blockNumber: verified.blockNumber ?? metadata.blockNumber,
|
|
136
|
+
timestamp: verified.timestamp ?? metadata.timestamp
|
|
137
|
+
};
|
|
138
|
+
const metadataFiles = (0, zipstamp_server_1.getMetadataFileNames)();
|
|
139
|
+
const outPath = outputPath ?? inputPath.replace(/(\.nzip|\.zip)$/i, '-upgrade$1');
|
|
140
|
+
const tempDir = path.dirname(outPath) || '.';
|
|
141
|
+
const tempPath = path.join(tempDir, `.neozip-upgrade-${Date.now()}.tmp`);
|
|
142
|
+
try {
|
|
143
|
+
const zipCopy = new node_2.ZipCopyNode(new node_1.default());
|
|
144
|
+
const { destPath, dataEndOffset, copiedEntries } = await zipCopy.copyZipEntriesOnly(inputPath, tempPath, {
|
|
145
|
+
entryFilter: (entry) => !metadataFiles.includes(entry.filename || '')
|
|
146
|
+
});
|
|
147
|
+
const newEntry = (0, zipstamp_server_1.createTimestampMetadataEntry)(zip, confirmedMetadata);
|
|
148
|
+
if (!newEntry) {
|
|
149
|
+
throw new Error('Failed to create timestamp metadata entry');
|
|
150
|
+
}
|
|
151
|
+
newEntry.localHdrOffset = dataEndOffset;
|
|
152
|
+
newEntry.cmpMethod = 0;
|
|
153
|
+
newEntry.compressedSize = newEntry.fileBuffer?.length ?? newEntry.uncompressedSize ?? 0;
|
|
154
|
+
const localHdr = newEntry.createLocalHdr();
|
|
155
|
+
const data = newEntry.fileBuffer ?? Buffer.alloc(0);
|
|
156
|
+
const fd = fs.openSync(destPath, 'r+');
|
|
157
|
+
try {
|
|
158
|
+
fs.writeSync(fd, localHdr, 0, localHdr.length, dataEndOffset);
|
|
159
|
+
fs.writeSync(fd, data, 0, data.length, dataEndOffset + localHdr.length);
|
|
160
|
+
}
|
|
161
|
+
finally {
|
|
162
|
+
fs.closeSync(fd);
|
|
163
|
+
}
|
|
164
|
+
const allEntries = [...copiedEntries, newEntry];
|
|
165
|
+
zipCopy.writeCentralDirectoryAndEOCD(destPath, allEntries, { zipComment: '' });
|
|
166
|
+
fs.renameSync(destPath, outPath);
|
|
167
|
+
console.log(`✓ Upgraded ZIP written to: ${outPath}`);
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
if (fs.existsSync(tempPath)) {
|
|
171
|
+
try {
|
|
172
|
+
fs.unlinkSync(tempPath);
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
// Ignore cleanup errors
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
179
|
+
(0, exit_codes_1.exitZip)(exit_codes_1.ZIP_EXIT_CODES.CANT_WRITE_ARCHIVE, `Error upgrading ZIP: ${msg}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=upgradeZip.js.map
|
package/dist/src/neozip.js
CHANGED
|
@@ -67,10 +67,19 @@ const user_interaction_1 = require("./neozip/user-interaction");
|
|
|
67
67
|
const createZip_1 = require("./neozip/createZip");
|
|
68
68
|
const file_operations_1 = require("./neozip/file-operations");
|
|
69
69
|
// ConfigSetup is lazy-loaded only when needed (init/config commands)
|
|
70
|
-
const
|
|
70
|
+
const neozip_blockchain_1 = require("neozip-blockchain");
|
|
71
71
|
const ConfigStore_1 = require("./config/ConfigStore");
|
|
72
72
|
const exit_codes_1 = require("./exit-codes");
|
|
73
73
|
const version_1 = require("./version");
|
|
74
|
+
/**
|
|
75
|
+
* Resolve dynamic import path so ts-node loads .ts and compiled dist loads .js
|
|
76
|
+
*/
|
|
77
|
+
function resolveScriptPath(jsPath) {
|
|
78
|
+
if (typeof __filename !== 'undefined' && __filename.endsWith('.ts')) {
|
|
79
|
+
return jsPath.replace(/\.js$/, '.ts');
|
|
80
|
+
}
|
|
81
|
+
return jsPath;
|
|
82
|
+
}
|
|
74
83
|
/**
|
|
75
84
|
* Parse command line arguments
|
|
76
85
|
*/
|
|
@@ -85,6 +94,7 @@ function parseArgs(args) {
|
|
|
85
94
|
blockchainMint: false, // Force mint new token disabled by default
|
|
86
95
|
network: 'base-sepolia',
|
|
87
96
|
walletPasskey: process.env.NEOZIP_WALLET_PASSKEY,
|
|
97
|
+
timestampEmail: process.env.NEOZIP_TIMESTAMP_EMAIL,
|
|
88
98
|
compression: 'zstd',
|
|
89
99
|
blockSize: 128 * 1024, // 128KB default
|
|
90
100
|
enableProgress: true,
|
|
@@ -168,6 +178,17 @@ function parseArgs(args) {
|
|
|
168
178
|
case '--opentimestamp':
|
|
169
179
|
options.blockchainOts = true;
|
|
170
180
|
break;
|
|
181
|
+
case '-ts':
|
|
182
|
+
case '--timestamp':
|
|
183
|
+
options.blockchainZipstamp = true;
|
|
184
|
+
break;
|
|
185
|
+
case '--timestamp-email':
|
|
186
|
+
options.timestampEmail = args[++i];
|
|
187
|
+
if (!options.timestampEmail) {
|
|
188
|
+
console.error('Error: --timestamp-email requires an email address');
|
|
189
|
+
(0, exit_codes_1.exitZip)(exit_codes_1.ZIP_EXIT_CODES.PARAMETER_ERROR);
|
|
190
|
+
}
|
|
191
|
+
break;
|
|
171
192
|
case '-bt':
|
|
172
193
|
case '--blockchain-token':
|
|
173
194
|
options.blockchain = true;
|
|
@@ -185,8 +206,8 @@ function parseArgs(args) {
|
|
|
185
206
|
case '-n':
|
|
186
207
|
case '--network':
|
|
187
208
|
const network = args[++i];
|
|
188
|
-
if ((0,
|
|
189
|
-
const supportedNetworks = (0,
|
|
209
|
+
if ((0, neozip_blockchain_1.getChainIdByName)(network) === null) {
|
|
210
|
+
const supportedNetworks = (0, neozip_blockchain_1.getSupportedNetworkNames)();
|
|
190
211
|
console.error(`Error: Unsupported network: "${network}"`);
|
|
191
212
|
console.error(`Supported networks: ${supportedNetworks.join(', ')}`);
|
|
192
213
|
(0, exit_codes_1.exitZip)(exit_codes_1.ZIP_EXIT_CODES.PARAMETER_ERROR);
|
|
@@ -239,45 +260,45 @@ function parseArgs(args) {
|
|
|
239
260
|
break;
|
|
240
261
|
case '-e':
|
|
241
262
|
case '--encrypt':
|
|
242
|
-
// InfoZip-compatible encryption option
|
|
243
263
|
options.encrypt = true;
|
|
244
|
-
// Only set encryption method if not already set
|
|
245
264
|
if (!options.encryptionMethod) {
|
|
246
|
-
options.encryptionMethod = '
|
|
265
|
+
options.encryptionMethod = 'aes256';
|
|
247
266
|
}
|
|
248
|
-
// Only prompt for password if not already provided
|
|
249
267
|
if (!options.password) {
|
|
250
|
-
options.password = 'PROMPT';
|
|
268
|
+
options.password = 'PROMPT';
|
|
251
269
|
}
|
|
252
270
|
break;
|
|
253
271
|
case '-P':
|
|
254
272
|
case '--password':
|
|
255
|
-
// InfoZip-compatible password option (uppercase P)
|
|
256
273
|
options.encrypt = true;
|
|
257
|
-
// Only set encryption method if not already set (e.g., by --pkzip-encrypt)
|
|
258
274
|
if (!options.encryptionMethod) {
|
|
259
|
-
options.encryptionMethod = '
|
|
275
|
+
options.encryptionMethod = 'aes256';
|
|
260
276
|
}
|
|
261
277
|
if (i + 1 < args.length && !args[i + 1].startsWith('-')) {
|
|
262
|
-
// Password provided directly
|
|
263
278
|
options.password = args[++i];
|
|
264
279
|
}
|
|
265
280
|
else {
|
|
266
|
-
// No password provided, will prompt later
|
|
267
281
|
options.password = 'PROMPT';
|
|
268
282
|
}
|
|
269
283
|
break;
|
|
270
284
|
case '-p':
|
|
271
285
|
case '--show-progress':
|
|
272
|
-
// InfoZip-compatible show-progress option (lowercase p)
|
|
273
286
|
options.showFiles = true;
|
|
274
287
|
break;
|
|
288
|
+
case '--aes256':
|
|
289
|
+
case '--aes-256':
|
|
290
|
+
options.encrypt = true;
|
|
291
|
+
options.encryptionMethod = 'aes256';
|
|
292
|
+
if (!options.password) {
|
|
293
|
+
options.password = 'PROMPT';
|
|
294
|
+
}
|
|
295
|
+
break;
|
|
296
|
+
case '--pkzip':
|
|
275
297
|
case '--pkzip-encrypt':
|
|
276
298
|
options.encrypt = true;
|
|
277
299
|
options.encryptionMethod = 'pkzip';
|
|
278
|
-
// Only prompt for password if not already provided
|
|
279
300
|
if (!options.password) {
|
|
280
|
-
options.password = 'PROMPT';
|
|
301
|
+
options.password = 'PROMPT';
|
|
281
302
|
}
|
|
282
303
|
break;
|
|
283
304
|
case '-x':
|
|
@@ -411,6 +432,12 @@ function parseArgs(args) {
|
|
|
411
432
|
break;
|
|
412
433
|
}
|
|
413
434
|
}
|
|
435
|
+
// -ots and -ts are mutually exclusive (choose Bitcoin OTS or Ethereum Zipstamp)
|
|
436
|
+
if (options.blockchainOts && options.blockchainZipstamp) {
|
|
437
|
+
console.error('Error: Cannot use both -ots (OpenTimestamps) and -ts (Zipstamp) in the same run');
|
|
438
|
+
console.error(' Use -ts for Zipstamp timestamping or -ots for Bitcoin timestamping');
|
|
439
|
+
(0, exit_codes_1.exitZip)(exit_codes_1.ZIP_EXIT_CODES.PARAMETER_ERROR);
|
|
440
|
+
}
|
|
414
441
|
if (!archive) {
|
|
415
442
|
console.error('Error: Archive name is required');
|
|
416
443
|
showHelp();
|
|
@@ -450,6 +477,9 @@ Usage: neozip [options] <archive> <files...>
|
|
|
450
477
|
Configuration Commands:
|
|
451
478
|
neozip init Interactive wallet setup wizard
|
|
452
479
|
neozip config Show current configuration and manage settings (interactive menu)
|
|
480
|
+
neozip upgrade <archive> [output] [--wait] Upgrade pending Zipstamp timestamp to confirmed
|
|
481
|
+
neozip mint <archive> [output] Mint TimestampProofNFT from confirmed timestamped ZIP
|
|
482
|
+
neozip verify-email [--email <email>] [--set-default] Configure email for Zipstamp timestamping
|
|
453
483
|
|
|
454
484
|
Options:
|
|
455
485
|
-h, --help Show this help message
|
|
@@ -478,6 +508,8 @@ Options:
|
|
|
478
508
|
-bd, --blockchain-default Auto-select default token option (use existing or mint new)
|
|
479
509
|
-bm, --blockchain-mint Force mint new token (skip existing token selection)
|
|
480
510
|
-ots, --opentimestamp Enable OpenTimestamp proof on Bitcoin blockchain
|
|
511
|
+
-ts, --timestamp Enable Ethereum Zipstamp timestamp (blockchain)
|
|
512
|
+
--timestamp-email <email> Email for Zipstamp server (some servers require verified email)
|
|
481
513
|
-n, --network <network> Blockchain network (base-sepolia, base-mainnet, default: base-sepolia)
|
|
482
514
|
-w, --wallet-key <key> Wallet private key (overrides NEOZIP_WALLET_PASSKEY)
|
|
483
515
|
-c Add one-line comments for files
|
|
@@ -487,10 +519,11 @@ Options:
|
|
|
487
519
|
--block-size <bytes> Block size for streaming (default: 131072)
|
|
488
520
|
--no-progress Disable progress reporting
|
|
489
521
|
--progress Enable enhanced progress reporting
|
|
490
|
-
-e, --encrypt Encrypt files (
|
|
491
|
-
-P, --password [pwd] Encrypt files with password
|
|
522
|
+
-e, --encrypt Encrypt files with AES-256 (default). Will prompt for password
|
|
523
|
+
-P, --password [pwd] Encrypt files with password. Provide password or will prompt
|
|
524
|
+
--aes256 Use AES-256 encryption (default, recommended)
|
|
525
|
+
--pkzip, --pkzip-encrypt Use legacy PKZIP encryption (weak, for compatibility only)
|
|
492
526
|
-p, --show-progress Show progress during compression (InfoZip-compatible)
|
|
493
|
-
--pkzip-encrypt Use PKZIP encryption (legacy compatibility only, same as -e)
|
|
494
527
|
-x, --exclude <pattern> Exclude files matching pattern (can be used multiple times)
|
|
495
528
|
-i, --include <pattern> Include only files matching pattern (can be used multiple times)
|
|
496
529
|
--suffixes <list> Don't compress files with these suffixes (can be used multiple times)
|
|
@@ -509,9 +542,9 @@ Arguments:
|
|
|
509
542
|
<files...> Files and directories to compress
|
|
510
543
|
|
|
511
544
|
Examples:
|
|
512
|
-
neozip output/test.nzip file1.txt file2.txt
|
|
513
|
-
neozip output/simple.nzip ./data/
|
|
514
|
-
neozip -r output/recursive.nzip ./project/
|
|
545
|
+
neozip tests/output/test.nzip file1.txt file2.txt
|
|
546
|
+
neozip tests/output/simple.nzip ./data/
|
|
547
|
+
neozip -r tests/output/recursive.nzip ./project/
|
|
515
548
|
`);
|
|
516
549
|
}
|
|
517
550
|
/**
|
|
@@ -671,7 +704,7 @@ async function main() {
|
|
|
671
704
|
// Handle `neozip init` - interactive setup wizard
|
|
672
705
|
if (command === 'init') {
|
|
673
706
|
// Lazy-load ConfigSetup only when needed
|
|
674
|
-
const { ConfigSetup } = await import('./config/ConfigSetup.js');
|
|
707
|
+
const { ConfigSetup } = await import(resolveScriptPath('./config/ConfigSetup.js'));
|
|
675
708
|
const wizard = new ConfigSetup();
|
|
676
709
|
const success = await wizard.run();
|
|
677
710
|
process.exit(success ? exit_codes_1.ZIP_EXIT_CODES.SUCCESS : exit_codes_1.ZIP_EXIT_CODES.BAD_ARCHIVE_FORMAT);
|
|
@@ -679,10 +712,113 @@ async function main() {
|
|
|
679
712
|
// Handle `neozip config` - show interactive menu
|
|
680
713
|
if (command === 'config') {
|
|
681
714
|
// Lazy-load ConfigSetup only when needed
|
|
682
|
-
const { ConfigSetup } = await import('./config/ConfigSetup.js');
|
|
715
|
+
const { ConfigSetup } = await import(resolveScriptPath('./config/ConfigSetup.js'));
|
|
683
716
|
await ConfigSetup.showAndManage();
|
|
684
717
|
// showAndManage handles its own exit
|
|
685
718
|
}
|
|
719
|
+
// Handle `neozip verify-email` - configure email for Zipstamp timestamping
|
|
720
|
+
if (command === 'verify-email') {
|
|
721
|
+
const verifyArgs = args.slice(1);
|
|
722
|
+
let email;
|
|
723
|
+
let setDefaultOnly = false;
|
|
724
|
+
let debug = false;
|
|
725
|
+
for (let i = 0; i < verifyArgs.length; i++) {
|
|
726
|
+
const arg = verifyArgs[i];
|
|
727
|
+
if (arg === '--email' && verifyArgs[i + 1]) {
|
|
728
|
+
email = verifyArgs[++i];
|
|
729
|
+
}
|
|
730
|
+
else if (arg === '--set-default') {
|
|
731
|
+
setDefaultOnly = true;
|
|
732
|
+
}
|
|
733
|
+
else if (arg === '--debug') {
|
|
734
|
+
debug = true;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
const { runVerifyEmail } = await import(resolveScriptPath('./commands/verifyEmail.js'));
|
|
738
|
+
const success = await runVerifyEmail({ email, setDefaultOnly, debug });
|
|
739
|
+
process.exit(success ? exit_codes_1.ZIP_EXIT_CODES.SUCCESS : exit_codes_1.ZIP_EXIT_CODES.BAD_ARCHIVE_FORMAT);
|
|
740
|
+
}
|
|
741
|
+
// Handle `neozip upgrade` - upgrade pending Zipstamp timestamp to confirmed
|
|
742
|
+
if (command === 'upgrade') {
|
|
743
|
+
const upgradeArgs = args.slice(1);
|
|
744
|
+
let inputPath = '';
|
|
745
|
+
let outputPath;
|
|
746
|
+
let wait = false;
|
|
747
|
+
let verbose = false;
|
|
748
|
+
let debug = false;
|
|
749
|
+
for (let i = 0; i < upgradeArgs.length; i++) {
|
|
750
|
+
const arg = upgradeArgs[i];
|
|
751
|
+
if (arg === '--wait') {
|
|
752
|
+
wait = true;
|
|
753
|
+
}
|
|
754
|
+
else if (arg === '-v' || arg === '--verbose') {
|
|
755
|
+
verbose = true;
|
|
756
|
+
}
|
|
757
|
+
else if (arg === '--debug') {
|
|
758
|
+
debug = true;
|
|
759
|
+
}
|
|
760
|
+
else if (!arg.startsWith('-')) {
|
|
761
|
+
if (!inputPath) {
|
|
762
|
+
inputPath = arg;
|
|
763
|
+
}
|
|
764
|
+
else if (!outputPath) {
|
|
765
|
+
outputPath = arg;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
if (!inputPath) {
|
|
770
|
+
console.error('Error: neozip upgrade requires an input archive path');
|
|
771
|
+
console.error(' Usage: neozip upgrade <archive> [output] [--wait]');
|
|
772
|
+
(0, exit_codes_1.exitZip)(exit_codes_1.ZIP_EXIT_CODES.PARAMETER_ERROR);
|
|
773
|
+
}
|
|
774
|
+
const { upgradeZipForTimestamp } = await import(resolveScriptPath('./neozip/upgradeZip.js'));
|
|
775
|
+
await upgradeZipForTimestamp(inputPath, outputPath, { wait, verbose, debug });
|
|
776
|
+
(0, utils_1.log)('✓ Upgrade completed successfully', { verbose, quiet: false });
|
|
777
|
+
process.exit(exit_codes_1.ZIP_EXIT_CODES.SUCCESS);
|
|
778
|
+
}
|
|
779
|
+
// Handle `neozip mint` - mint TimestampProofNFT from confirmed timestamped ZIP
|
|
780
|
+
if (command === 'mint') {
|
|
781
|
+
const mintArgs = args.slice(1);
|
|
782
|
+
let inputPath = '';
|
|
783
|
+
let outputPath;
|
|
784
|
+
let walletKey;
|
|
785
|
+
let network;
|
|
786
|
+
let debug = false;
|
|
787
|
+
for (let i = 0; i < mintArgs.length; i++) {
|
|
788
|
+
const arg = mintArgs[i];
|
|
789
|
+
if (arg === '-w' || arg === '--wallet-key') {
|
|
790
|
+
walletKey = mintArgs[++i];
|
|
791
|
+
}
|
|
792
|
+
else if (arg === '-n' || arg === '--network') {
|
|
793
|
+
network = mintArgs[++i];
|
|
794
|
+
}
|
|
795
|
+
else if (arg === '--debug') {
|
|
796
|
+
debug = true;
|
|
797
|
+
}
|
|
798
|
+
else if (!arg.startsWith('-')) {
|
|
799
|
+
if (!inputPath) {
|
|
800
|
+
inputPath = arg;
|
|
801
|
+
}
|
|
802
|
+
else if (outputPath === undefined) {
|
|
803
|
+
outputPath = arg;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
if (!inputPath) {
|
|
808
|
+
console.error('Error: neozip mint requires an input archive path');
|
|
809
|
+
console.error(' Usage: neozip mint <archive> [output] [-w <wallet-key>] [-n <network>]');
|
|
810
|
+
(0, exit_codes_1.exitZip)(exit_codes_1.ZIP_EXIT_CODES.PARAMETER_ERROR);
|
|
811
|
+
}
|
|
812
|
+
const { runMintTimestampProof } = await import(resolveScriptPath('./commands/mintTimestampProof.js'));
|
|
813
|
+
const success = await runMintTimestampProof({
|
|
814
|
+
inputPath,
|
|
815
|
+
outputPath,
|
|
816
|
+
walletKey,
|
|
817
|
+
network,
|
|
818
|
+
debug
|
|
819
|
+
});
|
|
820
|
+
process.exit(success ? exit_codes_1.ZIP_EXIT_CODES.SUCCESS : exit_codes_1.ZIP_EXIT_CODES.BAD_ARCHIVE_FORMAT);
|
|
821
|
+
}
|
|
686
822
|
}
|
|
687
823
|
let { archive, files, options } = parseArgs(args);
|
|
688
824
|
// If network not explicitly provided via CLI, use from ConfigStore (which reads from ENV or wallet.json)
|
package/env.example
CHANGED
|
@@ -55,6 +55,16 @@ NEOZIP_WALLET_PASSKEY=0x1234567890abcdef1234567890abcdef1234567890abcdef12345678
|
|
|
55
55
|
# - Arbitrum One: https://arb1.arbitrum.io/rpc
|
|
56
56
|
# - Ethereum Sepolia: https://rpc.sepolia.ethpandaops.io
|
|
57
57
|
|
|
58
|
+
# =============================================================================
|
|
59
|
+
# OPTIONAL: Zipstamp Timestamp Configuration
|
|
60
|
+
# =============================================================================
|
|
61
|
+
|
|
62
|
+
# Zipstamp server URL for Ethereum timestamping (default: https://zipstamp-dev.neozip.io)
|
|
63
|
+
# ZIPSTAMP_SERVER_URL=https://zipstamp-dev.neozip.io
|
|
64
|
+
|
|
65
|
+
# Email for Zipstamp server (some servers require verified email for stamping)
|
|
66
|
+
# NEOZIP_TIMESTAMP_EMAIL=your@email.com
|
|
67
|
+
|
|
58
68
|
# =============================================================================
|
|
59
69
|
# OPTIONAL: Debug Configuration
|
|
60
70
|
# =============================================================================
|