@cj-tech-master/excelts 4.2.1-canary.20260111102127.f808a37 → 4.2.1-canary.20260112134913.a3cecdd

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 (101) hide show
  1. package/dist/browser/modules/archive/io/archive-sink.d.ts +0 -1
  2. package/dist/browser/modules/archive/io/archive-sink.js +6 -38
  3. package/dist/browser/modules/archive/io/archive-source.d.ts +0 -2
  4. package/dist/browser/modules/archive/io/archive-source.js +1 -8
  5. package/dist/browser/modules/excel/utils/ooxml-validator.d.ts +48 -0
  6. package/dist/browser/modules/excel/utils/ooxml-validator.js +469 -0
  7. package/dist/browser/modules/excel/worksheet.js +5 -2
  8. package/dist/browser/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.d.ts +1 -0
  9. package/dist/browser/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +13 -1
  10. package/dist/browser/modules/excel/xlsx/xform/drawing/sp-xform.d.ts +18 -0
  11. package/dist/browser/modules/excel/xlsx/xform/drawing/sp-xform.js +112 -0
  12. package/dist/browser/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.d.ts +6 -1
  13. package/dist/browser/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +30 -2
  14. package/dist/browser/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +11 -0
  15. package/dist/browser/modules/excel/xlsx/xform/sheet/page-setup-xform.d.ts +1 -0
  16. package/dist/browser/modules/excel/xlsx/xform/sheet/page-setup-xform.js +16 -2
  17. package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +110 -12
  18. package/dist/browser/modules/stream/base-transform.d.ts +3 -0
  19. package/dist/browser/modules/stream/base-transform.js +34 -20
  20. package/dist/browser/modules/stream/buffered-stream.d.ts +2 -12
  21. package/dist/browser/modules/stream/chunked-builder.js +4 -4
  22. package/dist/browser/modules/stream/index.browser.d.ts +13 -19
  23. package/dist/browser/modules/stream/index.browser.js +10 -22
  24. package/dist/browser/modules/stream/index.d.ts +18 -41
  25. package/dist/browser/modules/stream/index.js +15 -44
  26. package/dist/browser/modules/stream/internal/event-utils.d.ts +17 -0
  27. package/dist/browser/modules/stream/internal/event-utils.js +40 -0
  28. package/dist/browser/modules/stream/internal/type-guards.d.ts +9 -0
  29. package/dist/browser/modules/stream/internal/type-guards.js +24 -0
  30. package/dist/browser/modules/stream/pull-stream.d.ts +5 -6
  31. package/dist/browser/modules/stream/pull-stream.js +107 -43
  32. package/dist/browser/modules/stream/shared.d.ts +1 -1
  33. package/dist/browser/modules/stream/shared.js +7 -4
  34. package/dist/browser/modules/stream/streams.browser.d.ts +4 -14
  35. package/dist/browser/modules/stream/streams.browser.js +129 -164
  36. package/dist/browser/modules/stream/streams.d.ts +4 -20
  37. package/dist/browser/modules/stream/streams.js +6 -37
  38. package/dist/browser/modules/stream/utils.js +5 -38
  39. package/dist/cjs/modules/archive/io/archive-sink.js +7 -40
  40. package/dist/cjs/modules/archive/io/archive-source.js +3 -12
  41. package/dist/cjs/modules/excel/utils/ooxml-validator.js +475 -0
  42. package/dist/cjs/modules/excel/worksheet.js +5 -2
  43. package/dist/cjs/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +13 -1
  44. package/dist/cjs/modules/excel/xlsx/xform/drawing/sp-xform.js +115 -0
  45. package/dist/cjs/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +30 -2
  46. package/dist/cjs/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +11 -0
  47. package/dist/cjs/modules/excel/xlsx/xform/sheet/page-setup-xform.js +16 -2
  48. package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +110 -12
  49. package/dist/cjs/modules/stream/base-transform.js +34 -20
  50. package/dist/cjs/modules/stream/chunked-builder.js +4 -4
  51. package/dist/cjs/modules/stream/index.browser.js +10 -17
  52. package/dist/cjs/modules/stream/index.js +15 -39
  53. package/dist/cjs/modules/stream/internal/event-utils.js +43 -0
  54. package/dist/cjs/modules/stream/internal/type-guards.js +30 -0
  55. package/dist/cjs/modules/stream/pull-stream.js +107 -43
  56. package/dist/cjs/modules/stream/shared.js +7 -4
  57. package/dist/cjs/modules/stream/streams.browser.js +135 -175
  58. package/dist/cjs/modules/stream/streams.js +16 -49
  59. package/dist/cjs/modules/stream/utils.js +3 -36
  60. package/dist/esm/modules/archive/io/archive-sink.js +6 -38
  61. package/dist/esm/modules/archive/io/archive-source.js +1 -8
  62. package/dist/esm/modules/excel/utils/ooxml-validator.js +469 -0
  63. package/dist/esm/modules/excel/worksheet.js +5 -2
  64. package/dist/esm/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +13 -1
  65. package/dist/esm/modules/excel/xlsx/xform/drawing/sp-xform.js +112 -0
  66. package/dist/esm/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +30 -2
  67. package/dist/esm/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +11 -0
  68. package/dist/esm/modules/excel/xlsx/xform/sheet/page-setup-xform.js +16 -2
  69. package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +110 -12
  70. package/dist/esm/modules/stream/base-transform.js +34 -20
  71. package/dist/esm/modules/stream/chunked-builder.js +4 -4
  72. package/dist/esm/modules/stream/index.browser.js +10 -22
  73. package/dist/esm/modules/stream/index.js +15 -44
  74. package/dist/esm/modules/stream/internal/event-utils.js +40 -0
  75. package/dist/esm/modules/stream/internal/type-guards.js +24 -0
  76. package/dist/esm/modules/stream/pull-stream.js +107 -43
  77. package/dist/esm/modules/stream/shared.js +7 -4
  78. package/dist/esm/modules/stream/streams.browser.js +129 -164
  79. package/dist/esm/modules/stream/streams.js +6 -37
  80. package/dist/esm/modules/stream/utils.js +5 -38
  81. package/dist/iife/excelts.iife.js +325 -60
  82. package/dist/iife/excelts.iife.js.map +1 -1
  83. package/dist/iife/excelts.iife.min.js +25 -25
  84. package/dist/types/modules/archive/io/archive-sink.d.ts +0 -1
  85. package/dist/types/modules/archive/io/archive-source.d.ts +0 -2
  86. package/dist/types/modules/excel/utils/ooxml-validator.d.ts +48 -0
  87. package/dist/types/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.d.ts +1 -0
  88. package/dist/types/modules/excel/xlsx/xform/drawing/sp-xform.d.ts +18 -0
  89. package/dist/types/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.d.ts +6 -1
  90. package/dist/types/modules/excel/xlsx/xform/sheet/page-setup-xform.d.ts +1 -0
  91. package/dist/types/modules/stream/base-transform.d.ts +3 -0
  92. package/dist/types/modules/stream/buffered-stream.d.ts +2 -12
  93. package/dist/types/modules/stream/index.browser.d.ts +13 -19
  94. package/dist/types/modules/stream/index.d.ts +18 -41
  95. package/dist/types/modules/stream/internal/event-utils.d.ts +17 -0
  96. package/dist/types/modules/stream/internal/type-guards.d.ts +9 -0
  97. package/dist/types/modules/stream/pull-stream.d.ts +5 -6
  98. package/dist/types/modules/stream/shared.d.ts +1 -1
  99. package/dist/types/modules/stream/streams.browser.d.ts +4 -14
  100. package/dist/types/modules/stream/streams.d.ts +4 -20
  101. package/package.json +10 -10
@@ -11,9 +11,10 @@
11
11
  * - Edge >= 89
12
12
  */
13
13
  import { EventEmitter } from "./event-emitter.js";
14
- import { PullStream as StandalonePullStream } from "./pull-stream.js";
15
- import { BufferedStream as StandaloneBufferedStream, StringChunk as StandaloneStringChunk, BufferChunk as StandaloneBufferChunk } from "./buffered-stream.js";
14
+ import { PullStream } from "./pull-stream.js";
15
+ import { BufferedStream, BufferChunk, StringChunk } from "./buffered-stream.js";
16
16
  import { concatUint8Arrays, getTextDecoder, textDecoder } from "./shared.js";
17
+ import { isAsyncIterable, isReadableStream, isTransformStream, isWritableStream } from "./internal/type-guards.js";
17
18
  const removeEmitterListener = (emitter, event, listener) => {
18
19
  if (typeof emitter.off === "function") {
19
20
  emitter.off(event, listener);
@@ -2405,21 +2406,8 @@ export class Collector extends Writable {
2405
2406
  // =============================================================================
2406
2407
  // PullStream / BufferedStream / DataChunk helpers
2407
2408
  // =============================================================================
2408
- export class PullStream extends StandalonePullStream {
2409
- // Keep constructor signature aligned with streams.browser.ts public API
2410
- constructor(options) {
2411
- super(options);
2412
- }
2413
- }
2414
- export class StringChunk extends StandaloneStringChunk {
2415
- }
2416
- export class BufferChunk extends StandaloneBufferChunk {
2417
- }
2418
- export class BufferedStream extends StandaloneBufferedStream {
2419
- constructor(options) {
2420
- super(options);
2421
- }
2422
- }
2409
+ // Standalone cross-platform helpers
2410
+ export { PullStream, BufferedStream, StringChunk, BufferChunk };
2423
2411
  // =============================================================================
2424
2412
  // Stream Creation Functions
2425
2413
  // =============================================================================
@@ -2502,20 +2490,6 @@ export function createPullStream(options) {
2502
2490
  export function createBufferedStream(options) {
2503
2491
  return new BufferedStream(options);
2504
2492
  }
2505
- const isReadableStream = (value) => !!value && typeof value === "object" && typeof value.getReader === "function";
2506
- const isAsyncIterable = (value) => {
2507
- if (!value || (typeof value !== "object" && typeof value !== "function")) {
2508
- return false;
2509
- }
2510
- return typeof value[Symbol.asyncIterator] === "function";
2511
- };
2512
- const isWritableStream = (value) => !!value && typeof value === "object" && typeof value.getWriter === "function";
2513
- const isTransformStream = (value) => !!value &&
2514
- typeof value === "object" &&
2515
- !!value.readable &&
2516
- !!value.writable &&
2517
- isReadableStream(value.readable) &&
2518
- isWritableStream(value.writable);
2519
2493
  const isPipelineOptions = (value) => {
2520
2494
  if (!value || typeof value !== "object") {
2521
2495
  return false;
@@ -2785,8 +2759,8 @@ export async function streamToPromise(stream) {
2785
2759
  * (Browser equivalent of Node.js streamToBuffer)
2786
2760
  */
2787
2761
  export async function streamToUint8Array(stream) {
2788
- const { chunks, totalLength } = await collectStreamChunks(stream);
2789
- return concatWithLength(chunks, totalLength);
2762
+ const [chunks, totalLength] = await collectStreamChunks(stream);
2763
+ return concatUint8Arrays(chunks, totalLength);
2790
2764
  }
2791
2765
  /**
2792
2766
  * Alias for streamToUint8Array (Node.js compatibility)
@@ -2796,8 +2770,8 @@ export const streamToBuffer = streamToUint8Array;
2796
2770
  * Collect all data from a readable stream into a string
2797
2771
  */
2798
2772
  export async function streamToString(stream, encoding) {
2799
- const { chunks, totalLength } = await collectStreamChunks(stream);
2800
- const combined = concatWithLength(chunks, totalLength);
2773
+ const [chunks, totalLength] = await collectStreamChunks(stream);
2774
+ const combined = concatUint8Arrays(chunks, totalLength);
2801
2775
  const decoder = encoding ? getTextDecoder(encoding) : textDecoder;
2802
2776
  return decoder.decode(combined);
2803
2777
  }
@@ -2805,16 +2779,7 @@ export async function streamToString(stream, encoding) {
2805
2779
  * Drain a stream (consume all data without processing)
2806
2780
  */
2807
2781
  export async function drainStream(stream) {
2808
- let iterable;
2809
- if (isReadableStream(stream)) {
2810
- iterable = Readable.fromWeb(stream);
2811
- }
2812
- else if (isAsyncIterable(stream)) {
2813
- iterable = stream;
2814
- }
2815
- else {
2816
- throw new Error("drainStream: unsupported stream type");
2817
- }
2782
+ const iterable = toReadableAsyncIterable(stream, "drainStream");
2818
2783
  for await (const _chunk of iterable) {
2819
2784
  // Consume data
2820
2785
  }
@@ -3034,94 +2999,117 @@ export function compose(...transforms) {
3034
2999
  for (let i = 0; i < len - 1; i++) {
3035
3000
  transforms[i].pipe(transforms[i + 1]);
3036
3001
  }
3037
- class ComposedTransform extends Transform {
3038
- constructor(options) {
3039
- super(options);
3040
- this._dataForwarding = false;
3041
- this._endForwarding = false;
3042
- this._dataForwardCleanup = null;
3043
- this._endForwardCleanup = null;
3044
- this._errorForwardCleanup = [];
3045
- for (const t of transforms) {
3046
- const onError = (err) => {
3047
- this.emit("error", err);
3048
- };
3049
- this._errorForwardCleanup.push(addEmitterListener(t, "error", onError));
3050
- }
3051
- }
3052
- on(event, listener) {
3053
- if (event === "data" && !this._dataForwarding) {
3054
- this._dataForwarding = true;
3055
- const onData = (chunk) => {
3056
- this.emit("data", chunk);
3057
- };
3058
- this._dataForwardCleanup = addEmitterListener(last, "data", onData);
3059
- }
3060
- if (event === "end" && !this._endForwarding) {
3061
- this._endForwarding = true;
3062
- const onEnd = () => {
3063
- this.emit("end");
3064
- };
3065
- this._endForwardCleanup = addEmitterListener(last, "end", onEnd, { once: true });
3066
- }
3067
- return super.on(event, listener);
3068
- }
3069
- write(chunk, encodingOrCallback, callback) {
3070
- if (typeof encodingOrCallback === "function") {
3071
- return first.write(chunk, encodingOrCallback);
3072
- }
3073
- return first.write(chunk, encodingOrCallback, callback);
3074
- }
3075
- end(chunkOrCallback, encodingOrCallback, callback) {
3076
- if (typeof chunkOrCallback === "function") {
3077
- first.end(chunkOrCallback);
3078
- return this;
3079
- }
3080
- if (typeof encodingOrCallback === "function") {
3081
- first.end(chunkOrCallback, encodingOrCallback);
3082
- return this;
3083
- }
3084
- first.end(chunkOrCallback, encodingOrCallback, callback);
3085
- return this;
3002
+ // A lightweight Transform wrapper that delegates:
3003
+ // - writable side to `first`
3004
+ // - readable side to `last`
3005
+ // It forwards relevant events lazily to avoid per-chunk overhead when unused.
3006
+ const composed = new Transform({
3007
+ objectMode: first?.objectMode ?? true,
3008
+ transform: chunk => chunk
3009
+ });
3010
+ const registry = createListenerRegistry();
3011
+ // Always forward errors; they are critical for pipeline semantics.
3012
+ for (const t of transforms) {
3013
+ registry.add(t, "error", (err) => composed.emit("error", err));
3014
+ }
3015
+ // Forward writable-side backpressure/completion events from `first`.
3016
+ registry.add(first, "drain", () => composed.emit("drain"));
3017
+ registry.once(first, "finish", () => composed.emit("finish"));
3018
+ // Forward readable-side events from `last` lazily.
3019
+ let forwardData = false;
3020
+ let forwardEnd = false;
3021
+ let forwardReadable = false;
3022
+ const ensureDataForwarding = () => {
3023
+ if (forwardData) {
3024
+ return;
3086
3025
  }
3087
- pipe(destination) {
3088
- return last.pipe(destination);
3026
+ forwardData = true;
3027
+ registry.add(last, "data", (chunk) => composed.emit("data", chunk));
3028
+ };
3029
+ const ensureEndForwarding = () => {
3030
+ if (forwardEnd) {
3031
+ return;
3089
3032
  }
3090
- destroy(error) {
3091
- if (this._dataForwardCleanup) {
3092
- this._dataForwardCleanup();
3093
- this._dataForwardCleanup = null;
3094
- }
3095
- if (this._endForwardCleanup) {
3096
- this._endForwardCleanup();
3097
- this._endForwardCleanup = null;
3098
- }
3099
- for (let i = this._errorForwardCleanup.length - 1; i >= 0; i--) {
3100
- this._errorForwardCleanup[i]();
3101
- }
3102
- this._errorForwardCleanup.length = 0;
3103
- for (const t of transforms) {
3104
- t.destroy(error);
3105
- }
3106
- super.destroy(error);
3033
+ forwardEnd = true;
3034
+ registry.once(last, "end", () => composed.emit("end"));
3035
+ };
3036
+ const ensureReadableForwarding = () => {
3037
+ if (forwardReadable) {
3038
+ return;
3107
3039
  }
3108
- read(size) {
3109
- return typeof last.read === "function" ? last.read(size) : null;
3040
+ forwardReadable = true;
3041
+ registry.add(last, "readable", () => composed.emit("readable"));
3042
+ };
3043
+ const originalOn = composed.on.bind(composed);
3044
+ const originalOnce = composed.once.bind(composed);
3045
+ composed.on = (event, listener) => {
3046
+ if (event === "data") {
3047
+ ensureDataForwarding();
3110
3048
  }
3111
- async *[Symbol.asyncIterator]() {
3112
- const it = last?.[Symbol.asyncIterator]?.();
3113
- if (it) {
3114
- for await (const chunk of it) {
3115
- yield chunk;
3116
- }
3117
- return;
3049
+ else if (event === "end") {
3050
+ ensureEndForwarding();
3051
+ }
3052
+ else if (event === "readable") {
3053
+ ensureReadableForwarding();
3054
+ }
3055
+ return originalOn(event, listener);
3056
+ };
3057
+ composed.once = (event, listener) => {
3058
+ if (event === "data") {
3059
+ ensureDataForwarding();
3060
+ }
3061
+ else if (event === "end") {
3062
+ ensureEndForwarding();
3063
+ }
3064
+ else if (event === "readable") {
3065
+ ensureReadableForwarding();
3066
+ }
3067
+ return originalOnce(event, listener);
3068
+ };
3069
+ // Delegate core stream methods
3070
+ const firstAny = first;
3071
+ const lastAny = last;
3072
+ composed.write = (chunk, encodingOrCallback, callback) => {
3073
+ if (typeof encodingOrCallback === "function") {
3074
+ return firstAny.write(chunk, encodingOrCallback);
3075
+ }
3076
+ return firstAny.write(chunk, encodingOrCallback, callback);
3077
+ };
3078
+ composed.end = (chunkOrCallback, encodingOrCallback, callback) => {
3079
+ if (typeof chunkOrCallback === "function") {
3080
+ firstAny.end(chunkOrCallback);
3081
+ return composed;
3082
+ }
3083
+ if (typeof encodingOrCallback === "function") {
3084
+ firstAny.end(chunkOrCallback, encodingOrCallback);
3085
+ return composed;
3086
+ }
3087
+ firstAny.end(chunkOrCallback, encodingOrCallback, callback);
3088
+ return composed;
3089
+ };
3090
+ composed.pipe = (destination) => {
3091
+ return lastAny.pipe(destination);
3092
+ };
3093
+ composed.read = (size) => {
3094
+ return typeof lastAny.read === "function" ? lastAny.read(size) : null;
3095
+ };
3096
+ composed[Symbol.asyncIterator] = async function* () {
3097
+ const it = lastAny?.[Symbol.asyncIterator]?.();
3098
+ if (it) {
3099
+ for await (const chunk of it) {
3100
+ yield chunk;
3118
3101
  }
3119
- yield* super[Symbol.asyncIterator]();
3102
+ return;
3120
3103
  }
3121
- }
3122
- const composed = new ComposedTransform({
3123
- objectMode: first?.objectMode ?? true,
3124
- transform: chunk => chunk
3104
+ yield* Transform.prototype[Symbol.asyncIterator].call(composed);
3105
+ };
3106
+ const originalDestroy = composed.destroy.bind(composed);
3107
+ composed.destroy = ((error) => {
3108
+ registry.cleanup();
3109
+ for (const t of transforms) {
3110
+ t.destroy(error);
3111
+ }
3112
+ originalDestroy(error);
3125
3113
  });
3126
3114
  // Reflect underlying readability/writability like the previous duck-typed wrapper
3127
3115
  Object.defineProperty(composed, "readable", {
@@ -3368,77 +3356,54 @@ export function duplexPair(options) {
3368
3356
  async function collectStreamChunks(stream) {
3369
3357
  const chunks = [];
3370
3358
  let totalLength = 0;
3371
- let iterable;
3372
- if (isReadableStream(stream)) {
3373
- iterable = Readable.fromWeb(stream);
3374
- }
3375
- else if (isAsyncIterable(stream)) {
3376
- iterable = stream;
3377
- }
3378
- else {
3379
- throw new Error("collectStreamChunks: unsupported stream type");
3380
- }
3359
+ const iterable = toReadableAsyncIterable(stream, "collectStreamChunks");
3381
3360
  for await (const chunk of iterable) {
3382
3361
  chunks.push(chunk);
3383
3362
  totalLength += chunk.length;
3384
3363
  }
3385
- return { chunks, totalLength };
3364
+ return [chunks, totalLength];
3386
3365
  }
3387
- // Helper to concatenate with known length (faster)
3388
- function concatWithLength(chunks, totalLength) {
3389
- const len = chunks.length;
3390
- if (len === 0) {
3391
- return new Uint8Array(0);
3392
- }
3393
- if (len === 1) {
3394
- return chunks[0];
3366
+ function toReadableAsyncIterable(stream, name) {
3367
+ if (isReadableStream(stream)) {
3368
+ return Readable.fromWeb(stream);
3395
3369
  }
3396
- const result = new Uint8Array(totalLength);
3397
- let offset = 0;
3398
- for (let i = 0; i < len; i++) {
3399
- result.set(chunks[i], offset);
3400
- offset += chunks[i].length;
3370
+ if (isAsyncIterable(stream)) {
3371
+ return stream;
3401
3372
  }
3402
- return result;
3373
+ throw new Error(`${name}: unsupported stream type`);
3403
3374
  }
3404
3375
  export const consumers = {
3405
3376
  /**
3406
3377
  * Consume entire stream as ArrayBuffer
3407
3378
  */
3408
3379
  async arrayBuffer(stream) {
3409
- const { chunks, totalLength } = await collectStreamChunks(stream);
3410
- const combined = concatWithLength(chunks, totalLength);
3411
- return combined.buffer.slice(combined.byteOffset, combined.byteOffset + combined.byteLength);
3380
+ const bytes = await streamToUint8Array(stream);
3381
+ return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
3412
3382
  },
3413
3383
  /**
3414
3384
  * Consume entire stream as Blob
3415
3385
  */
3416
3386
  async blob(stream, options) {
3417
- const { chunks } = await collectStreamChunks(stream);
3387
+ const [chunks] = await collectStreamChunks(stream);
3418
3388
  return new Blob(chunks, options);
3419
3389
  },
3420
3390
  /**
3421
3391
  * Consume entire stream as Buffer (Uint8Array in browser)
3422
3392
  */
3423
3393
  async buffer(stream) {
3424
- const { chunks, totalLength } = await collectStreamChunks(stream);
3425
- return concatWithLength(chunks, totalLength);
3394
+ return streamToUint8Array(stream);
3426
3395
  },
3427
3396
  /**
3428
3397
  * Consume entire stream as JSON
3429
3398
  */
3430
3399
  async json(stream) {
3431
- const text = await consumers.text(stream);
3432
- return JSON.parse(text);
3400
+ return JSON.parse(await streamToString(stream));
3433
3401
  },
3434
3402
  /**
3435
3403
  * Consume entire stream as text
3436
3404
  */
3437
3405
  async text(stream, encoding) {
3438
- const { chunks, totalLength } = await collectStreamChunks(stream);
3439
- const combined = concatWithLength(chunks, totalLength);
3440
- const decoder = encoding ? getTextDecoder(encoding) : textDecoder;
3441
- return decoder.decode(combined);
3406
+ return streamToString(stream, encoding);
3442
3407
  }
3443
3408
  };
3444
3409
  // =============================================================================
@@ -5,8 +5,9 @@
5
5
  * Provides Readable, Writable, Transform, Duplex, and PassThrough streams.
6
6
  */
7
7
  import { Readable, Writable as NodeWritable, Transform, Duplex, PassThrough, pipeline as nodePipeline, finished as nodeFinished } from "stream";
8
- import { BufferedStream as StandaloneBufferedStream, StringChunk as StandaloneStringChunk, BufferChunk as StandaloneBufferChunk } from "./buffered-stream.js";
9
- import { PullStream as StandalonePullStream } from "./pull-stream.js";
8
+ import { BufferedStream, BufferChunk, StringChunk } from "./buffered-stream.js";
9
+ import { PullStream } from "./pull-stream.js";
10
+ import { isAsyncIterable, isReadableStream, isTransformStream, isWritableStream } from "./internal/type-guards.js";
10
11
  /**
11
12
  * Unified Writable class - wraps Node.js Writable with browser-compatible API
12
13
  *
@@ -59,6 +60,8 @@ export class Writable extends NodeWritable {
59
60
  // Re-export native classes with our interfaces
60
61
  // =============================================================================
61
62
  export { Readable, Transform, Duplex, PassThrough };
63
+ // Standalone cross-platform helpers
64
+ export { PullStream, BufferedStream, StringChunk, BufferChunk };
62
65
  // =============================================================================
63
66
  // Cross-environment stream normalization
64
67
  // =============================================================================
@@ -84,29 +87,12 @@ export function normalizeWritable(stream) {
84
87
  }
85
88
  // Import for internal use
86
89
  import { textDecoder } from "./shared.js";
87
- const isReadableStream = (value) => !!value && typeof value === "object" && typeof value.getReader === "function";
88
- const isAsyncIterable = (value) => {
89
- if (!value || (typeof value !== "object" && typeof value !== "function")) {
90
- return false;
91
- }
92
- return typeof value[Symbol.asyncIterator] === "function";
93
- };
94
- const isWritableStream = (value) => !!value && typeof value === "object" && typeof value.getWriter === "function";
95
- const isTransformStream = (value) => !!value &&
96
- typeof value === "object" &&
97
- !!value.readable &&
98
- !!value.writable &&
99
- isReadableStream(value.readable) &&
100
- isWritableStream(value.writable);
101
90
  const isPipelineOptions = (value) => {
102
91
  if (!value || typeof value !== "object") {
103
92
  return false;
104
93
  }
105
- // IMPORTANT:
106
- // Do NOT use `"end" in obj` here because streams have `.end()` and would be
107
- // misclassified as options, breaking argument parsing and potentially hanging.
94
+ // Avoid treating streams as options objects.
108
95
  if (typeof value.pipe === "function" ||
109
- typeof value.write === "function" ||
110
96
  typeof value.end === "function" ||
111
97
  typeof value.getReader === "function" ||
112
98
  typeof value.getWriter === "function") {
@@ -425,8 +411,6 @@ export function createCollector(options) {
425
411
  // =============================================================================
426
412
  // Pull Stream - Read data on demand with pattern matching
427
413
  // =============================================================================
428
- export class PullStream extends StandalonePullStream {
429
- }
430
414
  /**
431
415
  * Create a pull stream
432
416
  */
@@ -436,21 +420,6 @@ export function createPullStream(options) {
436
420
  // =============================================================================
437
421
  // Buffered Stream - Efficient chunk management
438
422
  // =============================================================================
439
- /**
440
- * String chunk implementation
441
- */
442
- export class StringChunk extends StandaloneStringChunk {
443
- }
444
- /**
445
- * Buffer chunk implementation
446
- */
447
- export class BufferChunk extends StandaloneBufferChunk {
448
- }
449
- /**
450
- * Buffered stream with efficient chunk management
451
- */
452
- export class BufferedStream extends StandaloneBufferedStream {
453
- }
454
423
  /**
455
424
  * Create a buffered stream
456
425
  */
@@ -4,8 +4,8 @@
4
4
  * Small, cross-platform helpers built on top of the platform stream
5
5
  * implementation selected by `./streams` (Node.js or browser).
6
6
  */
7
- import { createReadableFromArray, createTransform } from "./streams.js";
8
- import { stringToUint8Array as _stringToUint8Array, uint8ArrayToString as _uint8ArrayToString } from "./shared.js";
7
+ import { consumers, createReadableFromArray, createTransform } from "./streams.js";
8
+ import { stringToUint8Array as _stringToUint8Array } from "./shared.js";
9
9
  // =============================================================================
10
10
  // High-Level Stream Consumers
11
11
  // =============================================================================
@@ -17,46 +17,13 @@ export async function collect(stream) {
17
17
  return result;
18
18
  }
19
19
  export async function text(stream) {
20
- const chunks = [];
21
- let totalLength = 0;
22
- for await (const chunk of stream) {
23
- chunks.push(chunk);
24
- totalLength += chunk.length;
25
- }
26
- if (chunks.length === 1) {
27
- return _uint8ArrayToString(chunks[0]);
28
- }
29
- const result = new Uint8Array(totalLength);
30
- let offset = 0;
31
- for (let i = 0, len = chunks.length; i < len; i++) {
32
- const c = chunks[i];
33
- result.set(c, offset);
34
- offset += c.length;
35
- }
36
- return _uint8ArrayToString(result);
20
+ return consumers.text(stream);
37
21
  }
38
22
  export async function json(stream) {
39
- const str = await text(stream);
40
- return JSON.parse(str);
23
+ return consumers.json(stream);
41
24
  }
42
25
  export async function bytes(stream) {
43
- const chunks = [];
44
- let totalLength = 0;
45
- for await (const chunk of stream) {
46
- chunks.push(chunk);
47
- totalLength += chunk.length;
48
- }
49
- if (chunks.length === 1) {
50
- return chunks[0];
51
- }
52
- const result = new Uint8Array(totalLength);
53
- let offset = 0;
54
- for (let i = 0, len = chunks.length; i < len; i++) {
55
- const c = chunks[i];
56
- result.set(c, offset);
57
- offset += c.length;
58
- }
59
- return result;
26
+ return consumers.buffer(stream);
60
27
  }
61
28
  // =============================================================================
62
29
  // Stream Factory Helpers