UNPKG

@worker-tools/stream-response

Version:

Fetch API Response objects made from async generators. Build streaming HTML responses or SSE with JS sugar.

80 lines 3.6 kB
var _a, _b; // deno-lint-ignore-file no-explicit-any import * as dntShim from "./_dnt.shims.js"; import { asyncIterToStream, streamToAsyncIter } from 'whatwg-stream-to-async-iter'; import { concatUint8Arrays } from 'typed-array-utils'; import { aMap, aJoin, collect, promiseToStream } from './iter.js'; const maybeAsyncIterToStream = (x) => x instanceof ReadableStream ? x : asyncIterToStream(x); const maybeStreamToAsyncIter = (x) => x instanceof ReadableStream ? streamToAsyncIter(x) : x; // FIXME: add exception for newer versions that support streams correctly!? const isCFWorkers = ((_b = (_a = globalThis.navigator) === null || _a === void 0 ? void 0 : _a.userAgent) === null || _b === void 0 ? void 0 : _b.includes('Cloudflare-Workers')) || !('TextEncoderStream' in dntShim.dntGlobalThis); // CF Workers doesn't support non-binary Transform Streams, // so we use a version that does the byte encoding in a async iterator instead: const stringStreamToByteStream = isCFWorkers ? body => { const encoder = new TextEncoder(); return asyncIterToStream(aMap(maybeStreamToAsyncIter(body), x => encoder.encode(x))); } : body => maybeAsyncIterToStream(body).pipeThrough(new TextEncoderStream()); const CONTENT_TYPE = 'content-type'; const OCTET_STREAM = 'application/octet-stream'; export class StreamResponse extends Response { constructor(body, init) { super(body && stringStreamToByteStream(body), init); if (!this.headers.has(CONTENT_TYPE)) this.headers.set(CONTENT_TYPE, OCTET_STREAM); } } export class ByteStreamResponse extends Response { constructor(body, init) { super(body && maybeAsyncIterToStream(body), init); if (!this.headers.has(CONTENT_TYPE)) this.headers.set(CONTENT_TYPE, OCTET_STREAM); } } /** * If for any reason you don't want to use streaming response bodies, * you can use this class instead, which will buffer the entire body before releasing it to the network. * Note that headers will still be sent immediately. */ export class BufferedStreamResponse extends Response { constructor(body, init) { super(body && promiseToStream(aJoin(maybeStreamToAsyncIter(body)).then(str => new TextEncoder().encode(str))), init); if (!this.headers.has(CONTENT_TYPE)) this.headers.set(CONTENT_TYPE, OCTET_STREAM); } } export class BufferedByteStreamResponse extends Response { constructor(body, init) { super(body && promiseToStream(collect(maybeStreamToAsyncIter(body)).then(chunks => concatUint8Arrays(...chunks))), init); if (!this.headers.has(CONTENT_TYPE)) this.headers.set(CONTENT_TYPE, OCTET_STREAM); } } export { BufferedStreamResponse as BufferedResponse }; export class StreamRequest extends Request { constructor(input, init) { const { body, ...rest } = init || {}; super(input, { ...body ? { body: stringStreamToByteStream(body) } : {}, ...rest, }); if (body && !this.headers.has(CONTENT_TYPE)) this.headers.set(CONTENT_TYPE, OCTET_STREAM); } } export class ByteStreamRequest extends Request { constructor(input, init) { const { body, ...rest } = init || {}; super(input, { ...body ? { body: maybeAsyncIterToStream(body) } : {}, ...rest, }); if (body && !this.headers.has(CONTENT_TYPE)) this.headers.set(CONTENT_TYPE, OCTET_STREAM); } } // TODO: BufferedStreamRequest... // TODO: BufferedByteStreamRequest... //# sourceMappingURL=index.js.map