web-streams-shim 1.0.2 → 1.0.4
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.
- package/README.md +35 -16
- package/ReadableStreamDefaultReader-constructor.js +1 -0
- package/Record-body.js +9 -0
- package/extensions/Recod-stream.js +77 -0
- package/extensions/web-streams-extensions.js +131 -0
- package/package.json +1 -1
- package/web-streams-core.js +10 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
## Web Streams Shim Library
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The Web Streams Shim Library is designed to create parity between the streaming interfaces within modern runtimes. This does not polyfill the interfaces if they are missing entirely. For that you will want [web-streams-polyfill](https://www.npmjs.com/package/web-streams-polyfill) which is not affiliated with the project.
|
|
4
4
|
|
|
5
5
|
This library provides essential polyfills and shims to ensure modern Web Streams functionality is available and compliant across environments where native support is missing or incomplete, particularly focusing on `ReadableStream`, `Request`, `Response`, and `Blob` objects.
|
|
6
6
|
|
|
@@ -10,26 +10,27 @@ This library provides essential polyfills and shims to ensure modern Web Streams
|
|
|
10
10
|
|
|
11
11
|
The library focuses on extending core browser APIs to meet the latest Web Stream and Fetch specifications.
|
|
12
12
|
|
|
13
|
-
### 1. ReadableStream Async Iteration
|
|
13
|
+
### 1. ReadableStream Async Iteration
|
|
14
14
|
|
|
15
|
-
The library adds **comprehensive support for modern JavaScript iteration
|
|
15
|
+
The library adds **comprehensive support for modern JavaScript iteration patterns** to `ReadableStream` and its readers.
|
|
16
16
|
|
|
17
17
|
| Target | Method/Property | Description |
|
|
18
18
|
| :--- | :--- | :--- |
|
|
19
|
-
| `ReadableStream.
|
|
20
|
-
| `ReadableStream.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
| `ReadableStreamDefaultReader.prototype` | `[Symbol.asyncDispose]` | **Supports the async disposal pattern (`await using`)**. It safely cleans up resources by calling the internal `terminate` function. |
|
|
19
|
+
| [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) | `[Symbol.asyncIterator]` | Allows the stream to be directly iterable in `for-await-of` loops. |
|
|
20
|
+
| [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) | `values()` | An alias for `[Symbol.asyncIterator]` for explicit iteration. |
|
|
21
|
+
|
|
22
|
+

|
|
23
|
+

|
|
25
24
|
|
|
26
25
|
### 2. Stream Construction Utility
|
|
27
26
|
|
|
28
27
|
The library adds the static method for creating streams from existing data sources.
|
|
29
28
|
|
|
30
|
-
| Target | Method | Description |
|
|
29
|
+
| Target | Method/Property | Description |
|
|
31
30
|
| :--- | :--- | :--- |
|
|
32
|
-
| `ReadableStream` | `from(obj)` | **Creates a new `ReadableStream` from any iterable or async iterable object**. It handles both synchronous and asynchronous iterators, including objects that yield `Promise`-like values. |
|
|
31
|
+
| [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) | [`from(obj)`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/from_static) | **Creates a new `ReadableStream` from any iterable or async iterable object**. It handles both synchronous and asynchronous iterators, including objects that yield `Promise`-like values. |
|
|
32
|
+
|
|
33
|
+

|
|
33
34
|
|
|
34
35
|
### 3. Fetch and Body Integration Shims
|
|
35
36
|
|
|
@@ -37,14 +38,32 @@ These shims ensure `Request` and `Response` objects (Records) consistently expos
|
|
|
37
38
|
|
|
38
39
|
| Target | Method/Property | Description |
|
|
39
40
|
| :--- | :--- | :--- |
|
|
40
|
-
| `Request
|
|
41
|
-
| `Response
|
|
42
|
-
| `Request.
|
|
41
|
+
| `Request` | [`body`](https://developer.mozilla.org/en-US/docs/Web/API/Request/body) | Polyfills the `body` property to return a **`ReadableStream` representation of the body content**. This is crucial for environments where `fetch` exists but streaming is absent. |
|
|
42
|
+
| `Response` | [`body`](https://developer.mozilla.org/en-US/docs/Web/API/Response/body) | Provides the body content as a `ReadableStream`. The implementation clones the original record, converts the body to a `Blob`, gets the blob's stream, and enqueues chunks via a controller. |
|
|
43
|
+
| [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request/bytes), [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response/bytes), [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob/bytes) | `bytes()` | Adds the `bytes()` method, which **asynchronously returns the object's body/content as a `Uint8Array`**. It achieves this by calling the native `arrayBuffer()` and wrapping the result. |
|
|
44
|
+
|
|
45
|
+

|
|
46
|
+

|
|
47
|
+

|
|
48
|
+

|
|
49
|
+

|
|
43
50
|
|
|
44
51
|
### 4. Duplex Compliance Shim
|
|
45
52
|
|
|
46
53
|
To satisfy modern `fetch` specifications when streaming request bodies, the library ensures compliance for **half-duplex operations**.
|
|
47
54
|
|
|
48
55
|
* **Property Injection:** The `duplex: 'half'` property is added to the prototypes of `Request`, `Response`, `ReadableStream`, and `Blob`.
|
|
49
|
-
* **Constructor Wrapping:** The global `Request` and `Response` constructors are subclassed and **wrapped** to automatically apply
|
|
50
|
-
* **Fetch Wrapping:** The global `fetch` function is **wrapped** to automatically apply
|
|
56
|
+
* **Constructor Wrapping:** The global `Request` and `Response` constructors are subclassed and **wrapped** to automatically apply `duplex: 'half'` utility function to all arguments passed during instantiation.
|
|
57
|
+
* **Fetch Wrapping:** The global `fetch` function is **wrapped** to automatically apply `duplex: 'half'` to its arguments before execution, guaranteeing compliance when streams are used in options.
|
|
58
|
+
|
|
59
|
+

|
|
60
|
+
|
|
61
|
+
### 5. ReadableStreamDefaultReader Constructor Support
|
|
62
|
+
|
|
63
|
+
The library adds support for the `ReadableStreamDefaultReader` constructor.
|
|
64
|
+
|
|
65
|
+
| Target | Method/Property | Description |
|
|
66
|
+
| :--- | :--- | :--- |
|
|
67
|
+
| [`ReadableStreamDefaultReader`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader) | [`constructor(stream)`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/ReadableStream) | **Polyfills the `ReadableStreamDefaultReader` constructor** to accept a stream directly. In environments where the native constructor doesn't support this (like Bun), it delegates to `stream.getReader()` and properly sets up the prototype chain. This allows `new ReadableStreamDefaultReader(stream)` to work consistently across all runtimes. |
|
|
68
|
+
|
|
69
|
+

|
|
@@ -103,6 +103,7 @@
|
|
|
103
103
|
return $ReadableStreamDefaultReader(stream)
|
|
104
104
|
},$ReadableStreamDefaultReader.prototype)
|
|
105
105
|
},$ReadableStreamDefaultReader));
|
|
106
|
+
globalThis.ReadableStreamDefaultReader.prototype.constructor = globalThis.ReadableStreamDefaultReader
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
})();
|
package/Record-body.js
CHANGED
|
@@ -267,6 +267,15 @@
|
|
|
267
267
|
configurable: true,
|
|
268
268
|
enumerable: true,
|
|
269
269
|
});
|
|
270
|
+
if('bodyUsed' in record.prototype)return;
|
|
271
|
+
Object.defineProperty(record.prototype, "bodyUsed", {
|
|
272
|
+
get:setStrings(function bodyUsed(){
|
|
273
|
+
return this.body?.locked;
|
|
274
|
+
}),
|
|
275
|
+
set:()=>{},
|
|
276
|
+
configurable:true,
|
|
277
|
+
enumerable:true
|
|
278
|
+
});
|
|
270
279
|
})();
|
|
271
280
|
|
|
272
281
|
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
|
|
2
|
+
(() => {
|
|
3
|
+
const Q = fn => {
|
|
4
|
+
try {
|
|
5
|
+
return fn?.()
|
|
6
|
+
} catch {}
|
|
7
|
+
};
|
|
8
|
+
const constructPrototype = newClass => {
|
|
9
|
+
try {
|
|
10
|
+
if (newClass?.prototype) return newClass;
|
|
11
|
+
const constProto = newClass?.constructor?.prototype;
|
|
12
|
+
if (constProto) {
|
|
13
|
+
newClass.prototype = Q(() => constProto?.bind?.(constProto)) ?? Object.create(Object(constProto));
|
|
14
|
+
return newClass;
|
|
15
|
+
}
|
|
16
|
+
newClass.prototype = Q(() => newClass?.bind?.(newClass)) ?? Object.create(Object(newClass));
|
|
17
|
+
} catch (e) {
|
|
18
|
+
console.warn(e, newClass);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const extend = (thisClass, superClass) => {
|
|
22
|
+
try {
|
|
23
|
+
constructPrototype(thisClass);
|
|
24
|
+
constructPrototype(superClass);
|
|
25
|
+
Object.setPrototypeOf(
|
|
26
|
+
thisClass.prototype,
|
|
27
|
+
superClass?.prototype ??
|
|
28
|
+
superClass?.constructor?.prototype ??
|
|
29
|
+
superClass
|
|
30
|
+
);
|
|
31
|
+
Object.setPrototypeOf(thisClass, superClass);
|
|
32
|
+
|
|
33
|
+
} catch (e) {
|
|
34
|
+
console.warn(e, {
|
|
35
|
+
thisClass,
|
|
36
|
+
superClass
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return thisClass;
|
|
40
|
+
};
|
|
41
|
+
const makeStringer = str => {
|
|
42
|
+
const stringer = () => str;
|
|
43
|
+
['valueOf', 'toString', 'toLocaleString', Symbol.toPrimitive].forEach(x => {
|
|
44
|
+
stringer[x] = stringer;
|
|
45
|
+
});
|
|
46
|
+
stringer[Symbol.toStringTag] = str;
|
|
47
|
+
return stringer;
|
|
48
|
+
};
|
|
49
|
+
const setStrings = (obj, name) => {
|
|
50
|
+
for (const str of ['toString', 'toLocaleString', Symbol.toStringTag]) {
|
|
51
|
+
Object.defineProperty(obj, str, {
|
|
52
|
+
value: makeStringer(`function ${obj.name}() { [polyfill code] }`),
|
|
53
|
+
configurable: true,
|
|
54
|
+
writable: true,
|
|
55
|
+
enumerable: false,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return obj;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
for (const record of [Q(() => Request), Q(() => Response)]) {
|
|
62
|
+
(() => {
|
|
63
|
+
while(record.__proto__.name === record.name) record = record.__proto__;
|
|
64
|
+
(record?.prototype ?? {}).stream ??= extend(setStrings(function stream() {
|
|
65
|
+
return this.body;
|
|
66
|
+
}), Q(() => ReadableStream) ?? {});
|
|
67
|
+
})();
|
|
68
|
+
}
|
|
69
|
+
if(!('body' in Blob.prototype)){
|
|
70
|
+
Object.defineProperty(Blob.prototype,'body',{
|
|
71
|
+
get:extend(setStrings(function body(){return this.stream();},ReadableStream)),
|
|
72
|
+
set:()=>{},
|
|
73
|
+
configurable:true,
|
|
74
|
+
enumerable:false
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
})();
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
|
|
2
|
+
(() => {
|
|
3
|
+
const Q = fn => {
|
|
4
|
+
try {
|
|
5
|
+
return fn?.()
|
|
6
|
+
} catch {}
|
|
7
|
+
};
|
|
8
|
+
const constructPrototype = newClass => {
|
|
9
|
+
try {
|
|
10
|
+
if (newClass?.prototype) return newClass;
|
|
11
|
+
const constProto = newClass?.constructor?.prototype;
|
|
12
|
+
if (constProto) {
|
|
13
|
+
newClass.prototype = Q(() => constProto?.bind?.(constProto)) ?? Object.create(Object(constProto));
|
|
14
|
+
return newClass;
|
|
15
|
+
}
|
|
16
|
+
newClass.prototype = Q(() => newClass?.bind?.(newClass)) ?? Object.create(Object(newClass));
|
|
17
|
+
} catch (e) {
|
|
18
|
+
console.warn(e, newClass);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const extend = (thisClass, superClass) => {
|
|
22
|
+
try {
|
|
23
|
+
constructPrototype(thisClass);
|
|
24
|
+
constructPrototype(superClass);
|
|
25
|
+
Object.setPrototypeOf(
|
|
26
|
+
thisClass.prototype,
|
|
27
|
+
superClass?.prototype ??
|
|
28
|
+
superClass?.constructor?.prototype ??
|
|
29
|
+
superClass
|
|
30
|
+
);
|
|
31
|
+
Object.setPrototypeOf(thisClass, superClass);
|
|
32
|
+
|
|
33
|
+
} catch (e) {
|
|
34
|
+
console.warn(e, {
|
|
35
|
+
thisClass,
|
|
36
|
+
superClass
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return thisClass;
|
|
40
|
+
};
|
|
41
|
+
const makeStringer = str => {
|
|
42
|
+
const stringer = () => str;
|
|
43
|
+
['valueOf', 'toString', 'toLocaleString', Symbol.toPrimitive].forEach(x => {
|
|
44
|
+
stringer[x] = stringer;
|
|
45
|
+
});
|
|
46
|
+
stringer[Symbol.toStringTag] = str;
|
|
47
|
+
return stringer;
|
|
48
|
+
};
|
|
49
|
+
const setStrings = (obj, name) => {
|
|
50
|
+
for (const str of ['toString', 'toLocaleString', Symbol.toStringTag]) {
|
|
51
|
+
Object.defineProperty(obj, str, {
|
|
52
|
+
value: makeStringer(`function ${obj.name}() { [polyfill code] }`),
|
|
53
|
+
configurable: true,
|
|
54
|
+
writable: true,
|
|
55
|
+
enumerable: false,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return obj;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
for (const record of [Q(() => Request), Q(() => Response)]) {
|
|
62
|
+
(() => {
|
|
63
|
+
while (record.__proto__.name === record.name) record = record.__proto__;
|
|
64
|
+
(record?.prototype ?? {}).stream ??= extend(setStrings(function stream() {
|
|
65
|
+
return this.body;
|
|
66
|
+
}), Q(() => ReadableStream) ?? {});
|
|
67
|
+
})();
|
|
68
|
+
}
|
|
69
|
+
for (const record of [Q(() => Request), Q(() => Response), Q(() => Blob)]) {
|
|
70
|
+
(() => {
|
|
71
|
+
while (record.__proto__.name === record.name) record = record.__proto__;
|
|
72
|
+
record.prototype[Symbol.asyncIterator] ??= extend(setStrings(Object.defineProperty(function asyncIterator() {
|
|
73
|
+
return this.stream()[Symbol.asyncIterator]();
|
|
74
|
+
}, 'name', {
|
|
75
|
+
value: 'Symbol.asyncIterator',
|
|
76
|
+
configurable: true,
|
|
77
|
+
writable: true,
|
|
78
|
+
enumerable: true,
|
|
79
|
+
})), ReadableStream.prototype[Symbol.asyncIterator]);
|
|
80
|
+
record.prototype.values ??= extend(setStrings(function values() {
|
|
81
|
+
return this[Symbol.asyncIterator]();
|
|
82
|
+
}), ReadableStream.prototype.values);
|
|
83
|
+
})();
|
|
84
|
+
}
|
|
85
|
+
if (!('body' in Blob.prototype)) {
|
|
86
|
+
Object.defineProperty(Blob.prototype, 'body', {
|
|
87
|
+
get: extend(setStrings(function body() {
|
|
88
|
+
return this.stream();
|
|
89
|
+
}, ReadableStream)),
|
|
90
|
+
set: () => {},
|
|
91
|
+
configurable: true,
|
|
92
|
+
enumerable: true
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
if (!('bodyUsed' in Blob.prototype)) {
|
|
96
|
+
Object.defineProperty(Blob.prototype, "bodyUsed", {
|
|
97
|
+
get: setStrings(function bodyUsed() {
|
|
98
|
+
return this.body?.locked;
|
|
99
|
+
}),
|
|
100
|
+
set: () => {},
|
|
101
|
+
configurable: true,
|
|
102
|
+
enumerable: true
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
Blob.prototype.blob ??= extend(setStrings(function blob() {
|
|
106
|
+
return this;
|
|
107
|
+
}), Blob);
|
|
108
|
+
Blob.prototype.clone ??= extend(setStrings(function clone() {
|
|
109
|
+
return this.slice();
|
|
110
|
+
}), Blob);
|
|
111
|
+
Blob.prototype.formData ??= extend(setStrings(function formData() {
|
|
112
|
+
return new Response(this).formData();
|
|
113
|
+
}), FormData);
|
|
114
|
+
Blob.prototype.json ??= extend(setStrings(function json() {
|
|
115
|
+
return new Response(this).json();
|
|
116
|
+
}), JSON);
|
|
117
|
+
ArrayBuffer.prototype.bytes ??= extend(setStrings(function bytes() {
|
|
118
|
+
return new Uint8Array(this);
|
|
119
|
+
}), Uint8Array);
|
|
120
|
+
ArrayBuffer.prototype[Symbol.iterator] ??= extend(setStrings(Object.defineProperty(function iterator() {
|
|
121
|
+
return this.bytes()[Symbol.iterator]();
|
|
122
|
+
}, 'name', {
|
|
123
|
+
value: 'Symbol.iterator',
|
|
124
|
+
configurable: true,
|
|
125
|
+
writable: true,
|
|
126
|
+
enumerable: true,
|
|
127
|
+
})), Uint8Array.prototype[Symbol.iterator]);
|
|
128
|
+
ArrayBuffer.prototype.values ??= extend(setStrings(function values() {
|
|
129
|
+
return this[Symbol.iterator]();
|
|
130
|
+
}), Uint8Array.prototype.values);
|
|
131
|
+
})();
|
package/package.json
CHANGED
package/web-streams-core.js
CHANGED
|
@@ -635,6 +635,15 @@
|
|
|
635
635
|
configurable: true,
|
|
636
636
|
enumerable: true,
|
|
637
637
|
});
|
|
638
|
+
if('bodyUsed' in record.prototype)return;
|
|
639
|
+
Object.defineProperty(record.prototype, "bodyUsed", {
|
|
640
|
+
get:setStrings(function bodyUsed(){
|
|
641
|
+
return this.body?.locked;
|
|
642
|
+
}),
|
|
643
|
+
set:()=>{},
|
|
644
|
+
configurable:true,
|
|
645
|
+
enumerable:true
|
|
646
|
+
});
|
|
638
647
|
})();
|
|
639
648
|
|
|
640
649
|
|
|
@@ -839,5 +848,6 @@
|
|
|
839
848
|
return $ReadableStreamDefaultReader(stream)
|
|
840
849
|
},$ReadableStreamDefaultReader.prototype)
|
|
841
850
|
},$ReadableStreamDefaultReader));
|
|
851
|
+
globalThis.ReadableStreamDefaultReader.prototype.constructor = globalThis.ReadableStreamDefaultReader;
|
|
842
852
|
}
|
|
843
853
|
})();
|