web-streams-shim 1.0.4 → 1.0.6

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 CHANGED
@@ -1,69 +1,129 @@
1
- ## Web Streams Shim Library
1
+ ## Web Streams Shim
2
2
 
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.
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
+ At the top of your web page put
10
+
11
+ ```html
12
+ <script src="https://cdn.jsdelivr.net/npm/web-streams-shim/web-streams-core.js"></script>
13
+ ```
14
+
15
+ Dynamic import
16
+
17
+ `await import('`[https://cdn.jsdelivr.net/npm/web-streams-shim/web-streams-core.js](https://cdn.jsdelivr.net/npm/web-streams-shim/web-streams-core.js)`');`
18
+
7
19
  ***
8
20
 
9
21
  ## Key Features and Polyfills
10
22
 
11
- The library focuses on extending core browser APIs to meet the latest Web Stream and Fetch specifications.
23
+ The library focuses on extending core browser APIs to meet the latest Web Stream and Fetch specifications. Compatibility tables are generated dynamically from mdn's caniuse api.
12
24
 
13
- ### 1. ReadableStream Async Iteration
25
+ ### Conditional Filling
26
+
27
+ 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.
28
+
29
+ ### ReadableStream Async Iteration
14
30
 
15
31
  The library adds **comprehensive support for modern JavaScript iteration patterns** to `ReadableStream` and its readers.
16
32
 
17
- | Target | Method/Property | Description |
33
+ ![ReadableStream.asyncIterator](https://caniuse.smokestack.workers.dev/?feature=ReadableStream.@@asyncIterator)
34
+
35
+ | | | |
18
36
  | :--- | :--- | :--- |
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. |
37
+ | [`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. |
21
38
 
22
- ![ReadableStream.asyncIterator](https://caniuse.smokestack.workers.dev/?feature=api.ReadableStream.@@asyncIterator)
23
39
  ![ReadableStream.values](https://caniuse.smokestack.workers.dev/?feature=api.ReadableStream.values)
24
40
 
25
- ### 2. Stream Construction Utility
41
+ | | | |
42
+ | :--- | :--- | :--- |
43
+ | [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) | `values()` | An alias for `[Symbol.asyncIterator]` for explicit iteration. |
44
+
45
+
46
+ ### Stream Construction Utility
26
47
 
27
48
  The library adds the static method for creating streams from existing data sources.
28
49
 
29
- | Target | Method/Property | Description |
50
+ | | | |
30
51
  | :--- | :--- | :--- |
31
52
  | [`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
53
 
33
- ![ReadableStream.from](https://caniuse.smokestack.workers.dev/?feature=api.ReadableStream.from)
54
+ ![ReadableStream.from](https://caniuse.smokestack.workers.dev/?feature=ReadableStream.from)
34
55
 
35
- ### 3. Fetch and Body Integration Shims
56
+ ### Body Shim
36
57
 
37
- These shims ensure `Request` and `Response` objects (Records) consistently expose their body as a stream and provide the `bytes()` utility.
58
+ This shim ensures `Request` and `Response` objects consistently expose their body as a stream.
38
59
 
39
- | Target | Method/Property | Description |
60
+ ![Request.body](https://caniuse.smokestack.workers.dev/?feature=Request.body)
61
+
62
+ | | | |
40
63
  | :--- | :--- | :--- |
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. |
64
+ | [`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. |
44
65
 
45
- ![Request.body](https://caniuse.smokestack.workers.dev/?feature=api.Request.body)
46
66
  ![Response.body](https://caniuse.smokestack.workers.dev/?feature=api.Response.body)
47
- ![Request.bytes](https://caniuse.smokestack.workers.dev/?feature=api.Request.bytes)
48
- ![Response.bytes](https://caniuse.smokestack.workers.dev/?feature=api.Response.bytes)
49
- ![Blob.bytes](https://caniuse.smokestack.workers.dev/?feature=api.Blob.bytes)
50
67
 
51
- ### 4. Duplex Compliance Shim
68
+ | | | |
69
+ | :--- | :--- | :--- |
70
+ | [`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`. |
71
+
72
+
73
+ ### Bytes Shim
74
+
75
+ This shim ensures `Request` and `Response`, and `Blob` objects consistently provide the `bytes()` utility.
76
+
77
+ ![Request.bytes](https://caniuse.smokestack.workers.dev/?feature=Request.bytes)
52
78
 
53
- To satisfy modern `fetch` specifications when streaming request bodies, the library ensures compliance for **half-duplex operations**.
79
+ | | | |
80
+ | :--- | :--- | :--- |
81
+ | [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request/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`**. |
82
+
83
+ ![Response.bytes](https://caniuse.smokestack.workers.dev/?feature=Response.bytes)
84
+
85
+ | | | |
86
+ | :--- | :--- | :--- |
87
+ | [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response/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`**. |
88
+
89
+ ![Blob.bytes](https://caniuse.smokestack.workers.dev/?feature=Blob.bytes)
90
+
91
+ | | | |
92
+ | :--- | :--- | :--- |
93
+ | [`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`**. |
94
+
95
+
96
+ ### Duplex Compliance Shim
97
+
98
+ 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
99
 
55
100
  * **Property Injection:** The `duplex: 'half'` property is added to the prototypes of `Request`, `Response`, `ReadableStream`, and `Blob`.
56
101
  * **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
102
  * **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
103
 
59
- ![Request.duplex](https://caniuse.smokestack.workers.dev/?feature=api.Request.duplex)
104
+ ![Request.duplex](https://caniuse.smokestack.workers.dev/?feature=Request.duplex)
60
105
 
61
- ### 5. ReadableStreamDefaultReader Constructor Support
106
+
107
+ ### ReadableStreamDefaultReader Constructor Support
62
108
 
63
109
  The library adds support for the `ReadableStreamDefaultReader` constructor.
64
110
 
65
- | Target | Method/Property | Description |
111
+ ![ReadableStreamDefaultReader.constructor](https://caniuse.smokestack.workers.dev/?feature=ReadableStreamDefaultReader.constructor)
112
+
113
+ | | | |
66
114
  | :--- | :--- | :--- |
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. |
115
+ | [`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. |
116
+
117
+
118
+ ### Additional Shims
119
+
120
+ ![ReadableStreamBYOBReader](https://caniuse.smokestack.workers.dev/?feature=ReadableStreamBYOBReader)
121
+
122
+ ![ReadableStreamBYOBReader.constructor](https://caniuse.smokestack.workers.dev/?feature=ReadableStreamBYOBReader.constructor)
123
+
124
+ ![ReadableStreamBYOBRequest](https://caniuse.smokestack.workers.dev/?feature=ReadableStreamBYOBRequest)
125
+
126
+ ![ReadableByteStreamContoller](https://caniuse.smokestack.workers.dev/?feature=ReadableByteStreamContoller)
127
+
68
128
 
69
- ![ReadableStreamDefaultReader.constructor](https://caniuse.smokestack.workers.dev/?feature=api.ReadableStreamDefaultReader.constructor)
129
+ ![](https://cdn.jsdelivr.net/npm/web-streams-shim/web-streams-core.js)
@@ -0,0 +1,330 @@
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
+ let type = 'function';
61
+ if(String(obj).trim().startsWith('class')||/^[A-Z]|^.[A-Z]/.test(obj?.name)){
62
+ type = 'class';
63
+ }
64
+ if(String(obj).trim().startsWith('async')||/async/i.test(obj?.name)){
65
+ type = 'async function';
66
+ }
67
+ for (const str of ['toString', 'toLocaleString', Symbol.toStringTag]) {
68
+ Object.defineProperty(obj, str, {
69
+ value: makeStringer(`${type} ${obj.name} { [polyfill code] }`),
70
+ configurable: true,
71
+ writable: true,
72
+ enumerable: false,
73
+ });
74
+ }
75
+ return obj;
76
+ };
77
+ const assign = (target, source) => {
78
+ const props = Object.getOwnPropertyDescriptors(source);
79
+ for (const key in props) {
80
+ try {
81
+ Object.defineProperty(target, key, props[key]);
82
+ } catch (e) {
83
+ console.warn(e, key, props[key]);
84
+ }
85
+ }
86
+ for (const key in source) {
87
+ try {
88
+ target[key] ??= source[key];
89
+ } catch (e) {
90
+ console.warn(e, key, props[key]);
91
+ }
92
+ }
93
+ return target;
94
+ };
95
+ const cloneClass = $class => {
96
+ const clonePrototype = assign({}, $class.prototype);
97
+ const clone = $class.bind(clonePrototype);
98
+ assign(clone, $class);
99
+ clone.prototype = Object.setPrototypeOf(clonePrototype, Object.getPrototypeOf($class.prototype));
100
+ Object.setPrototypeOf(clone, Object.getPrototypeOf($class));
101
+ return clone;
102
+ };
103
+
104
+ const _closed = Object.getOwnPropertyDescriptor($global.ReadableStreamDefaultReader.prototype, 'closed')?.get;
105
+ if (_closed) {
106
+ Object.defineProperty($global.ReadableStreamDefaultReader.prototype, 'closed', {
107
+ get: extend(setStrings(async function closed() {
108
+ try {
109
+ return await _closed.call(this);
110
+ } catch (e) {
111
+ console.warn(e);
112
+ }
113
+ }), _closed),
114
+ enumerable: false,
115
+ configurable: true
116
+ });
117
+ }
118
+
119
+ if (!$global.ReadableStreamBYOBReader) {
120
+ $global.ReadableStreamBYOBReader ??= cloneClass(ReadableStreamDefaultReader);
121
+ Object.defineProperty(ReadableStreamBYOBReader, 'name', {
122
+ value: 'ReadableStreamBYOBReader',
123
+ enumerable: true,
124
+ configurable: true,
125
+ writable: true
126
+ });
127
+ setStrings(ReadableStreamBYOBReader);
128
+ const _getReader = ReadableStream.prototype.getReader;
129
+ ReadableStream.prototype.getReader = Object.setPrototypeOf(function getReader(options) {
130
+ const reader = _getReader.call(this);
131
+ if (options?.mode == 'byob') {
132
+ Object.setPrototypeOf(reader, ReadableStreamBYOBReader);
133
+ }
134
+ return reader;
135
+ }, _getReader);
136
+ extend(ReadableStreamBYOBReader, ReadableStreamDefaultReader);
137
+ const _read = ReadableStreamBYOBReader.prototype.read;
138
+ ReadableStreamBYOBReader.prototype.read = extend(setStrings(async function read(view) {
139
+ // If no view is provided, fall back to default behavior
140
+ if (!view) {
141
+ return _read.call(this, view);
142
+ }
143
+ // Read from the underlying stream (default reader behavior)
144
+ const result = await _read.call(this, view);
145
+ // If done, return with the view and done flag
146
+ if (result.done != false) {
147
+ return {
148
+ value: view,
149
+ done: true
150
+ };
151
+ }
152
+ // Convert the chunk to Uint8Array if needed
153
+ const chunk = result.value instanceof Uint8Array ? result.value : new Uint8Array(result.value);
154
+ // Determine how much data we can copy
155
+ const bytesToCopy = Math.min(chunk.byteLength, view.byteLength);
156
+ // Create a temporary view to copy into the provided view
157
+ const targetView = new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
158
+ // Copy the data into the provided buffer
159
+ targetView.set(chunk.subarray(0, bytesToCopy), 0);
160
+ // Create a view of the filled portion
161
+ const filledView = new view.constructor(view.buffer, view.byteOffset, bytesToCopy);
162
+ return {
163
+ value: filledView,
164
+ done: false
165
+ };
166
+ }), _read);
167
+ }
168
+ const supportsReadableStreamBYOBReaderConstructor = () => {
169
+ try {
170
+ const stream = new ReadableStream({
171
+ start(controller) {
172
+ controller.enqueue(new Uint8Array([0]));
173
+ controller.close();
174
+ },
175
+ type: 'bytes'
176
+ });
177
+ const reader = new ReadableStreamBYOBReader(stream);
178
+ reader.read(new Uint8Array([0])).catch((e) => console.warn(e));
179
+ return true;
180
+ } catch {
181
+ return false;
182
+ }
183
+ };
184
+ if (!supportsReadableStreamBYOBReaderConstructor()) {
185
+ const _ReadableStreamBYOBReader = $global.ReadableStreamBYOBReader;
186
+ const $ReadableStreamBYOBReader = function ReadableStreamBYOBReader(stream) {
187
+ return Object.setPrototypeOf(stream.getReader(), $global.ReadableStreamBYOBReader.prototype);
188
+ };
189
+ setStrings($ReadableStreamBYOBReader);
190
+ extend($ReadableStreamBYOBReader, _ReadableStreamBYOBReader);
191
+ $global.ReadableStreamBYOBReader = new Proxy($ReadableStreamBYOBReader, Object.setPrototypeOf({
192
+ construct: Object.setPrototypeOf(function construct(_, [stream]) {
193
+ return $ReadableStreamBYOBReader(stream);
194
+ }, $ReadableStreamBYOBReader.prototype)
195
+ }, $ReadableStreamBYOBReader));
196
+ $global.ReadableStreamBYOBReader.prototype.constructor = $global.ReadableStreamBYOBReader;
197
+ }
198
+ if (!$global.ReadableStreamBYOBRequest) {
199
+
200
+ const protectedProp = (obj, key, value) =>
201
+ Object.defineProperty(obj, `&${key}`, {
202
+ value,
203
+ writable: true,
204
+ enumerable: false,
205
+ configurable: true,
206
+ });
207
+
208
+ if (!$global.ReadableStreamBYOBRequest) {
209
+
210
+ class ReadableStreamBYOBRequest {
211
+ constructor(controller, view) {
212
+ protectedProp(this, 'controller', controller);
213
+ protectedProp(this, 'view', view);
214
+ protectedProp(this, 'responded', false);
215
+ }
216
+
217
+ get view() {
218
+ return this['&responded'] ? null : this['&view'];
219
+ }
220
+
221
+ respond(bytesWritten) {
222
+ if (this['&responded']) {
223
+ throw new TypeError('This BYOB request has already been responded to');
224
+ }
225
+ this['&responded'] = true;
226
+
227
+ const filledView = new this['&view'].constructor(
228
+ this['&view'].buffer,
229
+ this['&view'].byteOffset,
230
+ bytesWritten
231
+ );
232
+
233
+ this['&controller'].enqueue(filledView);
234
+ }
235
+
236
+ respondWithNewView(view) {
237
+ if (this['&responded']) {
238
+ throw new TypeError('This BYOB request has already been responded to');
239
+ }
240
+ this['&responded'] = true;
241
+ this['&controller'].enqueue(view);
242
+ }
243
+ }
244
+
245
+ setStrings(ReadableStreamBYOBRequest);
246
+ $global.ReadableStreamBYOBRequest = ReadableStreamBYOBRequest;
247
+
248
+ // Symbols to link streams and controllers
249
+ const $stream = Symbol('*stream');
250
+ const $controller = Symbol('*controller');
251
+ const controllerPendingViews = new WeakMap();
252
+
253
+ // Add byobRequest property to default controller
254
+ if (!('byobRequest' in ReadableStreamDefaultController.prototype)) {
255
+ Object.defineProperty(ReadableStreamDefaultController.prototype, 'byobRequest', {
256
+ get: extend(setStrings(function byobRequest() {
257
+ const view = controllerPendingViews.get(this);
258
+ if (view) {
259
+ return new ReadableStreamBYOBRequest(this, view);
260
+ }
261
+ return null;
262
+ }), ReadableStreamBYOBRequest),
263
+ configurable: true,
264
+ enumerable: true
265
+ });
266
+ }
267
+
268
+ // Wrap ReadableStream constructor
269
+ const _ReadableStream = ReadableStream;
270
+
271
+ $global.ReadableStream = extend(setStrings(function ReadableStream(underlyingSource = {}, strategy) {
272
+ const $this = this;
273
+
274
+ if (underlyingSource?.type === 'bytes') {
275
+ const wrappedSource = Object.assign({}, underlyingSource);
276
+ const originalStart = underlyingSource.start;
277
+ const originalPull = underlyingSource.pull;
278
+
279
+ wrappedSource.start = extend(setStrings(function start(controller) {
280
+ controller[$stream] = $this;
281
+ $this[$controller] = controller;
282
+ return originalStart?.call(this, controller);
283
+ }), originalStart ?? ReadableStreamDefaultController);
284
+
285
+ wrappedSource.pull = extend(setStrings(function pull(controller) {
286
+ controller[$stream] = $this;
287
+ $this[$controller] = controller;
288
+ return originalPull?.call(this, controller);
289
+ }), originalPull ?? ReadableStreamDefaultController);
290
+
291
+ const stream = new _ReadableStream(wrappedSource, strategy);
292
+ return Object.setPrototypeOf($this, stream);
293
+ }
294
+
295
+ return new _ReadableStream(underlyingSource, strategy);
296
+ }), _ReadableStream);
297
+
298
+ // Patch getReader to connect BYOB readers with controllers
299
+ const _getReader = $global.ReadableStream.prototype.getReader;
300
+ $global.ReadableStream.prototype.getReader = extend(setStrings(function getReader(options) {
301
+ const reader = _getReader.call(this, options);
302
+
303
+ if (options?.mode === 'byob') {
304
+ const _read = reader.read;
305
+
306
+ reader.read = extend(setStrings(async function read(view) {
307
+ const controller = this[$controller] ?? reader[$controller] ?? this[$stream]?.[$controller];
308
+
309
+ if (controller && view) {
310
+ controllerPendingViews.set(controller, view);
311
+ }
312
+
313
+ const result = await _read.call(this, view);
314
+
315
+ if (controller) {
316
+ controllerPendingViews.delete(controller);
317
+ }
318
+
319
+ return result;
320
+ }), _read);
321
+ }
322
+
323
+ return reader;
324
+ }), _getReader);
325
+ if(typeof ReadableByteStreamController === 'undefined'){
326
+ $global.ReadableByteStreamContoller = setStrings(class ReadableByteStreamContoller extends ReadableStreamDefaultController{});
327
+ }
328
+ }
329
+ }
330
+ })();
@@ -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 = globalThis.ReadableStreamDefaultReader;
96
+ const _ReadableStreamDefaultReader = $global.ReadableStreamDefaultReader;
96
97
  const $ReadableStreamDefaultReader = function ReadableStreamDefaultReader(stream) {
97
- return Object.setPrototypeOf(stream.getReader(), globalThis.ReadableStreamDefaultReader.prototype);
98
+ return Object.setPrototypeOf(stream.getReader(), $global.ReadableStreamDefaultReader.prototype);
98
99
  };
99
100
  setStrings($ReadableStreamDefaultReader);
100
101
  extend($ReadableStreamDefaultReader, _ReadableStreamDefaultReader);
101
- globalThis.ReadableStreamDefaultReader = new Proxy($ReadableStreamDefaultReader, Object.setPrototypeOf({
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
- globalThis.ReadableStreamDefaultReader.prototype.constructor = globalThis.ReadableStreamDefaultReader
107
+ $global.ReadableStreamDefaultReader.prototype.constructor = $global.ReadableStreamDefaultReader
107
108
  }
108
109
 
109
110
  })();
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
- let $Request = Request;
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
- $Request = class Request extends $Request {
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 = $Request;
111
+ $global.Request = _Request;
112
112
 
113
113
 
114
114
  })();
@@ -0,0 +1,43 @@
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
+ if (typeof File === 'undefined') {
9
+ // Sham File class extending Blob
10
+ $global.File = class File extends Blob {
11
+ constructor(bits, filename, options = {}) {
12
+ // Extract File-specific options
13
+ const {
14
+ lastModified = Date.now(), ...blobOptions
15
+ } = options;
16
+
17
+ // Call Blob constructor with bits and blob options
18
+ super(bits, blobOptions);
19
+
20
+ // Add File-specific properties
21
+ this['&name'] = filename;
22
+ this['&lastModified'] = lastModified;
23
+ this['&lastModifiedDate'] = new Date(lastModified);
24
+ }
25
+
26
+ get name() {
27
+ return this['&name'];
28
+ }
29
+
30
+ get lastModified() {
31
+ return this['&lastModified'];
32
+ }
33
+
34
+ get lastModifiedDate() {
35
+ return this['&lastModifiedDate'];
36
+ }
37
+
38
+ get webkitRelativePath() {
39
+ return '';
40
+ }
41
+ }
42
+ }
43
+ })();
@@ -0,0 +1,42 @@
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
+
9
+ if (typeof Location === 'undefined') {
10
+ // Sham Location class extending URL
11
+ $global.Location = class Location extends URL {
12
+ constructor(href, base) {
13
+ super(href, base);
14
+ }
15
+
16
+ // Location properties that delegate to URL
17
+ get ancestorOrigins() {
18
+ return {
19
+ length: 0
20
+ };
21
+ }
22
+
23
+ // Location methods
24
+ assign(url) {
25
+ this.href = url;
26
+ }
27
+
28
+ reload(forceReload = false) {
29
+ // Sham implementation - does nothing
30
+ console.log(`reload(${forceReload}) called`);
31
+ }
32
+
33
+ replace(url) {
34
+ this.href = url;
35
+ }
36
+
37
+ toString() {
38
+ return this.href;
39
+ }
40
+ }
41
+ }
42
+ })();
@@ -5,6 +5,7 @@
5
5
  return fn?.()
6
6
  } catch {}
7
7
  };
8
+ const $global = Q(() => globalThis) ?? Q(() => global) ?? Q(() => self) ?? Q(() => window) ?? this;
8
9
  const constructPrototype = newClass => {
9
10
  try {
10
11
  if (newClass?.prototype) return newClass;