neozipkit 0.2.1 → 0.3.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/LICENSE +22 -0
- package/README.md +410 -186
- package/contracts/ABI.txt +889 -0
- package/contracts/Bytecode.txt +1 -0
- package/contracts/COMPILATION_NOTES.md +59 -0
- package/contracts/QUICK_DEPLOY.md +286 -0
- package/contracts/README.md +235 -131
- package/contracts/VERIFICATION.md +308 -0
- package/contracts/deploy-interactive.js +448 -0
- package/contracts/deployment-arbitrum-sepolia.json +12 -0
- package/contracts/deployment-arbitrum.json +12 -0
- package/contracts/deployment-eth-sepolia.json +12 -0
- package/contracts/hardhat.config.js +114 -0
- package/contracts/package.json +20 -0
- package/contracts/scripts/compile-and-extract.js +119 -0
- package/contracts/scripts/verify-contract.js +223 -0
- package/contracts/src/{NZIP-NFT-Private.sol → NZIP-NFT-v2.0.sol} +66 -151
- package/contracts/src/NZIP-NFT.sol +9 -15
- package/dist/blockchain/browser/TokenVerifierBrowser.d.ts +67 -0
- package/dist/blockchain/browser/TokenVerifierBrowser.d.ts.map +1 -0
- package/dist/blockchain/browser/TokenVerifierBrowser.js +313 -0
- package/dist/blockchain/browser/TokenVerifierBrowser.js.map +1 -0
- package/dist/blockchain/browser/WalletManagerBrowser.d.ts +98 -0
- package/dist/blockchain/browser/WalletManagerBrowser.d.ts.map +1 -0
- package/dist/blockchain/browser/WalletManagerBrowser.js +434 -0
- package/dist/blockchain/browser/WalletManagerBrowser.js.map +1 -0
- package/dist/blockchain/browser/ZipkitMinterBrowser.d.ts +58 -0
- package/dist/blockchain/browser/ZipkitMinterBrowser.d.ts.map +1 -0
- package/dist/blockchain/browser/ZipkitMinterBrowser.js +317 -0
- package/dist/blockchain/browser/ZipkitMinterBrowser.js.map +1 -0
- package/dist/blockchain/browser/index.d.ts +11 -0
- package/dist/blockchain/browser/index.d.ts.map +1 -0
- package/dist/blockchain/browser/index.js +16 -0
- package/dist/blockchain/browser/index.js.map +1 -0
- package/dist/blockchain/core/WalletManager.d.ts +124 -0
- package/dist/blockchain/core/WalletManager.d.ts.map +1 -0
- package/dist/blockchain/{ZipKitWallet.js → core/WalletManager.js} +157 -177
- package/dist/blockchain/core/WalletManager.js.map +1 -0
- package/dist/blockchain/{ZipKitMinter.d.ts → core/ZipkitMinter.d.ts} +46 -11
- package/dist/blockchain/core/ZipkitMinter.d.ts.map +1 -0
- package/dist/blockchain/core/ZipkitMinter.js +548 -0
- package/dist/blockchain/core/ZipkitMinter.js.map +1 -0
- package/dist/blockchain/{ZipKitOTS.d.ts → core/ZipkitOTS.d.ts} +6 -15
- package/dist/blockchain/core/ZipkitOTS.d.ts.map +1 -0
- package/dist/blockchain/{ZipKitOTS.js → core/ZipkitOTS.js} +26 -84
- package/dist/blockchain/core/ZipkitOTS.js.map +1 -0
- package/dist/blockchain/core/ZipkitVerifier.d.ts +177 -0
- package/dist/blockchain/core/ZipkitVerifier.d.ts.map +1 -0
- package/dist/blockchain/core/ZipkitVerifier.js +632 -0
- package/dist/blockchain/core/ZipkitVerifier.js.map +1 -0
- package/dist/blockchain/core/contracts.d.ts +83 -0
- package/dist/blockchain/core/contracts.d.ts.map +1 -0
- package/dist/blockchain/core/contracts.js +341 -0
- package/dist/blockchain/core/contracts.js.map +1 -0
- package/dist/blockchain/core/index.d.ts +12 -0
- package/dist/blockchain/core/index.d.ts.map +1 -0
- package/dist/blockchain/core/index.js +59 -0
- package/dist/blockchain/core/index.js.map +1 -0
- package/dist/blockchain/index.d.ts +11 -7
- package/dist/blockchain/index.d.ts.map +1 -0
- package/dist/blockchain/index.js +18 -34
- package/dist/blockchain/index.js.map +1 -0
- package/dist/blockchain/node/WalletManagerNode.d.ts +47 -0
- package/dist/blockchain/node/WalletManagerNode.d.ts.map +1 -0
- package/dist/blockchain/node/WalletManagerNode.js +203 -0
- package/dist/blockchain/node/WalletManagerNode.js.map +1 -0
- package/dist/blockchain/node/index.d.ts +12 -0
- package/dist/blockchain/node/index.d.ts.map +1 -0
- package/dist/blockchain/node/index.js +24 -0
- package/dist/blockchain/node/index.js.map +1 -0
- package/dist/browser/ZipkitBrowser.d.ts +27 -0
- package/dist/browser/ZipkitBrowser.d.ts.map +1 -0
- package/dist/browser/{ZipKitBrowser.js → ZipkitBrowser.js} +96 -43
- package/dist/browser/ZipkitBrowser.js.map +1 -0
- package/dist/browser/index.d.ts +12 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +42 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser-esm/index.d.ts +12 -0
- package/dist/browser-esm/index.js +59559 -0
- package/dist/browser-esm/index.js.map +7 -0
- package/dist/browser-umd/index.d.ts +12 -0
- package/dist/browser-umd/index.js +59576 -0
- package/dist/browser-umd/index.js.map +7 -0
- package/dist/browser-umd/index.min.js +63 -0
- package/dist/browser.d.ts +8 -14
- package/dist/browser.js +13 -28
- package/dist/core/ZipCompress.d.ts +99 -0
- package/dist/core/ZipCompress.d.ts.map +1 -0
- package/dist/core/ZipCompress.js +309 -0
- package/dist/core/ZipCompress.js.map +1 -0
- package/dist/core/ZipDecompress.d.ts +58 -0
- package/dist/core/ZipDecompress.d.ts.map +1 -0
- package/dist/core/ZipDecompress.js +172 -0
- package/dist/core/ZipDecompress.js.map +1 -0
- package/dist/{shared → core}/ZipEntry.d.ts +8 -1
- package/dist/core/ZipEntry.d.ts.map +1 -0
- package/dist/{shared → core}/ZipEntry.js +225 -82
- package/dist/core/ZipEntry.js.map +1 -0
- package/dist/core/Zipkit.d.ts +315 -0
- package/dist/core/Zipkit.d.ts.map +1 -0
- package/dist/core/Zipkit.js +647 -0
- package/dist/core/Zipkit.js.map +1 -0
- package/dist/core/components/HashCalculator.d.ts +138 -0
- package/dist/core/components/HashCalculator.d.ts.map +1 -0
- package/dist/core/components/HashCalculator.js +360 -0
- package/dist/core/components/HashCalculator.js.map +1 -0
- package/dist/core/components/Logger.d.ts +73 -0
- package/dist/core/components/Logger.d.ts.map +1 -0
- package/dist/core/components/Logger.js +156 -0
- package/dist/core/components/Logger.js.map +1 -0
- package/dist/core/components/ProgressTracker.d.ts +43 -0
- package/dist/core/components/ProgressTracker.d.ts.map +1 -0
- package/dist/core/components/ProgressTracker.js +112 -0
- package/dist/core/components/ProgressTracker.js.map +1 -0
- package/dist/{shared → core}/components/Support.d.ts +1 -0
- package/dist/core/components/Support.d.ts.map +1 -0
- package/dist/{shared → core}/components/Support.js +1 -0
- package/dist/core/components/Support.js.map +1 -0
- package/dist/{shared → core}/components/Util.d.ts +7 -2
- package/dist/core/components/Util.d.ts.map +1 -0
- package/dist/{shared → core}/components/Util.js +14 -34
- package/dist/core/components/Util.js.map +1 -0
- package/dist/{shared → core}/constants/Errors.d.ts +1 -2
- package/dist/core/constants/Errors.d.ts.map +1 -0
- package/dist/{shared → core}/constants/Errors.js +1 -3
- package/dist/core/constants/Errors.js.map +1 -0
- package/dist/{shared → core}/constants/Headers.d.ts +3 -0
- package/dist/core/constants/Headers.d.ts.map +1 -0
- package/dist/{shared → core}/constants/Headers.js +20 -17
- package/dist/core/constants/Headers.js.map +1 -0
- package/dist/core/encryption/Manager.d.ts +58 -0
- package/dist/core/encryption/Manager.d.ts.map +1 -0
- package/dist/core/encryption/Manager.js +121 -0
- package/dist/core/encryption/Manager.js.map +1 -0
- package/dist/core/encryption/ZipCrypto.d.ts +172 -0
- package/dist/core/encryption/ZipCrypto.d.ts.map +1 -0
- package/dist/core/encryption/ZipCrypto.js +554 -0
- package/dist/core/encryption/ZipCrypto.js.map +1 -0
- package/dist/core/encryption/index.d.ts +9 -0
- package/dist/core/encryption/index.d.ts.map +1 -0
- package/dist/core/encryption/index.js +17 -0
- package/dist/core/encryption/index.js.map +1 -0
- package/dist/core/encryption/types.d.ts +29 -0
- package/dist/core/encryption/types.d.ts.map +1 -0
- package/dist/core/encryption/types.js +12 -0
- package/dist/core/encryption/types.js.map +1 -0
- package/dist/core/index.d.ts +24 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +57 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/version.d.ts +5 -0
- package/dist/core/version.d.ts.map +1 -0
- package/dist/core/version.js +31 -0
- package/dist/core/version.js.map +1 -0
- package/dist/index.d.ts +8 -18
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -35
- package/dist/index.js.map +1 -0
- package/dist/node/ZipCompressNode.d.ts +123 -0
- package/dist/node/ZipCompressNode.d.ts.map +1 -0
- package/dist/node/ZipCompressNode.js +576 -0
- package/dist/node/ZipCompressNode.js.map +1 -0
- package/dist/node/ZipDecompressNode.d.ts +120 -0
- package/dist/node/ZipDecompressNode.d.ts.map +1 -0
- package/dist/node/ZipDecompressNode.js +461 -0
- package/dist/node/ZipDecompressNode.js.map +1 -0
- package/dist/node/ZipkitNode.d.ts +406 -0
- package/dist/node/ZipkitNode.d.ts.map +1 -0
- package/dist/node/ZipkitNode.js +1305 -0
- package/dist/node/ZipkitNode.js.map +1 -0
- package/dist/node/index.d.ts +26 -0
- package/dist/node/index.d.ts.map +1 -0
- package/dist/node/index.js +65 -0
- package/dist/node/index.js.map +1 -0
- package/dist/types/index.d.ts +59 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +36 -1
- package/dist/types/index.js.map +1 -0
- package/examples/README.md +269 -0
- package/examples/blockchain-tokenize.ts +354 -0
- package/examples/create-zip.ts +172 -0
- package/examples/extract-zip.ts +158 -0
- package/examples/list-zip.ts +161 -0
- package/examples/test-files/data.json +116 -0
- package/examples/test-files/document.md +80 -0
- package/examples/test-files/document.txt +2 -0
- package/examples/test-files/file1.txt +48 -0
- package/examples/test-files/file2.txt +80 -0
- package/examples/tsconfig.json +44 -0
- package/examples/unzip-token.ts +491 -0
- package/examples/verify-tokenized-zip.ts +305 -0
- package/examples/zip-token.ts +604 -0
- package/package.json +108 -24
- package/src/blockchain/README.md +59 -66
- package/src/{browser/TokenVerifierBrowser.ts-remove → blockchain/browser/TokenVerifierBrowser.ts} +125 -79
- package/src/blockchain/browser/WalletManagerBrowser.ts +486 -0
- package/src/blockchain/browser/ZipkitMinterBrowser.ts +400 -0
- package/src/blockchain/browser/index.ts +13 -0
- package/src/blockchain/{ZipKitWallet.ts → core/WalletManager.ts} +241 -143
- package/src/blockchain/core/ZipkitMinter.ts +716 -0
- package/src/blockchain/{ZipKitOTS.ts → core/ZipkitOTS.ts} +28 -62
- package/src/blockchain/core/ZipkitVerifier.ts +853 -0
- package/src/blockchain/core/contracts.ts +370 -0
- package/src/blockchain/core/index.ts +71 -0
- package/src/blockchain/index.ts +21 -55
- package/src/blockchain/node/WalletManagerNode.ts +171 -0
- package/src/blockchain/node/index.ts +40 -0
- package/src/browser/{ZipKitBrowser.ts → ZipkitBrowser.ts} +104 -41
- package/src/browser/index.esm.ts +37 -0
- package/src/browser/index.ts +25 -0
- package/src/core/ZipCompress.ts +398 -0
- package/src/core/ZipDecompress.ts +212 -0
- package/src/{shared → core}/ZipEntry.ts +240 -90
- package/src/core/Zipkit.ts +794 -0
- package/src/core/components/HashCalculator.ts +384 -0
- package/src/core/components/Logger.ts +180 -0
- package/src/core/components/ProgressTracker.ts +134 -0
- package/src/{shared → core}/components/Util.ts +12 -34
- package/src/{shared → core}/constants/Errors.ts +0 -4
- package/src/{shared → core}/constants/Headers.ts +19 -17
- package/src/core/encryption/Manager.ts +137 -0
- package/src/core/encryption/ZipCrypto.ts +650 -0
- package/src/core/encryption/index.ts +15 -0
- package/src/core/encryption/types.ts +33 -0
- package/src/core/index.ts +34 -0
- package/src/core/version.ts +33 -0
- package/src/index.ts +54 -25
- package/src/node/ZipCompressNode.ts +632 -0
- package/src/node/ZipDecompressNode.ts +508 -0
- package/src/node/ZipkitNode.ts +1559 -0
- package/src/node/index.ts +69 -0
- package/src/types/index.ts +131 -1
- package/src/types/modules.d.ts +1 -11
- package/src/types/opentimestamps.d.ts +1 -23
- package/contracts/INTEGRATION.md +0 -338
- package/contracts/NETWORKS.md +0 -156
- package/contracts/NZIP-NFT-bytecode.txt +0 -1
- package/contracts/constants.ts +0 -952
- package/contracts/deploy-bytecode.mjs +0 -94
- package/dist/blockchain/CertificateToken.d.ts +0 -48
- package/dist/blockchain/CertificateToken.js +0 -386
- package/dist/blockchain/ZipKitMinter.js +0 -347
- package/dist/blockchain/ZipKitNFT.d.ts +0 -3
- package/dist/blockchain/ZipKitNFT.js +0 -7
- package/dist/blockchain/ZipKitVerifier.d.ts +0 -69
- package/dist/blockchain/ZipKitVerifier.js +0 -289
- package/dist/blockchain/ZipKitWallet.d.ts +0 -69
- package/dist/blockchain/contracts.d.ts +0 -14
- package/dist/blockchain/contracts.js +0 -77
- package/dist/blockchain/types.d.ts +0 -47
- package/dist/blockchain/types.js +0 -30
- package/dist/browser/ZipKitBrowser.d.ts +0 -18
- package/dist/browser/ZipKitStampBrowser.d.ts +0 -2
- package/dist/browser/ZipKitStampBrowser.js +0 -12
- package/dist/browser-index.d.ts +0 -18
- package/dist/browser-index.js +0 -57
- package/dist/server/ZipKitServer.d.ts +0 -74
- package/dist/server/ZipKitServer.js +0 -310
- package/dist/shared/ZipKit.d.ts +0 -243
- package/dist/shared/ZipKit.js +0 -772
- package/dist/shared/components/CertificateOTS.d.ts +0 -15
- package/dist/shared/components/CertificateOTS.js +0 -116
- package/dist/shared/components/FileSys.d.ts +0 -2
- package/dist/shared/components/FileSys.js +0 -113
- package/dist/shared/components/HashAccumulator.d.ts +0 -55
- package/dist/shared/components/HashAccumulator.js +0 -100
- package/dist/shared/components/ZipCrypto.d.ts +0 -3
- package/dist/shared/components/ZipCrypto.js +0 -78
- package/dist/shared/components/merkleTree.d.ts +0 -66
- package/dist/shared/components/merkleTree.js +0 -136
- package/dist/shared/types/index.d.ts +0 -21
- package/dist/shared/types/index.js +0 -3
- package/dist/shared/types.d.ts +0 -33
- package/dist/shared/types.js +0 -8
- package/dist/shared/version.d.ts +0 -2
- package/dist/shared/version.js +0 -6
- package/src/blockchain/CertificateToken.ts +0 -444
- package/src/blockchain/ZipKitMinter.ts +0 -470
- package/src/blockchain/ZipKitNFT.ts +0 -12
- package/src/blockchain/ZipKitVerifier.ts +0 -382
- package/src/blockchain/contracts.ts +0 -88
- package/src/blockchain/types.ts +0 -91
- package/src/browser/CertificateGeneratorBrowser.ts-remove +0 -498
- package/src/browser/ZipKitStampBrowser.ts +0 -9
- package/src/browser-index.ts +0 -36
- package/src/server/README.md +0 -25
- package/src/server/ZipKitServer.ts +0 -305
- package/src/shared/ZipKit.ts +0 -881
- package/src/shared/components/CertificateOTS.ts +0 -132
- package/src/shared/components/FileSys.ts +0 -87
- package/src/shared/components/HashAccumulator.ts +0 -113
- package/src/shared/components/ZipCrypto.ts +0 -91
- package/src/shared/components/merkleTree.ts +0 -162
- package/src/shared/types/index.ts +0 -25
- package/src/shared/types/modules.d.ts +0 -22
- package/src/shared/types/opentimestamps.d.ts +0 -23
- package/src/shared/types.d.ts +0 -8
- package/src/shared/types.ts +0 -43
- package/src/shared/version.ts +0 -3
- /package/src/{shared → core}/components/Support.ts +0 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Blockchain Tokenization Example
|
|
5
|
+
*
|
|
6
|
+
* Demonstrates creating a tokenized ZIP file with blockchain NFT minting.
|
|
7
|
+
* This is a minimal example showing the basic tokenization flow.
|
|
8
|
+
*
|
|
9
|
+
* SECURITY WARNING:
|
|
10
|
+
* - NEVER use mainnet private keys in examples
|
|
11
|
+
* - ONLY use testnet keys with minimal test funds
|
|
12
|
+
* - NEVER commit private keys to version control
|
|
13
|
+
* - Store private keys in .env file (excluded from git)
|
|
14
|
+
* - Rotate keys immediately if accidentally exposed
|
|
15
|
+
* - Wallet files (wallet/neozip-wallet.json) are automatically excluded from git
|
|
16
|
+
*
|
|
17
|
+
* See SECURITY.md for complete security guidelines.
|
|
18
|
+
*
|
|
19
|
+
* Note: This example requires:
|
|
20
|
+
* - A wallet private key with testnet ETH
|
|
21
|
+
* - Network configuration (defaults to Base Sepolia testnet)
|
|
22
|
+
* - Gas fees for minting
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { ZipkitNode } from '../src/node';
|
|
26
|
+
import { ZipkitMinter } from '../src/blockchain/core/ZipkitMinter';
|
|
27
|
+
import type { CompressOptions } from '../src/core';
|
|
28
|
+
import type { TokenMetadata } from '../src/types';
|
|
29
|
+
import { TOKENIZED_METADATA } from '../src/core/constants/Headers';
|
|
30
|
+
import { crc32 } from '../src/core/encryption/ZipCrypto';
|
|
31
|
+
import * as fs from 'fs';
|
|
32
|
+
import * as path from 'path';
|
|
33
|
+
import dotenv from 'dotenv';
|
|
34
|
+
|
|
35
|
+
// Load .env.local first (local overrides), then .env
|
|
36
|
+
dotenv.config({ path: '.env.local' });
|
|
37
|
+
dotenv.config(); // Loads .env if .env.local doesn't exist
|
|
38
|
+
|
|
39
|
+
async function main() {
|
|
40
|
+
console.log('Blockchain Tokenization Example\n');
|
|
41
|
+
|
|
42
|
+
// Check for wallet private key
|
|
43
|
+
const walletPrivateKey = process.env.NEOZIP_WALLET_PASSKEY;
|
|
44
|
+
if (!walletPrivateKey) {
|
|
45
|
+
console.error('❌ Error: NEOZIP_WALLET_PASSKEY environment variable is required');
|
|
46
|
+
console.error(' Please set your wallet private key:');
|
|
47
|
+
console.error(' export NEOZIP_WALLET_PASSKEY="0x..."');
|
|
48
|
+
console.error('\n💡 Get testnet ETH from:');
|
|
49
|
+
console.error(' https://www.coinbase.com/faucets/base-ethereum-sepolia-faucet');
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Network configuration (default to Base Sepolia testnet)
|
|
54
|
+
const network = process.env.NEOZIP_NETWORK || 'base-sepolia';
|
|
55
|
+
|
|
56
|
+
// Create some test files
|
|
57
|
+
const testFiles: string[] = [];
|
|
58
|
+
const testDir = path.join(__dirname, 'test-files');
|
|
59
|
+
|
|
60
|
+
if (!fs.existsSync(testDir)) {
|
|
61
|
+
fs.mkdirSync(testDir, { recursive: true });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const file1 = path.join(testDir, 'document.txt');
|
|
65
|
+
const file2 = path.join(testDir, 'data.json');
|
|
66
|
+
|
|
67
|
+
if (!fs.existsSync(file1)) {
|
|
68
|
+
fs.writeFileSync(file1, 'This is a sample document.\nIt will be tokenized on the blockchain.');
|
|
69
|
+
}
|
|
70
|
+
testFiles.push(file1);
|
|
71
|
+
|
|
72
|
+
if (!fs.existsSync(file2)) {
|
|
73
|
+
fs.writeFileSync(file2, JSON.stringify({ name: 'Sample Data', value: 12345 }, null, 2));
|
|
74
|
+
}
|
|
75
|
+
testFiles.push(file2);
|
|
76
|
+
|
|
77
|
+
console.log('Source files:');
|
|
78
|
+
testFiles.forEach(file => {
|
|
79
|
+
const stats = fs.statSync(file);
|
|
80
|
+
console.log(` - ${path.basename(file)} (${stats.size} bytes)`);
|
|
81
|
+
});
|
|
82
|
+
console.log();
|
|
83
|
+
|
|
84
|
+
// Create ZipkitNode instance
|
|
85
|
+
const zip = new ZipkitNode();
|
|
86
|
+
|
|
87
|
+
// Define output ZIP file path
|
|
88
|
+
const outputZip = path.join(__dirname, 'output', 'tokenized.zip');
|
|
89
|
+
const outputDir = path.dirname(outputZip);
|
|
90
|
+
if (!fs.existsSync(outputDir)) {
|
|
91
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Compression options with SHA-256 enabled (required for merkle root calculation)
|
|
95
|
+
const options: CompressOptions = {
|
|
96
|
+
level: 6,
|
|
97
|
+
useZstd: true,
|
|
98
|
+
useSHA256: true // IMPORTANT: Enable SHA-256 for blockchain features
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
console.log('Step 1: Creating ZIP archive with SHA-256 hashes...');
|
|
103
|
+
|
|
104
|
+
// Create ZIP file from files
|
|
105
|
+
await zip.createZipFromFiles(testFiles, outputZip, options);
|
|
106
|
+
|
|
107
|
+
console.log(`✅ ZIP archive created: ${outputZip}\n`);
|
|
108
|
+
|
|
109
|
+
// Load the ZIP to get entries and calculate merkle root
|
|
110
|
+
console.log('Step 2: Calculating merkle root...');
|
|
111
|
+
await zip.loadZipFile(outputZip);
|
|
112
|
+
|
|
113
|
+
// Get merkle root (this requires SHA-256 hashes to be calculated)
|
|
114
|
+
const merkleRoot = (zip as any).getMerkleRoot?.();
|
|
115
|
+
|
|
116
|
+
if (!merkleRoot) {
|
|
117
|
+
console.error('❌ Error: Could not calculate merkle root');
|
|
118
|
+
console.error(' Make sure useSHA256: true is set in compression options');
|
|
119
|
+
await zip.closeFile(); // Close file handle before exiting
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
console.log(`✅ Merkle root calculated: ${merkleRoot}\n`);
|
|
124
|
+
|
|
125
|
+
// Close file handle to prevent warnings
|
|
126
|
+
await zip.closeFile();
|
|
127
|
+
|
|
128
|
+
// Initialize blockchain minter
|
|
129
|
+
console.log('Step 3: Initializing blockchain minter...');
|
|
130
|
+
const minter = new ZipkitMinter(merkleRoot, {
|
|
131
|
+
walletPrivateKey: walletPrivateKey,
|
|
132
|
+
network: network,
|
|
133
|
+
verbose: true,
|
|
134
|
+
debug: false
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Get wallet information
|
|
138
|
+
const walletInfo = await minter.getWalletInfo();
|
|
139
|
+
console.log(`✅ Wallet: ${walletInfo.address}`);
|
|
140
|
+
console.log(` Balance: ${walletInfo.balance} ETH`);
|
|
141
|
+
console.log(` Network: ${walletInfo.networkName}\n`);
|
|
142
|
+
|
|
143
|
+
// Check for existing tokens
|
|
144
|
+
console.log('Step 4: Checking for existing tokens...');
|
|
145
|
+
const duplicateCheck = await minter.checkForDuplicates();
|
|
146
|
+
|
|
147
|
+
if (duplicateCheck.hasExistingTokens) {
|
|
148
|
+
console.log(`⚠️ Found ${duplicateCheck.allTokens.length} existing token(s) with this merkle root:`);
|
|
149
|
+
duplicateCheck.userOwnedTokens.forEach(token => {
|
|
150
|
+
console.log(` - Token ID ${token.tokenId} (owned by you)`);
|
|
151
|
+
});
|
|
152
|
+
duplicateCheck.othersTokens.forEach(token => {
|
|
153
|
+
console.log(` - Token ID ${token.tokenId} (owned by others)`);
|
|
154
|
+
});
|
|
155
|
+
console.log('\n💡 This example will proceed with minting a new token.');
|
|
156
|
+
console.log(' In a real application, you might want to use an existing token instead.\n');
|
|
157
|
+
} else {
|
|
158
|
+
console.log('✅ No existing tokens found. Proceeding with new mint.\n');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Estimate gas costs
|
|
162
|
+
console.log('Step 5: Estimating gas costs...');
|
|
163
|
+
const gasCosts = await minter.estimateGasCosts();
|
|
164
|
+
console.log(` Estimated gas cost: ${gasCosts.estimatedCost} ETH\n`);
|
|
165
|
+
|
|
166
|
+
// Mint the token
|
|
167
|
+
console.log('Step 6: Minting NFT token on blockchain...');
|
|
168
|
+
console.log(' This will incur gas costs. Please wait...\n');
|
|
169
|
+
|
|
170
|
+
const mintResult = await minter.mintToken();
|
|
171
|
+
|
|
172
|
+
if (mintResult.success) {
|
|
173
|
+
console.log(`✅ Token minted successfully!`);
|
|
174
|
+
console.log(` Token ID: ${mintResult.tokenId}`);
|
|
175
|
+
console.log(` Transaction: ${mintResult.transactionHash}`);
|
|
176
|
+
console.log(` Contract: ${mintResult.contractAddress}`);
|
|
177
|
+
if (mintResult.gasUsed) {
|
|
178
|
+
console.log(` Gas Used: ${mintResult.gasUsed}`);
|
|
179
|
+
}
|
|
180
|
+
if (mintResult.gasCost) {
|
|
181
|
+
console.log(` Gas Cost: ${mintResult.gasCost} ETH`);
|
|
182
|
+
}
|
|
183
|
+
console.log();
|
|
184
|
+
|
|
185
|
+
// Step 7: Add token metadata to ZIP file
|
|
186
|
+
console.log('Step 7: Adding token metadata to ZIP file...');
|
|
187
|
+
|
|
188
|
+
// Create token metadata object
|
|
189
|
+
const tokenMetadata: TokenMetadata = {
|
|
190
|
+
version: '1.0',
|
|
191
|
+
tokenId: mintResult.tokenId!,
|
|
192
|
+
contractAddress: mintResult.contractAddress!,
|
|
193
|
+
network: walletInfo.networkName,
|
|
194
|
+
networkChainId: walletInfo.networkName === 'Base Sepolia' ? 84532 : undefined,
|
|
195
|
+
transactionHash: mintResult.transactionHash,
|
|
196
|
+
merkleRoot: merkleRoot,
|
|
197
|
+
mintedAt: new Date().toISOString(),
|
|
198
|
+
mintDate: new Date().toISOString()
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// Rebuild ZIP with token metadata
|
|
202
|
+
await addTokenMetadataToZip(zip, outputZip, tokenMetadata, testFiles, options);
|
|
203
|
+
|
|
204
|
+
console.log(`✅ Token metadata added to ZIP file`);
|
|
205
|
+
console.log(` Metadata file: ${TOKENIZED_METADATA}`);
|
|
206
|
+
console.log();
|
|
207
|
+
console.log(`📄 View token on explorer:`);
|
|
208
|
+
const explorerUrl = `https://sepolia.basescan.org/token/${mintResult.contractAddress}?a=${mintResult.tokenId}`;
|
|
209
|
+
console.log(` ${explorerUrl}`);
|
|
210
|
+
|
|
211
|
+
// Explicitly exit to prevent hanging
|
|
212
|
+
process.exit(0);
|
|
213
|
+
|
|
214
|
+
} else {
|
|
215
|
+
console.error(`❌ Token minting failed: ${mintResult.message}`);
|
|
216
|
+
process.exit(1);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
} catch (error) {
|
|
220
|
+
console.error('❌ Error during tokenization:');
|
|
221
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
222
|
+
if (error instanceof Error && error.stack) {
|
|
223
|
+
console.error('\nStack trace:');
|
|
224
|
+
console.error(error.stack);
|
|
225
|
+
}
|
|
226
|
+
// Ensure file handle is closed on error
|
|
227
|
+
try {
|
|
228
|
+
await zip.closeFile();
|
|
229
|
+
} catch (closeError) {
|
|
230
|
+
// Ignore close errors
|
|
231
|
+
}
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Add token metadata to ZIP file by rebuilding it with the metadata entry
|
|
238
|
+
*/
|
|
239
|
+
async function addTokenMetadataToZip(
|
|
240
|
+
zip: ZipkitNode,
|
|
241
|
+
zipPath: string,
|
|
242
|
+
tokenMetadata: TokenMetadata,
|
|
243
|
+
originalFiles: string[],
|
|
244
|
+
options: CompressOptions
|
|
245
|
+
): Promise<void> {
|
|
246
|
+
// Create token metadata content
|
|
247
|
+
const tokenContent = JSON.stringify(tokenMetadata, null, 2);
|
|
248
|
+
const tokenBuffer = Buffer.from(tokenContent, 'utf8');
|
|
249
|
+
|
|
250
|
+
// Create temporary ZIP file
|
|
251
|
+
const tempZipPath = zipPath + '.tmp';
|
|
252
|
+
|
|
253
|
+
// Create a fresh ZipkitNode instance for the new ZIP
|
|
254
|
+
const newZip = new ZipkitNode();
|
|
255
|
+
|
|
256
|
+
// Initialize new ZIP file
|
|
257
|
+
const writer = await newZip.initializeZipFile(tempZipPath);
|
|
258
|
+
|
|
259
|
+
try {
|
|
260
|
+
// Add all original files
|
|
261
|
+
for (const filePath of originalFiles) {
|
|
262
|
+
const entry = await newZip.prepareEntryFromFile(filePath);
|
|
263
|
+
await newZip.writeZipEntry(writer, entry, filePath, options);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Add token metadata entry (STORED, uncompressed)
|
|
267
|
+
const tokenEntry = newZip.createZipEntry(TOKENIZED_METADATA);
|
|
268
|
+
tokenEntry.timeDateDOS = tokenEntry.setDateTime(new Date());
|
|
269
|
+
tokenEntry.uncompressedSize = tokenBuffer.length;
|
|
270
|
+
tokenEntry.compressedSize = tokenBuffer.length;
|
|
271
|
+
tokenEntry.cmpMethod = 0; // STORED (no compression)
|
|
272
|
+
tokenEntry.crc = crc32(tokenBuffer);
|
|
273
|
+
tokenEntry.fileBuffer = tokenBuffer;
|
|
274
|
+
|
|
275
|
+
// Add entry to ZIP entries list
|
|
276
|
+
newZip.getDirectory().push(tokenEntry);
|
|
277
|
+
|
|
278
|
+
// Write token entry manually (STORED method)
|
|
279
|
+
tokenEntry.localHdrOffset = writer.currentPosition;
|
|
280
|
+
writer.entryPositions.set(TOKENIZED_METADATA, tokenEntry.localHdrOffset);
|
|
281
|
+
const localHeader = tokenEntry.createLocalHdr();
|
|
282
|
+
|
|
283
|
+
await new Promise<void>((resolve, reject) => {
|
|
284
|
+
writer.outputStream.write(localHeader, (error) => {
|
|
285
|
+
if (error) {
|
|
286
|
+
reject(error);
|
|
287
|
+
} else {
|
|
288
|
+
writer.currentPosition += localHeader.length;
|
|
289
|
+
resolve();
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
// Write token data
|
|
295
|
+
await new Promise<void>((resolve, reject) => {
|
|
296
|
+
writer.outputStream.write(tokenBuffer, (error) => {
|
|
297
|
+
if (error) {
|
|
298
|
+
reject(error);
|
|
299
|
+
} else {
|
|
300
|
+
writer.currentPosition += tokenBuffer.length;
|
|
301
|
+
resolve();
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
// Get all entries (including token metadata)
|
|
307
|
+
const allEntries = newZip.getDirectory();
|
|
308
|
+
|
|
309
|
+
// Write central directory
|
|
310
|
+
const centralDirOffset = writer.currentPosition;
|
|
311
|
+
const centralDirSize = await newZip.writeCentralDirectory(writer, allEntries);
|
|
312
|
+
|
|
313
|
+
// Write EOCD
|
|
314
|
+
await newZip.writeEndOfCentralDirectory(
|
|
315
|
+
writer,
|
|
316
|
+
allEntries.length,
|
|
317
|
+
centralDirSize,
|
|
318
|
+
centralDirOffset
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
// Finalize and close
|
|
322
|
+
await newZip.finalizeZipFile(writer);
|
|
323
|
+
|
|
324
|
+
// Wait a moment for file system to sync
|
|
325
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
326
|
+
|
|
327
|
+
// Replace original ZIP with new one
|
|
328
|
+
if (fs.existsSync(zipPath)) {
|
|
329
|
+
fs.unlinkSync(zipPath);
|
|
330
|
+
}
|
|
331
|
+
fs.renameSync(tempZipPath, zipPath);
|
|
332
|
+
|
|
333
|
+
// Ensure file handles are released
|
|
334
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
335
|
+
|
|
336
|
+
} catch (error) {
|
|
337
|
+
// Clean up temp file on error
|
|
338
|
+
if (fs.existsSync(tempZipPath)) {
|
|
339
|
+
try {
|
|
340
|
+
fs.unlinkSync(tempZipPath);
|
|
341
|
+
} catch (unlinkError) {
|
|
342
|
+
// Ignore unlink errors
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
throw error;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Run the example
|
|
350
|
+
main().catch((error) => {
|
|
351
|
+
console.error('Fatal error:', error);
|
|
352
|
+
process.exit(1);
|
|
353
|
+
});
|
|
354
|
+
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Create ZIP Example
|
|
5
|
+
*
|
|
6
|
+
* Demonstrates creating a ZIP archive from multiple files using ZipkitNode.
|
|
7
|
+
* This is a minimal example showing the basic API usage.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import ZipkitNode from '../src/node';
|
|
11
|
+
import type { CompressOptions } from '../src/core';
|
|
12
|
+
import * as fs from 'fs';
|
|
13
|
+
import * as path from 'path';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Helper function to format bytes
|
|
17
|
+
*/
|
|
18
|
+
function formatBytes(bytes: number): string {
|
|
19
|
+
if (bytes === 0) return '0 B';
|
|
20
|
+
const k = 1024;
|
|
21
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
22
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
23
|
+
return (bytes / Math.pow(k, i)).toFixed(1) + ' ' + sizes[i];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Helper function to pad string to the right
|
|
28
|
+
*/
|
|
29
|
+
function padRight(str: string, length: number): string {
|
|
30
|
+
return (str + ' '.repeat(length)).slice(0, length);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Helper function to pad string to the left
|
|
35
|
+
*/
|
|
36
|
+
function padLeft(str: string, length: number): string {
|
|
37
|
+
return (' '.repeat(length) + str).slice(-length);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function main() {
|
|
41
|
+
console.log('Creating ZIP archive example...\n');
|
|
42
|
+
|
|
43
|
+
// Test files to compress (located in test-files directory)
|
|
44
|
+
const testDir = path.join(__dirname, 'test-files');
|
|
45
|
+
const testFiles = [
|
|
46
|
+
path.join(testDir, 'file1.txt'),
|
|
47
|
+
path.join(testDir, 'file2.txt'),
|
|
48
|
+
path.join(testDir, 'document.md'),
|
|
49
|
+
path.join(testDir, 'data.json')
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
// Verify all test files exist
|
|
53
|
+
for (const file of testFiles) {
|
|
54
|
+
if (!fs.existsSync(file)) {
|
|
55
|
+
console.error(`❌ Error: Test file not found: ${file}`);
|
|
56
|
+
console.error(' Make sure test-files directory contains the required files.');
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
console.log('Source files:');
|
|
62
|
+
testFiles.forEach(file => {
|
|
63
|
+
const stats = fs.statSync(file);
|
|
64
|
+
console.log(` - ${path.basename(file)} (${stats.size} bytes)`);
|
|
65
|
+
});
|
|
66
|
+
console.log();
|
|
67
|
+
|
|
68
|
+
// Create ZipkitNode instance
|
|
69
|
+
const zip = new ZipkitNode();
|
|
70
|
+
|
|
71
|
+
// Define output ZIP file path
|
|
72
|
+
const outputZip = path.join(__dirname, 'output', 'example.zip');
|
|
73
|
+
|
|
74
|
+
// Ensure output directory exists
|
|
75
|
+
const outputDir = path.dirname(outputZip);
|
|
76
|
+
if (!fs.existsSync(outputDir)) {
|
|
77
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Compression options
|
|
81
|
+
const options: CompressOptions = {
|
|
82
|
+
level: 6, // Compression level (0-9, higher = better compression but slower)
|
|
83
|
+
useZstd: false, // Use Deflate compression (standard ZIP)
|
|
84
|
+
useSHA256: false // Don't calculate SHA-256 hashes (faster, but needed for blockchain features)
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
console.log('Creating ZIP archive...');
|
|
89
|
+
|
|
90
|
+
// Method 1: Simple API - create ZIP from file paths
|
|
91
|
+
// This is the easiest way to create a ZIP file
|
|
92
|
+
await zip.createZipFromFiles(testFiles, outputZip, options);
|
|
93
|
+
|
|
94
|
+
console.log(`✅ ZIP archive created successfully: ${outputZip}\n`);
|
|
95
|
+
|
|
96
|
+
// Load the ZIP to get entry details
|
|
97
|
+
await zip.loadZipFile(outputZip);
|
|
98
|
+
const entries = zip.getDirectory();
|
|
99
|
+
|
|
100
|
+
// Display summary of compressed files
|
|
101
|
+
console.log('Compression Summary:');
|
|
102
|
+
console.log('─'.repeat(80));
|
|
103
|
+
console.log(
|
|
104
|
+
padRight('Filename', 30) +
|
|
105
|
+
padLeft('Original', 10) +
|
|
106
|
+
padLeft('Compressed', 12) +
|
|
107
|
+
padLeft('Ratio', 10) +
|
|
108
|
+
' ' +
|
|
109
|
+
padRight('Method', 10)
|
|
110
|
+
);
|
|
111
|
+
console.log('─'.repeat(80));
|
|
112
|
+
|
|
113
|
+
let totalOriginal = 0;
|
|
114
|
+
let totalCompressed = 0;
|
|
115
|
+
|
|
116
|
+
entries.forEach((entry) => {
|
|
117
|
+
const filename = entry.filename || '(unnamed)';
|
|
118
|
+
const original = entry.uncompressedSize || 0;
|
|
119
|
+
const compressed = entry.compressedSize || 0;
|
|
120
|
+
const ratio = original > 0 ? ((1 - compressed / original) * 100).toFixed(1) : '0.0';
|
|
121
|
+
const method = entry.cmpMethodToString();
|
|
122
|
+
|
|
123
|
+
totalOriginal += original;
|
|
124
|
+
totalCompressed += compressed;
|
|
125
|
+
|
|
126
|
+
console.log(
|
|
127
|
+
padRight(filename.length > 28 ? filename.substring(0, 25) + '...' : filename, 30) +
|
|
128
|
+
padLeft(formatBytes(original), 10) +
|
|
129
|
+
padLeft(formatBytes(compressed), 12) +
|
|
130
|
+
padLeft(ratio + '%', 10) +
|
|
131
|
+
' ' +
|
|
132
|
+
padRight(method, 10)
|
|
133
|
+
);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
console.log('─'.repeat(80));
|
|
137
|
+
const totalRatio = totalOriginal > 0 ? ((1 - totalCompressed / totalOriginal) * 100).toFixed(1) : '0.0';
|
|
138
|
+
console.log(
|
|
139
|
+
padRight('Total', 30) +
|
|
140
|
+
padLeft(formatBytes(totalOriginal), 10) +
|
|
141
|
+
padLeft(formatBytes(totalCompressed), 12) +
|
|
142
|
+
padLeft(totalRatio + '%', 10) +
|
|
143
|
+
' ' +
|
|
144
|
+
padRight('', 10)
|
|
145
|
+
);
|
|
146
|
+
console.log('─'.repeat(80));
|
|
147
|
+
|
|
148
|
+
// Verify the ZIP was created
|
|
149
|
+
if (fs.existsSync(outputZip)) {
|
|
150
|
+
const zipStats = fs.statSync(outputZip);
|
|
151
|
+
console.log(`\nArchive file size: ${formatBytes(zipStats.size)}`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
console.log('\n💡 Tip: You can also use addFileToZip() for more control:');
|
|
155
|
+
console.log(' const zip = new ZipkitNode();');
|
|
156
|
+
console.log(' await zip.addFileToZip("file.txt", "file.txt", options);');
|
|
157
|
+
console.log(' // ... add more files ...');
|
|
158
|
+
console.log(' // Then manually write ZIP structure');
|
|
159
|
+
|
|
160
|
+
} catch (error) {
|
|
161
|
+
console.error('❌ Error creating ZIP archive:');
|
|
162
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Run the example
|
|
168
|
+
main().catch((error) => {
|
|
169
|
+
console.error('Fatal error:', error);
|
|
170
|
+
process.exit(1);
|
|
171
|
+
});
|
|
172
|
+
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Extract ZIP Example
|
|
5
|
+
*
|
|
6
|
+
* Demonstrates extracting files from a ZIP archive using ZipkitNode.
|
|
7
|
+
* This is a minimal example showing the basic extraction API.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import ZipkitNode from '../src/node';
|
|
11
|
+
import { crc32 } from '../src/core/encryption/ZipCrypto';
|
|
12
|
+
import * as fs from 'fs';
|
|
13
|
+
import * as path from 'path';
|
|
14
|
+
|
|
15
|
+
async function main() {
|
|
16
|
+
console.log('Extracting ZIP archive example...\n');
|
|
17
|
+
|
|
18
|
+
// Example: Use the ZIP file created by create-zip.ts
|
|
19
|
+
// You can also specify your own ZIP file path here
|
|
20
|
+
const archivePath = path.join(__dirname, 'output', 'example.zip');
|
|
21
|
+
const destination = path.join(__dirname, 'extracted');
|
|
22
|
+
|
|
23
|
+
// Check if ZIP file exists
|
|
24
|
+
if (!fs.existsSync(archivePath)) {
|
|
25
|
+
console.error(`❌ ZIP file not found: ${archivePath}`);
|
|
26
|
+
console.error('💡 Tip: Run create-zip.ts first to create a test ZIP file,');
|
|
27
|
+
console.error(' or modify archivePath to point to your own ZIP file.');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
console.log(`Archive: ${archivePath}`);
|
|
32
|
+
console.log(`Destination: ${destination}\n`);
|
|
33
|
+
|
|
34
|
+
// Create ZipkitNode instance
|
|
35
|
+
const zip = new ZipkitNode();
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
// Method 1: Simple API - extract entire ZIP to directory
|
|
39
|
+
// This is the easiest way to extract a ZIP file
|
|
40
|
+
console.log('Loading ZIP file...');
|
|
41
|
+
await zip.loadZipFile(archivePath);
|
|
42
|
+
|
|
43
|
+
// Get directory listing to show what will be extracted
|
|
44
|
+
const entries = zip.getDirectory();
|
|
45
|
+
console.log(`Found ${entries.length} file(s) in archive:\n`);
|
|
46
|
+
|
|
47
|
+
entries.forEach((entry, index) => {
|
|
48
|
+
const size = entry.uncompressedSize || 0;
|
|
49
|
+
const compressed = entry.compressedSize || 0;
|
|
50
|
+
const method = entry.cmpMethodToString();
|
|
51
|
+
console.log(` ${index + 1}. ${entry.filename}`);
|
|
52
|
+
console.log(` Size: ${size} bytes (compressed: ${compressed} bytes, ${method})`);
|
|
53
|
+
});
|
|
54
|
+
console.log();
|
|
55
|
+
|
|
56
|
+
// Extract all files to destination directory
|
|
57
|
+
console.log('Extracting files...');
|
|
58
|
+
const result = await zip.extractZipFile(archivePath, destination, {
|
|
59
|
+
overwrite: true, // Overwrite existing files
|
|
60
|
+
preserveTimestamps: true, // Preserve file timestamps
|
|
61
|
+
skipHashCheck: false // Verify file integrity (CRC/SHA checks)
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
console.log(`✅ Extraction completed successfully!`);
|
|
65
|
+
console.log(` Files extracted: ${result.filesExtracted}`);
|
|
66
|
+
console.log(` Total bytes: ${result.bytesExtracted}`);
|
|
67
|
+
|
|
68
|
+
// Verify CRC-32 for each extracted file
|
|
69
|
+
console.log('\nCRC-32 Verification:');
|
|
70
|
+
const extractedFiles = getAllFiles(destination);
|
|
71
|
+
let allCrcMatch = true;
|
|
72
|
+
|
|
73
|
+
// Create a map of filename to entry for quick lookup
|
|
74
|
+
const entryMap = new Map<string, typeof entries[0]>();
|
|
75
|
+
entries.forEach(entry => {
|
|
76
|
+
const filename = path.basename(entry.filename);
|
|
77
|
+
entryMap.set(filename, entry);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
extractedFiles.forEach(file => {
|
|
81
|
+
const relativePath = path.relative(destination, file);
|
|
82
|
+
const filename = path.basename(file);
|
|
83
|
+
const stats = fs.statSync(file);
|
|
84
|
+
const entry = entryMap.get(filename);
|
|
85
|
+
|
|
86
|
+
if (entry) {
|
|
87
|
+
const storedCrc = entry.crc || 0;
|
|
88
|
+
const storedCrcHex = `0x${storedCrc.toString(16).padStart(8, '0').toUpperCase()}`;
|
|
89
|
+
|
|
90
|
+
// Calculate CRC-32 of extracted file
|
|
91
|
+
const fileData = fs.readFileSync(file);
|
|
92
|
+
const calculatedCrc = crc32(fileData);
|
|
93
|
+
const calculatedCrcHex = `0x${calculatedCrc.toString(16).padStart(8, '0').toUpperCase()}`;
|
|
94
|
+
|
|
95
|
+
// Compare CRC-32 values
|
|
96
|
+
const crcMatch = storedCrc === calculatedCrc;
|
|
97
|
+
const status = crcMatch ? '✓' : '✗';
|
|
98
|
+
const statusText = crcMatch ? 'PASS' : 'FAILED';
|
|
99
|
+
|
|
100
|
+
if (!crcMatch) {
|
|
101
|
+
allCrcMatch = false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
console.log(` ${filename}:`);
|
|
105
|
+
console.log(` Stored CRC-32: ${storedCrcHex}`);
|
|
106
|
+
console.log(` Calculated CRC-32: ${calculatedCrcHex}`);
|
|
107
|
+
console.log(` Status: ${status} ${statusText}`);
|
|
108
|
+
} else {
|
|
109
|
+
console.log(` ${filename}: Entry not found in ZIP`);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
if (allCrcMatch) {
|
|
114
|
+
console.log('\n✅ All CRC-32 checks passed!');
|
|
115
|
+
} else {
|
|
116
|
+
console.log('\n❌ Some CRC-32 checks failed!');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
console.log('\n💡 Tip: You can also extract individual entries:');
|
|
120
|
+
console.log(' await zip.loadZipFile("archive.zip");');
|
|
121
|
+
console.log(' const entries = zip.getDirectory();');
|
|
122
|
+
console.log(' await zip.extractToFile(entries[0], "output.txt");');
|
|
123
|
+
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error('❌ Error extracting ZIP archive:');
|
|
126
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
127
|
+
if (error instanceof Error && error.stack) {
|
|
128
|
+
console.error('\nStack trace:');
|
|
129
|
+
console.error(error.stack);
|
|
130
|
+
}
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Helper function to recursively get all files in a directory
|
|
137
|
+
*/
|
|
138
|
+
function getAllFiles(dirPath: string, arrayOfFiles: string[] = []): string[] {
|
|
139
|
+
const files = fs.readdirSync(dirPath);
|
|
140
|
+
|
|
141
|
+
files.forEach((file) => {
|
|
142
|
+
const filePath = path.join(dirPath, file);
|
|
143
|
+
if (fs.statSync(filePath).isDirectory()) {
|
|
144
|
+
arrayOfFiles = getAllFiles(filePath, arrayOfFiles);
|
|
145
|
+
} else {
|
|
146
|
+
arrayOfFiles.push(filePath);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
return arrayOfFiles;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Run the example
|
|
154
|
+
main().catch((error) => {
|
|
155
|
+
console.error('Fatal error:', error);
|
|
156
|
+
process.exit(1);
|
|
157
|
+
});
|
|
158
|
+
|