web-streams-shim 1.0.3 → 1.0.5
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 +25 -15
- package/ReadableStreamBYOBReader.js +175 -0
- package/ReadableStreamDefaultReader-constructor.js +5 -4
- package/Record-body.js +9 -0
- package/Record-duplex.js +3 -3
- 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 +13 -3
package/README.md
CHANGED
|
@@ -1,28 +1,38 @@
|
|
|
1
|
-
## Web Streams Shim
|
|
1
|
+
## Web Streams Shim
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
🛶 Web Streams Shim 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
|
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<script src="https://cdn.jsdelivr.net/npm/web-streams-shim@1.0.4/web-streams-core.js"></script>
|
|
11
|
+
```
|
|
12
|
+
|
|
7
13
|
***
|
|
8
14
|
|
|
9
15
|
## Key Features and Polyfills
|
|
10
16
|
|
|
11
17
|
The library focuses on extending core browser APIs to meet the latest Web Stream and Fetch specifications.
|
|
12
18
|
|
|
13
|
-
###
|
|
19
|
+
### Conditional Filling
|
|
20
|
+
|
|
21
|
+
Each polyfill performs feature detection before initializing. If a feature is detected as already present then it is skipped so as not to overwrite native behavior where possible.
|
|
22
|
+
|
|
23
|
+
### ReadableStream Async Iteration
|
|
14
24
|
|
|
15
25
|
The library adds **comprehensive support for modern JavaScript iteration patterns** to `ReadableStream` and its readers.
|
|
16
26
|
|
|
17
27
|
| Target | Method/Property | Description |
|
|
18
28
|
| :--- | :--- | :--- |
|
|
19
|
-
| [`ReadableStream
|
|
20
|
-
| [`ReadableStream
|
|
29
|
+
| [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) | [`[Symbol.asyncIterator]`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncIterator) | Allows the stream to be directly iterable in `for-await-of` loops. |
|
|
30
|
+
| [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) | `values()` | An alias for `[Symbol.asyncIterator]` for explicit iteration. |
|
|
21
31
|
|
|
22
32
|

|
|
23
33
|

|
|
24
34
|
|
|
25
|
-
###
|
|
35
|
+
### Stream Construction Utility
|
|
26
36
|
|
|
27
37
|
The library adds the static method for creating streams from existing data sources.
|
|
28
38
|
|
|
@@ -30,17 +40,17 @@ The library adds the static method for creating streams from existing data sourc
|
|
|
30
40
|
| :--- | :--- | :--- |
|
|
31
41
|
| [`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
42
|
|
|
33
|
-

|
|
34
44
|
|
|
35
|
-
###
|
|
45
|
+
### Body and Bytes Shims
|
|
36
46
|
|
|
37
47
|
These shims ensure `Request` and `Response` objects (Records) consistently expose their body as a stream and provide the `bytes()` utility.
|
|
38
48
|
|
|
39
49
|
| Target | Method/Property | Description |
|
|
40
50
|
| :--- | :--- | :--- |
|
|
41
|
-
| `Request.
|
|
42
|
-
| `Response.
|
|
43
|
-
| [`Request
|
|
51
|
+
| [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request/body) | [`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. |
|
|
52
|
+
| [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response/body) | [`body`](https://developer.mozilla.org/en-US/docs/Web/API/Response/body) | Provides the body content as a `ReadableStream`. |
|
|
53
|
+
| [`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()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) | Adds the `bytes()` method, which **asynchronously returns the object's body/content as a `Uint8Array`**. |
|
|
44
54
|
|
|
45
55
|

|
|
46
56
|

|
|
@@ -48,9 +58,9 @@ These shims ensure `Request` and `Response` objects (Records) consistently expos
|
|
|
48
58
|

|
|
49
59
|

|
|
50
60
|
|
|
51
|
-
###
|
|
61
|
+
### Duplex Compliance Shim
|
|
52
62
|
|
|
53
|
-
To satisfy modern `fetch` specifications when streaming request bodies, the library ensures compliance for **half-duplex operations**.
|
|
63
|
+
To satisfy modern `fetch` specifications when streaming request bodies, the library ensures compliance for **half-duplex operations**. This is in many ways a reverse shim as it allows legacy code to continue to work in the absence of a duplex parameter that did not exist when the code was implemented.
|
|
54
64
|
|
|
55
65
|
* **Property Injection:** The `duplex: 'half'` property is added to the prototypes of `Request`, `Response`, `ReadableStream`, and `Blob`.
|
|
56
66
|
* **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.
|
|
@@ -58,12 +68,12 @@ To satisfy modern `fetch` specifications when streaming request bodies, the libr
|
|
|
58
68
|
|
|
59
69
|

|
|
60
70
|
|
|
61
|
-
###
|
|
71
|
+
### ReadableStreamDefaultReader Constructor Support
|
|
62
72
|
|
|
63
73
|
The library adds support for the `ReadableStreamDefaultReader` constructor.
|
|
64
74
|
|
|
65
75
|
| Target | Method/Property | Description |
|
|
66
76
|
| :--- | :--- | :--- |
|
|
67
|
-
| [`ReadableStreamDefaultReader`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader) | [`constructor(stream)`](https://developer.mozilla.org/en-US/docs/Web/API/
|
|
77
|
+
| [`ReadableStreamDefaultReader`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader) | [`constructor(stream)`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader/ReadableStreamDefaultReader) | **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
78
|
|
|
69
79
|

|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
const Q = fn => {
|
|
3
|
+
try {
|
|
4
|
+
return fn?.()
|
|
5
|
+
} catch {}
|
|
6
|
+
};
|
|
7
|
+
const $global = Q(() => globalThis) ?? Q(() => global) ?? Q(() => self) ?? Q(() => window) ?? this;
|
|
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(thisClass.prototype, superClass?.prototype ?? superClass?.constructor?.prototype ?? superClass);
|
|
26
|
+
Object.setPrototypeOf(thisClass, superClass);
|
|
27
|
+
} catch (e) {
|
|
28
|
+
console.warn(e, {
|
|
29
|
+
thisClass,
|
|
30
|
+
superClass
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return thisClass;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
|
|
37
|
+
- Creates a function that returns a string for all string conversion methods
|
|
38
|
+
- Used to provide consistent string representations for polyfilled functions
|
|
39
|
+
- @param {string} str - The string to return
|
|
40
|
+
- @returns {Function} A function that returns the string for all conversion methods
|
|
41
|
+
- @private
|
|
42
|
+
*/
|
|
43
|
+
const makeStringer = str => {
|
|
44
|
+
const stringer = () => str;
|
|
45
|
+
['valueOf', 'toString', 'toLocaleString', Symbol.toPrimitive].forEach(x => {
|
|
46
|
+
stringer[x] = stringer;
|
|
47
|
+
});
|
|
48
|
+
stringer[Symbol.toStringTag] = str;
|
|
49
|
+
return stringer;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
|
|
53
|
+
- Sets string conversion methods on a function to indicate it’s polyfill code
|
|
54
|
+
- Provides consistent debugging experience by showing polyfill status
|
|
55
|
+
- @param {Function} obj - The function to modify
|
|
56
|
+
- @returns {Function} The modified function
|
|
57
|
+
- @private
|
|
58
|
+
*/
|
|
59
|
+
const setStrings = (obj) => {
|
|
60
|
+
for (const str of ['toString', 'toLocaleString', Symbol.toStringTag]) {
|
|
61
|
+
Object.defineProperty(obj, str, {
|
|
62
|
+
value: makeStringer(`function ${obj.name}() { [polyfill code] }`),
|
|
63
|
+
configurable: true,
|
|
64
|
+
writable: true,
|
|
65
|
+
enumerable: false,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return obj;
|
|
69
|
+
};
|
|
70
|
+
const assign = (target, source) => {
|
|
71
|
+
const props = Object.getOwnPropertyDescriptors(source);
|
|
72
|
+
for (const key in props) {
|
|
73
|
+
try {
|
|
74
|
+
Object.defineProperty(target, key, props[key]);
|
|
75
|
+
} catch (e) {
|
|
76
|
+
console.warn(e, key, props[key]);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
for (const key in source) {
|
|
80
|
+
try {
|
|
81
|
+
target[key] ??= source[key];
|
|
82
|
+
} catch (e) {
|
|
83
|
+
console.warn(e, key, props[key]);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return target;
|
|
87
|
+
};
|
|
88
|
+
const cloneClass = $class => {
|
|
89
|
+
const clonePrototype = assign({}, $class.prototype);
|
|
90
|
+
const clone = $class.bind(clonePrototype);
|
|
91
|
+
assign(clone, $class);
|
|
92
|
+
clone.prototype = Object.setPrototypeOf(clonePrototype, Object.getPrototypeOf($class.prototype));
|
|
93
|
+
Object.setPrototypeOf(clone, Object.getPrototypeOf($class));
|
|
94
|
+
return clone;
|
|
95
|
+
};
|
|
96
|
+
if (!$global.ReadableStreamBYOBReader) {
|
|
97
|
+
$global.ReadableStreamBYOBReader ??= cloneClass(ReadableStreamDefaultReader);
|
|
98
|
+
Object.defineProperty(ReadableStreamBYOBReader, 'name', {
|
|
99
|
+
value: 'ReadableStreamBYOBReader',
|
|
100
|
+
enumerable: true,
|
|
101
|
+
configurable: true,
|
|
102
|
+
writable: true
|
|
103
|
+
});
|
|
104
|
+
setStrings(ReadableStreamBYOBReader);
|
|
105
|
+
const _getReader = ReadableStream.prototype.getReader;
|
|
106
|
+
ReadableStream.prototype.getReader = Object.setPrototypeOf(function getReader(options) {
|
|
107
|
+
const reader = _getReader.call(this);
|
|
108
|
+
if (options?.mode == 'byob') {
|
|
109
|
+
Object.setPrototypeOf(reader, ReadableStreamBYOBReader);
|
|
110
|
+
}
|
|
111
|
+
return reader;
|
|
112
|
+
}, _getReader);
|
|
113
|
+
extend(ReadableStreamBYOBReader, ReadableStreamDefaultReader);
|
|
114
|
+
const _read = ReadableStreamBYOBReader.prototype.read;
|
|
115
|
+
ReadableStreamBYOBReader.prototype.read = extend(setStrings(async function read(view) {
|
|
116
|
+
// If no view is provided, fall back to default behavior
|
|
117
|
+
if (!view) {
|
|
118
|
+
return _read.call(this,view);
|
|
119
|
+
}
|
|
120
|
+
// Read from the underlying stream (default reader behavior)
|
|
121
|
+
const result = await _read.call(this,view);
|
|
122
|
+
// If done, return with the view and done flag
|
|
123
|
+
if (result.done != false) {
|
|
124
|
+
return {
|
|
125
|
+
value: view,
|
|
126
|
+
done: true
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
// Convert the chunk to Uint8Array if needed
|
|
130
|
+
const chunk = result.value instanceof Uint8Array ? result.value : new Uint8Array(result.value);
|
|
131
|
+
// Determine how much data we can copy
|
|
132
|
+
const bytesToCopy = Math.min(chunk.byteLength, view.byteLength);
|
|
133
|
+
// Create a temporary view to copy into the provided view
|
|
134
|
+
const targetView = new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
|
|
135
|
+
// Copy the data into the provided buffer
|
|
136
|
+
targetView.set(chunk.subarray(0, bytesToCopy), 0);
|
|
137
|
+
// Create a view of the filled portion
|
|
138
|
+
const filledView = new view.constructor(view.buffer, view.byteOffset, bytesToCopy);
|
|
139
|
+
return {
|
|
140
|
+
value: filledView,
|
|
141
|
+
done: false
|
|
142
|
+
};
|
|
143
|
+
}), _read);
|
|
144
|
+
}
|
|
145
|
+
const supportsReadableStreamBYOBReaderConstructor = () => {
|
|
146
|
+
try {
|
|
147
|
+
const stream = new ReadableStream({
|
|
148
|
+
start(controller) {
|
|
149
|
+
controller.enqueue(new Uint8Array([0]));
|
|
150
|
+
controller.close();
|
|
151
|
+
},
|
|
152
|
+
type: 'bytes'
|
|
153
|
+
});
|
|
154
|
+
const reader = new ReadableStreamBYOBReader(stream);
|
|
155
|
+
reader.read(new Uint8Array([0]));
|
|
156
|
+
return true;
|
|
157
|
+
} catch {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
if (!supportsReadableStreamBYOBReaderConstructor()) {
|
|
162
|
+
const _ReadableStreamBYOBReader = $global.ReadableStreamBYOBReader;
|
|
163
|
+
const $ReadableStreamBYOBReader = function ReadableStreamBYOBReader(stream) {
|
|
164
|
+
return Object.setPrototypeOf(stream.getReader(), $global.ReadableStreamBYOBReader.prototype);
|
|
165
|
+
};
|
|
166
|
+
setStrings($ReadableStreamBYOBReader);
|
|
167
|
+
extend($ReadableStreamBYOBReader, _ReadableStreamBYOBReader);
|
|
168
|
+
$global.ReadableStreamBYOBReader = new Proxy($ReadableStreamBYOBReader, Object.setPrototypeOf({
|
|
169
|
+
construct: Object.setPrototypeOf(function construct(_, [stream]) {
|
|
170
|
+
return $ReadableStreamBYOBReader(stream);
|
|
171
|
+
}, $ReadableStreamBYOBReader.prototype)
|
|
172
|
+
}, $ReadableStreamBYOBReader));
|
|
173
|
+
$global.ReadableStreamBYOBReader.prototype.constructor = $global.ReadableStreamBYOBReader;
|
|
174
|
+
}
|
|
175
|
+
})();
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
return fn?.()
|
|
5
5
|
} catch {}
|
|
6
6
|
};
|
|
7
|
+
const $global = Q(()=>globalThis) ?? Q(()=>global) ?? Q(()=>self) ?? Q(()=>window) ?? this;
|
|
7
8
|
const constructPrototype = newClass => {
|
|
8
9
|
try {
|
|
9
10
|
if (newClass?.prototype) return newClass;
|
|
@@ -92,18 +93,18 @@
|
|
|
92
93
|
|
|
93
94
|
|
|
94
95
|
if (!supportsReadableStreamDefaultReaderConstructor()) {
|
|
95
|
-
const _ReadableStreamDefaultReader =
|
|
96
|
+
const _ReadableStreamDefaultReader = $global.ReadableStreamDefaultReader;
|
|
96
97
|
const $ReadableStreamDefaultReader = function ReadableStreamDefaultReader(stream) {
|
|
97
|
-
return Object.setPrototypeOf(stream.getReader(),
|
|
98
|
+
return Object.setPrototypeOf(stream.getReader(), $global.ReadableStreamDefaultReader.prototype);
|
|
98
99
|
};
|
|
99
100
|
setStrings($ReadableStreamDefaultReader);
|
|
100
101
|
extend($ReadableStreamDefaultReader, _ReadableStreamDefaultReader);
|
|
101
|
-
|
|
102
|
+
$global.ReadableStreamDefaultReader = new Proxy($ReadableStreamDefaultReader, Object.setPrototypeOf({
|
|
102
103
|
construct:Object.setPrototypeOf(function construct(_, [stream]) {
|
|
103
104
|
return $ReadableStreamDefaultReader(stream)
|
|
104
105
|
},$ReadableStreamDefaultReader.prototype)
|
|
105
106
|
},$ReadableStreamDefaultReader));
|
|
106
|
-
|
|
107
|
+
$global.ReadableStreamDefaultReader.prototype.constructor = $global.ReadableStreamDefaultReader
|
|
107
108
|
}
|
|
108
109
|
|
|
109
110
|
})();
|
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
|
|
package/Record-duplex.js
CHANGED
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
- Creates a new Request class that extends the original but processes arguments
|
|
90
90
|
*/
|
|
91
91
|
(() => {
|
|
92
|
-
|
|
92
|
+
const $Request = Request;
|
|
93
93
|
|
|
94
94
|
|
|
95
95
|
/**
|
|
@@ -102,13 +102,13 @@
|
|
|
102
102
|
* body: new ReadableStream()
|
|
103
103
|
* }); // ReadableStream automatically gets duplex: 'half'
|
|
104
104
|
*/
|
|
105
|
-
|
|
105
|
+
const _Request = class Request extends $Request {
|
|
106
106
|
constructor(...args) {
|
|
107
107
|
super(...args.map(duplexHalf));
|
|
108
108
|
}
|
|
109
109
|
};
|
|
110
110
|
|
|
111
|
-
$global.Request =
|
|
111
|
+
$global.Request = _Request;
|
|
112
112
|
|
|
113
113
|
|
|
114
114
|
})();
|
|
@@ -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
|
|
|
@@ -730,7 +739,7 @@
|
|
|
730
739
|
- Creates a new Request class that extends the original but processes arguments
|
|
731
740
|
*/
|
|
732
741
|
(() => {
|
|
733
|
-
|
|
742
|
+
const $Request = Request;
|
|
734
743
|
|
|
735
744
|
|
|
736
745
|
/**
|
|
@@ -743,13 +752,13 @@
|
|
|
743
752
|
* body: new ReadableStream()
|
|
744
753
|
* }); // ReadableStream automatically gets duplex: 'half'
|
|
745
754
|
*/
|
|
746
|
-
|
|
755
|
+
const _Request = class Request extends $Request {
|
|
747
756
|
constructor(...args) {
|
|
748
757
|
super(...args.map(duplexHalf));
|
|
749
758
|
}
|
|
750
759
|
};
|
|
751
760
|
|
|
752
|
-
$global.Request =
|
|
761
|
+
$global.Request = _Request;
|
|
753
762
|
|
|
754
763
|
|
|
755
764
|
})();
|
|
@@ -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
|
})();
|