@npy/fetch 0.1.3 → 0.1.4

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 (141) hide show
  1. package/LICENSE +21 -0
  2. package/_internal/consts.cjs +4 -0
  3. package/_internal/consts.d.cts +3 -0
  4. package/_internal/consts.d.ts +3 -0
  5. package/_internal/consts.js +4 -0
  6. package/_internal/decode-stream-error.cjs +18 -0
  7. package/{src/_internal/decode-stream-error.ts → _internal/decode-stream-error.d.cts} +2 -7
  8. package/_internal/decode-stream-error.d.ts +11 -0
  9. package/_internal/decode-stream-error.js +18 -0
  10. package/_internal/error-mapping.cjs +44 -0
  11. package/_internal/error-mapping.d.cts +15 -0
  12. package/_internal/error-mapping.d.ts +15 -0
  13. package/_internal/error-mapping.js +41 -0
  14. package/_internal/guards.cjs +23 -0
  15. package/_internal/guards.d.cts +15 -0
  16. package/_internal/guards.d.ts +15 -0
  17. package/_internal/guards.js +15 -0
  18. package/_internal/net.cjs +95 -0
  19. package/_internal/net.d.cts +11 -0
  20. package/_internal/net.d.ts +11 -0
  21. package/_internal/net.js +92 -0
  22. package/_internal/promises.cjs +18 -0
  23. package/_internal/promises.d.cts +1 -0
  24. package/_internal/promises.d.ts +1 -0
  25. package/_internal/promises.js +18 -0
  26. package/_internal/streams.cjs +37 -0
  27. package/_internal/streams.d.cts +21 -0
  28. package/_internal/streams.d.ts +21 -0
  29. package/_internal/streams.js +36 -0
  30. package/_internal/symbols.cjs +4 -0
  31. package/_internal/symbols.d.cts +1 -0
  32. package/_internal/symbols.d.ts +1 -0
  33. package/_internal/symbols.js +4 -0
  34. package/_virtual/_rolldown/runtime.cjs +23 -0
  35. package/agent-pool.cjs +96 -0
  36. package/agent-pool.d.cts +2 -0
  37. package/agent-pool.d.ts +2 -0
  38. package/agent-pool.js +95 -0
  39. package/agent.cjs +260 -0
  40. package/agent.d.cts +3 -0
  41. package/agent.d.ts +3 -0
  42. package/agent.js +259 -0
  43. package/body.cjs +105 -0
  44. package/body.d.cts +12 -0
  45. package/body.d.ts +12 -0
  46. package/body.js +102 -0
  47. package/dialers/index.d.cts +3 -0
  48. package/dialers/index.d.ts +3 -0
  49. package/dialers/proxy.cjs +56 -0
  50. package/dialers/proxy.d.cts +27 -0
  51. package/dialers/proxy.d.ts +27 -0
  52. package/dialers/proxy.js +55 -0
  53. package/dialers/tcp.cjs +92 -0
  54. package/dialers/tcp.d.cts +57 -0
  55. package/dialers/tcp.d.ts +57 -0
  56. package/dialers/tcp.js +89 -0
  57. package/encoding.cjs +114 -0
  58. package/encoding.d.cts +35 -0
  59. package/encoding.d.ts +35 -0
  60. package/encoding.js +110 -0
  61. package/errors.cjs +275 -0
  62. package/errors.d.cts +110 -0
  63. package/errors.d.ts +110 -0
  64. package/errors.js +259 -0
  65. package/fetch.cjs +353 -0
  66. package/fetch.d.cts +58 -0
  67. package/fetch.d.ts +58 -0
  68. package/fetch.js +350 -0
  69. package/http-client.cjs +75 -0
  70. package/http-client.d.cts +39 -0
  71. package/http-client.d.ts +39 -0
  72. package/http-client.js +75 -0
  73. package/index.cjs +49 -0
  74. package/index.d.cts +14 -0
  75. package/index.d.ts +14 -0
  76. package/index.js +11 -0
  77. package/io/_utils.cjs +56 -0
  78. package/io/_utils.d.cts +10 -0
  79. package/io/_utils.d.ts +10 -0
  80. package/io/_utils.js +51 -0
  81. package/io/buf-writer.cjs +149 -0
  82. package/io/buf-writer.d.cts +13 -0
  83. package/io/buf-writer.d.ts +13 -0
  84. package/io/buf-writer.js +148 -0
  85. package/io/io.cjs +199 -0
  86. package/io/io.d.cts +5 -0
  87. package/io/io.d.ts +5 -0
  88. package/io/io.js +198 -0
  89. package/io/readers.cjs +337 -0
  90. package/io/readers.d.cts +69 -0
  91. package/io/readers.d.ts +69 -0
  92. package/io/readers.js +333 -0
  93. package/io/writers.cjs +196 -0
  94. package/io/writers.d.cts +22 -0
  95. package/io/writers.d.ts +22 -0
  96. package/io/writers.js +195 -0
  97. package/package.json +30 -25
  98. package/{src/types/agent.ts → types/agent.d.cts} +21 -47
  99. package/types/agent.d.ts +72 -0
  100. package/{src/types/dialer.ts → types/dialer.d.cts} +9 -19
  101. package/types/dialer.d.ts +30 -0
  102. package/types/index.d.cts +2 -0
  103. package/types/index.d.ts +2 -0
  104. package/bun.lock +0 -68
  105. package/examples/custom-proxy-client.ts +0 -32
  106. package/examples/http-client.ts +0 -47
  107. package/examples/proxy.ts +0 -16
  108. package/examples/simple.ts +0 -15
  109. package/src/_internal/consts.ts +0 -3
  110. package/src/_internal/error-mapping.ts +0 -160
  111. package/src/_internal/guards.ts +0 -78
  112. package/src/_internal/net.ts +0 -173
  113. package/src/_internal/promises.ts +0 -22
  114. package/src/_internal/streams.ts +0 -52
  115. package/src/_internal/symbols.ts +0 -1
  116. package/src/agent-pool.ts +0 -157
  117. package/src/agent.ts +0 -408
  118. package/src/body.ts +0 -179
  119. package/src/dialers/index.ts +0 -3
  120. package/src/dialers/proxy.ts +0 -102
  121. package/src/dialers/tcp.ts +0 -162
  122. package/src/encoding.ts +0 -222
  123. package/src/errors.ts +0 -357
  124. package/src/fetch.ts +0 -626
  125. package/src/http-client.ts +0 -111
  126. package/src/index.ts +0 -14
  127. package/src/io/_utils.ts +0 -82
  128. package/src/io/buf-writer.ts +0 -183
  129. package/src/io/io.ts +0 -322
  130. package/src/io/readers.ts +0 -576
  131. package/src/io/writers.ts +0 -331
  132. package/src/types/index.ts +0 -2
  133. package/tests/agent-pool.test.ts +0 -111
  134. package/tests/agent.test.ts +0 -134
  135. package/tests/body.test.ts +0 -228
  136. package/tests/errors.test.ts +0 -152
  137. package/tests/fetch.test.ts +0 -421
  138. package/tests/io-options.test.ts +0 -127
  139. package/tests/multipart.test.ts +0 -348
  140. package/tests/test-utils.ts +0 -335
  141. package/tsconfig.json +0 -15
package/index.d.cts ADDED
@@ -0,0 +1,14 @@
1
+ export type { FormDataPolyfill } from './_internal/guards';
2
+ export type { WithSignal } from './_internal/net';
3
+ export { connectTcp, connectTls, upgradeTls } from './_internal/net';
4
+ export * from './agent';
5
+ export * from './agent-pool';
6
+ export * from './body';
7
+ export * from './dialers';
8
+ export * from './encoding';
9
+ export * from './errors';
10
+ export * from './fetch';
11
+ export * from './http-client';
12
+ export type { LineReader, Readers } from './io/readers';
13
+ export type { Writers } from './io/writers';
14
+ export * from './types';
package/index.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ export type { FormDataPolyfill } from './_internal/guards';
2
+ export type { WithSignal } from './_internal/net';
3
+ export { connectTcp, connectTls, upgradeTls } from './_internal/net';
4
+ export * from './agent';
5
+ export * from './agent-pool';
6
+ export * from './body';
7
+ export * from './dialers';
8
+ export * from './encoding';
9
+ export * from './errors';
10
+ export * from './fetch';
11
+ export * from './http-client';
12
+ export type { LineReader, Readers } from './io/readers';
13
+ export type { Writers } from './io/writers';
14
+ export * from './types';
package/index.js ADDED
@@ -0,0 +1,11 @@
1
+ import { connectTcp, connectTls, upgradeTls } from "./_internal/net.js";
2
+ import { AgentBusyError, AgentClosedError, ConnectTimeoutError, ConnectionError, ErrorType, FetchError, FetchErrorCode, HttpStatusError, OriginMismatchError, RequestAbortedError, RequestWriteError, ResponseBodyError, ResponseDecodeError, ResponseHeaderError, UnsupportedAlpnProtocolError, UnsupportedMethodError, UnsupportedProtocolError } from "./errors.js";
3
+ import { createDecoders, createEncoders, decodeStream, encodeStream } from "./encoding.js";
4
+ import { extractBody, fromRequestBody, getFormDataLength } from "./body.js";
5
+ import { createAgent } from "./agent.js";
6
+ import { ProxyDialer } from "./dialers/proxy.js";
7
+ import { AutoDialer, TcpDialer, TlsDialer, resolveHostPort } from "./dialers/tcp.js";
8
+ import { createAgentPool } from "./agent-pool.js";
9
+ import { HttpClient } from "./http-client.js";
10
+ import fetch, { createFetch, normalizeHeaders } from "./fetch.js";
11
+ export { AgentBusyError, AgentClosedError, AutoDialer, ConnectTimeoutError, ConnectionError, ErrorType, FetchError, FetchErrorCode, HttpClient, HttpStatusError, OriginMismatchError, ProxyDialer, RequestAbortedError, RequestWriteError, ResponseBodyError, ResponseDecodeError, ResponseHeaderError, TcpDialer, TlsDialer, UnsupportedAlpnProtocolError, UnsupportedMethodError, UnsupportedProtocolError, connectTcp, connectTls, createAgent, createAgentPool, createDecoders, createEncoders, createFetch, decodeStream, encodeStream, extractBody, fetch, fromRequestBody, getFormDataLength, normalizeHeaders, resolveHostPort, upgradeTls };
package/io/_utils.cjs ADDED
@@ -0,0 +1,56 @@
1
+ const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
2
+ let bytes = require("bytes");
3
+ bytes = require_runtime.__toESM(bytes);
4
+ //#region src/io/_utils.ts
5
+ function parseMaxBytes(value) {
6
+ if (value === void 0) return null;
7
+ if (typeof value === "number") {
8
+ if (!Number.isFinite(value) || value < 0) throw new Error(`invalid max size: ${String(value)}`);
9
+ return Math.floor(value);
10
+ }
11
+ const parsed = bytes.default.parse(value);
12
+ if (parsed == null || !Number.isFinite(parsed) || parsed < 0) throw new Error(`invalid max size: ${String(value)}`);
13
+ return parsed;
14
+ }
15
+ function splitTokens(v) {
16
+ if (!v) return [];
17
+ return v.split(",").map((s) => s.trim().toLowerCase()).filter(Boolean);
18
+ }
19
+ function parseTransferEncoding(headers) {
20
+ const raw = headers.get("transfer-encoding");
21
+ const tks = splitTokens(raw);
22
+ if (tks.length === 0) return {
23
+ has: false,
24
+ chunked: false,
25
+ codings: []
26
+ };
27
+ const chunkedIdx = tks.lastIndexOf("chunked");
28
+ const hasChunked = chunkedIdx !== -1;
29
+ if (hasChunked && chunkedIdx !== tks.length - 1) throw new Error(`Invalid transfer-encoding order: ${raw ?? ""}`);
30
+ if (hasChunked && tks.indexOf("chunked") !== chunkedIdx) throw new Error(`Invalid transfer-encoding (duplicate chunked): ${raw ?? ""}`);
31
+ return {
32
+ has: true,
33
+ chunked: hasChunked,
34
+ codings: tks.filter((t) => t !== "chunked" && t !== "identity")
35
+ };
36
+ }
37
+ function parseContentLength(headers) {
38
+ const raw = headers.get("content-length");
39
+ if (!raw) return null;
40
+ const parts = raw.split(",").map((s) => s.trim()).filter(Boolean);
41
+ if (parts.length === 0) return null;
42
+ let value = null;
43
+ for (const p of parts) {
44
+ if (!/^\d+$/.test(p)) throw new Error(`Invalid content-length: ${raw}`);
45
+ const n = Number.parseInt(p, 10);
46
+ if (!Number.isFinite(n) || n < 0) throw new Error(`Invalid content-length: ${raw}`);
47
+ if (value === null) value = n;
48
+ else if (value !== n) throw new Error(`Conflicting content-length values: ${raw}`);
49
+ }
50
+ return value;
51
+ }
52
+ //#endregion
53
+ exports.parseContentLength = parseContentLength;
54
+ exports.parseMaxBytes = parseMaxBytes;
55
+ exports.parseTransferEncoding = parseTransferEncoding;
56
+ exports.splitTokens = splitTokens;
@@ -0,0 +1,10 @@
1
+ type TransferEncodingInfo = {
2
+ has: boolean;
3
+ chunked: boolean;
4
+ codings: string[];
5
+ };
6
+ export declare function parseMaxBytes(value?: number | string): number | null;
7
+ export declare function splitTokens(v: string | null): string[];
8
+ export declare function parseTransferEncoding(headers: Headers): TransferEncodingInfo;
9
+ export declare function parseContentLength(headers: Headers): number | null;
10
+ export {};
package/io/_utils.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ type TransferEncodingInfo = {
2
+ has: boolean;
3
+ chunked: boolean;
4
+ codings: string[];
5
+ };
6
+ export declare function parseMaxBytes(value?: number | string): number | null;
7
+ export declare function splitTokens(v: string | null): string[];
8
+ export declare function parseTransferEncoding(headers: Headers): TransferEncodingInfo;
9
+ export declare function parseContentLength(headers: Headers): number | null;
10
+ export {};
package/io/_utils.js ADDED
@@ -0,0 +1,51 @@
1
+ import bytes from "bytes";
2
+ //#region src/io/_utils.ts
3
+ function parseMaxBytes(value) {
4
+ if (value === void 0) return null;
5
+ if (typeof value === "number") {
6
+ if (!Number.isFinite(value) || value < 0) throw new Error(`invalid max size: ${String(value)}`);
7
+ return Math.floor(value);
8
+ }
9
+ const parsed = bytes.parse(value);
10
+ if (parsed == null || !Number.isFinite(parsed) || parsed < 0) throw new Error(`invalid max size: ${String(value)}`);
11
+ return parsed;
12
+ }
13
+ function splitTokens(v) {
14
+ if (!v) return [];
15
+ return v.split(",").map((s) => s.trim().toLowerCase()).filter(Boolean);
16
+ }
17
+ function parseTransferEncoding(headers) {
18
+ const raw = headers.get("transfer-encoding");
19
+ const tks = splitTokens(raw);
20
+ if (tks.length === 0) return {
21
+ has: false,
22
+ chunked: false,
23
+ codings: []
24
+ };
25
+ const chunkedIdx = tks.lastIndexOf("chunked");
26
+ const hasChunked = chunkedIdx !== -1;
27
+ if (hasChunked && chunkedIdx !== tks.length - 1) throw new Error(`Invalid transfer-encoding order: ${raw ?? ""}`);
28
+ if (hasChunked && tks.indexOf("chunked") !== chunkedIdx) throw new Error(`Invalid transfer-encoding (duplicate chunked): ${raw ?? ""}`);
29
+ return {
30
+ has: true,
31
+ chunked: hasChunked,
32
+ codings: tks.filter((t) => t !== "chunked" && t !== "identity")
33
+ };
34
+ }
35
+ function parseContentLength(headers) {
36
+ const raw = headers.get("content-length");
37
+ if (!raw) return null;
38
+ const parts = raw.split(",").map((s) => s.trim()).filter(Boolean);
39
+ if (parts.length === 0) return null;
40
+ let value = null;
41
+ for (const p of parts) {
42
+ if (!/^\d+$/.test(p)) throw new Error(`Invalid content-length: ${raw}`);
43
+ const n = Number.parseInt(p, 10);
44
+ if (!Number.isFinite(n) || n < 0) throw new Error(`Invalid content-length: ${raw}`);
45
+ if (value === null) value = n;
46
+ else if (value !== n) throw new Error(`Conflicting content-length values: ${raw}`);
47
+ }
48
+ return value;
49
+ }
50
+ //#endregion
51
+ export { parseContentLength, parseMaxBytes, parseTransferEncoding, splitTokens };
@@ -0,0 +1,149 @@
1
+ require("../_virtual/_rolldown/runtime.cjs");
2
+ let _fuman_utils = require("@fuman/utils");
3
+ //#region src/io/buf-writer.ts
4
+ var DEFAULT_BUF_SIZE = 4096;
5
+ var MIN_BUF_SIZE = 16;
6
+ var BufWriter = class {
7
+ #buffer;
8
+ #writable;
9
+ #writePos = 0;
10
+ #error = null;
11
+ #pending = [];
12
+ #pendingBytes = 0;
13
+ #lastWrite = null;
14
+ constructor(writable, size = DEFAULT_BUF_SIZE) {
15
+ if (size < MIN_BUF_SIZE) size = MIN_BUF_SIZE;
16
+ this.#buffer = _fuman_utils.u8.alloc(size);
17
+ this.#writable = writable;
18
+ }
19
+ get bufferSize() {
20
+ return this.#buffer.byteLength;
21
+ }
22
+ get buffered() {
23
+ return this.#pendingBytes + this.#writePos;
24
+ }
25
+ get available() {
26
+ return this.#buffer.byteLength - this.#writePos;
27
+ }
28
+ reset(writable) {
29
+ this.#error = null;
30
+ this.#writePos = 0;
31
+ this.#pending.length = 0;
32
+ this.#pendingBytes = 0;
33
+ this.#lastWrite = null;
34
+ this.#writable = writable;
35
+ }
36
+ writeSync(bytes) {
37
+ if (this.#error) throw this.#error;
38
+ if (bytes < 0) throw new RangeError("bytes must be >= 0");
39
+ if (this.#lastWrite) throw new Error("disposeWriteSync must be called before the next writeSync");
40
+ if (bytes === 0) {
41
+ const empty = this.#buffer.subarray(this.#writePos, this.#writePos);
42
+ this.#lastWrite = {
43
+ buf: empty,
44
+ size: 0,
45
+ internal: true
46
+ };
47
+ return empty;
48
+ }
49
+ if (bytes > this.available && this.#writePos > 0) {
50
+ const copy = _fuman_utils.u8.allocWith(this.#buffer.subarray(0, this.#writePos));
51
+ this.#pending.push(copy);
52
+ this.#pendingBytes += copy.length;
53
+ this.#writePos = 0;
54
+ }
55
+ if (bytes <= this.#buffer.byteLength) {
56
+ if (bytes > this.available) {
57
+ const copy = _fuman_utils.u8.allocWith(this.#buffer.subarray(0, this.#writePos));
58
+ this.#pending.push(copy);
59
+ this.#pendingBytes += copy.length;
60
+ this.#writePos = 0;
61
+ }
62
+ const start = this.#writePos;
63
+ const end = start + bytes;
64
+ const slice = this.#buffer.subarray(start, end);
65
+ this.#writePos = end;
66
+ this.#lastWrite = {
67
+ buf: slice,
68
+ size: bytes,
69
+ internal: true
70
+ };
71
+ return slice;
72
+ }
73
+ const chunk = _fuman_utils.u8.alloc(bytes);
74
+ this.#lastWrite = {
75
+ buf: chunk,
76
+ size: bytes,
77
+ internal: false
78
+ };
79
+ return chunk;
80
+ }
81
+ disposeWriteSync(written) {
82
+ const lw = this.#lastWrite;
83
+ if (!lw) return;
84
+ const w = written ?? lw.size;
85
+ if (w < 0 || w > lw.size) throw new RangeError(`written out of bounds: ${w} (0..${lw.size})`);
86
+ if (lw.internal) this.#writePos -= lw.size - w;
87
+ else if (w > 0) {
88
+ const chunk = w === lw.size ? lw.buf : lw.buf.subarray(0, w);
89
+ this.#pending.push(chunk);
90
+ this.#pendingBytes += chunk.length;
91
+ }
92
+ this.#lastWrite = null;
93
+ }
94
+ async #flushPending() {
95
+ if (this.#error) throw this.#error;
96
+ if (this.#lastWrite) throw new Error("disposeWriteSync must be called before flush/write");
97
+ while (this.#pending.length > 0) {
98
+ const chunk = this.#pending[0];
99
+ try {
100
+ await this.#writable.write(chunk);
101
+ } catch (e) {
102
+ this.#error = e;
103
+ throw e;
104
+ }
105
+ this.#pending.shift();
106
+ this.#pendingBytes -= chunk.length;
107
+ }
108
+ }
109
+ async flush() {
110
+ await this.#flushPending();
111
+ if (this.#error) throw this.#error;
112
+ if (this.#writePos === 0) return;
113
+ try {
114
+ await this.#writable.write(this.#buffer.subarray(0, this.#writePos));
115
+ } catch (e) {
116
+ this.#error = e;
117
+ throw e;
118
+ }
119
+ this.#writePos = 0;
120
+ }
121
+ async write(bytes) {
122
+ if (this.#error) throw this.#error;
123
+ if (!bytes.length) return;
124
+ await this.#flushPending();
125
+ if (this.#writePos === 0 && bytes.length >= this.#buffer.byteLength) {
126
+ try {
127
+ await this.#writable.write(bytes);
128
+ } catch (e) {
129
+ this.#error = e;
130
+ throw e;
131
+ }
132
+ return;
133
+ }
134
+ let off = 0;
135
+ while (off < bytes.length) {
136
+ if (this.available === 0) {
137
+ await this.flush();
138
+ continue;
139
+ }
140
+ const toCopy = Math.min(this.available, bytes.length - off);
141
+ this.#buffer.set(bytes.subarray(off, off + toCopy), this.#writePos);
142
+ this.#writePos += toCopy;
143
+ off += toCopy;
144
+ if (this.#writePos === this.#buffer.byteLength) await this.flush();
145
+ }
146
+ }
147
+ };
148
+ //#endregion
149
+ exports.BufWriter = BufWriter;
@@ -0,0 +1,13 @@
1
+ import { ISyncWritable, IWritable } from '@fuman/io';
2
+ export declare class BufWriter implements IWritable, ISyncWritable {
3
+ #private;
4
+ constructor(writable: IWritable, size?: number);
5
+ get bufferSize(): number;
6
+ get buffered(): number;
7
+ get available(): number;
8
+ reset(writable: IWritable): void;
9
+ writeSync(bytes: number): Uint8Array;
10
+ disposeWriteSync(written?: number): void;
11
+ flush(): Promise<void>;
12
+ write(bytes: Uint8Array): Promise<void>;
13
+ }
@@ -0,0 +1,13 @@
1
+ import { ISyncWritable, IWritable } from '@fuman/io';
2
+ export declare class BufWriter implements IWritable, ISyncWritable {
3
+ #private;
4
+ constructor(writable: IWritable, size?: number);
5
+ get bufferSize(): number;
6
+ get buffered(): number;
7
+ get available(): number;
8
+ reset(writable: IWritable): void;
9
+ writeSync(bytes: number): Uint8Array;
10
+ disposeWriteSync(written?: number): void;
11
+ flush(): Promise<void>;
12
+ write(bytes: Uint8Array): Promise<void>;
13
+ }
@@ -0,0 +1,148 @@
1
+ import { u8 } from "@fuman/utils";
2
+ //#region src/io/buf-writer.ts
3
+ var DEFAULT_BUF_SIZE = 4096;
4
+ var MIN_BUF_SIZE = 16;
5
+ var BufWriter = class {
6
+ #buffer;
7
+ #writable;
8
+ #writePos = 0;
9
+ #error = null;
10
+ #pending = [];
11
+ #pendingBytes = 0;
12
+ #lastWrite = null;
13
+ constructor(writable, size = DEFAULT_BUF_SIZE) {
14
+ if (size < MIN_BUF_SIZE) size = MIN_BUF_SIZE;
15
+ this.#buffer = u8.alloc(size);
16
+ this.#writable = writable;
17
+ }
18
+ get bufferSize() {
19
+ return this.#buffer.byteLength;
20
+ }
21
+ get buffered() {
22
+ return this.#pendingBytes + this.#writePos;
23
+ }
24
+ get available() {
25
+ return this.#buffer.byteLength - this.#writePos;
26
+ }
27
+ reset(writable) {
28
+ this.#error = null;
29
+ this.#writePos = 0;
30
+ this.#pending.length = 0;
31
+ this.#pendingBytes = 0;
32
+ this.#lastWrite = null;
33
+ this.#writable = writable;
34
+ }
35
+ writeSync(bytes) {
36
+ if (this.#error) throw this.#error;
37
+ if (bytes < 0) throw new RangeError("bytes must be >= 0");
38
+ if (this.#lastWrite) throw new Error("disposeWriteSync must be called before the next writeSync");
39
+ if (bytes === 0) {
40
+ const empty = this.#buffer.subarray(this.#writePos, this.#writePos);
41
+ this.#lastWrite = {
42
+ buf: empty,
43
+ size: 0,
44
+ internal: true
45
+ };
46
+ return empty;
47
+ }
48
+ if (bytes > this.available && this.#writePos > 0) {
49
+ const copy = u8.allocWith(this.#buffer.subarray(0, this.#writePos));
50
+ this.#pending.push(copy);
51
+ this.#pendingBytes += copy.length;
52
+ this.#writePos = 0;
53
+ }
54
+ if (bytes <= this.#buffer.byteLength) {
55
+ if (bytes > this.available) {
56
+ const copy = u8.allocWith(this.#buffer.subarray(0, this.#writePos));
57
+ this.#pending.push(copy);
58
+ this.#pendingBytes += copy.length;
59
+ this.#writePos = 0;
60
+ }
61
+ const start = this.#writePos;
62
+ const end = start + bytes;
63
+ const slice = this.#buffer.subarray(start, end);
64
+ this.#writePos = end;
65
+ this.#lastWrite = {
66
+ buf: slice,
67
+ size: bytes,
68
+ internal: true
69
+ };
70
+ return slice;
71
+ }
72
+ const chunk = u8.alloc(bytes);
73
+ this.#lastWrite = {
74
+ buf: chunk,
75
+ size: bytes,
76
+ internal: false
77
+ };
78
+ return chunk;
79
+ }
80
+ disposeWriteSync(written) {
81
+ const lw = this.#lastWrite;
82
+ if (!lw) return;
83
+ const w = written ?? lw.size;
84
+ if (w < 0 || w > lw.size) throw new RangeError(`written out of bounds: ${w} (0..${lw.size})`);
85
+ if (lw.internal) this.#writePos -= lw.size - w;
86
+ else if (w > 0) {
87
+ const chunk = w === lw.size ? lw.buf : lw.buf.subarray(0, w);
88
+ this.#pending.push(chunk);
89
+ this.#pendingBytes += chunk.length;
90
+ }
91
+ this.#lastWrite = null;
92
+ }
93
+ async #flushPending() {
94
+ if (this.#error) throw this.#error;
95
+ if (this.#lastWrite) throw new Error("disposeWriteSync must be called before flush/write");
96
+ while (this.#pending.length > 0) {
97
+ const chunk = this.#pending[0];
98
+ try {
99
+ await this.#writable.write(chunk);
100
+ } catch (e) {
101
+ this.#error = e;
102
+ throw e;
103
+ }
104
+ this.#pending.shift();
105
+ this.#pendingBytes -= chunk.length;
106
+ }
107
+ }
108
+ async flush() {
109
+ await this.#flushPending();
110
+ if (this.#error) throw this.#error;
111
+ if (this.#writePos === 0) return;
112
+ try {
113
+ await this.#writable.write(this.#buffer.subarray(0, this.#writePos));
114
+ } catch (e) {
115
+ this.#error = e;
116
+ throw e;
117
+ }
118
+ this.#writePos = 0;
119
+ }
120
+ async write(bytes) {
121
+ if (this.#error) throw this.#error;
122
+ if (!bytes.length) return;
123
+ await this.#flushPending();
124
+ if (this.#writePos === 0 && bytes.length >= this.#buffer.byteLength) {
125
+ try {
126
+ await this.#writable.write(bytes);
127
+ } catch (e) {
128
+ this.#error = e;
129
+ throw e;
130
+ }
131
+ return;
132
+ }
133
+ let off = 0;
134
+ while (off < bytes.length) {
135
+ if (this.available === 0) {
136
+ await this.flush();
137
+ continue;
138
+ }
139
+ const toCopy = Math.min(this.available, bytes.length - off);
140
+ this.#buffer.set(bytes.subarray(off, off + toCopy), this.#writePos);
141
+ this.#writePos += toCopy;
142
+ off += toCopy;
143
+ if (this.#writePos === this.#buffer.byteLength) await this.flush();
144
+ }
145
+ }
146
+ };
147
+ //#endregion
148
+ export { BufWriter };