neozipkit 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/README.md +400 -0
  2. package/contracts/Lock.sol +34 -0
  3. package/contracts/bytecode.txt +1 -0
  4. package/contracts/compile-contract.js +168 -0
  5. package/contracts/deploy/deploy-both-contracts.js +286 -0
  6. package/contracts/deploy/deploy-enhanced-contract.js +197 -0
  7. package/contracts/deploy/deploy-private-contract.js +190 -0
  8. package/contracts/deploy/deploy-public-clean.js +1063 -0
  9. package/contracts/deploy/deploy-public-contract.js +1107 -0
  10. package/contracts/deployment.config.example.js +25 -0
  11. package/contracts/remix-compile.js +222 -0
  12. package/contracts/setup-deployment.js +51 -0
  13. package/contracts/src/NZIP-NFT-Private.sol +350 -0
  14. package/contracts/src/NZIP-NFT.sol +265 -0
  15. package/contracts/src/ZipFileNFT-DEPRECATED-6field.sol +260 -0
  16. package/contracts/src/ZipFileNFT-DEPRECATED-Enhanced.sol +289 -0
  17. package/dist/browser/CertificateGeneratorBrowser.d.ts +75 -0
  18. package/dist/browser/CertificateGeneratorBrowser.js +433 -0
  19. package/dist/browser/TokenVerifierBrowser.d.ts +76 -0
  20. package/dist/browser/TokenVerifierBrowser.js +299 -0
  21. package/dist/browser/ZipKitBrowser.d.ts +18 -0
  22. package/dist/browser/ZipKitBrowser.js +250 -0
  23. package/dist/browser/ZipKitStampBrowser.d.ts +2 -0
  24. package/dist/browser/ZipKitStampBrowser.js +12 -0
  25. package/dist/browser-index.d.ts +21 -0
  26. package/dist/browser-index.js +58 -0
  27. package/dist/browser.d.ts +21 -0
  28. package/dist/browser.js +58 -0
  29. package/dist/index.d.ts +29 -0
  30. package/dist/index.js +76 -0
  31. package/dist/server/blockchain/CertificateToken.d.ts +48 -0
  32. package/dist/server/blockchain/CertificateToken.js +386 -0
  33. package/dist/server/blockchain/NFTMinter.d.ts +41 -0
  34. package/dist/server/blockchain/NFTMinter.js +323 -0
  35. package/dist/server/blockchain/TokenQuerier.d.ts +31 -0
  36. package/dist/server/blockchain/TokenQuerier.js +259 -0
  37. package/dist/server/blockchain/TokenVerifier.d.ts +20 -0
  38. package/dist/server/blockchain/TokenVerifier.js +395 -0
  39. package/dist/server/blockchain/WalletAnalyzer.d.ts +81 -0
  40. package/dist/server/blockchain/WalletAnalyzer.js +356 -0
  41. package/dist/server/blockchain/WalletFormatter.d.ts +39 -0
  42. package/dist/server/blockchain/WalletFormatter.js +196 -0
  43. package/dist/server/blockchain/WalletManager.d.ts +46 -0
  44. package/dist/server/blockchain/WalletManager.js +294 -0
  45. package/dist/server/blockchain/ZipMetadata.d.ts +27 -0
  46. package/dist/server/blockchain/ZipMetadata.js +131 -0
  47. package/dist/server/blockchain/ZipTokenProcessor.d.ts +44 -0
  48. package/dist/server/blockchain/ZipTokenProcessor.js +204 -0
  49. package/dist/server/blockchain/constants.d.ts +102 -0
  50. package/dist/server/blockchain/constants.js +968 -0
  51. package/dist/server/blockchain/index.d.ts +9 -0
  52. package/dist/server/blockchain/index.js +44 -0
  53. package/dist/server/blockchain/test-certificate.d.ts +8 -0
  54. package/dist/server/blockchain/test-certificate.js +100 -0
  55. package/dist/server/blockchain/types.d.ts +69 -0
  56. package/dist/server/blockchain/types.js +51 -0
  57. package/dist/server/platform/server/ZipKitServer.d.ts +105 -0
  58. package/dist/server/platform/server/ZipKitServer.js +437 -0
  59. package/dist/server/platform/servercomponents/ZipKitOTS.d.ts +91 -0
  60. package/dist/server/platform/servercomponents/ZipKitOTS.js +271 -0
  61. package/dist/shared/ZipEntry.d.ts +131 -0
  62. package/dist/shared/ZipEntry.js +686 -0
  63. package/dist/shared/ZipKit.d.ts +249 -0
  64. package/dist/shared/ZipKit.js +789 -0
  65. package/dist/shared/components/CertificateOTS.d.ts +15 -0
  66. package/dist/shared/components/CertificateOTS.js +116 -0
  67. package/dist/shared/components/FileSys.d.ts +2 -0
  68. package/dist/shared/components/FileSys.js +113 -0
  69. package/dist/shared/components/HashAccumulator.d.ts +55 -0
  70. package/dist/shared/components/HashAccumulator.js +100 -0
  71. package/dist/shared/components/Support.d.ts +63 -0
  72. package/dist/shared/components/Support.js +70 -0
  73. package/dist/shared/components/Util.d.ts +21 -0
  74. package/dist/shared/components/Util.js +115 -0
  75. package/dist/shared/components/ZipCrypto.d.ts +3 -0
  76. package/dist/shared/components/ZipCrypto.js +78 -0
  77. package/dist/shared/components/merkleTree.d.ts +66 -0
  78. package/dist/shared/components/merkleTree.js +136 -0
  79. package/dist/shared/constants/Errors.d.ts +53 -0
  80. package/dist/shared/constants/Errors.js +69 -0
  81. package/dist/shared/constants/Headers.d.ts +167 -0
  82. package/dist/shared/constants/Headers.js +191 -0
  83. package/dist/shared/types/index.d.ts +21 -0
  84. package/dist/shared/types/index.js +3 -0
  85. package/dist/shared/types.d.ts +33 -0
  86. package/dist/shared/types.js +8 -0
  87. package/dist/shared/version.d.ts +4 -0
  88. package/dist/shared/version.js +7 -0
  89. package/dist/types/index.d.ts +21 -0
  90. package/dist/types/index.js +3 -0
  91. package/examples/unzip-token.ts +488 -0
  92. package/examples/zip-token.ts +604 -0
  93. package/package.json +117 -0
  94. package/src/browser/CertificateGeneratorBrowser.ts +498 -0
  95. package/src/browser/TokenVerifierBrowser.ts +344 -0
  96. package/src/browser/ZipKitBrowser.ts +242 -0
  97. package/src/browser/ZipKitStampBrowser.ts +9 -0
  98. package/src/browser-index.ts +36 -0
  99. package/src/index.ts +48 -0
  100. package/src/server/blockchain/CertificateToken.ts +444 -0
  101. package/src/server/blockchain/NFTMinter.ts +357 -0
  102. package/src/server/blockchain/TokenQuerier.ts +287 -0
  103. package/src/server/blockchain/TokenVerifier.ts +453 -0
  104. package/src/server/blockchain/WalletAnalyzer.ts +397 -0
  105. package/src/server/blockchain/WalletFormatter.ts +206 -0
  106. package/src/server/blockchain/WalletManager.ts +294 -0
  107. package/src/server/blockchain/ZipMetadata.ts +117 -0
  108. package/src/server/blockchain/ZipTokenProcessor.ts +234 -0
  109. package/src/server/blockchain/constants.ts +969 -0
  110. package/src/server/blockchain/index.ts +42 -0
  111. package/src/server/blockchain/test-certificate.ts +137 -0
  112. package/src/server/blockchain/types.ts +134 -0
  113. package/src/server/platform/server/ZipKitServer.ts +459 -0
  114. package/src/server/platform/servercomponents/ZipKitOTS.ts +313 -0
  115. package/src/server/platform/servercomponents/opentimestamps.d.ts +23 -0
  116. package/src/shared/ZipEntry.ts +767 -0
  117. package/src/shared/ZipKit.ts +899 -0
  118. package/src/shared/components/CertificateOTS.ts +132 -0
  119. package/src/shared/components/FileSys.ts +87 -0
  120. package/src/shared/components/HashAccumulator.ts +113 -0
  121. package/src/shared/components/Support.ts +77 -0
  122. package/src/shared/components/Util.ts +113 -0
  123. package/src/shared/components/ZipCrypto.ts +91 -0
  124. package/src/shared/components/merkleTree.ts +162 -0
  125. package/src/shared/constants/Errors.ts +82 -0
  126. package/src/shared/constants/Headers.ts +203 -0
  127. package/src/shared/types/index.ts +25 -0
  128. package/src/shared/types/modules.d.ts +22 -0
  129. package/src/shared/types/opentimestamps.d.ts +23 -0
  130. package/src/shared/types.d.ts +8 -0
  131. package/src/shared/types.ts +43 -0
  132. package/src/shared/version.ts +4 -0
  133. package/src/types/index.ts +25 -0
  134. package/src/types/modules.d.ts +22 -0
  135. package/src/types/opentimestamps.d.ts +23 -0
@@ -0,0 +1,344 @@
1
+ // ======================================
2
+ // TokenVerifierBrowser.ts
3
+ // Browser-compatible blockchain token verification utilities for ZIP archives
4
+ // Copyright (c) 2025 NeoWare, Inc. All rights reserved.
5
+ // ======================================
6
+
7
+ import ZipKitBrowser from './ZipKitBrowser';
8
+ import { ZipEntry } from '../shared/ZipKit';
9
+ import { TOKENIZED_METADATA } from '../shared/constants/Headers';
10
+ import { NZIP_CONTRACT_ABI, CURRENT_DEPLOYMENT } from '../server/blockchain/constants';
11
+
12
+ // Token types (adapted for browser)
13
+ export interface NZipTokenInfo {
14
+ version: string;
15
+ tokenId: string;
16
+ contractAddress: string;
17
+ network: string;
18
+ networkChainId: number;
19
+ transactionHash: string;
20
+ merkleRoot: string;
21
+ fileName: string;
22
+ mintedAt: string;
23
+ }
24
+
25
+ export interface TokenVerificationOptions {
26
+ skipHash?: boolean;
27
+ skipToken?: boolean;
28
+ generateCertificate?: boolean;
29
+ zipFileName?: string;
30
+ }
31
+
32
+ export interface TokenVerificationResult {
33
+ isTokenized: boolean;
34
+ tokenMetadata: NZipTokenInfo | null;
35
+ calculatedMerkleRoot: string | null;
36
+ blockchainMerkleRoot: string | null;
37
+ blockchainTimestamp?: number; // Actual blockchain timestamp from tokenizationTime
38
+ verificationPassed: boolean;
39
+ certificatePath?: string;
40
+ errorMessage?: string;
41
+ }
42
+
43
+ export interface BlockchainVerification {
44
+ merkleRootMatches: boolean;
45
+ blockchainMerkleRoot: string;
46
+ calculatedMerkleRoot: string;
47
+ verificationStatus: 'PASSED' | 'FAILED' | 'UNAVAILABLE';
48
+ verificationTime?: number;
49
+ blockNumber?: number;
50
+ }
51
+
52
+ // Network configuration for blockchain queries
53
+ const NETWORK_CONFIG: Record<string, any> = {
54
+ 'Base Sepolia': {
55
+ chainId: 84532,
56
+ rpcUrls: [
57
+ 'https://sepolia.base.org',
58
+ 'https://base-sepolia.g.alchemy.com/v2/demo',
59
+ 'https://base-sepolia-rpc.publicnode.com',
60
+ 'https://base-sepolia.blockpi.network/v1/rpc/public'
61
+ ]
62
+ },
63
+ 'Base Mainnet': {
64
+ chainId: 8453,
65
+ rpcUrls: [
66
+ 'https://mainnet.base.org',
67
+ 'https://base-mainnet.g.alchemy.com/v2/demo',
68
+ 'https://base-rpc.publicnode.com',
69
+ 'https://base.blockpi.network/v1/rpc/public'
70
+ ]
71
+ }
72
+ };
73
+
74
+ // Use the complete contract ABI from constants
75
+ const CONTRACT_ABI = NZIP_CONTRACT_ABI;
76
+
77
+ /**
78
+ * Browser-compatible token verification class
79
+ */
80
+ export class TokenVerifierBrowser {
81
+ private zipKit: ZipKitBrowser;
82
+
83
+ constructor(zipKit: ZipKitBrowser) {
84
+ this.zipKit = zipKit;
85
+ }
86
+
87
+ /**
88
+ * Checks if the ZIP file contains NFT token metadata and verifies the merkle root
89
+ */
90
+ async checkForTokenization(
91
+ zipEntries: ZipEntry[],
92
+ options: TokenVerificationOptions = {}
93
+ ): Promise<TokenVerificationResult> {
94
+ // Look for the tokenized metadata file
95
+ const tokenEntry = zipEntries.find(entry => entry.filename === TOKENIZED_METADATA);
96
+
97
+ if (!tokenEntry) {
98
+ return {
99
+ isTokenized: false,
100
+ tokenMetadata: null,
101
+ calculatedMerkleRoot: null,
102
+ blockchainMerkleRoot: null,
103
+ verificationPassed: false
104
+ };
105
+ }
106
+
107
+ try {
108
+ // Extract the token metadata
109
+ const tokenData = await this.zipKit.extractBlob(tokenEntry);
110
+
111
+ if (!tokenData) {
112
+ return {
113
+ isTokenized: false,
114
+ tokenMetadata: null,
115
+ calculatedMerkleRoot: null,
116
+ blockchainMerkleRoot: null,
117
+ verificationPassed: false,
118
+ errorMessage: 'Could not read token metadata'
119
+ };
120
+ }
121
+
122
+ const tokenContent = await this.blobToString(tokenData);
123
+ const tokenMetadata = JSON.parse(tokenContent);
124
+
125
+ // Validate token metadata structure
126
+ if (!this.validateTokenInfo(tokenMetadata)) {
127
+ return {
128
+ isTokenized: false,
129
+ tokenMetadata: null,
130
+ calculatedMerkleRoot: null,
131
+ blockchainMerkleRoot: null,
132
+ verificationPassed: false,
133
+ errorMessage: 'Invalid token metadata structure'
134
+ };
135
+ }
136
+
137
+ // Skip verification if requested
138
+ if (options.skipHash || options.skipToken) {
139
+ return {
140
+ isTokenized: true,
141
+ tokenMetadata,
142
+ calculatedMerkleRoot: null,
143
+ blockchainMerkleRoot: null,
144
+ verificationPassed: false,
145
+ errorMessage: options.skipHash ? 'Hash verification skipped' : 'Token verification skipped'
146
+ };
147
+ }
148
+
149
+ // Calculate merkle root excluding token file
150
+ const calculatedMerkleRoot = await this.calculateMerkleRootExcludingToken(zipEntries);
151
+
152
+ if (!calculatedMerkleRoot) {
153
+ return {
154
+ isTokenized: true,
155
+ tokenMetadata,
156
+ calculatedMerkleRoot: null,
157
+ blockchainMerkleRoot: null,
158
+ verificationPassed: false,
159
+ errorMessage: 'Could not calculate merkle root'
160
+ };
161
+ }
162
+
163
+ // Query blockchain for the actual merkle root and timestamp
164
+ const blockchainData = await this.queryBlockchainData(tokenMetadata);
165
+
166
+ if (!blockchainData.merkleRoot) {
167
+ return {
168
+ isTokenized: true,
169
+ tokenMetadata,
170
+ calculatedMerkleRoot,
171
+ blockchainMerkleRoot: null,
172
+ blockchainTimestamp: blockchainData.timestamp ?? undefined,
173
+ verificationPassed: false,
174
+ errorMessage: 'Could not retrieve merkle root from blockchain'
175
+ };
176
+ }
177
+
178
+ const verificationPassed = blockchainData.merkleRoot === calculatedMerkleRoot;
179
+
180
+ return {
181
+ isTokenized: true,
182
+ tokenMetadata,
183
+ calculatedMerkleRoot,
184
+ blockchainMerkleRoot: blockchainData.merkleRoot,
185
+ blockchainTimestamp: blockchainData.timestamp ?? undefined,
186
+ verificationPassed,
187
+ errorMessage: verificationPassed ? undefined : 'Merkle root mismatch - archive may be tampered'
188
+ };
189
+
190
+ } catch (error) {
191
+ return {
192
+ isTokenized: false,
193
+ tokenMetadata: null,
194
+ calculatedMerkleRoot: null,
195
+ blockchainMerkleRoot: null,
196
+ verificationPassed: false,
197
+ errorMessage: `Error processing token: ${error instanceof Error ? error.message : String(error)}`
198
+ };
199
+ }
200
+ }
201
+
202
+ /**
203
+ * Validates token metadata structure
204
+ */
205
+ private validateTokenInfo(tokenMetadata: any): tokenMetadata is NZipTokenInfo {
206
+ return tokenMetadata &&
207
+ typeof tokenMetadata.version === 'string' &&
208
+ typeof tokenMetadata.tokenId === 'string' &&
209
+ typeof tokenMetadata.contractAddress === 'string' &&
210
+ typeof tokenMetadata.network === 'string' &&
211
+ typeof tokenMetadata.networkChainId === 'number' &&
212
+ typeof tokenMetadata.transactionHash === 'string' &&
213
+ typeof tokenMetadata.merkleRoot === 'string' &&
214
+ typeof tokenMetadata.fileName === 'string' &&
215
+ typeof tokenMetadata.mintedAt === 'string';
216
+ }
217
+
218
+ /**
219
+ * Calculates the merkle root excluding the token metadata file
220
+ */
221
+ private async calculateMerkleRootExcludingToken(zipEntries: ZipEntry[]): Promise<string | null> {
222
+ try {
223
+ // Get all entries except the token file
224
+ const contentEntries = zipEntries.filter(entry => entry.filename !== TOKENIZED_METADATA);
225
+
226
+ if (contentEntries.length === 0) {
227
+ return null;
228
+ }
229
+
230
+ // For each content entry, ensure we have SHA-256 hash calculated
231
+ for (const entry of contentEntries) {
232
+ if (!entry.sha256) {
233
+ // Extract the file to calculate its SHA-256 hash
234
+ await this.zipKit.extractBlob(entry);
235
+ }
236
+ }
237
+
238
+ // Calculate merkle root from content files
239
+ // This would need to be implemented based on the ZipKit's merkle tree functionality
240
+ // For now, we'll use a placeholder that would need to be implemented
241
+ return await this.zipKit.getMerkleRoot?.() || null;
242
+ } catch (error) {
243
+ console.error('Error calculating merkle root:', error);
244
+ return null;
245
+ }
246
+ }
247
+
248
+ /**
249
+ * Queries the blockchain to get the actual merkle root and timestamp stored in the smart contract
250
+ */
251
+ private async queryBlockchainData(tokenMetadata: NZipTokenInfo): Promise<{merkleRoot: string | null, timestamp: number | null}> {
252
+ try {
253
+ // Dynamic import of ethers to avoid SSR issues
254
+ const { ethers } = await import('ethers');
255
+
256
+ const networkConfig = NETWORK_CONFIG[tokenMetadata.network];
257
+ if (!networkConfig) {
258
+ console.warn(`Unsupported network: ${tokenMetadata.network}`);
259
+ return { merkleRoot: null, timestamp: null };
260
+ }
261
+
262
+ // Try multiple RPC endpoints
263
+ for (const rpcUrl of networkConfig.rpcUrls) {
264
+ try {
265
+ const provider = new ethers.JsonRpcProvider(rpcUrl);
266
+
267
+ // Test connection with a timeout
268
+ const blockNumber = await Promise.race([
269
+ provider.getBlockNumber(),
270
+ new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), 5000))
271
+ ]);
272
+
273
+ // Create contract instance
274
+ const contract = new ethers.Contract(tokenMetadata.contractAddress, CONTRACT_ABI, provider);
275
+
276
+ // Call getZipFileInfo to get the blockchain-stored data
277
+ const zipInfo = await contract.getZipFileInfo(tokenMetadata.tokenId);
278
+
279
+ return {
280
+ merkleRoot: zipInfo.merkleRootHash,
281
+ timestamp: Number(zipInfo.tokenizationTime)
282
+ };
283
+
284
+ } catch (error) {
285
+ console.warn(`RPC ${rpcUrl} failed:`, error);
286
+ continue;
287
+ }
288
+ }
289
+
290
+ console.warn(`All RPC endpoints failed for network: ${tokenMetadata.network}`);
291
+ return { merkleRoot: null, timestamp: null };
292
+
293
+ } catch (error) {
294
+ console.error('Blockchain query error:', error);
295
+ return { merkleRoot: null, timestamp: null };
296
+ }
297
+ }
298
+
299
+ /**
300
+ * Helper to convert Blob to string
301
+ */
302
+ private async blobToString(blob: Blob): Promise<string> {
303
+ return new Promise((resolve, reject) => {
304
+ const reader = new FileReader();
305
+ reader.onload = () => resolve(reader.result as string);
306
+ reader.onerror = reject;
307
+ reader.readAsText(blob);
308
+ });
309
+ }
310
+
311
+ /**
312
+ * Creates a formatted summary of token information
313
+ */
314
+ createTokenSummary(tokenMetadata: NZipTokenInfo): string {
315
+ return `
316
+ 🎫 NFT Token Information:
317
+ Token ID: ${tokenMetadata.tokenId}
318
+ Network: ${tokenMetadata.network}
319
+ Contract: ${tokenMetadata.contractAddress}
320
+ Transaction: ${tokenMetadata.transactionHash}
321
+ File: ${tokenMetadata.fileName}
322
+ Minted: ${new Date(tokenMetadata.mintedAt).toLocaleString()}
323
+ `;
324
+ }
325
+ }
326
+
327
+ /**
328
+ * Creates a new TokenVerifierBrowser instance
329
+ */
330
+ export function createTokenVerifier(zipKit: ZipKitBrowser): TokenVerifierBrowser {
331
+ return new TokenVerifierBrowser(zipKit);
332
+ }
333
+
334
+ /**
335
+ * Convenience function to check for tokenization
336
+ */
337
+ export async function checkForTokenization(
338
+ zipKit: ZipKitBrowser,
339
+ zipEntries: ZipEntry[],
340
+ options: TokenVerificationOptions = {}
341
+ ): Promise<TokenVerificationResult> {
342
+ const verifier = new TokenVerifierBrowser(zipKit);
343
+ return verifier.checkForTokenization(zipEntries, options);
344
+ }
@@ -0,0 +1,242 @@
1
+ // ======================================
2
+ // ZipKitBrowser.ts
3
+ // Copyright (c) 2025 NeoWare, Inc. All rights reserved.
4
+ // ======================================
5
+
6
+ import ZipKit, { CompressOptions, CreateZipOptions } from '../shared/ZipKit';
7
+ import ZipEntry from '../shared/ZipEntry';
8
+ import Errors from '../shared/constants/Errors';
9
+ import * as Headers from '../shared/constants/Headers';
10
+ import { TOKENIZED_METADATA, TIMESTAMP_SUBMITTED, TIMESTAMP_METADATA } from '../shared/constants/Headers';
11
+ import { sha256 } from '../shared/components/ZipCrypto';
12
+ import { crc32 } from '../shared/components/Util';
13
+ import { DATATYPE, getTypeOf } from '../shared/components/Util';
14
+ import type { FileData } from '../shared/types';
15
+
16
+ // Re-export everything from ZipKit
17
+ export * from '../shared/ZipKit';
18
+ export { ZipEntry, Errors, Headers, sha256, getTypeOf };
19
+
20
+ // ======================================
21
+ // ZipKitBrowser
22
+ // ======================================
23
+
24
+ export default class ZipKitBrowser extends ZipKit {
25
+ constructor() {
26
+ super(); // Call the parent constructor
27
+
28
+ // console.log('ZipKit.support.isNode: ', ZipKit.support.isNode);
29
+ // console.log('ZipKit.support.buffer: ', ZipKit.support.buffer);
30
+ // console.log('ZipKit.support.blob: ', ZipKit.support.blob);
31
+ // console.log('ZipKit.support.streams: ', ZipKit.support.streams);
32
+ // console.log('ZipKit.support.fileReader: ', ZipKit.support.fileReader);
33
+ }
34
+
35
+ // --------------------------------------
36
+ // Load a ZIP file from a Blob and return the ZipEntry array
37
+
38
+ async loadZipBlob(data: Blob): Promise<ZipEntry[] | null> {
39
+ if (getTypeOf(data) !== DATATYPE.BLOB) {
40
+ throw new Error(Errors.DATATYPE_UNSUPPORTED);
41
+ }
42
+
43
+ return new Promise((resolve, reject) => {
44
+ const _readEntries = (data: Buffer): ZipEntry[] | null => {
45
+ try {
46
+ super.loadZip(data);
47
+ return super.getDirectory();
48
+ } catch (error) {
49
+ reject(error);
50
+ return null;
51
+ }
52
+ };
53
+
54
+ const reader = new window.FileReader();
55
+ reader.readAsArrayBuffer(data);
56
+
57
+ reader.onload = function(this: FileReader, e: ProgressEvent<FileReader>) {
58
+ if (!this.result) {
59
+ reject(new Error('Failed to read file'));
60
+ return;
61
+ }
62
+ const _inBuf = Buffer.from(this.result as ArrayBuffer);
63
+ resolve(_readEntries(_inBuf));
64
+ };
65
+
66
+ reader.onerror = function(this: FileReader, e: ProgressEvent<FileReader>) {
67
+ reject(this.error || new Error('Failed to read file'));
68
+ };
69
+ });
70
+ }
71
+
72
+ // --------------------------------------
73
+ // Create a ZipEntry for a File object
74
+
75
+ createZipFileEntry(file: FileData): ZipEntry {
76
+ const entry = super.createZipEntry(file.name);
77
+ entry.fileData = file;
78
+ entry.uncompressedSize = file.size;
79
+
80
+ const fileDate = new Date(file.lastModified);
81
+ entry.timeDateDOS = entry.setDateTime(fileDate);
82
+ entry.cmpMethod = Headers.CMP_METHOD.DEFLATED;
83
+
84
+ return entry;
85
+ }
86
+
87
+ // --------------------------------------
88
+ // Calculate the SHA256 hash of a File object
89
+
90
+ async hashFile(file: FileData): Promise<string> {
91
+ const arrayBuffer = await file.arrayBuffer();
92
+ const buffer = Buffer.from(arrayBuffer);
93
+ return sha256(buffer);
94
+ }
95
+
96
+ // --------------------------------------
97
+ // Compress the data and return the compressed data buffer
98
+ // Set the ZipEntry compressSize and CRC32 values
99
+
100
+ async compressDataBlob(entry: ZipEntry, data: Blob, options?: CompressOptions): Promise<Buffer> {
101
+ if (getTypeOf(data) !== DATATYPE.BLOB) {
102
+ throw new Error(Errors.DATATYPE_UNSUPPORTED);
103
+ }
104
+
105
+ return new Promise(async (resolve, reject) => {
106
+ const _compressData = async (entry: ZipEntry, data: Buffer, options?: CompressOptions): Promise<Buffer> => {
107
+ return await super.compressData(entry, data, options);
108
+ };
109
+
110
+ const reader = new window.FileReader();
111
+ reader.readAsArrayBuffer(data);
112
+
113
+ reader.onload = async function(this: FileReader, e: ProgressEvent<FileReader>) {
114
+ if (!this.result) {
115
+ reject(new Error('Failed to read file'));
116
+ return;
117
+ }
118
+ try {
119
+ const _inBuf = Buffer.from(this.result as ArrayBuffer);
120
+ const result = await _compressData(entry, _inBuf, options);
121
+ resolve(result);
122
+ } catch (error) {
123
+ reject(error);
124
+ }
125
+ };
126
+
127
+ reader.onerror = function(this: FileReader, e: ProgressEvent<FileReader>) {
128
+ reject(this.error || new Error('Failed to read file'));
129
+ };
130
+ });
131
+ }
132
+
133
+ // --------------------------------------
134
+ // Extract a Blob from a ZipEntry
135
+
136
+ async extractBlob(entry: ZipEntry, skipHashCheck?: boolean): Promise<Blob | null> {
137
+ try {
138
+ const _outBuf = await super.extract(entry, skipHashCheck);
139
+ if (!_outBuf) return null;
140
+
141
+ // Convert Buffer to Uint8Array for Blob compatibility
142
+ const uint8Array = new Uint8Array(_outBuf);
143
+ return new Blob([uint8Array], { type: 'application/octet-stream' });
144
+ } catch (error) {
145
+ throw error;
146
+ }
147
+ }
148
+
149
+ // --------------------------------------
150
+ // Create a ZIP file in memory and return a Blob
151
+
152
+ async createZipBlob(cmpOptions?: CompressOptions, options?: CreateZipOptions): Promise<Blob | null> {
153
+ const _onError = options?.onError || (() => {});
154
+ const _onEntryDone = options?.onEntryDone || (() => {});
155
+
156
+ const zipEntries = super.getDirectory();
157
+ if (!zipEntries) {
158
+ _onError(new Error(Errors.NO_FILES));
159
+ return null;
160
+ }
161
+
162
+ let offset = 0;
163
+ const buffers: Buffer[] = [];
164
+
165
+ for (const entry of zipEntries) {
166
+ if (!entry.isUpdated) {
167
+ // CRITICAL FIX: Check for token files even in copy mode
168
+ if (entry.filename === TOKENIZED_METADATA || entry.filename === TIMESTAMP_SUBMITTED || entry.filename === TIMESTAMP_METADATA) {
169
+ // Force this entry to be processed with special handling instead of copied
170
+ entry.isUpdated = true;
171
+ // Don't continue here - let it fall through to special handling below
172
+ } else {
173
+ const inData = super.copyEntry(entry);
174
+ entry.localHdrOffset = offset;
175
+ offset += inData.length;
176
+ buffers.push(inData);
177
+ _onEntryDone(entry, 'Copied');
178
+ continue;
179
+ }
180
+ }
181
+
182
+ if (!entry.fileData) {
183
+ _onError(new Error(Errors.FILE_NOT_FOUND));
184
+ return null;
185
+ }
186
+
187
+ const fileBuffer = await entry.fileData.arrayBuffer();
188
+
189
+ // Special handling for token metadata files - store uncompressed with CRC-32
190
+ if (entry.filename === TOKENIZED_METADATA || entry.filename === TIMESTAMP_SUBMITTED || entry.filename === TIMESTAMP_METADATA) {
191
+ // For token metadata, use STORED compression (no compression)
192
+ const buffer = Buffer.from(fileBuffer);
193
+
194
+ // Calculate CRC-32 for the token file (not SHA-256 to avoid Merkle Root interference)
195
+ entry.crc = crc32(buffer);
196
+
197
+ // Set up entry for STORED compression
198
+ entry.cmpMethod = 0; // STORED
199
+ entry.compressedSize = buffer.length;
200
+ entry.uncompressedSize = buffer.length;
201
+
202
+ // Do NOT set SHA-256 hash for token metadata to avoid Merkle Root calculation
203
+ // entry.sha256 should remain undefined for metadata files
204
+
205
+ const localHdr = entry.createLocalHdr();
206
+ entry.localHdrOffset = offset;
207
+ offset += localHdr.length + buffer.length;
208
+
209
+ buffers.push(localHdr);
210
+ buffers.push(buffer);
211
+ _onEntryDone(entry, 'Stored (metadata)');
212
+ } else {
213
+ // Normal file processing with compression
214
+ const cmpData = await super.compressData(entry, Buffer.from(fileBuffer), cmpOptions);
215
+ const localHdr = entry.createLocalHdr();
216
+
217
+ entry.localHdrOffset = offset;
218
+ offset += localHdr.length + cmpData.length;
219
+
220
+ buffers.push(localHdr);
221
+ buffers.push(cmpData);
222
+ _onEntryDone(entry, 'Written');
223
+ }
224
+ }
225
+
226
+ const centralDirOffset = offset;
227
+ for (const entry of zipEntries) {
228
+ const centralDirEntry = entry.centralDirEntry();
229
+ offset += centralDirEntry.length;
230
+ buffers.push(centralDirEntry);
231
+ }
232
+
233
+ const centralDirSize = offset - centralDirOffset;
234
+ const ceBuf = super.centralEndHdr(centralDirSize, centralDirOffset);
235
+ buffers.push(ceBuf);
236
+
237
+ const combinedBuffer = Buffer.concat(buffers);
238
+ // Convert Buffer to Uint8Array for Blob compatibility
239
+ const uint8Array = new Uint8Array(combinedBuffer);
240
+ return new Blob([uint8Array], { type: 'application/zip' });
241
+ }
242
+ }
@@ -0,0 +1,9 @@
1
+ // A browser-safe version of ZipKitStamp
2
+
3
+ export const createTimestamp = async (hash: string, options: any = {}): Promise<any> => {
4
+ throw new Error('Blockchain timestamp creation is not supported in browsers');
5
+ };
6
+
7
+ export const verifyTimestamp = async (timestamp: any, options: any = {}): Promise<any> => {
8
+ throw new Error('Blockchain timestamp verification is not supported in browsers');
9
+ };
@@ -0,0 +1,36 @@
1
+ // =============================================================================
2
+ // NeoZipKit - Browser-Only Package Exports
3
+ // =============================================================================
4
+
5
+ // Core shared exports
6
+ import ZipKit from './shared/ZipKit';
7
+ export { ZipEntry, Errors, CMP_METHOD, TIMESTAMP_METADATA, TIMESTAMP_SUBMITTED } from './shared/ZipKit';
8
+ export type { CompressOptions } from './shared/ZipKit';
9
+ export * from './shared/ZipKit';
10
+ export * from './shared/ZipEntry';
11
+ export default ZipKit;
12
+
13
+ // Browser-only exports
14
+ export { default as ZipKitBrowser } from './browser/ZipKitBrowser';
15
+ export { CertificateGeneratorBrowser } from './browser/CertificateGeneratorBrowser';
16
+ export { TokenVerificationResult, checkForTokenization as checkForTokenizationBrowser, NZipTokenInfo } from './browser/TokenVerifierBrowser';
17
+ export type { TokenVerificationOptions } from './browser/TokenVerifierBrowser';
18
+
19
+ // Shared component exports
20
+ export { default as HashAccumulator } from './shared/components/HashAccumulator';
21
+ export * from './shared/components/Util';
22
+ export * from './shared/components/Support';
23
+
24
+ // Type and constant exports
25
+ export * from './shared/types';
26
+ export * from './shared/constants/Headers';
27
+ export * from './shared/constants/Errors';
28
+ export * from './shared/version';
29
+
30
+ // Platform-specific conditional exports
31
+ export const PlatformUtils = {
32
+ // Browser detection
33
+ isBrowser: typeof window !== 'undefined' && typeof document !== 'undefined',
34
+ // Node.js detection
35
+ isNode: typeof process !== 'undefined' && process.versions && process.versions.node,
36
+ };
package/src/index.ts ADDED
@@ -0,0 +1,48 @@
1
+ // =============================================================================
2
+ // NeoZipKit - Unified Package Exports
3
+ // =============================================================================
4
+
5
+ // Core shared exports
6
+ import ZipKit from './shared/ZipKit';
7
+ export { ZipEntry, Errors, CMP_METHOD, TIMESTAMP_METADATA, TIMESTAMP_SUBMITTED } from './shared/ZipKit';
8
+ export type { CompressOptions } from './shared/ZipKit';
9
+ export * from './shared/ZipKit';
10
+ export * from './shared/ZipEntry';
11
+ export default ZipKit;
12
+
13
+ // Browser-only exports
14
+ export { default as ZipKitBrowser } from './browser/ZipKitBrowser';
15
+ export { CertificateGeneratorBrowser } from './browser/CertificateGeneratorBrowser';
16
+ export { TokenVerificationResult, checkForTokenization as checkForTokenizationBrowser, NZipTokenInfo } from './browser/TokenVerifierBrowser';
17
+ export type { TokenVerificationOptions } from './browser/TokenVerifierBrowser';
18
+
19
+ // Server-only exports (now included in main build)
20
+ export { default as ZipKitServer } from './server/platform/server/ZipKitServer';
21
+ export { verifyTimestamp, createTimestamp } from './server/platform/servercomponents/ZipKitOTS';
22
+
23
+ // Blockchain exports
24
+ export * from './server/blockchain';
25
+ export { checkForTokenization as checkForTokenizationServer } from './server/blockchain/TokenVerifier';
26
+ export { NFTMinter } from './server/blockchain/NFTMinter';
27
+ export { WalletAnalyzer } from './server/blockchain/WalletAnalyzer';
28
+ export { WalletManager } from './server/blockchain/WalletManager';
29
+ export { ZipTokenProcessor } from './server/blockchain/ZipTokenProcessor';
30
+
31
+ // Shared component exports
32
+ export { default as HashAccumulator } from './shared/components/HashAccumulator';
33
+ export * from './shared/components/Util';
34
+ export * from './shared/components/Support';
35
+
36
+ // Type and constant exports
37
+ export * from './shared/types';
38
+ export * from './shared/constants/Headers';
39
+ export * from './shared/constants/Errors';
40
+ export * from './shared/version';
41
+
42
+ // Platform-specific conditional exports
43
+ export const PlatformUtils = {
44
+ // Browser detection
45
+ isBrowser: typeof window !== 'undefined' && typeof document !== 'undefined',
46
+ // Node.js detection
47
+ isNode: typeof process !== 'undefined' && process.versions && process.versions.node,
48
+ };