@push.rocks/smartarchive 4.2.3 → 5.0.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 (42) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/bzip2/bititerator.d.ts +6 -1
  3. package/dist_ts/bzip2/bititerator.js +30 -24
  4. package/dist_ts/bzip2/bzip2.d.ts +27 -12
  5. package/dist_ts/bzip2/bzip2.js +325 -263
  6. package/dist_ts/bzip2/index.d.ts +4 -1
  7. package/dist_ts/bzip2/index.js +36 -38
  8. package/dist_ts/classes.archiveanalyzer.d.ts +25 -5
  9. package/dist_ts/classes.archiveanalyzer.js +19 -8
  10. package/dist_ts/classes.bzip2tools.d.ts +1 -1
  11. package/dist_ts/classes.gziptools.d.ts +39 -6
  12. package/dist_ts/classes.gziptools.js +85 -24
  13. package/dist_ts/classes.smartarchive.d.ts +101 -16
  14. package/dist_ts/classes.smartarchive.js +398 -61
  15. package/dist_ts/classes.tartools.d.ts +31 -4
  16. package/dist_ts/classes.tartools.js +97 -36
  17. package/dist_ts/classes.ziptools.d.ts +47 -12
  18. package/dist_ts/classes.ziptools.js +142 -23
  19. package/dist_ts/errors.d.ts +44 -0
  20. package/dist_ts/errors.js +62 -0
  21. package/dist_ts/index.d.ts +4 -0
  22. package/dist_ts/index.js +9 -1
  23. package/dist_ts/interfaces.d.ts +115 -0
  24. package/dist_ts/interfaces.js +2 -0
  25. package/dist_ts/plugins.d.ts +9 -3
  26. package/dist_ts/plugins.js +27 -4
  27. package/package.json +3 -4
  28. package/readme.hints.md +38 -1
  29. package/readme.md +248 -137
  30. package/ts/00_commitinfo_data.ts +1 -1
  31. package/ts/bzip2/bititerator.ts +43 -27
  32. package/ts/bzip2/bzip2.ts +289 -171
  33. package/ts/bzip2/index.ts +52 -50
  34. package/ts/classes.archiveanalyzer.ts +42 -28
  35. package/ts/classes.gziptools.ts +96 -33
  36. package/ts/classes.smartarchive.ts +472 -122
  37. package/ts/classes.tartools.ts +128 -59
  38. package/ts/classes.ziptools.ts +160 -34
  39. package/ts/errors.ts +70 -0
  40. package/ts/index.ts +11 -0
  41. package/ts/interfaces.ts +131 -0
  42. package/ts/plugins.ts +29 -3
@@ -1,11 +1,14 @@
1
- import type { SmartArchive } from './classes.smartarchive.js';
2
1
  import * as plugins from './plugins.js';
2
+ import type { IArchiveEntry, TCompressionLevel } from './interfaces.js';
3
+ import { GzipTools } from './classes.gziptools.js';
3
4
 
5
+ /**
6
+ * TAR archive creation and extraction utilities
7
+ */
4
8
  export class TarTools {
5
- // INSTANCE
6
- constructor() {}
7
-
8
- // packing
9
+ /**
10
+ * Add a file to a TAR pack stream
11
+ */
9
12
  public async addFileToPack(
10
13
  pack: plugins.tarStream.Pack,
11
14
  optionsArg: {
@@ -13,12 +16,12 @@ export class TarTools {
13
16
  content?:
14
17
  | string
15
18
  | Buffer
16
- | plugins.smartstream.stream.Readable
19
+ | plugins.stream.Readable
17
20
  | plugins.smartfile.SmartFile
18
21
  | plugins.smartfile.StreamFile;
19
22
  byteLength?: number;
20
23
  filePath?: string;
21
- },
24
+ }
22
25
  ): Promise<void> {
23
26
  return new Promise<void>(async (resolve, reject) => {
24
27
  let fileName: string | null = null;
@@ -26,18 +29,20 @@ export class TarTools {
26
29
  if (optionsArg.fileName) {
27
30
  fileName = optionsArg.fileName;
28
31
  } else if (optionsArg.content instanceof plugins.smartfile.SmartFile) {
29
- fileName = (optionsArg.content as plugins.smartfile.SmartFile).relative;
32
+ fileName = optionsArg.content.relative;
30
33
  } else if (optionsArg.content instanceof plugins.smartfile.StreamFile) {
31
- fileName = (optionsArg.content as plugins.smartfile.StreamFile)
32
- .relativeFilePath;
34
+ fileName = optionsArg.content.relativeFilePath;
33
35
  } else if (optionsArg.filePath) {
34
36
  fileName = optionsArg.filePath;
35
37
  }
36
38
 
37
- /**
38
- * contentByteLength is used to set the size of the entry in the tar file
39
- */
40
- let contentByteLength: number;
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;
41
46
  if (optionsArg.byteLength) {
42
47
  contentByteLength = optionsArg.byteLength;
43
48
  } else if (typeof optionsArg.content === 'string') {
@@ -45,95 +50,159 @@ export class TarTools {
45
50
  } else if (Buffer.isBuffer(optionsArg.content)) {
46
51
  contentByteLength = optionsArg.content.length;
47
52
  } else if (optionsArg.content instanceof plugins.smartfile.SmartFile) {
48
- contentByteLength = await optionsArg.content.getSize(); // assuming SmartFile has getSize method
53
+ contentByteLength = await optionsArg.content.getSize();
49
54
  } else if (optionsArg.content instanceof plugins.smartfile.StreamFile) {
50
- contentByteLength = await optionsArg.content.getSize(); // assuming StreamFile has getSize method
51
- } else if (
52
- optionsArg.content instanceof plugins.smartstream.stream.Readable
53
- ) {
54
- console.warn(
55
- '@push.rocks/smartarchive: When streaming, it is recommended to provide byteLength, if known.',
56
- );
55
+ contentByteLength = await optionsArg.content.getSize();
57
56
  } else if (optionsArg.filePath) {
58
- const fileStat = await plugins.smartfile.fs.stat(optionsArg.filePath);
57
+ const fileStat = await plugins.fsPromises.stat(optionsArg.filePath);
59
58
  contentByteLength = fileStat.size;
60
59
  }
61
60
 
62
- /**
63
- * here we try to harmonize all kind of entries towards a readable stream
64
- */
65
- let content: plugins.smartstream.stream.Readable;
61
+ // Convert all content types to Readable stream
62
+ let content: plugins.stream.Readable;
66
63
  if (Buffer.isBuffer(optionsArg.content)) {
67
- content = plugins.smartstream.stream.Readable.from(optionsArg.content);
64
+ content = plugins.stream.Readable.from(optionsArg.content);
68
65
  } else if (typeof optionsArg.content === 'string') {
69
- content = plugins.smartstream.stream.Readable.from(
70
- Buffer.from(optionsArg.content),
71
- );
66
+ content = plugins.stream.Readable.from(Buffer.from(optionsArg.content));
72
67
  } else if (optionsArg.content instanceof plugins.smartfile.SmartFile) {
73
- content = plugins.smartstream.stream.Readable.from(
74
- optionsArg.content.contents,
75
- );
68
+ content = plugins.stream.Readable.from(optionsArg.content.contents);
76
69
  } else if (optionsArg.content instanceof plugins.smartfile.StreamFile) {
77
70
  content = await optionsArg.content.createReadStream();
78
- } else if (
79
- optionsArg.content instanceof plugins.smartstream.stream.Readable
80
- ) {
71
+ } else if (optionsArg.content instanceof plugins.stream.Readable) {
81
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;
82
78
  }
83
79
 
84
80
  const entry = pack.entry(
85
81
  {
86
82
  name: fileName,
87
- ...(contentByteLength
88
- ? {
89
- size: contentByteLength,
90
- }
91
- : null),
83
+ ...(contentByteLength !== undefined ? { size: contentByteLength } : {}),
92
84
  },
93
- (err: Error) => {
85
+ (err: Error | null) => {
94
86
  if (err) {
95
87
  reject(err);
96
88
  } else {
97
89
  resolve();
98
90
  }
99
- },
91
+ }
100
92
  );
101
93
 
102
94
  content.pipe(entry);
103
- resolve();
95
+ // Note: resolve() is called in the callback above when pipe completes
104
96
  });
105
97
  }
106
98
 
107
99
  /**
108
- * packs a directory from disk into a tar stream
109
- * @param directoryPath
100
+ * Pack a directory into a TAR stream
110
101
  */
111
- public async packDirectory(directoryPath: string) {
112
- const fileTree = await plugins.smartfile.fs.listFileTree(
113
- directoryPath,
114
- '**/*',
115
- );
102
+ public async packDirectory(directoryPath: string): Promise<plugins.tarStream.Pack> {
103
+ const fileTree = await plugins.listFileTree(directoryPath, '**/*');
116
104
  const pack = await this.getPackStream();
105
+
117
106
  for (const filePath of fileTree) {
118
107
  const absolutePath = plugins.path.join(directoryPath, filePath);
119
- const fileStat = await plugins.smartfile.fs.stat(absolutePath);
108
+ const fileStat = await plugins.fsPromises.stat(absolutePath);
120
109
  await this.addFileToPack(pack, {
121
110
  byteLength: fileStat.size,
122
111
  filePath: absolutePath,
123
112
  fileName: filePath,
124
- content: plugins.smartfile.fsStream.createReadStream(absolutePath),
113
+ content: plugins.fs.createReadStream(absolutePath),
125
114
  });
126
115
  }
116
+
127
117
  return pack;
128
118
  }
129
119
 
130
- public async getPackStream() {
131
- const pack = plugins.tarStream.pack();
132
- return pack;
120
+ /**
121
+ * Get a new TAR pack stream
122
+ */
123
+ public async getPackStream(): Promise<plugins.tarStream.Pack> {
124
+ return plugins.tarStream.pack();
133
125
  }
134
126
 
135
- // extracting
136
- getDecompressionStream() {
127
+ /**
128
+ * Get a TAR extraction stream
129
+ */
130
+ public getDecompressionStream(): plugins.tarStream.Extract {
137
131
  return plugins.tarStream.extract();
138
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
160
+ */
161
+ public async packDirectoryToTarGz(
162
+ directoryPath: string,
163
+ compressionLevel?: TCompressionLevel
164
+ ): Promise<Buffer> {
165
+ const pack = await this.packDirectory(directoryPath);
166
+ pack.finalize();
167
+
168
+ 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
+ });
179
+ }
180
+
181
+ /**
182
+ * Pack a directory into a TAR.GZ stream
183
+ */
184
+ public async packDirectoryToTarGzStream(
185
+ directoryPath: string,
186
+ compressionLevel?: TCompressionLevel
187
+ ): 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);
207
+ }
139
208
  }
@@ -1,83 +1,209 @@
1
- import type { SmartArchive } from './classes.smartarchive.js';
2
1
  import * as plugins from './plugins.js';
2
+ import type { IArchiveEntry, TCompressionLevel } from './interfaces.js';
3
3
 
4
- class DecompressZipTransform extends plugins.smartstream
5
- .SmartDuplex<ArrayBufferLike> {
6
- private streamtools: plugins.smartstream.IStreamTools;
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<Buffer, plugins.smartfile.StreamFile> {
9
+ private streamtools!: plugins.smartstream.IStreamTools;
7
10
  private unzipper = new plugins.fflate.Unzip(async (fileArg) => {
8
11
  let resultBuffer: Buffer;
9
- fileArg.ondata = async (flateError, dat, final) => {
12
+ fileArg.ondata = async (_flateError, dat, final) => {
10
13
  resultBuffer
11
14
  ? (resultBuffer = Buffer.concat([resultBuffer, Buffer.from(dat)]))
12
15
  : (resultBuffer = Buffer.from(dat));
13
16
  if (final) {
14
- const streamFile =
15
- plugins.smartfile.StreamFile.fromBuffer(resultBuffer);
17
+ const streamFile = plugins.smartfile.StreamFile.fromBuffer(resultBuffer);
16
18
  streamFile.relativeFilePath = fileArg.name;
17
19
  this.streamtools.push(streamFile);
18
20
  }
19
21
  };
20
22
  fileArg.start();
21
23
  });
24
+
22
25
  constructor() {
23
26
  super({
24
27
  objectMode: true,
25
28
  writeFunction: async (chunkArg, streamtoolsArg) => {
26
29
  this.streamtools ? null : (this.streamtools = streamtoolsArg);
27
30
  this.unzipper.push(
28
- Buffer.isBuffer(chunkArg) ? chunkArg : Buffer.from(chunkArg),
29
- false,
31
+ Buffer.isBuffer(chunkArg) ? chunkArg : Buffer.from(chunkArg as unknown as ArrayBuffer),
32
+ false
30
33
  );
34
+ return null;
31
35
  },
32
36
  finalFunction: async () => {
33
37
  this.unzipper.push(Buffer.from(''), true);
34
38
  await plugins.smartdelay.delayFor(0);
35
39
  await this.streamtools.push(null);
40
+ return null;
36
41
  },
37
42
  });
38
43
  this.unzipper.register(plugins.fflate.UnzipInflate);
39
44
  }
40
45
  }
41
46
 
42
- // This class wraps fflate's zip in a Node.js Transform stream for compression
43
- export class CompressZipTransform extends plugins.stream.Transform {
44
- files: { [fileName: string]: Uint8Array };
47
+ /**
48
+ * Streaming ZIP compression using fflate
49
+ * Allows adding multiple entries before finalizing
50
+ */
51
+ export class ZipCompressionStream extends plugins.stream.Duplex {
52
+ private files: Map<string, { data: Uint8Array; options?: plugins.fflate.ZipOptions }> = new Map();
53
+ private finalized = false;
45
54
 
46
55
  constructor() {
47
56
  super();
48
- this.files = {};
49
57
  }
50
58
 
51
- _transform(
52
- chunk: Buffer,
53
- encoding: BufferEncoding,
54
- callback: plugins.stream.TransformCallback,
55
- ) {
56
- // Simple example: storing chunks in memory before finalizing ZIP in _flush
57
- this.files['file.txt'] = new Uint8Array(chunk);
58
- callback();
59
- }
59
+ /**
60
+ * Add a file entry to the ZIP archive
61
+ */
62
+ public async addEntry(
63
+ fileName: string,
64
+ content: Buffer | plugins.stream.Readable,
65
+ options?: { compressionLevel?: TCompressionLevel }
66
+ ): Promise<void> {
67
+ if (this.finalized) {
68
+ throw new Error('Cannot add entries to a finalized ZIP archive');
69
+ }
60
70
 
61
- _flush(callback: plugins.stream.TransformCallback) {
62
- plugins.fflate.zip(this.files, (err, zipped) => {
63
- if (err) {
64
- callback(err);
65
- } else {
66
- this.push(Buffer.from(zipped));
67
- callback();
71
+ let data: Buffer;
72
+ if (Buffer.isBuffer(content)) {
73
+ data = content;
74
+ } else {
75
+ // Collect stream to buffer
76
+ const chunks: Buffer[] = [];
77
+ for await (const chunk of content) {
78
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
68
79
  }
80
+ data = Buffer.concat(chunks);
81
+ }
82
+
83
+ this.files.set(fileName, {
84
+ data: new Uint8Array(data),
85
+ options: options?.compressionLevel !== undefined ? { level: options.compressionLevel } : undefined,
86
+ });
87
+ }
88
+
89
+ /**
90
+ * Finalize the ZIP archive and emit the compressed data
91
+ */
92
+ public async finalize(): Promise<void> {
93
+ if (this.finalized) {
94
+ return;
95
+ }
96
+ this.finalized = true;
97
+
98
+ const filesObj: plugins.fflate.Zippable = {};
99
+ for (const [name, { data, options }] of this.files) {
100
+ filesObj[name] = options ? [data, options] : data;
101
+ }
102
+
103
+ return new Promise((resolve, reject) => {
104
+ plugins.fflate.zip(filesObj, (err, result) => {
105
+ if (err) {
106
+ reject(err);
107
+ } else {
108
+ this.push(Buffer.from(result));
109
+ this.push(null);
110
+ resolve();
111
+ }
112
+ });
69
113
  });
70
114
  }
115
+
116
+ _read(): void {
117
+ // No-op: data is pushed when finalize() is called
118
+ }
119
+
120
+ _write(
121
+ _chunk: Buffer,
122
+ _encoding: BufferEncoding,
123
+ callback: (error?: Error | null) => void
124
+ ): void {
125
+ // Not used for ZIP creation - use addEntry() instead
126
+ callback(new Error('Use addEntry() to add files to the ZIP archive'));
127
+ }
71
128
  }
72
129
 
130
+ /**
131
+ * ZIP compression and decompression utilities
132
+ */
73
133
  export class ZipTools {
74
- constructor() {}
134
+ /**
135
+ * Get a streaming compression object for creating ZIP archives
136
+ */
137
+ public getCompressionStream(): ZipCompressionStream {
138
+ return new ZipCompressionStream();
139
+ }
75
140
 
76
- public getCompressionStream() {
77
- return new CompressZipTransform();
141
+ /**
142
+ * Get a streaming decompression transform for extracting ZIP archives
143
+ */
144
+ public getDecompressionStream(): ZipDecompressionTransform {
145
+ return new ZipDecompressionTransform();
78
146
  }
79
147
 
80
- public getDecompressionStream() {
81
- return new DecompressZipTransform();
148
+ /**
149
+ * Create a ZIP archive from an array of entries
150
+ */
151
+ public async createZip(entries: IArchiveEntry[], compressionLevel?: TCompressionLevel): Promise<Buffer> {
152
+ const filesObj: plugins.fflate.Zippable = {};
153
+
154
+ for (const entry of entries) {
155
+ let data: Uint8Array;
156
+
157
+ if (typeof entry.content === 'string') {
158
+ data = new TextEncoder().encode(entry.content);
159
+ } else if (Buffer.isBuffer(entry.content)) {
160
+ data = new Uint8Array(entry.content);
161
+ } else if (entry.content instanceof plugins.smartfile.SmartFile) {
162
+ data = new Uint8Array(entry.content.contents);
163
+ } else if (entry.content instanceof plugins.smartfile.StreamFile) {
164
+ const buffer = await entry.content.getContentAsBuffer();
165
+ data = new Uint8Array(buffer);
166
+ } else {
167
+ // Readable stream
168
+ const chunks: Buffer[] = [];
169
+ for await (const chunk of entry.content as plugins.stream.Readable) {
170
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
171
+ }
172
+ data = new Uint8Array(Buffer.concat(chunks));
173
+ }
174
+
175
+ if (compressionLevel !== undefined) {
176
+ filesObj[entry.archivePath] = [data, { level: compressionLevel }];
177
+ } else {
178
+ filesObj[entry.archivePath] = data;
179
+ }
180
+ }
181
+
182
+ return new Promise((resolve, reject) => {
183
+ plugins.fflate.zip(filesObj, (err, result) => {
184
+ if (err) reject(err);
185
+ else resolve(Buffer.from(result));
186
+ });
187
+ });
188
+ }
189
+
190
+ /**
191
+ * Extract a ZIP buffer to an array of entries
192
+ */
193
+ public async extractZip(data: Buffer): Promise<Array<{ path: string; content: Buffer }>> {
194
+ return new Promise((resolve, reject) => {
195
+ plugins.fflate.unzip(data, (err, result) => {
196
+ if (err) {
197
+ reject(err);
198
+ return;
199
+ }
200
+
201
+ const entries: Array<{ path: string; content: Buffer }> = [];
202
+ for (const [path, content] of Object.entries(result)) {
203
+ entries.push({ path, content: Buffer.from(content) });
204
+ }
205
+ resolve(entries);
206
+ });
207
+ });
82
208
  }
83
209
  }
package/ts/errors.ts ADDED
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Base error class for smartarchive
3
+ */
4
+ export class SmartArchiveError extends Error {
5
+ public readonly code: string;
6
+
7
+ constructor(message: string, code: string) {
8
+ super(message);
9
+ this.name = 'SmartArchiveError';
10
+ this.code = code;
11
+ // Maintains proper stack trace for where error was thrown (V8)
12
+ if (Error.captureStackTrace) {
13
+ Error.captureStackTrace(this, this.constructor);
14
+ }
15
+ }
16
+ }
17
+
18
+ /**
19
+ * BZIP2-specific decompression errors
20
+ */
21
+ export class Bzip2Error extends SmartArchiveError {
22
+ constructor(message: string, code: string = 'BZIP2_ERROR') {
23
+ super(message, code);
24
+ this.name = 'Bzip2Error';
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Archive format detection errors
30
+ */
31
+ export class ArchiveFormatError extends SmartArchiveError {
32
+ constructor(message: string) {
33
+ super(message, 'ARCHIVE_FORMAT_ERROR');
34
+ this.name = 'ArchiveFormatError';
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Stream processing errors
40
+ */
41
+ export class StreamError extends SmartArchiveError {
42
+ constructor(message: string) {
43
+ super(message, 'STREAM_ERROR');
44
+ this.name = 'StreamError';
45
+ }
46
+ }
47
+
48
+ /**
49
+ * BZIP2 error codes for programmatic error handling
50
+ */
51
+ export const BZIP2_ERROR_CODES = {
52
+ NO_MAGIC_NUMBER: 'BZIP2_NO_MAGIC',
53
+ INVALID_ARCHIVE: 'BZIP2_INVALID_ARCHIVE',
54
+ CRC_MISMATCH: 'BZIP2_CRC_MISMATCH',
55
+ INVALID_BLOCK_DATA: 'BZIP2_INVALID_BLOCK',
56
+ BUFFER_OVERFLOW: 'BZIP2_BUFFER_OVERFLOW',
57
+ INVALID_HUFFMAN: 'BZIP2_INVALID_HUFFMAN',
58
+ INVALID_SELECTOR: 'BZIP2_INVALID_SELECTOR',
59
+ INVALID_POSITION: 'BZIP2_INVALID_POSITION',
60
+ PREMATURE_END: 'BZIP2_PREMATURE_END',
61
+ } as const;
62
+
63
+ export type TBzip2ErrorCode = typeof BZIP2_ERROR_CODES[keyof typeof BZIP2_ERROR_CODES];
64
+
65
+ /**
66
+ * Throw a BZIP2 error with a specific code
67
+ */
68
+ export function throwBzip2Error(message: string, code: TBzip2ErrorCode): never {
69
+ throw new Bzip2Error(message, code);
70
+ }
package/ts/index.ts CHANGED
@@ -1,4 +1,15 @@
1
+ // Core types and errors
2
+ export * from './interfaces.js';
3
+ export * from './errors.js';
4
+
5
+ // Main archive class
1
6
  export * from './classes.smartarchive.js';
7
+
8
+ // Format-specific tools
2
9
  export * from './classes.tartools.js';
3
10
  export * from './classes.ziptools.js';
4
11
  export * from './classes.gziptools.js';
12
+ export * from './classes.bzip2tools.js';
13
+
14
+ // Archive analysis
15
+ export * from './classes.archiveanalyzer.js';