Mirror: A Node.js fetch shim using built-in Request, Response, and Headers (but without native fetch)
at v0.4.5 72 lines 2.0 kB view raw
1import { PassThrough, Transform, TransformCallback } from 'node:stream'; 2import * as zlib from 'node:zlib'; 3 4/** @see https://www.rfc-editor.org/rfc/rfc9112.html#section-7.2 */ 5type Encoding = 'gzip' | 'x-gzip' | 'deflate' | 'x-deflate' | 'br' | {}; 6 7/** @see https://github.com/nodejs/undici/pull/2650 */ 8class InflateStream extends Transform { 9 _opts?: zlib.ZlibOptions; 10 _inflate?: Transform; 11 12 constructor(opts?: zlib.ZlibOptions) { 13 super(); 14 this._opts = opts; 15 } 16 17 _transform( 18 chunk: Buffer, 19 encoding: BufferEncoding, 20 callback: TransformCallback 21 ) { 22 if (!this._inflate) { 23 if (chunk.length === 0) { 24 callback(); 25 return; 26 } 27 this._inflate = 28 (chunk[0] & 0x0f) === 0x08 29 ? zlib.createInflate(this._opts) 30 : zlib.createInflateRaw(this._opts); 31 this._inflate.on('data', this.push.bind(this)); 32 this._inflate.on('end', () => this.push(null)); 33 this._inflate.on('error', err => this.destroy(err)); 34 } 35 this._inflate.write(chunk, encoding, callback); 36 } 37 38 _final(callback: TransformCallback) { 39 if (this._inflate) { 40 this._inflate.once('finish', callback); 41 this._inflate.end(); 42 this._inflate = undefined; 43 } else { 44 callback(); 45 } 46 } 47} 48 49export const createContentDecoder = (encoding: Encoding | {}) => { 50 // See: https://github.com/nodejs/undici/blob/008187b/lib/web/fetch/index.js#L2138-L2160 51 switch (encoding) { 52 case 'br': 53 return zlib.createBrotliDecompress({ 54 flush: zlib.constants.BROTLI_OPERATION_FLUSH, 55 finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH, 56 }); 57 case 'gzip': 58 case 'x-gzip': 59 return zlib.createGunzip({ 60 flush: zlib.constants.Z_SYNC_FLUSH, 61 finishFlush: zlib.constants.Z_SYNC_FLUSH, 62 }); 63 case 'deflate': 64 case 'x-deflate': 65 return new InflateStream({ 66 flush: zlib.constants.Z_SYNC_FLUSH, 67 finishFlush: zlib.constants.Z_SYNC_FLUSH, 68 }); 69 default: 70 return new PassThrough(); 71 } 72};