@push.rocks/smartarchive 5.0.0 → 5.1.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.
Files changed (61) hide show
  1. package/dist_ts/00_commitinfo_data.js +2 -2
  2. package/dist_ts/classes.archiveanalyzer.d.ts +1 -1
  3. package/dist_ts/classes.archiveanalyzer.js +34 -4
  4. package/dist_ts/classes.smartarchive.d.ts +151 -54
  5. package/dist_ts/classes.smartarchive.js +484 -234
  6. package/dist_ts/classes.tartools.d.ts +9 -33
  7. package/dist_ts/classes.tartools.js +18 -153
  8. package/dist_ts/index.d.ts +2 -6
  9. package/dist_ts/index.js +7 -11
  10. package/dist_ts/paths.js +1 -1
  11. package/dist_ts/plugins.d.ts +2 -9
  12. package/dist_ts/plugins.js +6 -13
  13. package/npmextra.json +13 -7
  14. package/package.json +23 -14
  15. package/readme.hints.md +69 -23
  16. package/readme.md +360 -274
  17. package/ts/00_commitinfo_data.ts +1 -1
  18. package/ts/classes.archiveanalyzer.ts +33 -5
  19. package/ts/classes.smartarchive.ts +546 -256
  20. package/ts/classes.tartools.ts +20 -177
  21. package/ts/index.ts +7 -11
  22. package/ts/plugins.ts +5 -17
  23. package/{ts → ts_shared}/bzip2/bititerator.ts +1 -1
  24. package/{ts → ts_shared}/bzip2/bzip2.ts +2 -2
  25. package/{ts → ts_shared}/bzip2/index.ts +6 -6
  26. package/ts_shared/classes.bzip2tools.ts +14 -0
  27. package/ts_shared/classes.gziptools.ts +42 -0
  28. package/ts_shared/classes.tartools.ts +89 -0
  29. package/ts_shared/classes.ziptools.ts +107 -0
  30. package/ts_shared/index.ts +17 -0
  31. package/{ts → ts_shared}/interfaces.ts +23 -7
  32. package/ts_shared/plugins.ts +22 -0
  33. package/ts_web/00_commitinfo_data.ts +8 -0
  34. package/ts_web/index.ts +4 -0
  35. package/ts_web/plugins.ts +3 -0
  36. package/dist_ts/bzip2/bititerator.d.ts +0 -6
  37. package/dist_ts/bzip2/bititerator.js +0 -50
  38. package/dist_ts/bzip2/bzip2.d.ts +0 -29
  39. package/dist_ts/bzip2/bzip2.js +0 -398
  40. package/dist_ts/bzip2/index.d.ts +0 -5
  41. package/dist_ts/bzip2/index.js +0 -92
  42. package/dist_ts/classes.bzip2tools.d.ts +0 -7
  43. package/dist_ts/classes.bzip2tools.js +0 -11
  44. package/dist_ts/classes.gziptools.d.ts +0 -49
  45. package/dist_ts/classes.gziptools.js +0 -125
  46. package/dist_ts/classes.ziptools.d.ts +0 -56
  47. package/dist_ts/classes.ziptools.js +0 -185
  48. package/dist_ts/errors.d.ts +0 -44
  49. package/dist_ts/errors.js +0 -62
  50. package/dist_ts/interfaces.d.ts +0 -115
  51. package/dist_ts/interfaces.js +0 -2
  52. package/dist_ts/smartarchive.classes.smartarchive.d.ts +0 -34
  53. package/dist_ts/smartarchive.classes.smartarchive.js +0 -116
  54. package/dist_ts/smartarchive.paths.d.ts +0 -2
  55. package/dist_ts/smartarchive.paths.js +0 -4
  56. package/dist_ts/smartarchive.plugins.d.ts +0 -14
  57. package/dist_ts/smartarchive.plugins.js +0 -19
  58. package/ts/classes.bzip2tools.ts +0 -16
  59. package/ts/classes.gziptools.ts +0 -143
  60. package/ts/classes.ziptools.ts +0 -209
  61. /package/{ts → ts_shared}/errors.ts +0 -0
@@ -1,208 +1,51 @@
1
1
  import * as plugins from './plugins.js';
2
- import type { IArchiveEntry, TCompressionLevel } from './interfaces.js';
3
- import { GzipTools } from './classes.gziptools.js';
2
+ import type { IArchiveEntry, TCompressionLevel } from '../ts_shared/interfaces.js';
3
+ import { TarTools as SharedTarTools } from '../ts_shared/classes.tartools.js';
4
+ import { GzipTools } from '../ts_shared/classes.gziptools.js';
4
5
 
5
6
  /**
6
- * TAR archive creation and extraction utilities
7
+ * Extended TAR archive utilities with Node.js filesystem support
7
8
  */
8
- export class TarTools {
9
+ export class TarTools extends SharedTarTools {
9
10
  /**
10
- * Add a file to a TAR pack stream
11
+ * Pack a directory into a TAR buffer (Node.js only)
11
12
  */
12
- public async addFileToPack(
13
- pack: plugins.tarStream.Pack,
14
- optionsArg: {
15
- fileName?: string;
16
- content?:
17
- | string
18
- | Buffer
19
- | plugins.stream.Readable
20
- | plugins.smartfile.SmartFile
21
- | plugins.smartfile.StreamFile;
22
- byteLength?: number;
23
- filePath?: string;
24
- }
25
- ): Promise<void> {
26
- return new Promise<void>(async (resolve, reject) => {
27
- let fileName: string | null = null;
28
-
29
- if (optionsArg.fileName) {
30
- fileName = optionsArg.fileName;
31
- } else if (optionsArg.content instanceof plugins.smartfile.SmartFile) {
32
- fileName = optionsArg.content.relative;
33
- } else if (optionsArg.content instanceof plugins.smartfile.StreamFile) {
34
- fileName = optionsArg.content.relativeFilePath;
35
- } else if (optionsArg.filePath) {
36
- fileName = optionsArg.filePath;
37
- }
38
-
39
- if (!fileName) {
40
- reject(new Error('No filename specified for TAR entry'));
41
- return;
42
- }
43
-
44
- // Determine content byte length
45
- let contentByteLength: number | undefined;
46
- if (optionsArg.byteLength) {
47
- contentByteLength = optionsArg.byteLength;
48
- } else if (typeof optionsArg.content === 'string') {
49
- contentByteLength = Buffer.byteLength(optionsArg.content, 'utf8');
50
- } else if (Buffer.isBuffer(optionsArg.content)) {
51
- contentByteLength = optionsArg.content.length;
52
- } else if (optionsArg.content instanceof plugins.smartfile.SmartFile) {
53
- contentByteLength = await optionsArg.content.getSize();
54
- } else if (optionsArg.content instanceof plugins.smartfile.StreamFile) {
55
- contentByteLength = await optionsArg.content.getSize();
56
- } else if (optionsArg.filePath) {
57
- const fileStat = await plugins.fsPromises.stat(optionsArg.filePath);
58
- contentByteLength = fileStat.size;
59
- }
60
-
61
- // Convert all content types to Readable stream
62
- let content: plugins.stream.Readable;
63
- if (Buffer.isBuffer(optionsArg.content)) {
64
- content = plugins.stream.Readable.from(optionsArg.content);
65
- } else if (typeof optionsArg.content === 'string') {
66
- content = plugins.stream.Readable.from(Buffer.from(optionsArg.content));
67
- } else if (optionsArg.content instanceof plugins.smartfile.SmartFile) {
68
- content = plugins.stream.Readable.from(optionsArg.content.contents);
69
- } else if (optionsArg.content instanceof plugins.smartfile.StreamFile) {
70
- content = await optionsArg.content.createReadStream();
71
- } else if (optionsArg.content instanceof plugins.stream.Readable) {
72
- content = optionsArg.content;
73
- } else if (optionsArg.filePath) {
74
- content = plugins.fs.createReadStream(optionsArg.filePath);
75
- } else {
76
- reject(new Error('No content or filePath specified for TAR entry'));
77
- return;
78
- }
79
-
80
- const entry = pack.entry(
81
- {
82
- name: fileName,
83
- ...(contentByteLength !== undefined ? { size: contentByteLength } : {}),
84
- },
85
- (err: Error | null) => {
86
- if (err) {
87
- reject(err);
88
- } else {
89
- resolve();
90
- }
91
- }
92
- );
93
-
94
- content.pipe(entry);
95
- // Note: resolve() is called in the callback above when pipe completes
96
- });
97
- }
98
-
99
- /**
100
- * Pack a directory into a TAR stream
101
- */
102
- public async packDirectory(directoryPath: string): Promise<plugins.tarStream.Pack> {
13
+ public async packDirectory(directoryPath: string): Promise<Uint8Array> {
103
14
  const fileTree = await plugins.listFileTree(directoryPath, '**/*');
104
- const pack = await this.getPackStream();
15
+ const entries: IArchiveEntry[] = [];
105
16
 
106
17
  for (const filePath of fileTree) {
107
18
  const absolutePath = plugins.path.join(directoryPath, filePath);
108
- const fileStat = await plugins.fsPromises.stat(absolutePath);
109
- await this.addFileToPack(pack, {
110
- byteLength: fileStat.size,
111
- filePath: absolutePath,
112
- fileName: filePath,
113
- content: plugins.fs.createReadStream(absolutePath),
19
+ const content = await plugins.fsPromises.readFile(absolutePath);
20
+ entries.push({
21
+ archivePath: filePath,
22
+ content: new Uint8Array(content),
114
23
  });
115
24
  }
116
25
 
117
- return pack;
26
+ return this.packFiles(entries);
118
27
  }
119
28
 
120
29
  /**
121
- * Get a new TAR pack stream
122
- */
123
- public async getPackStream(): Promise<plugins.tarStream.Pack> {
124
- return plugins.tarStream.pack();
125
- }
126
-
127
- /**
128
- * Get a TAR extraction stream
129
- */
130
- public getDecompressionStream(): plugins.tarStream.Extract {
131
- return plugins.tarStream.extract();
132
- }
133
-
134
- /**
135
- * Pack files into a TAR buffer
136
- */
137
- public async packFiles(files: IArchiveEntry[]): Promise<Buffer> {
138
- const pack = await this.getPackStream();
139
-
140
- for (const file of files) {
141
- await this.addFileToPack(pack, {
142
- fileName: file.archivePath,
143
- content: file.content as string | Buffer | plugins.stream.Readable | plugins.smartfile.SmartFile | plugins.smartfile.StreamFile,
144
- byteLength: file.size,
145
- });
146
- }
147
-
148
- pack.finalize();
149
-
150
- const chunks: Buffer[] = [];
151
- return new Promise((resolve, reject) => {
152
- pack.on('data', (chunk: Buffer) => chunks.push(chunk));
153
- pack.on('end', () => resolve(Buffer.concat(chunks)));
154
- pack.on('error', reject);
155
- });
156
- }
157
-
158
- /**
159
- * Pack a directory into a TAR.GZ buffer
30
+ * Pack a directory into a TAR.GZ buffer (Node.js only)
160
31
  */
161
32
  public async packDirectoryToTarGz(
162
33
  directoryPath: string,
163
34
  compressionLevel?: TCompressionLevel
164
- ): Promise<Buffer> {
165
- const pack = await this.packDirectory(directoryPath);
166
- pack.finalize();
167
-
35
+ ): Promise<Uint8Array> {
36
+ const tarBuffer = await this.packDirectory(directoryPath);
168
37
  const gzipTools = new GzipTools();
169
- const gzipStream = gzipTools.getCompressionStream(compressionLevel);
170
-
171
- const chunks: Buffer[] = [];
172
- return new Promise((resolve, reject) => {
173
- pack
174
- .pipe(gzipStream)
175
- .on('data', (chunk: Buffer) => chunks.push(chunk))
176
- .on('end', () => resolve(Buffer.concat(chunks)))
177
- .on('error', reject);
178
- });
38
+ return gzipTools.compress(tarBuffer, compressionLevel);
179
39
  }
180
40
 
181
41
  /**
182
- * Pack a directory into a TAR.GZ stream
42
+ * Pack a directory into a TAR.GZ stream (Node.js only)
183
43
  */
184
44
  public async packDirectoryToTarGzStream(
185
45
  directoryPath: string,
186
46
  compressionLevel?: TCompressionLevel
187
47
  ): Promise<plugins.stream.Readable> {
188
- const pack = await this.packDirectory(directoryPath);
189
- pack.finalize();
190
-
191
- const gzipTools = new GzipTools();
192
- const gzipStream = gzipTools.getCompressionStream(compressionLevel);
193
-
194
- return pack.pipe(gzipStream);
195
- }
196
-
197
- /**
198
- * Pack files into a TAR.GZ buffer
199
- */
200
- public async packFilesToTarGz(
201
- files: IArchiveEntry[],
202
- compressionLevel?: TCompressionLevel
203
- ): Promise<Buffer> {
204
- const tarBuffer = await this.packFiles(files);
205
- const gzipTools = new GzipTools();
206
- return gzipTools.compress(tarBuffer, compressionLevel);
48
+ const buffer = await this.packDirectoryToTarGz(directoryPath, compressionLevel);
49
+ return plugins.stream.Readable.from(buffer);
207
50
  }
208
51
  }
package/ts/index.ts CHANGED
@@ -1,15 +1,11 @@
1
- // Core types and errors
2
- export * from './interfaces.js';
3
- export * from './errors.js';
1
+ // Re-export everything from ts_shared (browser-compatible)
2
+ export * from '../ts_shared/index.js';
4
3
 
5
- // Main archive class
4
+ // Node.js-specific: Main archive class with filesystem support
6
5
  export * from './classes.smartarchive.js';
7
6
 
8
- // Format-specific tools
9
- export * from './classes.tartools.js';
10
- export * from './classes.ziptools.js';
11
- export * from './classes.gziptools.js';
12
- export * from './classes.bzip2tools.js';
13
-
14
- // Archive analysis
7
+ // Node.js-specific: Archive analysis with SmartArchive integration
15
8
  export * from './classes.archiveanalyzer.js';
9
+
10
+ // Node.js-specific: Extended TarTools with filesystem support (overrides shared TarTools)
11
+ export { TarTools } from './classes.tartools.js';
package/ts/plugins.ts CHANGED
@@ -1,4 +1,4 @@
1
- // node native scope
1
+ // Node.js native scope
2
2
  import * as path from 'node:path';
3
3
  import * as stream from 'node:stream';
4
4
  import * as fs from 'node:fs';
@@ -30,32 +30,20 @@ export async function listFileTree(dirPath: string, _pattern: string = '**/*'):
30
30
  return results;
31
31
  }
32
32
 
33
- // @pushrocks scope
34
- import * as smartfile from '@push.rocks/smartfile';
35
- import * as smartdelay from '@push.rocks/smartdelay';
33
+ // Re-export browser-compatible plugins from ts_shared
34
+ export * from '../ts_shared/plugins.js';
35
+
36
+ // Additional Node.js-specific @pushrocks packages
36
37
  import * as smartpath from '@push.rocks/smartpath';
37
- import * as smartpromise from '@push.rocks/smartpromise';
38
38
  import * as smartrequest from '@push.rocks/smartrequest';
39
39
  import * as smartunique from '@push.rocks/smartunique';
40
- import * as smartstream from '@push.rocks/smartstream';
41
40
  import * as smartrx from '@push.rocks/smartrx';
42
41
  import * as smarturl from '@push.rocks/smarturl';
43
42
 
44
43
  export {
45
- smartfile,
46
- smartdelay,
47
44
  smartpath,
48
- smartpromise,
49
45
  smartrequest,
50
46
  smartunique,
51
- smartstream,
52
47
  smartrx,
53
48
  smarturl,
54
49
  };
55
-
56
- // third party scope
57
- import * as fileType from 'file-type';
58
- import * as fflate from 'fflate';
59
- import tarStream from 'tar-stream';
60
-
61
- export { fileType, fflate, tarStream };
@@ -6,7 +6,7 @@ const BITMASK = [0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff] as const;
6
6
  * Creates a bit reader function for BZIP2 decompression.
7
7
  * Takes a buffer iterator as input and returns a function that reads bits.
8
8
  */
9
- export function bitIterator(nextBuffer: () => Buffer): IBitReader {
9
+ export function bitIterator(nextBuffer: () => Uint8Array): IBitReader {
10
10
  let bit = 0;
11
11
  let byte = 0;
12
12
  let bytes = nextBuffer();
@@ -71,7 +71,7 @@ export class Bzip2 {
71
71
  /**
72
72
  * Create a bit reader from a byte array
73
73
  */
74
- array(bytes: Uint8Array | Buffer): (n: number) => number {
74
+ array(bytes: Uint8Array): (n: number) => number {
75
75
  let bit = 0;
76
76
  let byte = 0;
77
77
  const BITMASK = [0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff];
@@ -99,7 +99,7 @@ export class Bzip2 {
99
99
  /**
100
100
  * Simple decompression from a buffer
101
101
  */
102
- simple(srcbuffer: Uint8Array | Buffer, stream: (byte: number) => void): void {
102
+ simple(srcbuffer: Uint8Array, stream: (byte: number) => void): void {
103
103
  const bits = this.array(srcbuffer);
104
104
  const size = this.header(bits as IBitReader);
105
105
  let ret: number | null = 0;
@@ -8,16 +8,16 @@ import { bitIterator } from './bititerator.js';
8
8
  /**
9
9
  * Creates a streaming BZIP2 decompression transform
10
10
  */
11
- export function unbzip2Stream(): plugins.smartstream.SmartDuplex<Buffer, Buffer> {
11
+ export function unbzip2Stream(): plugins.smartstream.SmartDuplex<Uint8Array, Uint8Array> {
12
12
  const bzip2Instance = new Bzip2();
13
- const bufferQueue: Buffer[] = [];
13
+ const bufferQueue: Uint8Array[] = [];
14
14
  let hasBytes = 0;
15
15
  let blockSize = 0;
16
16
  let broken = false;
17
17
  let bitReader: IBitReader | null = null;
18
18
  let streamCRC: number | null = null;
19
19
 
20
- function decompressBlock(): Buffer | undefined {
20
+ function decompressBlock(): Uint8Array | undefined {
21
21
  if (!blockSize) {
22
22
  blockSize = bzip2Instance.header(bitReader!);
23
23
  streamCRC = 0;
@@ -40,12 +40,12 @@ export function unbzip2Stream(): plugins.smartstream.SmartDuplex<Buffer, Buffer>
40
40
  return undefined;
41
41
  }
42
42
 
43
- return Buffer.from(chunk);
43
+ return new Uint8Array(chunk);
44
44
  }
45
45
 
46
46
  let outlength = 0;
47
47
 
48
- const decompressAndPush = async (): Promise<Buffer | undefined> => {
48
+ const decompressAndPush = async (): Promise<Uint8Array | undefined> => {
49
49
  if (broken) return undefined;
50
50
 
51
51
  try {
@@ -63,7 +63,7 @@ export function unbzip2Stream(): plugins.smartstream.SmartDuplex<Buffer, Buffer>
63
63
  }
64
64
  };
65
65
 
66
- return new plugins.smartstream.SmartDuplex<Buffer, Buffer>({
66
+ return new plugins.smartstream.SmartDuplex<Uint8Array, Uint8Array>({
67
67
  objectMode: true,
68
68
  name: 'bzip2',
69
69
  highWaterMark: 1,
@@ -0,0 +1,14 @@
1
+ import * as plugins from './plugins.js';
2
+ import { unbzip2Stream } from './bzip2/index.js';
3
+
4
+ /**
5
+ * BZIP2 decompression utilities (browser-compatible)
6
+ */
7
+ export class Bzip2Tools {
8
+ /**
9
+ * Get a streaming decompression transform
10
+ */
11
+ getDecompressionStream(): plugins.smartstream.SmartDuplex<Uint8Array, Uint8Array> {
12
+ return unbzip2Stream();
13
+ }
14
+ }
@@ -0,0 +1,42 @@
1
+ import * as plugins from './plugins.js';
2
+ import type { TCompressionLevel } from './interfaces.js';
3
+
4
+ /**
5
+ * GZIP compression and decompression utilities (browser-compatible)
6
+ */
7
+ export class GzipTools {
8
+ /**
9
+ * Compress data synchronously
10
+ */
11
+ public compressSync(data: Uint8Array, level?: TCompressionLevel): Uint8Array {
12
+ const options = level !== undefined ? { level } : undefined;
13
+ return plugins.fflate.gzipSync(data, options);
14
+ }
15
+
16
+ /**
17
+ * Decompress data synchronously
18
+ */
19
+ public decompressSync(data: Uint8Array): Uint8Array {
20
+ return plugins.fflate.gunzipSync(data);
21
+ }
22
+
23
+ /**
24
+ * Compress data asynchronously
25
+ * Note: Uses sync version for Deno compatibility (fflate async uses Web Workers
26
+ * which have issues in Deno)
27
+ */
28
+ public async compress(data: Uint8Array, level?: TCompressionLevel): Promise<Uint8Array> {
29
+ // Use sync version wrapped in Promise for cross-runtime compatibility
30
+ return this.compressSync(data, level);
31
+ }
32
+
33
+ /**
34
+ * Decompress data asynchronously
35
+ * Note: Uses sync version for Deno compatibility (fflate async uses Web Workers
36
+ * which have issues in Deno)
37
+ */
38
+ public async decompress(data: Uint8Array): Promise<Uint8Array> {
39
+ // Use sync version wrapped in Promise for cross-runtime compatibility
40
+ return this.decompressSync(data);
41
+ }
42
+ }
@@ -0,0 +1,89 @@
1
+ import * as plugins from './plugins.js';
2
+ import type { IArchiveEntry, ITarEntry, TCompressionLevel } from './interfaces.js';
3
+ import { GzipTools } from './classes.gziptools.js';
4
+
5
+ /**
6
+ * TAR archive creation and extraction utilities using modern-tar (browser-compatible)
7
+ */
8
+ export class TarTools {
9
+ /**
10
+ * Pack files into a TAR buffer
11
+ */
12
+ public async packFiles(files: IArchiveEntry[]): Promise<Uint8Array> {
13
+ const entries: ITarEntry[] = [];
14
+
15
+ for (const file of files) {
16
+ let data: Uint8Array;
17
+
18
+ if (typeof file.content === 'string') {
19
+ data = new TextEncoder().encode(file.content);
20
+ } else if (file.content instanceof Uint8Array) {
21
+ data = file.content;
22
+ } else if (file.content instanceof plugins.smartfile.SmartFile) {
23
+ data = new Uint8Array(file.content.contents);
24
+ } else if (file.content instanceof plugins.smartfile.StreamFile) {
25
+ const buffer = await file.content.getContentAsBuffer();
26
+ data = new Uint8Array(buffer);
27
+ } else {
28
+ throw new Error('Unsupported content type for TAR entry');
29
+ }
30
+
31
+ entries.push({
32
+ header: {
33
+ name: file.archivePath,
34
+ size: data.length,
35
+ type: 'file',
36
+ mode: file.mode,
37
+ mtime: file.mtime,
38
+ },
39
+ body: data,
40
+ });
41
+ }
42
+
43
+ return plugins.modernTar.packTar(entries);
44
+ }
45
+
46
+ /**
47
+ * Extract a TAR buffer to an array of entries
48
+ */
49
+ public async extractTar(data: Uint8Array): Promise<Array<{ path: string; content: Uint8Array; isDirectory: boolean }>> {
50
+ const entries = await plugins.modernTar.unpackTar(data);
51
+ const result: Array<{ path: string; content: Uint8Array; isDirectory: boolean }> = [];
52
+
53
+ for (const entry of entries) {
54
+ const isDirectory = entry.header.type === 'directory' || entry.header.name.endsWith('/');
55
+
56
+ // modern-tar uses 'data' property, not 'body'
57
+ const content = entry.data ?? new Uint8Array(0);
58
+
59
+ result.push({
60
+ path: entry.header.name,
61
+ content,
62
+ isDirectory,
63
+ });
64
+ }
65
+
66
+ return result;
67
+ }
68
+
69
+ /**
70
+ * Pack files into a TAR.GZ buffer
71
+ */
72
+ public async packFilesToTarGz(
73
+ files: IArchiveEntry[],
74
+ compressionLevel?: TCompressionLevel
75
+ ): Promise<Uint8Array> {
76
+ const tarBuffer = await this.packFiles(files);
77
+ const gzipTools = new GzipTools();
78
+ return gzipTools.compress(tarBuffer, compressionLevel);
79
+ }
80
+
81
+ /**
82
+ * Extract a TAR.GZ buffer to an array of entries
83
+ */
84
+ public async extractTarGz(data: Uint8Array): Promise<Array<{ path: string; content: Uint8Array; isDirectory: boolean }>> {
85
+ const gzipTools = new GzipTools();
86
+ const tarBuffer = await gzipTools.decompress(data);
87
+ return this.extractTar(tarBuffer);
88
+ }
89
+ }
@@ -0,0 +1,107 @@
1
+ import * as plugins from './plugins.js';
2
+ import type { IArchiveEntry, TCompressionLevel } from './interfaces.js';
3
+
4
+ /**
5
+ * Transform stream for ZIP decompression using fflate
6
+ * Emits StreamFile objects for each file in the archive
7
+ */
8
+ export class ZipDecompressionTransform extends plugins.smartstream.SmartDuplex<Uint8Array, plugins.smartfile.StreamFile> {
9
+ private streamtools!: plugins.smartstream.IStreamTools;
10
+ private unzipper = new plugins.fflate.Unzip(async (fileArg) => {
11
+ let resultBuffer: Uint8Array;
12
+ fileArg.ondata = async (_flateError, dat, final) => {
13
+ if (resultBuffer) {
14
+ const combined = new Uint8Array(resultBuffer.length + dat.length);
15
+ combined.set(resultBuffer);
16
+ combined.set(dat, resultBuffer.length);
17
+ resultBuffer = combined;
18
+ } else {
19
+ resultBuffer = new Uint8Array(dat);
20
+ }
21
+ if (final) {
22
+ const streamFile = plugins.smartfile.StreamFile.fromBuffer(Buffer.from(resultBuffer));
23
+ streamFile.relativeFilePath = fileArg.name;
24
+ this.streamtools.push(streamFile);
25
+ }
26
+ };
27
+ fileArg.start();
28
+ });
29
+
30
+ constructor() {
31
+ super({
32
+ objectMode: true,
33
+ writeFunction: async (chunkArg, streamtoolsArg) => {
34
+ this.streamtools ? null : (this.streamtools = streamtoolsArg);
35
+ const chunk = chunkArg instanceof Uint8Array ? chunkArg : new Uint8Array(chunkArg);
36
+ this.unzipper.push(chunk, false);
37
+ return null;
38
+ },
39
+ finalFunction: async () => {
40
+ this.unzipper.push(new Uint8Array(0), true);
41
+ await plugins.smartdelay.delayFor(0);
42
+ await this.streamtools.push(null);
43
+ return null;
44
+ },
45
+ });
46
+ this.unzipper.register(plugins.fflate.UnzipInflate);
47
+ }
48
+ }
49
+
50
+ /**
51
+ * ZIP compression and decompression utilities
52
+ */
53
+ export class ZipTools {
54
+ /**
55
+ * Get a streaming decompression transform for extracting ZIP archives
56
+ */
57
+ public getDecompressionStream(): ZipDecompressionTransform {
58
+ return new ZipDecompressionTransform();
59
+ }
60
+
61
+ /**
62
+ * Create a ZIP archive from an array of entries
63
+ */
64
+ public async createZip(entries: IArchiveEntry[], compressionLevel?: TCompressionLevel): Promise<Uint8Array> {
65
+ const filesObj: plugins.fflate.Zippable = {};
66
+
67
+ for (const entry of entries) {
68
+ let data: Uint8Array;
69
+
70
+ if (typeof entry.content === 'string') {
71
+ data = new TextEncoder().encode(entry.content);
72
+ } else if (entry.content instanceof Uint8Array) {
73
+ data = entry.content;
74
+ } else if (entry.content instanceof plugins.smartfile.SmartFile) {
75
+ data = new Uint8Array(entry.content.contents);
76
+ } else if (entry.content instanceof plugins.smartfile.StreamFile) {
77
+ const buffer = await entry.content.getContentAsBuffer();
78
+ data = new Uint8Array(buffer);
79
+ } else {
80
+ throw new Error('Unsupported content type for ZIP entry');
81
+ }
82
+
83
+ if (compressionLevel !== undefined) {
84
+ filesObj[entry.archivePath] = [data, { level: compressionLevel }];
85
+ } else {
86
+ filesObj[entry.archivePath] = data;
87
+ }
88
+ }
89
+
90
+ // Use sync version for Deno compatibility (fflate async uses Web Workers)
91
+ const result = plugins.fflate.zipSync(filesObj);
92
+ return result;
93
+ }
94
+
95
+ /**
96
+ * Extract a ZIP buffer to an array of entries
97
+ */
98
+ public async extractZip(data: Uint8Array): Promise<Array<{ path: string; content: Uint8Array }>> {
99
+ // Use sync version for Deno compatibility (fflate async uses Web Workers)
100
+ const result = plugins.fflate.unzipSync(data);
101
+ const entries: Array<{ path: string; content: Uint8Array }> = [];
102
+ for (const [path, content] of Object.entries(result)) {
103
+ entries.push({ path, content });
104
+ }
105
+ return entries;
106
+ }
107
+ }
@@ -0,0 +1,17 @@
1
+ // ts_shared - Browser-compatible shared code
2
+
3
+ // Interfaces and types
4
+ export * from './interfaces.js';
5
+
6
+ // Error classes
7
+ export * from './errors.js';
8
+
9
+ // Tool classes
10
+ export { ZipTools, ZipDecompressionTransform } from './classes.ziptools.js';
11
+ export { GzipTools } from './classes.gziptools.js';
12
+ export { TarTools } from './classes.tartools.js';
13
+ export { Bzip2Tools } from './classes.bzip2tools.js';
14
+
15
+ // BZIP2 internals (for advanced usage)
16
+ export { unbzip2Stream } from './bzip2/index.js';
17
+ export { Bzip2 } from './bzip2/bzip2.js';