main
js 135 lines 3.99 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @flow
8 */
9
10 /* global Bun */
11
12 import type {Writable} from 'stream';
13
14 type BunReadableStreamController = ReadableStreamController & {
15 end(): mixed,
16 write(data: Chunk | BinaryChunk): void,
17 error(error: Error): void,
18 flush?: () => void,
19 };
20
21 interface MightBeFlushable {
22 flush?: () => void;
23 }
24
25 export type Destination =
26 | BunReadableStreamController
27 | (Writable & MightBeFlushable);
28
29 export type PrecomputedChunk = string;
30 export opaque type Chunk = string;
31 export type BinaryChunk = $ArrayBufferView;
32
33 export function scheduleWork(callback: () => void) {
34 setTimeout(callback, 0);
35 }
36
37 export const scheduleMicrotask = queueMicrotask;
38
39 export function flushBuffered(destination: Destination) {
40 // Bun direct streams provide a flush function.
41 // If we don't have any more data to send right now.
42 // Flush whatever is in the buffer to the wire.
43 if (typeof destination.flush === 'function') {
44 destination.flush();
45 }
46 }
47
48 export function beginWriting(destination: Destination) {}
49
50 export function writeChunk(
51 destination: Destination,
52 chunk: PrecomputedChunk | Chunk | BinaryChunk,
53 ): void {
54 if (chunk.length === 0) {
55 return;
56 }
57
58 // $FlowFixMe[incompatible-type]: write() is compatible with both types in Bun
59 destination.write(chunk);
60 }
61
62 export function writeChunkAndReturn(
63 destination: Destination,
64 chunk: PrecomputedChunk | Chunk | BinaryChunk,
65 ): boolean {
66 // $FlowFixMe[incompatible-type]: write() is compatible with both types in Bun
67 return !!destination.write(chunk);
68 }
69
70 export function completeWriting(destination: Destination) {}
71
72 export function close(destination: Destination) {
73 destination.end();
74 }
75
76 export function stringToChunk(content: string): Chunk {
77 return content;
78 }
79
80 export function stringToPrecomputedChunk(content: string): PrecomputedChunk {
81 return content;
82 }
83
84 export function typedArrayToBinaryChunk(
85 content: $ArrayBufferView,
86 ): BinaryChunk {
87 // TODO: Does this needs to be cloned if it's transferred in enqueue()?
88 return content;
89 }
90
91 export function byteLengthOfChunk(chunk: Chunk | PrecomputedChunk): number {
92 return Buffer.byteLength(chunk, 'utf8');
93 }
94
95 export function byteLengthOfBinaryChunk(chunk: BinaryChunk): number {
96 return chunk.byteLength;
97 }
98
99 export function closeWithError(destination: Destination, error: mixed): void {
100 // $FlowFixMe[incompatible-use]
101 // $FlowFixMe[method-unbinding]
102 if (typeof destination.error === 'function') {
103 // $FlowFixMe[incompatible-type]: This is an Error object or the destination accepts other types.
104 destination.error(error);
105
106 // $FlowFixMe[incompatible-use]
107 // $FlowFixMe[method-unbinding]
108 } else if (typeof destination.destroy === 'function') {
109 // $FlowFixMe[incompatible-type]: This is an Error object or the destination accepts other types.
110 destination.destroy(error);
111
112 // $FlowFixMe[incompatible-use]
113 // $FlowFixMe[method-unbinding]
114 } else if (typeof destination.close === 'function') {
115 // Earlier implementations doesn't support this method. In that environment you're
116 // supposed to throw from a promise returned but we don't return a promise in our
117 // approach. We could fork this implementation but this is environment is an edge
118 // case to begin with. It's even less common to run this in an older environment.
119 // Even then, this is not where errors are supposed to happen and they get reported
120 // to a global callback in addition to this anyway. So it's fine just to close this.
121 destination.close();
122 }
123 }
124
125 export function createFastHash(input: string): number {
126 return Bun.hash(input);
127 }
128
129 export function readAsDataURL(blob: Blob): Promise<string> {
130 return blob.arrayBuffer().then(arrayBuffer => {
131 const encoded = Buffer.from(arrayBuffer).toString('base64');
132 const mimeType = blob.type || 'application/octet-stream';
133 return 'data:' + mimeType + ';base64,' + encoded;
134 });
135 }