extract-base-iterator 3.2.2 → 3.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.
@@ -57,4 +57,20 @@ export default class BufferList {
57
57
  * Note: This creates a copy, so use sparingly for large buffers
58
58
  */
59
59
  toBuffer(): Buffer;
60
+ /**
61
+ * Read UInt16 (little-endian) at offset without consuming
62
+ * Returns null if not enough data
63
+ */
64
+ readUInt16LEAt(offset: number): number | null;
65
+ /**
66
+ * Read UInt32 (little-endian) at offset without consuming
67
+ * Returns null if not enough data
68
+ */
69
+ readUInt32LEAt(offset: number): number | null;
70
+ /**
71
+ * Read bytes at offset without consuming.
72
+ * Returns a slice (zero-copy) when data fits within a single chunk,
73
+ * otherwise allocates and copies from multiple chunks.
74
+ */
75
+ readBytesAt(offset: number, length: number): Buffer;
60
76
  }
@@ -57,4 +57,20 @@ export default class BufferList {
57
57
  * Note: This creates a copy, so use sparingly for large buffers
58
58
  */
59
59
  toBuffer(): Buffer;
60
+ /**
61
+ * Read UInt16 (little-endian) at offset without consuming
62
+ * Returns null if not enough data
63
+ */
64
+ readUInt16LEAt(offset: number): number | null;
65
+ /**
66
+ * Read UInt32 (little-endian) at offset without consuming
67
+ * Returns null if not enough data
68
+ */
69
+ readUInt32LEAt(offset: number): number | null;
70
+ /**
71
+ * Read bytes at offset without consuming.
72
+ * Returns a slice (zero-copy) when data fits within a single chunk,
73
+ * otherwise allocates and copies from multiple chunks.
74
+ */
75
+ readBytesAt(offset: number, length: number): Buffer;
60
76
  }
@@ -202,6 +202,61 @@ var BufferList = /*#__PURE__*/ function() {
202
202
  if (this.length === 0) return (0, _extractbaseiterator.allocBuffer)(0);
203
203
  return this.slice(0, this.length);
204
204
  };
205
+ /**
206
+ * Read UInt16 (little-endian) at offset without consuming
207
+ * Returns null if not enough data
208
+ */ _proto.readUInt16LEAt = function readUInt16LEAt(offset) {
209
+ if (offset < 0 || offset + 2 > this.length) return null;
210
+ var bytes = this.readBytesAt(offset, 2);
211
+ if (bytes.length < 2) return null;
212
+ return bytes.readUInt16LE(0);
213
+ };
214
+ /**
215
+ * Read UInt32 (little-endian) at offset without consuming
216
+ * Returns null if not enough data
217
+ */ _proto.readUInt32LEAt = function readUInt32LEAt(offset) {
218
+ if (offset < 0 || offset + 4 > this.length) return null;
219
+ var bytes = this.readBytesAt(offset, 4);
220
+ if (bytes.length < 4) return null;
221
+ return bytes.readUInt32LE(0);
222
+ };
223
+ /**
224
+ * Read bytes at offset without consuming.
225
+ * Returns a slice (zero-copy) when data fits within a single chunk,
226
+ * otherwise allocates and copies from multiple chunks.
227
+ */ _proto.readBytesAt = function readBytesAt(offset, length) {
228
+ if (length <= 0) return (0, _extractbaseiterator.allocBuffer)(0);
229
+ if (offset < 0 || offset >= this.length) return (0, _extractbaseiterator.allocBuffer)(0);
230
+ // Clamp length to available data
231
+ var available = this.length - offset;
232
+ if (length > available) length = available;
233
+ // Find the node containing the offset
234
+ var bufOffset = 0;
235
+ var node = this.head;
236
+ while(node && bufOffset + node.data.length <= offset){
237
+ bufOffset += node.data.length;
238
+ node = node.next;
239
+ }
240
+ if (!node) return (0, _extractbaseiterator.allocBuffer)(0);
241
+ var startInChunk = offset - bufOffset;
242
+ // Single-buffer optimization: zero-copy slice
243
+ if (startInChunk + length <= node.data.length) {
244
+ return node.data.slice(startInChunk, startInChunk + length);
245
+ }
246
+ // Multi-buffer case: must allocate and copy
247
+ var result = (0, _extractbaseiterator.allocBuffer)(length);
248
+ var resultOffset = 0;
249
+ while(node && resultOffset < length){
250
+ var chunk = node.data;
251
+ var chunkStart = resultOffset === 0 ? startInChunk : 0;
252
+ var chunkAvailable = chunk.length - chunkStart;
253
+ var toCopy = Math.min(chunkAvailable, length - resultOffset);
254
+ chunk.copy(result, resultOffset, chunkStart, chunkStart + toCopy);
255
+ resultOffset += toCopy;
256
+ node = node.next;
257
+ }
258
+ return result;
259
+ };
205
260
  return BufferList;
206
261
  }();
207
262
  /* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/extract-base-iterator/src/shared/BufferList.ts"],"sourcesContent":["/**\n * Buffer List for Streaming\n *\n * Simple linked list for accumulating buffer chunks during streaming.\n * Provides efficient append, consume, and slice operations.\n */\n\nimport { allocBuffer } from 'extract-base-iterator';\n\ninterface BufferNode {\n data: Buffer;\n next: BufferNode | null;\n}\n\nexport default class BufferList {\n private head: BufferNode | null = null;\n private tail: BufferNode | null = null;\n\n /** Total bytes in the buffer list */\n public length = 0;\n\n /**\n * Append a buffer to the end of the list\n */\n append(buf: Buffer): void {\n if (buf.length === 0) return;\n\n const node: BufferNode = { data: buf, next: null };\n\n if (this.tail) {\n this.tail.next = node;\n this.tail = node;\n } else {\n this.head = this.tail = node;\n }\n\n this.length += buf.length;\n }\n\n /**\n * Prepend a buffer to the front of the list\n */\n prepend(buf: Buffer): void {\n if (buf.length === 0) return;\n\n const node: BufferNode = { data: buf, next: this.head };\n\n if (!this.tail) {\n this.tail = node;\n }\n this.head = node;\n\n this.length += buf.length;\n }\n\n /**\n * Consume n bytes from the front of the list\n * Returns a new buffer containing the consumed bytes\n */\n consume(n: number): Buffer {\n if (n <= 0) return allocBuffer(0);\n if (n > this.length) n = this.length;\n\n const result = allocBuffer(n);\n let offset = 0;\n\n while (offset < n && this.head) {\n const chunk = this.head.data;\n const needed = n - offset;\n\n if (chunk.length <= needed) {\n // Use entire chunk\n chunk.copy(result, offset);\n offset += chunk.length;\n this.head = this.head.next;\n if (!this.head) this.tail = null;\n } else {\n // Use partial chunk\n chunk.copy(result, offset, 0, needed);\n this.head.data = chunk.slice(needed);\n offset = n;\n }\n }\n\n this.length -= n;\n return result;\n }\n\n /**\n * Get a slice of the buffer without consuming\n * Returns a new buffer containing the bytes\n */\n slice(start: number, end: number): Buffer {\n const len = end - start;\n if (len <= 0) return allocBuffer(0);\n if (start >= this.length) return allocBuffer(0);\n\n const result = allocBuffer(Math.min(len, this.length - start));\n let resultOffset = 0;\n let bufOffset = 0;\n let node = this.head;\n\n // Skip to start position\n while (node && bufOffset + node.data.length <= start) {\n bufOffset += node.data.length;\n node = node.next;\n }\n\n // Copy data\n while (node && resultOffset < result.length) {\n const chunk = node.data;\n const chunkStart = Math.max(0, start - bufOffset);\n const chunkEnd = Math.min(chunk.length, end - bufOffset);\n const toCopy = chunkEnd - chunkStart;\n\n if (toCopy > 0) {\n chunk.copy(result, resultOffset, chunkStart, chunkEnd);\n resultOffset += toCopy;\n }\n\n bufOffset += chunk.length;\n node = node.next;\n }\n\n return result;\n }\n\n /**\n * Read a single byte at offset without consuming\n */\n readByte(offset: number): number {\n if (offset < 0 || offset >= this.length) return -1;\n\n let bufOffset = 0;\n let node = this.head;\n\n while (node) {\n if (offset < bufOffset + node.data.length) {\n return node.data[offset - bufOffset];\n }\n bufOffset += node.data.length;\n node = node.next;\n }\n\n return -1;\n }\n\n /**\n * Search for a byte sequence in the buffer\n * Returns offset of first match, or -1 if not found\n */\n indexOf(signature: number[], startOffset = 0): number {\n if (signature.length === 0) return startOffset;\n if (startOffset + signature.length > this.length) return -1;\n\n // Simple byte-by-byte search\n // Could be optimized with KMP/Boyer-Moore for larger signatures\n for (let i = startOffset; i <= this.length - signature.length; i++) {\n let match = true;\n for (let j = 0; j < signature.length; j++) {\n if (this.readByte(i + j) !== signature[j]) {\n match = false;\n break;\n }\n }\n if (match) return i;\n }\n\n return -1;\n }\n\n /**\n * Skip (consume) n bytes without returning them\n */\n skip(n: number): void {\n if (n <= 0) return;\n if (n >= this.length) {\n this.clear();\n return;\n }\n\n let remaining = n;\n\n while (remaining > 0 && this.head) {\n const chunk = this.head.data;\n\n if (chunk.length <= remaining) {\n remaining -= chunk.length;\n this.head = this.head.next;\n if (!this.head) this.tail = null;\n } else {\n this.head.data = chunk.slice(remaining);\n remaining = 0;\n }\n }\n\n this.length -= n;\n }\n\n /**\n * Clear all buffers\n */\n clear(): void {\n this.head = null;\n this.tail = null;\n this.length = 0;\n }\n\n /**\n * Check if buffer has at least n bytes available\n */\n has(n: number): boolean {\n return this.length >= n;\n }\n\n /**\n * Check if the buffer starts with a signature at offset 0\n */\n startsWith(signature: number[]): boolean {\n if (signature.length > this.length) return false;\n for (let i = 0; i < signature.length; i++) {\n if (this.readByte(i) !== signature[i]) return false;\n }\n return true;\n }\n\n /**\n * Get a consolidated buffer of the entire contents\n * Note: This creates a copy, so use sparingly for large buffers\n */\n toBuffer(): Buffer {\n if (this.length === 0) return allocBuffer(0);\n return this.slice(0, this.length);\n }\n}\n"],"names":["BufferList","head","tail","length","append","buf","node","data","next","prepend","consume","n","allocBuffer","result","offset","chunk","needed","copy","slice","start","end","len","Math","min","resultOffset","bufOffset","chunkStart","max","chunkEnd","toCopy","readByte","indexOf","signature","startOffset","i","match","j","skip","clear","remaining","has","startsWith","toBuffer"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/extract-base-iterator/src/shared/BufferList.ts"],"sourcesContent":["/**\n * Buffer List for Streaming\n *\n * Simple linked list for accumulating buffer chunks during streaming.\n * Provides efficient append, consume, and slice operations.\n */\n\nimport { allocBuffer } from 'extract-base-iterator';\n\ninterface BufferNode {\n data: Buffer;\n next: BufferNode | null;\n}\n\nexport default class BufferList {\n private head: BufferNode | null = null;\n private tail: BufferNode | null = null;\n\n /** Total bytes in the buffer list */\n public length = 0;\n\n /**\n * Append a buffer to the end of the list\n */\n append(buf: Buffer): void {\n if (buf.length === 0) return;\n\n const node: BufferNode = { data: buf, next: null };\n\n if (this.tail) {\n this.tail.next = node;\n this.tail = node;\n } else {\n this.head = this.tail = node;\n }\n\n this.length += buf.length;\n }\n\n /**\n * Prepend a buffer to the front of the list\n */\n prepend(buf: Buffer): void {\n if (buf.length === 0) return;\n\n const node: BufferNode = { data: buf, next: this.head };\n\n if (!this.tail) {\n this.tail = node;\n }\n this.head = node;\n\n this.length += buf.length;\n }\n\n /**\n * Consume n bytes from the front of the list\n * Returns a new buffer containing the consumed bytes\n */\n consume(n: number): Buffer {\n if (n <= 0) return allocBuffer(0);\n if (n > this.length) n = this.length;\n\n const result = allocBuffer(n);\n let offset = 0;\n\n while (offset < n && this.head) {\n const chunk = this.head.data;\n const needed = n - offset;\n\n if (chunk.length <= needed) {\n // Use entire chunk\n chunk.copy(result, offset);\n offset += chunk.length;\n this.head = this.head.next;\n if (!this.head) this.tail = null;\n } else {\n // Use partial chunk\n chunk.copy(result, offset, 0, needed);\n this.head.data = chunk.slice(needed);\n offset = n;\n }\n }\n\n this.length -= n;\n return result;\n }\n\n /**\n * Get a slice of the buffer without consuming\n * Returns a new buffer containing the bytes\n */\n slice(start: number, end: number): Buffer {\n const len = end - start;\n if (len <= 0) return allocBuffer(0);\n if (start >= this.length) return allocBuffer(0);\n\n const result = allocBuffer(Math.min(len, this.length - start));\n let resultOffset = 0;\n let bufOffset = 0;\n let node = this.head;\n\n // Skip to start position\n while (node && bufOffset + node.data.length <= start) {\n bufOffset += node.data.length;\n node = node.next;\n }\n\n // Copy data\n while (node && resultOffset < result.length) {\n const chunk = node.data;\n const chunkStart = Math.max(0, start - bufOffset);\n const chunkEnd = Math.min(chunk.length, end - bufOffset);\n const toCopy = chunkEnd - chunkStart;\n\n if (toCopy > 0) {\n chunk.copy(result, resultOffset, chunkStart, chunkEnd);\n resultOffset += toCopy;\n }\n\n bufOffset += chunk.length;\n node = node.next;\n }\n\n return result;\n }\n\n /**\n * Read a single byte at offset without consuming\n */\n readByte(offset: number): number {\n if (offset < 0 || offset >= this.length) return -1;\n\n let bufOffset = 0;\n let node = this.head;\n\n while (node) {\n if (offset < bufOffset + node.data.length) {\n return node.data[offset - bufOffset];\n }\n bufOffset += node.data.length;\n node = node.next;\n }\n\n return -1;\n }\n\n /**\n * Search for a byte sequence in the buffer\n * Returns offset of first match, or -1 if not found\n */\n indexOf(signature: number[], startOffset = 0): number {\n if (signature.length === 0) return startOffset;\n if (startOffset + signature.length > this.length) return -1;\n\n // Simple byte-by-byte search\n // Could be optimized with KMP/Boyer-Moore for larger signatures\n for (let i = startOffset; i <= this.length - signature.length; i++) {\n let match = true;\n for (let j = 0; j < signature.length; j++) {\n if (this.readByte(i + j) !== signature[j]) {\n match = false;\n break;\n }\n }\n if (match) return i;\n }\n\n return -1;\n }\n\n /**\n * Skip (consume) n bytes without returning them\n */\n skip(n: number): void {\n if (n <= 0) return;\n if (n >= this.length) {\n this.clear();\n return;\n }\n\n let remaining = n;\n\n while (remaining > 0 && this.head) {\n const chunk = this.head.data;\n\n if (chunk.length <= remaining) {\n remaining -= chunk.length;\n this.head = this.head.next;\n if (!this.head) this.tail = null;\n } else {\n this.head.data = chunk.slice(remaining);\n remaining = 0;\n }\n }\n\n this.length -= n;\n }\n\n /**\n * Clear all buffers\n */\n clear(): void {\n this.head = null;\n this.tail = null;\n this.length = 0;\n }\n\n /**\n * Check if buffer has at least n bytes available\n */\n has(n: number): boolean {\n return this.length >= n;\n }\n\n /**\n * Check if the buffer starts with a signature at offset 0\n */\n startsWith(signature: number[]): boolean {\n if (signature.length > this.length) return false;\n for (let i = 0; i < signature.length; i++) {\n if (this.readByte(i) !== signature[i]) return false;\n }\n return true;\n }\n\n /**\n * Get a consolidated buffer of the entire contents\n * Note: This creates a copy, so use sparingly for large buffers\n */\n toBuffer(): Buffer {\n if (this.length === 0) return allocBuffer(0);\n return this.slice(0, this.length);\n }\n\n /**\n * Read UInt16 (little-endian) at offset without consuming\n * Returns null if not enough data\n */\n readUInt16LEAt(offset: number): number | null {\n if (offset < 0 || offset + 2 > this.length) return null;\n\n const bytes = this.readBytesAt(offset, 2);\n if (bytes.length < 2) return null;\n\n return bytes.readUInt16LE(0);\n }\n\n /**\n * Read UInt32 (little-endian) at offset without consuming\n * Returns null if not enough data\n */\n readUInt32LEAt(offset: number): number | null {\n if (offset < 0 || offset + 4 > this.length) return null;\n\n const bytes = this.readBytesAt(offset, 4);\n if (bytes.length < 4) return null;\n\n return bytes.readUInt32LE(0);\n }\n\n /**\n * Read bytes at offset without consuming.\n * Returns a slice (zero-copy) when data fits within a single chunk,\n * otherwise allocates and copies from multiple chunks.\n */\n readBytesAt(offset: number, length: number): Buffer {\n if (length <= 0) return allocBuffer(0);\n if (offset < 0 || offset >= this.length) return allocBuffer(0);\n\n // Clamp length to available data\n const available = this.length - offset;\n if (length > available) length = available;\n\n // Find the node containing the offset\n let bufOffset = 0;\n let node = this.head;\n while (node && bufOffset + node.data.length <= offset) {\n bufOffset += node.data.length;\n node = node.next;\n }\n\n if (!node) return allocBuffer(0);\n\n const startInChunk = offset - bufOffset;\n\n // Single-buffer optimization: zero-copy slice\n if (startInChunk + length <= node.data.length) {\n return node.data.slice(startInChunk, startInChunk + length);\n }\n\n // Multi-buffer case: must allocate and copy\n const result = allocBuffer(length);\n let resultOffset = 0;\n\n while (node && resultOffset < length) {\n const chunk = node.data;\n const chunkStart = resultOffset === 0 ? startInChunk : 0;\n const chunkAvailable = chunk.length - chunkStart;\n const toCopy = Math.min(chunkAvailable, length - resultOffset);\n\n chunk.copy(result, resultOffset, chunkStart, chunkStart + toCopy);\n resultOffset += toCopy;\n\n node = node.next;\n }\n\n return result;\n }\n}\n"],"names":["BufferList","head","tail","length","append","buf","node","data","next","prepend","consume","n","allocBuffer","result","offset","chunk","needed","copy","slice","start","end","len","Math","min","resultOffset","bufOffset","chunkStart","max","chunkEnd","toCopy","readByte","indexOf","signature","startOffset","i","match","j","skip","clear","remaining","has","startsWith","toBuffer","readUInt16LEAt","bytes","readBytesAt","readUInt16LE","readUInt32LEAt","readUInt32LE","available","startInChunk","chunkAvailable"],"mappings":"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"}
@@ -8,7 +8,6 @@ Object.defineProperty(exports, "default", {
8
8
  return stripPath;
9
9
  }
10
10
  });
11
- var _lodashcompact = /*#__PURE__*/ _interop_require_default(require("lodash.compact"));
12
11
  var _path = /*#__PURE__*/ _interop_require_default(require("path"));
13
12
  function _interop_require_default(obj) {
14
13
  return obj && obj.__esModule ? obj : {
@@ -18,7 +17,7 @@ function _interop_require_default(obj) {
18
17
  function stripPath(relativePath, options) {
19
18
  var strip = options.strip || 0;
20
19
  if (!strip) return relativePath;
21
- var parts = (0, _lodashcompact.default)(relativePath.split(_path.default.sep));
20
+ var parts = relativePath.split(_path.default.sep).filter(Boolean);
22
21
  if (parts.length < strip) throw new Error("You cannot strip more levels than there are directories. Strip: ".concat(strip, ". Path: ").concat(relativePath));
23
22
  return parts.slice(strip).join(_path.default.sep);
24
23
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/extract-base-iterator/src/shared/stripPath.ts"],"sourcesContent":["import compact from 'lodash.compact';\nimport path from 'path';\n\nimport type { ExtractOptions } from '../types.ts';\n\nexport default function stripPath(relativePath: string, options: ExtractOptions): string {\n const strip = options.strip || 0;\n if (!strip) return relativePath;\n const parts = compact(relativePath.split(path.sep));\n if (parts.length < strip) throw new Error(`You cannot strip more levels than there are directories. Strip: ${strip}. Path: ${relativePath}`);\n return parts.slice(strip).join(path.sep);\n}\n"],"names":["stripPath","relativePath","options","strip","parts","compact","split","path","sep","length","Error","slice","join"],"mappings":";;;;+BAKA;;;eAAwBA;;;oEALJ;2DACH;;;;;;AAIF,SAASA,UAAUC,YAAoB,EAAEC,OAAuB;IAC7E,IAAMC,QAAQD,QAAQC,KAAK,IAAI;IAC/B,IAAI,CAACA,OAAO,OAAOF;IACnB,IAAMG,QAAQC,IAAAA,sBAAO,EAACJ,aAAaK,KAAK,CAACC,aAAI,CAACC,GAAG;IACjD,IAAIJ,MAAMK,MAAM,GAAGN,OAAO,MAAM,IAAIO,MAAM,AAAC,mEAAkFT,OAAhBE,OAAM,YAAuB,OAAbF;IAC7H,OAAOG,MAAMO,KAAK,CAACR,OAAOS,IAAI,CAACL,aAAI,CAACC,GAAG;AACzC"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/extract-base-iterator/src/shared/stripPath.ts"],"sourcesContent":["import path from 'path';\n\nimport type { ExtractOptions } from '../types.ts';\n\nexport default function stripPath(relativePath: string, options: ExtractOptions): string {\n const strip = options.strip || 0;\n if (!strip) return relativePath;\n const parts = relativePath.split(path.sep).filter(Boolean);\n if (parts.length < strip) throw new Error(`You cannot strip more levels than there are directories. Strip: ${strip}. Path: ${relativePath}`);\n return parts.slice(strip).join(path.sep);\n}\n"],"names":["stripPath","relativePath","options","strip","parts","split","path","sep","filter","Boolean","length","Error","slice","join"],"mappings":";;;;+BAIA;;;eAAwBA;;;2DAJP;;;;;;AAIF,SAASA,UAAUC,YAAoB,EAAEC,OAAuB;IAC7E,IAAMC,QAAQD,QAAQC,KAAK,IAAI;IAC/B,IAAI,CAACA,OAAO,OAAOF;IACnB,IAAMG,QAAQH,aAAaI,KAAK,CAACC,aAAI,CAACC,GAAG,EAAEC,MAAM,CAACC;IAClD,IAAIL,MAAMM,MAAM,GAAGP,OAAO,MAAM,IAAIQ,MAAM,AAAC,mEAAkFV,OAAhBE,OAAM,YAAuB,OAAbF;IAC7H,OAAOG,MAAMQ,KAAK,CAACT,OAAOU,IAAI,CAACP,aAAI,CAACC,GAAG;AACzC"}
@@ -1,2 +1,2 @@
1
1
  import type { NoParamCallback } from './types.js';
2
- export default function waitForAccess(fullPath: string, noFollowOrCallback: boolean | NoParamCallback, callbackOrAttempts?: NoParamCallback | number, attempts?: number): NodeJS.Timeout;
2
+ export default function waitForAccess(fullPath: string, noFollowOrCallback: boolean | NoParamCallback, callbackOrAttempts?: NoParamCallback | number, attempts?: number): void;
@@ -1,2 +1,2 @@
1
1
  import type { NoParamCallback } from './types.js';
2
- export default function waitForAccess(fullPath: string, noFollowOrCallback: boolean | NoParamCallback, callbackOrAttempts?: NoParamCallback | number, attempts?: number): NodeJS.Timeout;
2
+ export default function waitForAccess(fullPath: string, noFollowOrCallback: boolean | NoParamCallback, callbackOrAttempts?: NoParamCallback | number, attempts?: number): void;
@@ -32,8 +32,8 @@ function waitForAccess(fullPath, noFollowOrCallback, callbackOrAttempts) {
32
32
  callback = callbackOrAttempts;
33
33
  }
34
34
  // POSIX: finish event is reliable after decompression stream fixes
35
- // Use setTimeout(0) to maintain async consistency (avoid Zalgo)
36
- if (!isWindows) return setTimeout(callback, 0);
35
+ // Avoid Zalgo: ensure callback is always async for consistent API
36
+ if (!isWindows) return process.nextTick(callback);
37
37
  // Windows: NTFS metadata may not be committed yet, verify accessibility
38
38
  // For symlinks (noFollow=true), use lstat to check the link itself exists
39
39
  // For files/dirs/hardlinks, use open to verify the file is accessible
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/extract-base-iterator/src/waitForAccess.ts"],"sourcesContent":["import fs from 'fs';\n\nimport type { NoParamCallback } from './types.ts';\n\nconst isWindows = process.platform === 'win32' || /^(msys|cygwin)$/.test(process.env.OSTYPE);\n\n// Backward compatible: waitForAccess(path, callback) or waitForAccess(path, noFollow, callback)\nexport default function waitForAccess(fullPath: string, noFollowOrCallback: boolean | NoParamCallback, callbackOrAttempts?: NoParamCallback | number, attempts = 0) {\n // Parse arguments for backward compatibility\n let noFollow: boolean;\n let callback: NoParamCallback;\n if (typeof noFollowOrCallback === 'function') {\n // Old signature: waitForAccess(path, callback, attempts?)\n noFollow = false;\n callback = noFollowOrCallback;\n attempts = (callbackOrAttempts as number) || 0;\n } else {\n // New signature: waitForAccess(path, noFollow, callback, attempts?)\n noFollow = noFollowOrCallback;\n callback = callbackOrAttempts as NoParamCallback;\n }\n\n // POSIX: finish event is reliable after decompression stream fixes\n // Use setTimeout(0) to maintain async consistency (avoid Zalgo)\n if (!isWindows) return setTimeout(callback, 0);\n\n // Windows: NTFS metadata may not be committed yet, verify accessibility\n // For symlinks (noFollow=true), use lstat to check the link itself exists\n // For files/dirs/hardlinks, use open to verify the file is accessible\n if (noFollow) {\n fs.lstat(fullPath, (err) => {\n if (err) {\n if (err.code === 'ENOENT' && attempts < 10) {\n const delay = Math.min(5 * 2 ** attempts, 2560);\n return setTimeout(() => waitForAccess(fullPath, noFollow, callback, attempts + 1), delay);\n }\n return callback(err);\n }\n callback();\n });\n } else {\n fs.open(fullPath, 'r', (err, fd) => {\n if (err) {\n if (err.code === 'ENOENT' && attempts < 10) {\n // Exponential backoff: 5, 10, 20, 40, 80, 160, 320, 640, 1280, 2560ms\n // Total max wait: ~5 seconds\n const delay = Math.min(5 * 2 ** attempts, 2560);\n return setTimeout(() => waitForAccess(fullPath, noFollow, callback, attempts + 1), delay);\n }\n return callback(err);\n }\n fs.close(fd, () => callback());\n });\n }\n}\n"],"names":["waitForAccess","isWindows","process","platform","test","env","OSTYPE","fullPath","noFollowOrCallback","callbackOrAttempts","attempts","noFollow","callback","setTimeout","fs","lstat","err","code","delay","Math","min","open","fd","close"],"mappings":";;;;+BAMA,gGAAgG;AAChG;;;eAAwBA;;;yDAPT;;;;;;AAIf,IAAMC,YAAYC,QAAQC,QAAQ,KAAK,WAAW,kBAAkBC,IAAI,CAACF,QAAQG,GAAG,CAACC,MAAM;AAG5E,SAASN,cAAcO,QAAgB,EAAEC,kBAA6C,EAAEC,kBAA6C;QAAEC,WAAAA,iEAAW;IAC/J,6CAA6C;IAC7C,IAAIC;IACJ,IAAIC;IACJ,IAAI,OAAOJ,uBAAuB,YAAY;QAC5C,0DAA0D;QAC1DG,WAAW;QACXC,WAAWJ;QACXE,WAAW,AAACD,sBAAiC;IAC/C,OAAO;QACL,oEAAoE;QACpEE,WAAWH;QACXI,WAAWH;IACb;IAEA,mEAAmE;IACnE,gEAAgE;IAChE,IAAI,CAACR,WAAW,OAAOY,WAAWD,UAAU;IAE5C,wEAAwE;IACxE,0EAA0E;IAC1E,sEAAsE;IACtE,IAAID,UAAU;QACZG,WAAE,CAACC,KAAK,CAACR,UAAU,SAACS;YAClB,IAAIA,KAAK;gBACP,IAAIA,IAAIC,IAAI,KAAK,YAAYP,WAAW,IAAI;oBAC1C,IAAMQ,QAAQC,KAAKC,GAAG,CAAC,aAAI,GAAKV,WAAU;oBAC1C,OAAOG,WAAW;+BAAMb,cAAcO,UAAUI,UAAUC,UAAUF,WAAW;uBAAIQ;gBACrF;gBACA,OAAON,SAASI;YAClB;YACAJ;QACF;IACF,OAAO;QACLE,WAAE,CAACO,IAAI,CAACd,UAAU,KAAK,SAACS,KAAKM;YAC3B,IAAIN,KAAK;gBACP,IAAIA,IAAIC,IAAI,KAAK,YAAYP,WAAW,IAAI;oBAC1C,sEAAsE;oBACtE,6BAA6B;oBAC7B,IAAMQ,QAAQC,KAAKC,GAAG,CAAC,aAAI,GAAKV,WAAU;oBAC1C,OAAOG,WAAW;+BAAMb,cAAcO,UAAUI,UAAUC,UAAUF,WAAW;uBAAIQ;gBACrF;gBACA,OAAON,SAASI;YAClB;YACAF,WAAE,CAACS,KAAK,CAACD,IAAI;uBAAMV;;QACrB;IACF;AACF"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/extract-base-iterator/src/waitForAccess.ts"],"sourcesContent":["import fs from 'fs';\n\nimport type { NoParamCallback } from './types.ts';\n\nconst isWindows = process.platform === 'win32' || /^(msys|cygwin)$/.test(process.env.OSTYPE);\n\n// Backward compatible: waitForAccess(path, callback) or waitForAccess(path, noFollow, callback)\nexport default function waitForAccess(fullPath: string, noFollowOrCallback: boolean | NoParamCallback, callbackOrAttempts?: NoParamCallback | number, attempts = 0) {\n // Parse arguments for backward compatibility\n let noFollow: boolean;\n let callback: NoParamCallback;\n if (typeof noFollowOrCallback === 'function') {\n // Old signature: waitForAccess(path, callback, attempts?)\n noFollow = false;\n callback = noFollowOrCallback;\n attempts = (callbackOrAttempts as number) || 0;\n } else {\n // New signature: waitForAccess(path, noFollow, callback, attempts?)\n noFollow = noFollowOrCallback;\n callback = callbackOrAttempts as NoParamCallback;\n }\n\n // POSIX: finish event is reliable after decompression stream fixes\n // Avoid Zalgo: ensure callback is always async for consistent API\n if (!isWindows) return process.nextTick(callback);\n\n // Windows: NTFS metadata may not be committed yet, verify accessibility\n // For symlinks (noFollow=true), use lstat to check the link itself exists\n // For files/dirs/hardlinks, use open to verify the file is accessible\n if (noFollow) {\n fs.lstat(fullPath, (err) => {\n if (err) {\n if (err.code === 'ENOENT' && attempts < 10) {\n const delay = Math.min(5 * 2 ** attempts, 2560);\n return setTimeout(() => waitForAccess(fullPath, noFollow, callback, attempts + 1), delay);\n }\n return callback(err);\n }\n callback();\n });\n } else {\n fs.open(fullPath, 'r', (err, fd) => {\n if (err) {\n if (err.code === 'ENOENT' && attempts < 10) {\n // Exponential backoff: 5, 10, 20, 40, 80, 160, 320, 640, 1280, 2560ms\n // Total max wait: ~5 seconds\n const delay = Math.min(5 * 2 ** attempts, 2560);\n return setTimeout(() => waitForAccess(fullPath, noFollow, callback, attempts + 1), delay);\n }\n return callback(err);\n }\n fs.close(fd, () => callback());\n });\n }\n}\n"],"names":["waitForAccess","isWindows","process","platform","test","env","OSTYPE","fullPath","noFollowOrCallback","callbackOrAttempts","attempts","noFollow","callback","nextTick","fs","lstat","err","code","delay","Math","min","setTimeout","open","fd","close"],"mappings":";;;;+BAMA,gGAAgG;AAChG;;;eAAwBA;;;yDAPT;;;;;;AAIf,IAAMC,YAAYC,QAAQC,QAAQ,KAAK,WAAW,kBAAkBC,IAAI,CAACF,QAAQG,GAAG,CAACC,MAAM;AAG5E,SAASN,cAAcO,QAAgB,EAAEC,kBAA6C,EAAEC,kBAA6C;QAAEC,WAAAA,iEAAW;IAC/J,6CAA6C;IAC7C,IAAIC;IACJ,IAAIC;IACJ,IAAI,OAAOJ,uBAAuB,YAAY;QAC5C,0DAA0D;QAC1DG,WAAW;QACXC,WAAWJ;QACXE,WAAW,AAACD,sBAAiC;IAC/C,OAAO;QACL,oEAAoE;QACpEE,WAAWH;QACXI,WAAWH;IACb;IAEA,mEAAmE;IACnE,kEAAkE;IAClE,IAAI,CAACR,WAAW,OAAOC,QAAQW,QAAQ,CAACD;IAExC,wEAAwE;IACxE,0EAA0E;IAC1E,sEAAsE;IACtE,IAAID,UAAU;QACZG,WAAE,CAACC,KAAK,CAACR,UAAU,SAACS;YAClB,IAAIA,KAAK;gBACP,IAAIA,IAAIC,IAAI,KAAK,YAAYP,WAAW,IAAI;oBAC1C,IAAMQ,QAAQC,KAAKC,GAAG,CAAC,aAAI,GAAKV,WAAU;oBAC1C,OAAOW,WAAW;+BAAMrB,cAAcO,UAAUI,UAAUC,UAAUF,WAAW;uBAAIQ;gBACrF;gBACA,OAAON,SAASI;YAClB;YACAJ;QACF;IACF,OAAO;QACLE,WAAE,CAACQ,IAAI,CAACf,UAAU,KAAK,SAACS,KAAKO;YAC3B,IAAIP,KAAK;gBACP,IAAIA,IAAIC,IAAI,KAAK,YAAYP,WAAW,IAAI;oBAC1C,sEAAsE;oBACtE,6BAA6B;oBAC7B,IAAMQ,QAAQC,KAAKC,GAAG,CAAC,aAAI,GAAKV,WAAU;oBAC1C,OAAOW,WAAW;+BAAMrB,cAAcO,UAAUI,UAAUC,UAAUF,WAAW;uBAAIQ;gBACrF;gBACA,OAAON,SAASI;YAClB;YACAF,WAAE,CAACU,KAAK,CAACD,IAAI;uBAAMX;;QACrB;IACF;AACF"}
@@ -57,4 +57,20 @@ export default class BufferList {
57
57
  * Note: This creates a copy, so use sparingly for large buffers
58
58
  */
59
59
  toBuffer(): Buffer;
60
+ /**
61
+ * Read UInt16 (little-endian) at offset without consuming
62
+ * Returns null if not enough data
63
+ */
64
+ readUInt16LEAt(offset: number): number | null;
65
+ /**
66
+ * Read UInt32 (little-endian) at offset without consuming
67
+ * Returns null if not enough data
68
+ */
69
+ readUInt32LEAt(offset: number): number | null;
70
+ /**
71
+ * Read bytes at offset without consuming.
72
+ * Returns a slice (zero-copy) when data fits within a single chunk,
73
+ * otherwise allocates and copies from multiple chunks.
74
+ */
75
+ readBytesAt(offset: number, length: number): Buffer;
60
76
  }
@@ -178,6 +178,61 @@ let BufferList = class BufferList {
178
178
  if (this.length === 0) return allocBuffer(0);
179
179
  return this.slice(0, this.length);
180
180
  }
181
+ /**
182
+ * Read UInt16 (little-endian) at offset without consuming
183
+ * Returns null if not enough data
184
+ */ readUInt16LEAt(offset) {
185
+ if (offset < 0 || offset + 2 > this.length) return null;
186
+ const bytes = this.readBytesAt(offset, 2);
187
+ if (bytes.length < 2) return null;
188
+ return bytes.readUInt16LE(0);
189
+ }
190
+ /**
191
+ * Read UInt32 (little-endian) at offset without consuming
192
+ * Returns null if not enough data
193
+ */ readUInt32LEAt(offset) {
194
+ if (offset < 0 || offset + 4 > this.length) return null;
195
+ const bytes = this.readBytesAt(offset, 4);
196
+ if (bytes.length < 4) return null;
197
+ return bytes.readUInt32LE(0);
198
+ }
199
+ /**
200
+ * Read bytes at offset without consuming.
201
+ * Returns a slice (zero-copy) when data fits within a single chunk,
202
+ * otherwise allocates and copies from multiple chunks.
203
+ */ readBytesAt(offset, length) {
204
+ if (length <= 0) return allocBuffer(0);
205
+ if (offset < 0 || offset >= this.length) return allocBuffer(0);
206
+ // Clamp length to available data
207
+ const available = this.length - offset;
208
+ if (length > available) length = available;
209
+ // Find the node containing the offset
210
+ let bufOffset = 0;
211
+ let node = this.head;
212
+ while(node && bufOffset + node.data.length <= offset){
213
+ bufOffset += node.data.length;
214
+ node = node.next;
215
+ }
216
+ if (!node) return allocBuffer(0);
217
+ const startInChunk = offset - bufOffset;
218
+ // Single-buffer optimization: zero-copy slice
219
+ if (startInChunk + length <= node.data.length) {
220
+ return node.data.slice(startInChunk, startInChunk + length);
221
+ }
222
+ // Multi-buffer case: must allocate and copy
223
+ const result = allocBuffer(length);
224
+ let resultOffset = 0;
225
+ while(node && resultOffset < length){
226
+ const chunk = node.data;
227
+ const chunkStart = resultOffset === 0 ? startInChunk : 0;
228
+ const chunkAvailable = chunk.length - chunkStart;
229
+ const toCopy = Math.min(chunkAvailable, length - resultOffset);
230
+ chunk.copy(result, resultOffset, chunkStart, chunkStart + toCopy);
231
+ resultOffset += toCopy;
232
+ node = node.next;
233
+ }
234
+ return result;
235
+ }
181
236
  constructor(){
182
237
  this.head = null;
183
238
  this.tail = null;
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/extract-base-iterator/src/shared/BufferList.ts"],"sourcesContent":["/**\n * Buffer List for Streaming\n *\n * Simple linked list for accumulating buffer chunks during streaming.\n * Provides efficient append, consume, and slice operations.\n */\n\nimport { allocBuffer } from 'extract-base-iterator';\n\ninterface BufferNode {\n data: Buffer;\n next: BufferNode | null;\n}\n\nexport default class BufferList {\n private head: BufferNode | null = null;\n private tail: BufferNode | null = null;\n\n /** Total bytes in the buffer list */\n public length = 0;\n\n /**\n * Append a buffer to the end of the list\n */\n append(buf: Buffer): void {\n if (buf.length === 0) return;\n\n const node: BufferNode = { data: buf, next: null };\n\n if (this.tail) {\n this.tail.next = node;\n this.tail = node;\n } else {\n this.head = this.tail = node;\n }\n\n this.length += buf.length;\n }\n\n /**\n * Prepend a buffer to the front of the list\n */\n prepend(buf: Buffer): void {\n if (buf.length === 0) return;\n\n const node: BufferNode = { data: buf, next: this.head };\n\n if (!this.tail) {\n this.tail = node;\n }\n this.head = node;\n\n this.length += buf.length;\n }\n\n /**\n * Consume n bytes from the front of the list\n * Returns a new buffer containing the consumed bytes\n */\n consume(n: number): Buffer {\n if (n <= 0) return allocBuffer(0);\n if (n > this.length) n = this.length;\n\n const result = allocBuffer(n);\n let offset = 0;\n\n while (offset < n && this.head) {\n const chunk = this.head.data;\n const needed = n - offset;\n\n if (chunk.length <= needed) {\n // Use entire chunk\n chunk.copy(result, offset);\n offset += chunk.length;\n this.head = this.head.next;\n if (!this.head) this.tail = null;\n } else {\n // Use partial chunk\n chunk.copy(result, offset, 0, needed);\n this.head.data = chunk.slice(needed);\n offset = n;\n }\n }\n\n this.length -= n;\n return result;\n }\n\n /**\n * Get a slice of the buffer without consuming\n * Returns a new buffer containing the bytes\n */\n slice(start: number, end: number): Buffer {\n const len = end - start;\n if (len <= 0) return allocBuffer(0);\n if (start >= this.length) return allocBuffer(0);\n\n const result = allocBuffer(Math.min(len, this.length - start));\n let resultOffset = 0;\n let bufOffset = 0;\n let node = this.head;\n\n // Skip to start position\n while (node && bufOffset + node.data.length <= start) {\n bufOffset += node.data.length;\n node = node.next;\n }\n\n // Copy data\n while (node && resultOffset < result.length) {\n const chunk = node.data;\n const chunkStart = Math.max(0, start - bufOffset);\n const chunkEnd = Math.min(chunk.length, end - bufOffset);\n const toCopy = chunkEnd - chunkStart;\n\n if (toCopy > 0) {\n chunk.copy(result, resultOffset, chunkStart, chunkEnd);\n resultOffset += toCopy;\n }\n\n bufOffset += chunk.length;\n node = node.next;\n }\n\n return result;\n }\n\n /**\n * Read a single byte at offset without consuming\n */\n readByte(offset: number): number {\n if (offset < 0 || offset >= this.length) return -1;\n\n let bufOffset = 0;\n let node = this.head;\n\n while (node) {\n if (offset < bufOffset + node.data.length) {\n return node.data[offset - bufOffset];\n }\n bufOffset += node.data.length;\n node = node.next;\n }\n\n return -1;\n }\n\n /**\n * Search for a byte sequence in the buffer\n * Returns offset of first match, or -1 if not found\n */\n indexOf(signature: number[], startOffset = 0): number {\n if (signature.length === 0) return startOffset;\n if (startOffset + signature.length > this.length) return -1;\n\n // Simple byte-by-byte search\n // Could be optimized with KMP/Boyer-Moore for larger signatures\n for (let i = startOffset; i <= this.length - signature.length; i++) {\n let match = true;\n for (let j = 0; j < signature.length; j++) {\n if (this.readByte(i + j) !== signature[j]) {\n match = false;\n break;\n }\n }\n if (match) return i;\n }\n\n return -1;\n }\n\n /**\n * Skip (consume) n bytes without returning them\n */\n skip(n: number): void {\n if (n <= 0) return;\n if (n >= this.length) {\n this.clear();\n return;\n }\n\n let remaining = n;\n\n while (remaining > 0 && this.head) {\n const chunk = this.head.data;\n\n if (chunk.length <= remaining) {\n remaining -= chunk.length;\n this.head = this.head.next;\n if (!this.head) this.tail = null;\n } else {\n this.head.data = chunk.slice(remaining);\n remaining = 0;\n }\n }\n\n this.length -= n;\n }\n\n /**\n * Clear all buffers\n */\n clear(): void {\n this.head = null;\n this.tail = null;\n this.length = 0;\n }\n\n /**\n * Check if buffer has at least n bytes available\n */\n has(n: number): boolean {\n return this.length >= n;\n }\n\n /**\n * Check if the buffer starts with a signature at offset 0\n */\n startsWith(signature: number[]): boolean {\n if (signature.length > this.length) return false;\n for (let i = 0; i < signature.length; i++) {\n if (this.readByte(i) !== signature[i]) return false;\n }\n return true;\n }\n\n /**\n * Get a consolidated buffer of the entire contents\n * Note: This creates a copy, so use sparingly for large buffers\n */\n toBuffer(): Buffer {\n if (this.length === 0) return allocBuffer(0);\n return this.slice(0, this.length);\n }\n}\n"],"names":["allocBuffer","BufferList","append","buf","length","node","data","next","tail","head","prepend","consume","n","result","offset","chunk","needed","copy","slice","start","end","len","Math","min","resultOffset","bufOffset","chunkStart","max","chunkEnd","toCopy","readByte","indexOf","signature","startOffset","i","match","j","skip","clear","remaining","has","startsWith","toBuffer"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/extract-base-iterator/src/shared/BufferList.ts"],"sourcesContent":["/**\n * Buffer List for Streaming\n *\n * Simple linked list for accumulating buffer chunks during streaming.\n * Provides efficient append, consume, and slice operations.\n */\n\nimport { allocBuffer } from 'extract-base-iterator';\n\ninterface BufferNode {\n data: Buffer;\n next: BufferNode | null;\n}\n\nexport default class BufferList {\n private head: BufferNode | null = null;\n private tail: BufferNode | null = null;\n\n /** Total bytes in the buffer list */\n public length = 0;\n\n /**\n * Append a buffer to the end of the list\n */\n append(buf: Buffer): void {\n if (buf.length === 0) return;\n\n const node: BufferNode = { data: buf, next: null };\n\n if (this.tail) {\n this.tail.next = node;\n this.tail = node;\n } else {\n this.head = this.tail = node;\n }\n\n this.length += buf.length;\n }\n\n /**\n * Prepend a buffer to the front of the list\n */\n prepend(buf: Buffer): void {\n if (buf.length === 0) return;\n\n const node: BufferNode = { data: buf, next: this.head };\n\n if (!this.tail) {\n this.tail = node;\n }\n this.head = node;\n\n this.length += buf.length;\n }\n\n /**\n * Consume n bytes from the front of the list\n * Returns a new buffer containing the consumed bytes\n */\n consume(n: number): Buffer {\n if (n <= 0) return allocBuffer(0);\n if (n > this.length) n = this.length;\n\n const result = allocBuffer(n);\n let offset = 0;\n\n while (offset < n && this.head) {\n const chunk = this.head.data;\n const needed = n - offset;\n\n if (chunk.length <= needed) {\n // Use entire chunk\n chunk.copy(result, offset);\n offset += chunk.length;\n this.head = this.head.next;\n if (!this.head) this.tail = null;\n } else {\n // Use partial chunk\n chunk.copy(result, offset, 0, needed);\n this.head.data = chunk.slice(needed);\n offset = n;\n }\n }\n\n this.length -= n;\n return result;\n }\n\n /**\n * Get a slice of the buffer without consuming\n * Returns a new buffer containing the bytes\n */\n slice(start: number, end: number): Buffer {\n const len = end - start;\n if (len <= 0) return allocBuffer(0);\n if (start >= this.length) return allocBuffer(0);\n\n const result = allocBuffer(Math.min(len, this.length - start));\n let resultOffset = 0;\n let bufOffset = 0;\n let node = this.head;\n\n // Skip to start position\n while (node && bufOffset + node.data.length <= start) {\n bufOffset += node.data.length;\n node = node.next;\n }\n\n // Copy data\n while (node && resultOffset < result.length) {\n const chunk = node.data;\n const chunkStart = Math.max(0, start - bufOffset);\n const chunkEnd = Math.min(chunk.length, end - bufOffset);\n const toCopy = chunkEnd - chunkStart;\n\n if (toCopy > 0) {\n chunk.copy(result, resultOffset, chunkStart, chunkEnd);\n resultOffset += toCopy;\n }\n\n bufOffset += chunk.length;\n node = node.next;\n }\n\n return result;\n }\n\n /**\n * Read a single byte at offset without consuming\n */\n readByte(offset: number): number {\n if (offset < 0 || offset >= this.length) return -1;\n\n let bufOffset = 0;\n let node = this.head;\n\n while (node) {\n if (offset < bufOffset + node.data.length) {\n return node.data[offset - bufOffset];\n }\n bufOffset += node.data.length;\n node = node.next;\n }\n\n return -1;\n }\n\n /**\n * Search for a byte sequence in the buffer\n * Returns offset of first match, or -1 if not found\n */\n indexOf(signature: number[], startOffset = 0): number {\n if (signature.length === 0) return startOffset;\n if (startOffset + signature.length > this.length) return -1;\n\n // Simple byte-by-byte search\n // Could be optimized with KMP/Boyer-Moore for larger signatures\n for (let i = startOffset; i <= this.length - signature.length; i++) {\n let match = true;\n for (let j = 0; j < signature.length; j++) {\n if (this.readByte(i + j) !== signature[j]) {\n match = false;\n break;\n }\n }\n if (match) return i;\n }\n\n return -1;\n }\n\n /**\n * Skip (consume) n bytes without returning them\n */\n skip(n: number): void {\n if (n <= 0) return;\n if (n >= this.length) {\n this.clear();\n return;\n }\n\n let remaining = n;\n\n while (remaining > 0 && this.head) {\n const chunk = this.head.data;\n\n if (chunk.length <= remaining) {\n remaining -= chunk.length;\n this.head = this.head.next;\n if (!this.head) this.tail = null;\n } else {\n this.head.data = chunk.slice(remaining);\n remaining = 0;\n }\n }\n\n this.length -= n;\n }\n\n /**\n * Clear all buffers\n */\n clear(): void {\n this.head = null;\n this.tail = null;\n this.length = 0;\n }\n\n /**\n * Check if buffer has at least n bytes available\n */\n has(n: number): boolean {\n return this.length >= n;\n }\n\n /**\n * Check if the buffer starts with a signature at offset 0\n */\n startsWith(signature: number[]): boolean {\n if (signature.length > this.length) return false;\n for (let i = 0; i < signature.length; i++) {\n if (this.readByte(i) !== signature[i]) return false;\n }\n return true;\n }\n\n /**\n * Get a consolidated buffer of the entire contents\n * Note: This creates a copy, so use sparingly for large buffers\n */\n toBuffer(): Buffer {\n if (this.length === 0) return allocBuffer(0);\n return this.slice(0, this.length);\n }\n\n /**\n * Read UInt16 (little-endian) at offset without consuming\n * Returns null if not enough data\n */\n readUInt16LEAt(offset: number): number | null {\n if (offset < 0 || offset + 2 > this.length) return null;\n\n const bytes = this.readBytesAt(offset, 2);\n if (bytes.length < 2) return null;\n\n return bytes.readUInt16LE(0);\n }\n\n /**\n * Read UInt32 (little-endian) at offset without consuming\n * Returns null if not enough data\n */\n readUInt32LEAt(offset: number): number | null {\n if (offset < 0 || offset + 4 > this.length) return null;\n\n const bytes = this.readBytesAt(offset, 4);\n if (bytes.length < 4) return null;\n\n return bytes.readUInt32LE(0);\n }\n\n /**\n * Read bytes at offset without consuming.\n * Returns a slice (zero-copy) when data fits within a single chunk,\n * otherwise allocates and copies from multiple chunks.\n */\n readBytesAt(offset: number, length: number): Buffer {\n if (length <= 0) return allocBuffer(0);\n if (offset < 0 || offset >= this.length) return allocBuffer(0);\n\n // Clamp length to available data\n const available = this.length - offset;\n if (length > available) length = available;\n\n // Find the node containing the offset\n let bufOffset = 0;\n let node = this.head;\n while (node && bufOffset + node.data.length <= offset) {\n bufOffset += node.data.length;\n node = node.next;\n }\n\n if (!node) return allocBuffer(0);\n\n const startInChunk = offset - bufOffset;\n\n // Single-buffer optimization: zero-copy slice\n if (startInChunk + length <= node.data.length) {\n return node.data.slice(startInChunk, startInChunk + length);\n }\n\n // Multi-buffer case: must allocate and copy\n const result = allocBuffer(length);\n let resultOffset = 0;\n\n while (node && resultOffset < length) {\n const chunk = node.data;\n const chunkStart = resultOffset === 0 ? startInChunk : 0;\n const chunkAvailable = chunk.length - chunkStart;\n const toCopy = Math.min(chunkAvailable, length - resultOffset);\n\n chunk.copy(result, resultOffset, chunkStart, chunkStart + toCopy);\n resultOffset += toCopy;\n\n node = node.next;\n }\n\n return result;\n }\n}\n"],"names":["allocBuffer","BufferList","append","buf","length","node","data","next","tail","head","prepend","consume","n","result","offset","chunk","needed","copy","slice","start","end","len","Math","min","resultOffset","bufOffset","chunkStart","max","chunkEnd","toCopy","readByte","indexOf","signature","startOffset","i","match","j","skip","clear","remaining","has","startsWith","toBuffer","readUInt16LEAt","bytes","readBytesAt","readUInt16LE","readUInt32LEAt","readUInt32LE","available","startInChunk","chunkAvailable"],"mappings":"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"}
@@ -1,9 +1,8 @@
1
- import compact from 'lodash.compact';
2
1
  import path from 'path';
3
2
  export default function stripPath(relativePath, options) {
4
3
  const strip = options.strip || 0;
5
4
  if (!strip) return relativePath;
6
- const parts = compact(relativePath.split(path.sep));
5
+ const parts = relativePath.split(path.sep).filter(Boolean);
7
6
  if (parts.length < strip) throw new Error(`You cannot strip more levels than there are directories. Strip: ${strip}. Path: ${relativePath}`);
8
7
  return parts.slice(strip).join(path.sep);
9
8
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/extract-base-iterator/src/shared/stripPath.ts"],"sourcesContent":["import compact from 'lodash.compact';\nimport path from 'path';\n\nimport type { ExtractOptions } from '../types.ts';\n\nexport default function stripPath(relativePath: string, options: ExtractOptions): string {\n const strip = options.strip || 0;\n if (!strip) return relativePath;\n const parts = compact(relativePath.split(path.sep));\n if (parts.length < strip) throw new Error(`You cannot strip more levels than there are directories. Strip: ${strip}. Path: ${relativePath}`);\n return parts.slice(strip).join(path.sep);\n}\n"],"names":["compact","path","stripPath","relativePath","options","strip","parts","split","sep","length","Error","slice","join"],"mappings":"AAAA,OAAOA,aAAa,iBAAiB;AACrC,OAAOC,UAAU,OAAO;AAIxB,eAAe,SAASC,UAAUC,YAAoB,EAAEC,OAAuB;IAC7E,MAAMC,QAAQD,QAAQC,KAAK,IAAI;IAC/B,IAAI,CAACA,OAAO,OAAOF;IACnB,MAAMG,QAAQN,QAAQG,aAAaI,KAAK,CAACN,KAAKO,GAAG;IACjD,IAAIF,MAAMG,MAAM,GAAGJ,OAAO,MAAM,IAAIK,MAAM,CAAC,gEAAgE,EAAEL,MAAM,QAAQ,EAAEF,cAAc;IAC3I,OAAOG,MAAMK,KAAK,CAACN,OAAOO,IAAI,CAACX,KAAKO,GAAG;AACzC"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/extract-base-iterator/src/shared/stripPath.ts"],"sourcesContent":["import path from 'path';\n\nimport type { ExtractOptions } from '../types.ts';\n\nexport default function stripPath(relativePath: string, options: ExtractOptions): string {\n const strip = options.strip || 0;\n if (!strip) return relativePath;\n const parts = relativePath.split(path.sep).filter(Boolean);\n if (parts.length < strip) throw new Error(`You cannot strip more levels than there are directories. Strip: ${strip}. Path: ${relativePath}`);\n return parts.slice(strip).join(path.sep);\n}\n"],"names":["path","stripPath","relativePath","options","strip","parts","split","sep","filter","Boolean","length","Error","slice","join"],"mappings":"AAAA,OAAOA,UAAU,OAAO;AAIxB,eAAe,SAASC,UAAUC,YAAoB,EAAEC,OAAuB;IAC7E,MAAMC,QAAQD,QAAQC,KAAK,IAAI;IAC/B,IAAI,CAACA,OAAO,OAAOF;IACnB,MAAMG,QAAQH,aAAaI,KAAK,CAACN,KAAKO,GAAG,EAAEC,MAAM,CAACC;IAClD,IAAIJ,MAAMK,MAAM,GAAGN,OAAO,MAAM,IAAIO,MAAM,CAAC,gEAAgE,EAAEP,MAAM,QAAQ,EAAEF,cAAc;IAC3I,OAAOG,MAAMO,KAAK,CAACR,OAAOS,IAAI,CAACb,KAAKO,GAAG;AACzC"}
@@ -1,2 +1,2 @@
1
1
  import type { NoParamCallback } from './types.js';
2
- export default function waitForAccess(fullPath: string, noFollowOrCallback: boolean | NoParamCallback, callbackOrAttempts?: NoParamCallback | number, attempts?: number): NodeJS.Timeout;
2
+ export default function waitForAccess(fullPath: string, noFollowOrCallback: boolean | NoParamCallback, callbackOrAttempts?: NoParamCallback | number, attempts?: number): void;
@@ -16,8 +16,8 @@ export default function waitForAccess(fullPath, noFollowOrCallback, callbackOrAt
16
16
  callback = callbackOrAttempts;
17
17
  }
18
18
  // POSIX: finish event is reliable after decompression stream fixes
19
- // Use setTimeout(0) to maintain async consistency (avoid Zalgo)
20
- if (!isWindows) return setTimeout(callback, 0);
19
+ // Avoid Zalgo: ensure callback is always async for consistent API
20
+ if (!isWindows) return process.nextTick(callback);
21
21
  // Windows: NTFS metadata may not be committed yet, verify accessibility
22
22
  // For symlinks (noFollow=true), use lstat to check the link itself exists
23
23
  // For files/dirs/hardlinks, use open to verify the file is accessible
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/extract-base-iterator/src/waitForAccess.ts"],"sourcesContent":["import fs from 'fs';\n\nimport type { NoParamCallback } from './types.ts';\n\nconst isWindows = process.platform === 'win32' || /^(msys|cygwin)$/.test(process.env.OSTYPE);\n\n// Backward compatible: waitForAccess(path, callback) or waitForAccess(path, noFollow, callback)\nexport default function waitForAccess(fullPath: string, noFollowOrCallback: boolean | NoParamCallback, callbackOrAttempts?: NoParamCallback | number, attempts = 0) {\n // Parse arguments for backward compatibility\n let noFollow: boolean;\n let callback: NoParamCallback;\n if (typeof noFollowOrCallback === 'function') {\n // Old signature: waitForAccess(path, callback, attempts?)\n noFollow = false;\n callback = noFollowOrCallback;\n attempts = (callbackOrAttempts as number) || 0;\n } else {\n // New signature: waitForAccess(path, noFollow, callback, attempts?)\n noFollow = noFollowOrCallback;\n callback = callbackOrAttempts as NoParamCallback;\n }\n\n // POSIX: finish event is reliable after decompression stream fixes\n // Use setTimeout(0) to maintain async consistency (avoid Zalgo)\n if (!isWindows) return setTimeout(callback, 0);\n\n // Windows: NTFS metadata may not be committed yet, verify accessibility\n // For symlinks (noFollow=true), use lstat to check the link itself exists\n // For files/dirs/hardlinks, use open to verify the file is accessible\n if (noFollow) {\n fs.lstat(fullPath, (err) => {\n if (err) {\n if (err.code === 'ENOENT' && attempts < 10) {\n const delay = Math.min(5 * 2 ** attempts, 2560);\n return setTimeout(() => waitForAccess(fullPath, noFollow, callback, attempts + 1), delay);\n }\n return callback(err);\n }\n callback();\n });\n } else {\n fs.open(fullPath, 'r', (err, fd) => {\n if (err) {\n if (err.code === 'ENOENT' && attempts < 10) {\n // Exponential backoff: 5, 10, 20, 40, 80, 160, 320, 640, 1280, 2560ms\n // Total max wait: ~5 seconds\n const delay = Math.min(5 * 2 ** attempts, 2560);\n return setTimeout(() => waitForAccess(fullPath, noFollow, callback, attempts + 1), delay);\n }\n return callback(err);\n }\n fs.close(fd, () => callback());\n });\n }\n}\n"],"names":["fs","isWindows","process","platform","test","env","OSTYPE","waitForAccess","fullPath","noFollowOrCallback","callbackOrAttempts","attempts","noFollow","callback","setTimeout","lstat","err","code","delay","Math","min","open","fd","close"],"mappings":"AAAA,OAAOA,QAAQ,KAAK;AAIpB,MAAMC,YAAYC,QAAQC,QAAQ,KAAK,WAAW,kBAAkBC,IAAI,CAACF,QAAQG,GAAG,CAACC,MAAM;AAE3F,gGAAgG;AAChG,eAAe,SAASC,cAAcC,QAAgB,EAAEC,kBAA6C,EAAEC,kBAA6C,EAAEC,WAAW,CAAC;IAChK,6CAA6C;IAC7C,IAAIC;IACJ,IAAIC;IACJ,IAAI,OAAOJ,uBAAuB,YAAY;QAC5C,0DAA0D;QAC1DG,WAAW;QACXC,WAAWJ;QACXE,WAAW,AAACD,sBAAiC;IAC/C,OAAO;QACL,oEAAoE;QACpEE,WAAWH;QACXI,WAAWH;IACb;IAEA,mEAAmE;IACnE,gEAAgE;IAChE,IAAI,CAACT,WAAW,OAAOa,WAAWD,UAAU;IAE5C,wEAAwE;IACxE,0EAA0E;IAC1E,sEAAsE;IACtE,IAAID,UAAU;QACZZ,GAAGe,KAAK,CAACP,UAAU,CAACQ;YAClB,IAAIA,KAAK;gBACP,IAAIA,IAAIC,IAAI,KAAK,YAAYN,WAAW,IAAI;oBAC1C,MAAMO,QAAQC,KAAKC,GAAG,CAAC,IAAI,KAAKT,UAAU;oBAC1C,OAAOG,WAAW,IAAMP,cAAcC,UAAUI,UAAUC,UAAUF,WAAW,IAAIO;gBACrF;gBACA,OAAOL,SAASG;YAClB;YACAH;QACF;IACF,OAAO;QACLb,GAAGqB,IAAI,CAACb,UAAU,KAAK,CAACQ,KAAKM;YAC3B,IAAIN,KAAK;gBACP,IAAIA,IAAIC,IAAI,KAAK,YAAYN,WAAW,IAAI;oBAC1C,sEAAsE;oBACtE,6BAA6B;oBAC7B,MAAMO,QAAQC,KAAKC,GAAG,CAAC,IAAI,KAAKT,UAAU;oBAC1C,OAAOG,WAAW,IAAMP,cAAcC,UAAUI,UAAUC,UAAUF,WAAW,IAAIO;gBACrF;gBACA,OAAOL,SAASG;YAClB;YACAhB,GAAGuB,KAAK,CAACD,IAAI,IAAMT;QACrB;IACF;AACF"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/extract-base-iterator/src/waitForAccess.ts"],"sourcesContent":["import fs from 'fs';\n\nimport type { NoParamCallback } from './types.ts';\n\nconst isWindows = process.platform === 'win32' || /^(msys|cygwin)$/.test(process.env.OSTYPE);\n\n// Backward compatible: waitForAccess(path, callback) or waitForAccess(path, noFollow, callback)\nexport default function waitForAccess(fullPath: string, noFollowOrCallback: boolean | NoParamCallback, callbackOrAttempts?: NoParamCallback | number, attempts = 0) {\n // Parse arguments for backward compatibility\n let noFollow: boolean;\n let callback: NoParamCallback;\n if (typeof noFollowOrCallback === 'function') {\n // Old signature: waitForAccess(path, callback, attempts?)\n noFollow = false;\n callback = noFollowOrCallback;\n attempts = (callbackOrAttempts as number) || 0;\n } else {\n // New signature: waitForAccess(path, noFollow, callback, attempts?)\n noFollow = noFollowOrCallback;\n callback = callbackOrAttempts as NoParamCallback;\n }\n\n // POSIX: finish event is reliable after decompression stream fixes\n // Avoid Zalgo: ensure callback is always async for consistent API\n if (!isWindows) return process.nextTick(callback);\n\n // Windows: NTFS metadata may not be committed yet, verify accessibility\n // For symlinks (noFollow=true), use lstat to check the link itself exists\n // For files/dirs/hardlinks, use open to verify the file is accessible\n if (noFollow) {\n fs.lstat(fullPath, (err) => {\n if (err) {\n if (err.code === 'ENOENT' && attempts < 10) {\n const delay = Math.min(5 * 2 ** attempts, 2560);\n return setTimeout(() => waitForAccess(fullPath, noFollow, callback, attempts + 1), delay);\n }\n return callback(err);\n }\n callback();\n });\n } else {\n fs.open(fullPath, 'r', (err, fd) => {\n if (err) {\n if (err.code === 'ENOENT' && attempts < 10) {\n // Exponential backoff: 5, 10, 20, 40, 80, 160, 320, 640, 1280, 2560ms\n // Total max wait: ~5 seconds\n const delay = Math.min(5 * 2 ** attempts, 2560);\n return setTimeout(() => waitForAccess(fullPath, noFollow, callback, attempts + 1), delay);\n }\n return callback(err);\n }\n fs.close(fd, () => callback());\n });\n }\n}\n"],"names":["fs","isWindows","process","platform","test","env","OSTYPE","waitForAccess","fullPath","noFollowOrCallback","callbackOrAttempts","attempts","noFollow","callback","nextTick","lstat","err","code","delay","Math","min","setTimeout","open","fd","close"],"mappings":"AAAA,OAAOA,QAAQ,KAAK;AAIpB,MAAMC,YAAYC,QAAQC,QAAQ,KAAK,WAAW,kBAAkBC,IAAI,CAACF,QAAQG,GAAG,CAACC,MAAM;AAE3F,gGAAgG;AAChG,eAAe,SAASC,cAAcC,QAAgB,EAAEC,kBAA6C,EAAEC,kBAA6C,EAAEC,WAAW,CAAC;IAChK,6CAA6C;IAC7C,IAAIC;IACJ,IAAIC;IACJ,IAAI,OAAOJ,uBAAuB,YAAY;QAC5C,0DAA0D;QAC1DG,WAAW;QACXC,WAAWJ;QACXE,WAAW,AAACD,sBAAiC;IAC/C,OAAO;QACL,oEAAoE;QACpEE,WAAWH;QACXI,WAAWH;IACb;IAEA,mEAAmE;IACnE,kEAAkE;IAClE,IAAI,CAACT,WAAW,OAAOC,QAAQY,QAAQ,CAACD;IAExC,wEAAwE;IACxE,0EAA0E;IAC1E,sEAAsE;IACtE,IAAID,UAAU;QACZZ,GAAGe,KAAK,CAACP,UAAU,CAACQ;YAClB,IAAIA,KAAK;gBACP,IAAIA,IAAIC,IAAI,KAAK,YAAYN,WAAW,IAAI;oBAC1C,MAAMO,QAAQC,KAAKC,GAAG,CAAC,IAAI,KAAKT,UAAU;oBAC1C,OAAOU,WAAW,IAAMd,cAAcC,UAAUI,UAAUC,UAAUF,WAAW,IAAIO;gBACrF;gBACA,OAAOL,SAASG;YAClB;YACAH;QACF;IACF,OAAO;QACLb,GAAGsB,IAAI,CAACd,UAAU,KAAK,CAACQ,KAAKO;YAC3B,IAAIP,KAAK;gBACP,IAAIA,IAAIC,IAAI,KAAK,YAAYN,WAAW,IAAI;oBAC1C,sEAAsE;oBACtE,6BAA6B;oBAC7B,MAAMO,QAAQC,KAAKC,GAAG,CAAC,IAAI,KAAKT,UAAU;oBAC1C,OAAOU,WAAW,IAAMd,cAAcC,UAAUI,UAAUC,UAAUF,WAAW,IAAIO;gBACrF;gBACA,OAAOL,SAASG;YAClB;YACAhB,GAAGwB,KAAK,CAACD,IAAI,IAAMV;QACrB;IACF;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "extract-base-iterator",
3
- "version": "3.2.2",
3
+ "version": "3.3.0",
4
4
  "description": "Base iterator for extract iterators like tar-iterator and zip-iterator",
5
5
  "keywords": [
6
6
  "extract",
@@ -46,9 +46,7 @@
46
46
  "fs-remove-compat": "^1.0.0",
47
47
  "graceful-fs": "^4.2.11",
48
48
  "is-absolute": "^1.0.0",
49
- "lodash.compact": "^3.0.1",
50
49
  "mkdirp-classic": "^0.5.2",
51
- "next-tick": "^1.1.0",
52
50
  "on-one": "^1.0.0",
53
51
  "pako": "1.0.11",
54
52
  "queue-cb": "^1.0.0",