@npy/fetch 0.1.2 → 0.1.3

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 (142) hide show
  1. package/README.md +143 -50
  2. package/bun.lock +68 -0
  3. package/examples/custom-proxy-client.ts +32 -0
  4. package/examples/http-client.ts +47 -0
  5. package/examples/proxy.ts +16 -0
  6. package/examples/simple.ts +15 -0
  7. package/package.json +25 -30
  8. package/src/_internal/consts.ts +3 -0
  9. package/{_internal/decode-stream-error.d.cts → src/_internal/decode-stream-error.ts} +7 -2
  10. package/src/_internal/error-mapping.ts +160 -0
  11. package/src/_internal/guards.ts +78 -0
  12. package/src/_internal/net.ts +173 -0
  13. package/src/_internal/promises.ts +22 -0
  14. package/src/_internal/streams.ts +52 -0
  15. package/src/_internal/symbols.ts +1 -0
  16. package/src/agent-pool.ts +157 -0
  17. package/src/agent.ts +408 -0
  18. package/src/body.ts +179 -0
  19. package/src/dialers/index.ts +3 -0
  20. package/src/dialers/proxy.ts +102 -0
  21. package/src/dialers/tcp.ts +162 -0
  22. package/src/encoding.ts +222 -0
  23. package/src/errors.ts +357 -0
  24. package/src/fetch.ts +626 -0
  25. package/src/http-client.ts +111 -0
  26. package/src/index.ts +14 -0
  27. package/src/io/_utils.ts +82 -0
  28. package/src/io/buf-writer.ts +183 -0
  29. package/src/io/io.ts +322 -0
  30. package/src/io/readers.ts +576 -0
  31. package/src/io/writers.ts +331 -0
  32. package/{types/agent.d.cts → src/types/agent.ts} +47 -21
  33. package/{types/dialer.d.cts → src/types/dialer.ts} +19 -9
  34. package/src/types/index.ts +2 -0
  35. package/tests/agent-pool.test.ts +111 -0
  36. package/tests/agent.test.ts +134 -0
  37. package/tests/body.test.ts +228 -0
  38. package/tests/errors.test.ts +152 -0
  39. package/tests/fetch.test.ts +421 -0
  40. package/tests/io-options.test.ts +127 -0
  41. package/tests/multipart.test.ts +348 -0
  42. package/tests/test-utils.ts +335 -0
  43. package/tsconfig.json +15 -0
  44. package/LICENSE +0 -21
  45. package/_internal/consts.cjs +0 -4
  46. package/_internal/consts.d.cts +0 -3
  47. package/_internal/consts.d.ts +0 -3
  48. package/_internal/consts.js +0 -4
  49. package/_internal/decode-stream-error.cjs +0 -18
  50. package/_internal/decode-stream-error.d.ts +0 -11
  51. package/_internal/decode-stream-error.js +0 -18
  52. package/_internal/error-mapping.cjs +0 -44
  53. package/_internal/error-mapping.d.cts +0 -15
  54. package/_internal/error-mapping.d.ts +0 -15
  55. package/_internal/error-mapping.js +0 -41
  56. package/_internal/guards.cjs +0 -23
  57. package/_internal/guards.d.cts +0 -15
  58. package/_internal/guards.d.ts +0 -15
  59. package/_internal/guards.js +0 -15
  60. package/_internal/net.cjs +0 -95
  61. package/_internal/net.d.cts +0 -11
  62. package/_internal/net.d.ts +0 -11
  63. package/_internal/net.js +0 -92
  64. package/_internal/promises.cjs +0 -18
  65. package/_internal/promises.d.cts +0 -1
  66. package/_internal/promises.d.ts +0 -1
  67. package/_internal/promises.js +0 -18
  68. package/_internal/streams.cjs +0 -37
  69. package/_internal/streams.d.cts +0 -21
  70. package/_internal/streams.d.ts +0 -21
  71. package/_internal/streams.js +0 -36
  72. package/_internal/symbols.cjs +0 -4
  73. package/_internal/symbols.d.cts +0 -1
  74. package/_internal/symbols.d.ts +0 -1
  75. package/_internal/symbols.js +0 -4
  76. package/_virtual/_rolldown/runtime.cjs +0 -23
  77. package/agent-pool.cjs +0 -96
  78. package/agent-pool.d.cts +0 -2
  79. package/agent-pool.d.ts +0 -2
  80. package/agent-pool.js +0 -95
  81. package/agent.cjs +0 -260
  82. package/agent.d.cts +0 -3
  83. package/agent.d.ts +0 -3
  84. package/agent.js +0 -259
  85. package/body.cjs +0 -105
  86. package/body.d.cts +0 -12
  87. package/body.d.ts +0 -12
  88. package/body.js +0 -102
  89. package/dialers/index.d.cts +0 -3
  90. package/dialers/index.d.ts +0 -3
  91. package/dialers/proxy.cjs +0 -56
  92. package/dialers/proxy.d.cts +0 -27
  93. package/dialers/proxy.d.ts +0 -27
  94. package/dialers/proxy.js +0 -55
  95. package/dialers/tcp.cjs +0 -92
  96. package/dialers/tcp.d.cts +0 -57
  97. package/dialers/tcp.d.ts +0 -57
  98. package/dialers/tcp.js +0 -89
  99. package/encoding.cjs +0 -114
  100. package/encoding.d.cts +0 -35
  101. package/encoding.d.ts +0 -35
  102. package/encoding.js +0 -110
  103. package/errors.cjs +0 -275
  104. package/errors.d.cts +0 -110
  105. package/errors.d.ts +0 -110
  106. package/errors.js +0 -259
  107. package/fetch.cjs +0 -353
  108. package/fetch.d.cts +0 -58
  109. package/fetch.d.ts +0 -58
  110. package/fetch.js +0 -350
  111. package/http-client.cjs +0 -75
  112. package/http-client.d.cts +0 -39
  113. package/http-client.d.ts +0 -39
  114. package/http-client.js +0 -75
  115. package/index.cjs +0 -49
  116. package/index.d.cts +0 -14
  117. package/index.d.ts +0 -14
  118. package/index.js +0 -11
  119. package/io/_utils.cjs +0 -56
  120. package/io/_utils.d.cts +0 -10
  121. package/io/_utils.d.ts +0 -10
  122. package/io/_utils.js +0 -51
  123. package/io/buf-writer.cjs +0 -149
  124. package/io/buf-writer.d.cts +0 -13
  125. package/io/buf-writer.d.ts +0 -13
  126. package/io/buf-writer.js +0 -148
  127. package/io/io.cjs +0 -199
  128. package/io/io.d.cts +0 -5
  129. package/io/io.d.ts +0 -5
  130. package/io/io.js +0 -198
  131. package/io/readers.cjs +0 -337
  132. package/io/readers.d.cts +0 -69
  133. package/io/readers.d.ts +0 -69
  134. package/io/readers.js +0 -333
  135. package/io/writers.cjs +0 -196
  136. package/io/writers.d.cts +0 -22
  137. package/io/writers.d.ts +0 -22
  138. package/io/writers.js +0 -195
  139. package/types/agent.d.ts +0 -72
  140. package/types/dialer.d.ts +0 -30
  141. package/types/index.d.cts +0 -2
  142. package/types/index.d.ts +0 -2
package/index.d.cts DELETED
@@ -1,14 +0,0 @@
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 DELETED
@@ -1,14 +0,0 @@
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 DELETED
@@ -1,11 +0,0 @@
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 DELETED
@@ -1,56 +0,0 @@
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;
package/io/_utils.d.cts DELETED
@@ -1,10 +0,0 @@
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 DELETED
@@ -1,10 +0,0 @@
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 DELETED
@@ -1,51 +0,0 @@
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 };
package/io/buf-writer.cjs DELETED
@@ -1,149 +0,0 @@
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;
@@ -1,13 +0,0 @@
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
- }
@@ -1,13 +0,0 @@
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
- }
package/io/buf-writer.js DELETED
@@ -1,148 +0,0 @@
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 };