1pub const NODE_BUFFER_JS: &str = r#"
11// ─── Encoding helpers ────────────────────────────────────────────────────────
12
13function utf8Encode(str) {
14 return new TextEncoder().encode(str);
15}
16
17function utf8Decode(bytes, start, end) {
18 return new TextDecoder().decode(bytes.subarray(start, end));
19}
20
21function hexEncode(bytes) {
22 let out = '';
23 for (let i = 0; i < bytes.length; i++) {
24 out += bytes[i].toString(16).padStart(2, '0');
25 }
26 return out;
27}
28
29function hexDecode(str) {
30 const len = str.length >>> 1;
31 const bytes = new Uint8Array(len);
32 for (let i = 0; i < len; i++) {
33 bytes[i] = parseInt(str.slice(i * 2, i * 2 + 2), 16);
34 }
35 return bytes;
36}
37
38function base64Encode(bytes) {
39 let binary = '';
40 for (let i = 0; i < bytes.length; i++) {
41 binary += String.fromCharCode(bytes[i]);
42 }
43 return globalThis.btoa(binary);
44}
45
46function base64Decode(str) {
47 const binary = globalThis.atob(str);
48 const bytes = new Uint8Array(binary.length);
49 for (let i = 0; i < binary.length; i++) {
50 bytes[i] = binary.charCodeAt(i);
51 }
52 return bytes;
53}
54
55function latin1Encode(str) {
56 const bytes = new Uint8Array(str.length);
57 for (let i = 0; i < str.length; i++) {
58 bytes[i] = str.charCodeAt(i) & 0xFF;
59 }
60 return bytes;
61}
62
63function latin1Decode(bytes, start, end) {
64 let out = '';
65 for (let i = start; i < end; i++) {
66 out += String.fromCharCode(bytes[i]);
67 }
68 return out;
69}
70
71function normalizeEncoding(enc) {
72 if (!enc || enc === 'utf8' || enc === 'utf-8') return 'utf8';
73 const lower = enc.toLowerCase();
74 if (lower === 'utf8' || lower === 'utf-8') return 'utf8';
75 if (lower === 'hex') return 'hex';
76 if (lower === 'base64') return 'base64';
77 if (lower === 'ascii' || lower === 'binary' || lower === 'latin1') return 'latin1';
78 return 'utf8';
79}
80
81function encodeString(str, encoding) {
82 switch (normalizeEncoding(encoding)) {
83 case 'hex': return hexDecode(str);
84 case 'base64': return base64Decode(str);
85 case 'latin1': return latin1Encode(str);
86 default: return utf8Encode(str);
87 }
88}
89
90function decodeBytes(bytes, encoding, start, end) {
91 start = start || 0;
92 end = end != null ? end : bytes.length;
93 switch (normalizeEncoding(encoding)) {
94 case 'hex': return hexEncode(bytes.subarray(start, end));
95 case 'base64': return base64Encode(bytes.subarray(start, end));
96 case 'latin1': return latin1Decode(bytes, start, end);
97 default: return utf8Decode(bytes, start, end);
98 }
99}
100
101// ─── Buffer class ────────────────────────────────────────────────────────────
102
103class Buffer extends Uint8Array {
104 // ── Static factory methods ─────────────────────────────────────────────
105 static from(input, encodingOrOffset, length) {
106 if (typeof input === 'string') {
107 const bytes = encodeString(input, encodingOrOffset);
108 const buf = new Buffer(bytes.length);
109 buf.set(bytes);
110 return buf;
111 }
112 if (input instanceof ArrayBuffer || input instanceof SharedArrayBuffer) {
113 const offset = encodingOrOffset || 0;
114 const len = length != null ? length : input.byteLength - offset;
115 return new Buffer(input, offset, len);
116 }
117 if (ArrayBuffer.isView(input)) {
118 const buf = new Buffer(input.length);
119 buf.set(input);
120 return buf;
121 }
122 if (Array.isArray(input)) {
123 const buf = new Buffer(input.length);
124 buf.set(input);
125 return buf;
126 }
127 if (input && typeof input === 'object' && typeof input.length === 'number') {
128 const buf = new Buffer(input.length);
129 for (let i = 0; i < input.length; i++) buf[i] = input[i] & 0xFF;
130 return buf;
131 }
132 throw new TypeError('The first argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.');
133 }
134
135 static alloc(size, fill, encoding) {
136 const buf = new Buffer(size);
137 if (fill !== undefined && fill !== 0) {
138 buf.fill(fill, 0, size, encoding);
139 }
140 return buf;
141 }
142
143 static allocUnsafe(size) {
144 return new Buffer(size);
145 }
146
147 static allocUnsafeSlow(size) {
148 return new Buffer(size);
149 }
150
151 static isBuffer(obj) {
152 return obj instanceof Buffer;
153 }
154
155 static isEncoding(encoding) {
156 return ['utf8', 'utf-8', 'hex', 'base64', 'ascii', 'binary', 'latin1']
157 .includes((encoding || '').toLowerCase());
158 }
159
160 static byteLength(string, encoding) {
161 if (typeof string !== 'string') {
162 if (ArrayBuffer.isView(string)) return string.byteLength;
163 if (string instanceof ArrayBuffer) return string.byteLength;
164 throw new TypeError('The "string" argument must be a string, Buffer, or ArrayBuffer');
165 }
166 return encodeString(string, encoding).length;
167 }
168
169 static concat(list, totalLength) {
170 if (!Array.isArray(list)) throw new TypeError('"list" argument must be an Array of Buffers');
171 if (list.length === 0) return Buffer.alloc(0);
172 const total = totalLength != null
173 ? totalLength
174 : list.reduce((acc, b) => acc + b.length, 0);
175 const result = Buffer.alloc(total);
176 let offset = 0;
177 for (const buf of list) {
178 const src = buf instanceof Uint8Array ? buf : Buffer.from(buf);
179 const copyLen = Math.min(src.length, total - offset);
180 result.set(src.subarray(0, copyLen), offset);
181 offset += copyLen;
182 if (offset >= total) break;
183 }
184 return result;
185 }
186
187 static compare(a, b) {
188 if (!(a instanceof Uint8Array) || !(b instanceof Uint8Array)) {
189 throw new TypeError('Arguments must be Buffers');
190 }
191 const len = Math.min(a.length, b.length);
192 for (let i = 0; i < len; i++) {
193 if (a[i] < b[i]) return -1;
194 if (a[i] > b[i]) return 1;
195 }
196 if (a.length < b.length) return -1;
197 if (a.length > b.length) return 1;
198 return 0;
199 }
200
201 // ── Instance methods ───────────────────────────────────────────────────
202 toString(encoding, start, end) {
203 return decodeBytes(this, encoding, start, end);
204 }
205
206 write(string, offset, length, encoding) {
207 if (typeof offset === 'string') { encoding = offset; offset = 0; length = this.length; }
208 else if (typeof length === 'string') { encoding = length; length = this.length - (offset || 0); }
209 offset = offset || 0;
210 length = length != null ? length : this.length - offset;
211 const bytes = encodeString(string, encoding);
212 const writeLen = Math.min(bytes.length, length, this.length - offset);
213 this.set(bytes.subarray(0, writeLen), offset);
214 return writeLen;
215 }
216
217 toJSON() {
218 return { type: 'Buffer', data: Array.from(this) };
219 }
220
221 equals(other) {
222 if (!(other instanceof Uint8Array)) throw new TypeError('Argument must be a Buffer');
223 return Buffer.compare(this, other) === 0;
224 }
225
226 compare(other, targetStart, targetEnd, sourceStart, sourceEnd) {
227 if (!(other instanceof Uint8Array)) throw new TypeError('Argument must be a Buffer');
228 targetStart = targetStart || 0;
229 targetEnd = targetEnd != null ? targetEnd : other.length;
230 sourceStart = sourceStart || 0;
231 sourceEnd = sourceEnd != null ? sourceEnd : this.length;
232 return Buffer.compare(
233 this.subarray(sourceStart, sourceEnd),
234 other.subarray(targetStart, targetEnd)
235 );
236 }
237
238 copy(target, targetStart, sourceStart, sourceEnd) {
239 targetStart = targetStart || 0;
240 sourceStart = sourceStart || 0;
241 sourceEnd = sourceEnd != null ? sourceEnd : this.length;
242 const len = Math.min(sourceEnd - sourceStart, target.length - targetStart);
243 target.set(this.subarray(sourceStart, sourceStart + len), targetStart);
244 return len;
245 }
246
247 indexOf(value, byteOffset, encoding) {
248 if (typeof value === 'number') {
249 byteOffset = byteOffset || 0;
250 for (let i = byteOffset; i < this.length; i++) {
251 if (this[i] === (value & 0xFF)) return i;
252 }
253 return -1;
254 }
255 if (typeof value === 'string') {
256 value = Buffer.from(value, encoding);
257 }
258 if (value instanceof Uint8Array) {
259 byteOffset = byteOffset || 0;
260 if (value.length === 0) return byteOffset <= this.length ? byteOffset : -1;
261 outer: for (let i = byteOffset; i <= this.length - value.length; i++) {
262 for (let j = 0; j < value.length; j++) {
263 if (this[i + j] !== value[j]) continue outer;
264 }
265 return i;
266 }
267 }
268 return -1;
269 }
270
271 includes(value, byteOffset, encoding) {
272 return this.indexOf(value, byteOffset, encoding) !== -1;
273 }
274
275 fill(value, offset, end, encoding) {
276 offset = offset || 0;
277 end = end != null ? end : this.length;
278 if (typeof value === 'number') {
279 for (let i = offset; i < end; i++) this[i] = value & 0xFF;
280 } else if (typeof value === 'string') {
281 const bytes = encodeString(value, encoding);
282 if (bytes.length === 0) return this;
283 for (let i = offset; i < end; i++) {
284 this[i] = bytes[(i - offset) % bytes.length];
285 }
286 }
287 return this;
288 }
289
290 slice(start, end) {
291 const sliced = super.slice(start, end);
292 const buf = new Buffer(sliced.length);
293 buf.set(sliced);
294 return buf;
295 }
296
297 subarray(start, end) {
298 // Override to return a Buffer, not a plain Uint8Array
299 const sub = super.subarray(start, end);
300 Object.setPrototypeOf(sub, Buffer.prototype);
301 return sub;
302 }
303
304 swap16() {
305 if (this.length % 2 !== 0) throw new RangeError('Buffer size must be a multiple of 16-bits');
306 for (let i = 0; i < this.length; i += 2) {
307 const t = this[i]; this[i] = this[i + 1]; this[i + 1] = t;
308 }
309 return this;
310 }
311
312 swap32() {
313 if (this.length % 4 !== 0) throw new RangeError('Buffer size must be a multiple of 32-bits');
314 for (let i = 0; i < this.length; i += 4) {
315 const t0 = this[i], t1 = this[i + 1];
316 this[i] = this[i + 3]; this[i + 1] = this[i + 2];
317 this[i + 2] = t1; this[i + 3] = t0;
318 }
319 return this;
320 }
321
322 // Read/write integers (LE/BE) — commonly used by extensions
323 readUInt8(offset) {
324 offset = offset >>> 0;
325 if (offset >= this.length) throw new RangeError('Index out of range');
326 return this[offset];
327 }
328
329 readUInt16LE(offset) {
330 offset = offset >>> 0;
331 if (offset + 2 > this.length) throw new RangeError('Index out of range');
332 return this[offset] | (this[offset + 1] << 8);
333 }
334
335 readUInt16BE(offset) {
336 offset = offset >>> 0;
337 if (offset + 2 > this.length) throw new RangeError('Index out of range');
338 return (this[offset] << 8) | this[offset + 1];
339 }
340
341 readUInt32LE(offset) {
342 offset = offset >>> 0;
343 if (offset + 4 > this.length) throw new RangeError('Index out of range');
344 return (this[offset] | (this[offset+1] << 8) | (this[offset+2] << 16)) + (this[offset+3] * 0x1000000);
345 }
346
347 readUInt32BE(offset) {
348 offset = offset >>> 0;
349 if (offset + 4 > this.length) throw new RangeError('Index out of range');
350 return (this[offset] * 0x1000000) + ((this[offset+1] << 16) | (this[offset+2] << 8) | this[offset+3]);
351 }
352
353 readInt8(offset) {
354 offset = offset >>> 0;
355 if (offset >= this.length) throw new RangeError('Index out of range');
356 const v = this[offset];
357 return v > 127 ? v - 256 : v;
358 }
359
360 writeUInt8(value, offset) {
361 offset = offset >>> 0;
362 if (offset >= this.length) throw new RangeError('Index out of range');
363 this[offset] = value & 0xFF;
364 return offset + 1;
365 }
366
367 writeUInt16LE(value, offset) {
368 offset = offset >>> 0;
369 if (offset + 2 > this.length) throw new RangeError('Index out of range');
370 this[offset] = value & 0xFF;
371 this[offset + 1] = (value >>> 8) & 0xFF;
372 return offset + 2;
373 }
374
375 writeUInt16BE(value, offset) {
376 offset = offset >>> 0;
377 if (offset + 2 > this.length) throw new RangeError('Index out of range');
378 this[offset] = (value >>> 8) & 0xFF;
379 this[offset + 1] = value & 0xFF;
380 return offset + 2;
381 }
382
383 writeUInt32LE(value, offset) {
384 offset = offset >>> 0;
385 if (offset + 4 > this.length) throw new RangeError('Index out of range');
386 this[offset] = value & 0xFF;
387 this[offset+1] = (value >>> 8) & 0xFF;
388 this[offset+2] = (value >>> 16) & 0xFF;
389 this[offset+3] = (value >>> 24) & 0xFF;
390 return offset + 4;
391 }
392
393 writeUInt32BE(value, offset) {
394 offset = offset >>> 0;
395 if (offset + 4 > this.length) throw new RangeError('Index out of range');
396 this[offset] = (value >>> 24) & 0xFF;
397 this[offset+1] = (value >>> 16) & 0xFF;
398 this[offset+2] = (value >>> 8) & 0xFF;
399 this[offset+3] = value & 0xFF;
400 return offset + 4;
401 }
402}
403
404// Make Buffer available globally (Node.js compatibility)
405globalThis.Buffer = Buffer;
406
407export { Buffer };
408export default { Buffer };
409"#;