@wix/himalaya-cli 0.1579.0 → 0.1580.0

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.
@@ -0,0 +1,540 @@
1
+ // ../../core/dev-server/src/quickjs-web-globals.ts
2
+ var WEB_GLOBALS_SHIM = `
3
+ (function () {
4
+ var P = globalThis.__himiParseUrl, S = globalThis.__himiSetUrlPart;
5
+ var DI = globalThis.__himiDecoderInfo, DD = globalThis.__himiDecodeBytes;
6
+ var QD = globalThis.__himiQueryDecode, QE = globalThis.__himiQueryEncode;
7
+ delete globalThis.__himiParseUrl; delete globalThis.__himiSetUrlPart;
8
+ delete globalThis.__himiDecoderInfo; delete globalThis.__himiDecodeBytes;
9
+ delete globalThis.__himiQueryDecode; delete globalThis.__himiQueryEncode;
10
+
11
+ // CAPTURED BEFORE ANY BUNDLE RUNS, the same rule the Intl shim follows. This is not hygiene for
12
+ // its own sake: the URL parser is a HOST hook, and its answer comes back as a JSON string that
13
+ // this code parses. A bundle that replaced JSON.parse could therefore forge the parsed result of
14
+ // a URL it did not pass \u2014 turning a host-side, correct-by-construction parser into one the guest
15
+ // steers. Everything the wrappers touch on a hot path is captured for the same reason.
16
+ var $TypeError = TypeError, $String = String, $Array = Array, $Object = Object;
17
+ var $parse = JSON.parse, $stringify = JSON.stringify;
18
+ var $encodeURIComponent = encodeURIComponent, $decodeURIComponent = decodeURIComponent;
19
+ var $defineProperty = Object.defineProperty, $hasOwn = Object.prototype.hasOwnProperty;
20
+ var $fromCharCode = String.fromCharCode, $Uint8Array = Uint8Array, $Error = Error;
21
+ var $Symbol = Symbol, $RangeError = RangeError;
22
+ var $ArrayBuffer = ArrayBuffer, $isView = ArrayBuffer.isView;
23
+
24
+ // \u2500\u2500 URLSearchParams \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
25
+ //
26
+ // application/x-www-form-urlencoded, which is NOT encodeURIComponent: space is "+", and
27
+ // !'()~ are escaped where encodeURIComponent leaves them. Getting that subset wrong is
28
+ // invisible until a signature or a filter value stops matching on the server.
29
+ // PARSE AND SERIALIZE IN THE HOST. The hand-written pair was wrong twice: the escape set is not
30
+ // encodeURIComponent's (space is "+", and !'()~ differ), and decoding is not decodeURIComponent
31
+ // either \u2014 the host uses FORGIVING percent/UTF-8 decoding, so "q=a%20%E0%A4%A" keeps the decoded
32
+ // space and inserts replacement characters, where a try/catch around decodeURIComponent returned
33
+ // the whole raw component instead. Query strings are built from server and user URLs, so a
34
+ // component that silently differs is a request sent somewhere else.
35
+ var parseQuery = function (str) { return $parse(QD($String(str))); };
36
+ var serializeQuery = function (pairs) {
37
+ var body = "[";
38
+ for (var i = 0; i < pairs.length; i++) {
39
+ body += (i ? "," : "") + $stringify(pairs[i][0]) + "," + $stringify(pairs[i][1]);
40
+ }
41
+ return QE(body + "]");
42
+ };
43
+
44
+ // The host requires each sequence member to have EXACTLY two elements and throws otherwise; a
45
+ // silently-accepted 1- or 3-element entry would build a different query.
46
+ var pair = function (entry) {
47
+ if (entry === null || entry === undefined || typeof entry === "string") {
48
+ throw new $TypeError("Failed to construct URLSearchParams: the provided value cannot be converted to a sequence");
49
+ }
50
+ var len = entry.length;
51
+ if (entry[$Symbol.iterator] !== undefined && !$Array.isArray(entry)) {
52
+ var out = [], i2 = it2(entry);
53
+ for (var v2 = i2.next(); !v2.done; v2 = i2.next()) out.push(v2.value);
54
+ entry = out; len = out.length;
55
+ }
56
+ if (len !== 2) {
57
+ throw new $TypeError("Failed to construct URLSearchParams: each entry must have exactly two elements");
58
+ }
59
+ return [$String(entry[0]), $String(entry[1])];
60
+ };
61
+ var it2 = function (o) { return o[$Symbol.iterator](); };
62
+
63
+ function USP(init) {
64
+ if (!(this instanceof USP)) throw new $TypeError("Constructor URLSearchParams requires 'new'");
65
+ var pairs = [];
66
+ if (init !== undefined && init !== null) {
67
+ if (typeof init === "string") {
68
+ var parsed = parseQuery(init);
69
+ for (var i = 0; i < parsed.length; i++) pairs.push([parsed[i][0], parsed[i][1]]);
70
+ } else if (init instanceof USP) {
71
+ for (var j = 0; j < init._p.length; j++) pairs.push([init._p[j][0], init._p[j][1]]);
72
+ } else if ($Array.isArray(init)) {
73
+ for (var k = 0; k < init.length; k++) pairs.push(pair(init[k]));
74
+ } else if (typeof init === "object" && init[$Symbol.iterator] !== undefined) {
75
+ // ITERABLES BEFORE THE RECORD FALLBACK. Treating every non-array object as a record meant
76
+ // 'new URLSearchParams(new Map([["q","a b"]]))' produced an EMPTY query where the host
77
+ // gives q=a+b, because a Map has no own enumerable keys. Generated SDK clients build
78
+ // params from Maps and entries iterables, so this dropped request parameters in the
79
+ // contained realm only.
80
+ var it = init[$Symbol.iterator](), step;
81
+ while (!(step = it.next()).done) pairs.push(pair(step.value));
82
+ } else if (typeof init === "object") {
83
+ for (var key in init) if ($hasOwn.call(init, key)) pairs.push([key, $String(init[key])]);
84
+ }
85
+ }
86
+ this._p = pairs;
87
+ this._owner = null; // set when this belongs to a URL, so mutations write back to it
88
+ }
89
+ var sync = function (self) { if (self._owner) self._owner._sync(); };
90
+ USP.prototype.append = function (n, v) { this._p.push([$String(n), $String(v)]); sync(this); };
91
+ USP.prototype.set = function (n, v) {
92
+ n = $String(n); v = $String(v);
93
+ var done = false, out = [];
94
+ for (var i = 0; i < this._p.length; i++) {
95
+ if (this._p[i][0] !== n) { out.push(this._p[i]); continue; }
96
+ if (!done) { out.push([n, v]); done = true; }
97
+ }
98
+ if (!done) out.push([n, v]);
99
+ this._p = out; sync(this);
100
+ };
101
+ USP.prototype.get = function (n) {
102
+ n = $String(n);
103
+ for (var i = 0; i < this._p.length; i++) if (this._p[i][0] === n) return this._p[i][1];
104
+ return null;
105
+ };
106
+ USP.prototype.getAll = function (n) {
107
+ n = $String(n); var out = [];
108
+ for (var i = 0; i < this._p.length; i++) if (this._p[i][0] === n) out.push(this._p[i][1]);
109
+ return out;
110
+ };
111
+ // AN EXPLICIT 'undefined' COUNTS AS OMITTED, deliberately \u2014 review asked for the opposite and
112
+ // MEASUREMENT DISAGREED. WebIDL treats an optional argument passed as 'undefined' as not
113
+ // present, and node implements that:
114
+ //
115
+ // new URLSearchParams("a=1").has("a", undefined) node true
116
+ // new URLSearchParams("a=1&a=2").delete("a", undefined) node removes BOTH
117
+ //
118
+ // Keying on arguments.length alone \u2014 the change review asked for \u2014 made both diverge (false,
119
+ // and neither removed), so the finding is REJECTED rather than applied. Recorded here because
120
+ // the next reader will reasonably wonder, and because the only reason this was caught is that
121
+ // the probe compares against node rather than against a description of node.
122
+ USP.prototype.has = function (n, v) {
123
+ n = $String(n);
124
+ var wantValue = arguments.length > 1 && v !== undefined;
125
+ var want = wantValue ? $String(v) : "";
126
+ for (var i = 0; i < this._p.length; i++) {
127
+ if (this._p[i][0] !== n) continue;
128
+ if (!wantValue || this._p[i][1] === want) return true;
129
+ }
130
+ return false;
131
+ };
132
+ // Same rule as has(), and the same rejected finding: an explicit 'undefined' is omitted.
133
+ USP.prototype["delete"] = function (n, v) {
134
+ n = $String(n);
135
+ var wantValue = arguments.length > 1 && v !== undefined;
136
+ var want = wantValue ? $String(v) : "";
137
+ var out = [];
138
+ for (var i = 0; i < this._p.length; i++) {
139
+ var keep = this._p[i][0] !== n || (wantValue && this._p[i][1] !== want);
140
+ if (keep) out.push(this._p[i]);
141
+ }
142
+ this._p = out; sync(this);
143
+ };
144
+ USP.prototype.forEach = function (fn, thisArg) {
145
+ for (var i = 0; i < this._p.length; i++) fn.call(thisArg, this._p[i][1], this._p[i][0], this);
146
+ };
147
+ USP.prototype.keys = function () { return this._p.map(function (x) { return x[0]; })[Symbol.iterator](); };
148
+ USP.prototype.values = function () { return this._p.map(function (x) { return x[1]; })[Symbol.iterator](); };
149
+ USP.prototype.entries = function () { return this._p.map(function (x) { return [x[0], x[1]]; })[Symbol.iterator](); };
150
+ USP.prototype[Symbol.iterator] = USP.prototype.entries;
151
+ USP.prototype.sort = function () {
152
+ this._p.sort(function (a, b) { return a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0; }); sync(this);
153
+ };
154
+ USP.prototype.toString = function () { return serializeQuery(this._p); };
155
+ $defineProperty(USP.prototype, "size", { get: function () { return this._p.length; }, configurable: true });
156
+
157
+ // \u2500\u2500 URL \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
158
+ //
159
+ // Parsed by the HOST, then held here. Every setter re-parses through the host too, so a
160
+ // mutation cannot drift from what node would have produced for the same href.
161
+ function URLCtor(url, base) {
162
+ if (!(this instanceof URLCtor)) throw new $TypeError("Constructor URL requires 'new'");
163
+ // Created ONCE, before the first load, so every later load and setter refills this same
164
+ // object rather than replacing it.
165
+ this._sp = new USP("");
166
+ this._sp._owner = this;
167
+ this._load(P($String(url), base === undefined || base === null ? "" : $String(base)));
168
+ }
169
+ // ONE URLSearchParams per URL, for the URL's whole lifetime. Its pair list is rewritten in
170
+ // place; the object identity never changes, which is the contract node keeps.
171
+ var adoptQuery = function (url, search) {
172
+ var pairs = parseQuery(search);
173
+ var out = [];
174
+ for (var i = 0; i < pairs.length; i++) out.push([pairs[i][0], pairs[i][1]]);
175
+ // Assigned directly rather than through append(), so refilling does not call back into
176
+ // _sync() and rebuild the URL we are in the middle of loading.
177
+ url._sp._p = out;
178
+ };
179
+ URLCtor.prototype._load = function (json) {
180
+ var p = $parse(json);
181
+ if (p.error) throw new $TypeError(p.error);
182
+ this._c = p;
183
+ adoptQuery(this, p.search);
184
+ };
185
+ // Keep the query string and the live URLSearchParams in agreement in BOTH directions: node's
186
+ // URL does, and a bundle that appends a param and then reads .href would otherwise silently
187
+ // send the un-appended URL.
188
+ URLCtor.prototype._sync = function () {
189
+ // Through the host setter as well: the search component has its own normalisation, and the
190
+ // concatenated rebuild this replaced could not express a non-special scheme at all.
191
+ var q = this._sp.toString();
192
+ var p = $parse(S(this._c.href, "search", q));
193
+ if (!p.error) this._c = p;
194
+ };
195
+ // Assign through the HOST. Rebuilding an href by concatenation was wrong in every direction:
196
+ // it skipped normalisation and, worse, produced a different URL entirely \u2014 see the note on
197
+ // __himiSetUrlPart. Non-special schemes were broken too, since a mailto: has no "//" to splice.
198
+ URLCtor.prototype._set = function (part, value) {
199
+ var p = $parse(S(this._c.href, part, $String(value)));
200
+ if (p.error) throw new $TypeError(p.error);
201
+ this._c = p;
202
+ adoptQuery(this, p.search);
203
+ };
204
+ var plain = ["protocol", "username", "password", "host", "hostname", "port", "pathname", "hash", "href"];
205
+ for (var pi = 0; pi < plain.length; pi++) {
206
+ (function (name) {
207
+ $defineProperty(URLCtor.prototype, name, {
208
+ configurable: true,
209
+ get: function () { return this._c[name]; },
210
+ set: function (v) {
211
+ if (name === "href") { this._load(P($String(v), "")); return; }
212
+ this._set(name, v);
213
+ },
214
+ });
215
+ })(plain[pi]);
216
+ }
217
+ $defineProperty(URLCtor.prototype, "origin", { configurable: true, get: function () { return this._c.origin; } });
218
+ $defineProperty(URLCtor.prototype, "searchParams", { configurable: true, get: function () { return this._sp; } });
219
+ $defineProperty(URLCtor.prototype, "search", {
220
+ configurable: true,
221
+ get: function () { return this._c.search; },
222
+ set: function (v) { this._set("search", v); },
223
+ });
224
+ URLCtor.prototype.toString = function () { return this._c.href; };
225
+ URLCtor.prototype.toJSON = function () { return this._c.href; };
226
+
227
+ // \u2500\u2500 TextEncoder / TextDecoder \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
228
+ //
229
+ // UTF-8 only, which is all either class supports for encoding anyway. Surrogate pairs are
230
+ // combined and a LONE surrogate becomes U+FFFD, exactly as the host does \u2014 a naive
231
+ // charCodeAt loop instead emits invalid bytes for any emoji.
232
+ // One place that turns any BufferSource into a byte view, honouring a view's own range.
233
+ // The host accepts only an ArrayBuffer or an ArrayBufferView. The old fallback coerced anything
234
+ // \u2014 'decode([0x41])' and 'decode({})' returned a string here and THROW under node:vm \u2014 so
235
+ // worker code that relies on a decode failure diverged silently.
236
+ var viewOf = function (input) {
237
+ if (input instanceof $Uint8Array) return input;
238
+ if ($isView(input)) {
239
+ return new $Uint8Array(input.buffer, input.byteOffset || 0, input.byteLength);
240
+ }
241
+ if (input instanceof $ArrayBuffer) return new $Uint8Array(input);
242
+ throw new $TypeError(
243
+ "Failed to execute 'decode' on 'TextDecoder': The provided value is not of type '(ArrayBuffer or ArrayBufferView)'",
244
+ );
245
+ };
246
+ var stringifyArr = function (a) {
247
+ var out = "[";
248
+ for (var i = 0; i < a.length; i++) out += (i ? "," : "") + a[i];
249
+ return out + "]";
250
+ };
251
+
252
+ function TextEncoderCtor() {}
253
+ // encodeInto, which node has and this did not \u2014 a bundle calling it worked in the host sandbox
254
+ // and threw here, diverging before any transport call.
255
+ //
256
+ // Written out rather than delegated because the destination is a GUEST buffer: the host cannot
257
+ // write into it, so only the byte computation could cross and that is the whole of the work.
258
+ // The one rule that makes it more than a loop: a code point is never SPLIT \u2014 if its bytes do
259
+ // not all fit, nothing of it is written and 'read' stops before it.
260
+ TextEncoderCtor.prototype.encodeInto = function (source, dest) {
261
+ var s2 = source === undefined ? "" : $String(source);
262
+ if (!(dest instanceof $Uint8Array)) {
263
+ throw new $TypeError(
264
+ "Failed to execute 'encodeInto' on 'TextEncoder': parameter 2 is not of type 'Uint8Array'",
265
+ );
266
+ }
267
+ var read = 0, written = 0, cap = dest.length;
268
+ for (var i = 0; i < s2.length; ) {
269
+ var c = s2.charCodeAt(i), units = 1;
270
+ if (c >= 0xd800 && c <= 0xdbff && i + 1 < s2.length) {
271
+ var d = s2.charCodeAt(i + 1);
272
+ if (d >= 0xdc00 && d <= 0xdfff) { c = 0x10000 + ((c - 0xd800) << 10) + (d - 0xdc00); units = 2; }
273
+ }
274
+ if (c >= 0xd800 && c <= 0xdfff) c = 0xfffd; // lone surrogate, as encode() does
275
+ var need = c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;
276
+ if (written + need > cap) break; // never a partial code point
277
+ if (need === 1) dest[written] = c;
278
+ else if (need === 2) { dest[written] = 0xc0 | (c >> 6); dest[written + 1] = 0x80 | (c & 63); }
279
+ else if (need === 3) {
280
+ dest[written] = 0xe0 | (c >> 12);
281
+ dest[written + 1] = 0x80 | ((c >> 6) & 63);
282
+ dest[written + 2] = 0x80 | (c & 63);
283
+ } else {
284
+ dest[written] = 0xf0 | (c >> 18);
285
+ dest[written + 1] = 0x80 | ((c >> 12) & 63);
286
+ dest[written + 2] = 0x80 | ((c >> 6) & 63);
287
+ dest[written + 3] = 0x80 | (c & 63);
288
+ }
289
+ written += need;
290
+ read += units;
291
+ i += units;
292
+ }
293
+ return { read: read, written: written };
294
+ };
295
+ TextEncoderCtor.prototype.encode = function (input) {
296
+ var s = input === undefined ? "" : $String(input);
297
+ var bytes = [];
298
+ for (var i = 0; i < s.length; i++) {
299
+ var c = s.charCodeAt(i);
300
+ if (c >= 0xd800 && c <= 0xdbff && i + 1 < s.length) {
301
+ var d = s.charCodeAt(i + 1);
302
+ if (d >= 0xdc00 && d <= 0xdfff) { c = 0x10000 + ((c - 0xd800) << 10) + (d - 0xdc00); i++; }
303
+ }
304
+ if (c >= 0xd800 && c <= 0xdfff) c = 0xfffd; // lone surrogate
305
+ if (c < 0x80) bytes.push(c);
306
+ else if (c < 0x800) bytes.push(0xc0 | (c >> 6), 0x80 | (c & 63));
307
+ else if (c < 0x10000) bytes.push(0xe0 | (c >> 12), 0x80 | ((c >> 6) & 63), 0x80 | (c & 63));
308
+ else bytes.push(0xf0 | (c >> 18), 0x80 | ((c >> 12) & 63), 0x80 | ((c >> 6) & 63), 0x80 | (c & 63));
309
+ }
310
+ return new $Uint8Array(bytes);
311
+ };
312
+ // LABEL AND OPTIONS ARE PART OF THE CONTRACT. Hard-coding utf-8 non-fatal diverged from the host
313
+ // twice over: 'new TextDecoder("utf-16le").decode([0x41,0x00])' gives "A" there and "A\0"
314
+ // here, and '{ fatal: true }' must THROW on malformed input rather than emit U+FFFD.
315
+ //
316
+ // The split is deliberate. utf-8 \u2014 every real worker's case, and the one whose 13 malformed
317
+ // shapes are already verified byte-for-byte against node \u2014 decodes LOCALLY, with 'fatal' handled
318
+ // by throwing instead of substituting. Any other encoding DELEGATES to the host, because
319
+ // implementing the Encoding Standard's legacy label set here would be a large near-miss, and a
320
+ // near-miss is what this shim exists to avoid. An unknown label throws at CONSTRUCTION, as the
321
+ // host does, via the same hook.
322
+ var decoderSeq = 0;
323
+ function TextDecoderCtor(label, options) {
324
+ var info = $parse(DI(label === undefined ? "utf-8" : $String(label)));
325
+ if (info.error) throw new $RangeError(info.error);
326
+ // Internal slots with readonly accessors below. As own writable properties, guest code could
327
+ // do 'd.encoding = "utf-16le"' before the first decode and the host decoder would then be
328
+ // created with the mutated value, where node keeps decoding as utf-8 and ignores the write.
329
+ this._encoding = info.encoding;
330
+ this._fatal = !!(options && options.fatal);
331
+ this._ignoreBOM = !!(options && options.ignoreBOM);
332
+ // A DECODER IS STATEFUL. 'decode(bytes, { stream: true })' must buffer an incomplete trailing
333
+ // sequence and emit nothing for it, so the next call completes it \u2014 a host decoder returns ""
334
+ // for [0xE2] and then the euro sign for [0x82,0xAC]. Emitting a replacement per call instead
335
+ // corrupts every chunked response body, which is how a worker reads a large one.
336
+ this._pending = [];
337
+ this._bomSeen = false;
338
+ // Non-utf-8 delegates, so its state has to live where its decoder does: the host keeps one
339
+ // real TextDecoder per id and this is the handle to it.
340
+ this._id = ++decoderSeq;
341
+ }
342
+ // MALFORMED INPUT MUST BECOME U+FFFD, not a guess. The first cut accepted any non-ASCII lead
343
+ // byte and blindly consumed continuations, so a lone 0x80 \u2014 which the host decodes to "\uFFFD"
344
+ // with the default non-fatal decoder \u2014 produced a NUL here. Server bytes are exactly where
345
+ // truncated or invalid UTF-8 shows up, and a decoder that silently invents a different string
346
+ // from the same bytes is the divergence class this shim exists to remove.
347
+ //
348
+ // Implements WHATWG's non-fatal UTF-8 decode: range-check the lead byte, validate each
349
+ // continuation, reject overlong encodings, surrogates and values above U+10FFFF, and emit one
350
+ // replacement character per maximal subpart while RE-EXAMINING the byte that broke the sequence.
351
+ // ALWAYS DELEGATED, including utf-8.
352
+ //
353
+ // A local fast path existed for utf-8 and produced four separate findings on its own: malformed
354
+ // sequences, label and options handling, streaming state, and BOM stripping \u2014 each fixed only
355
+ // after review named it. Every one came from the same reasoning ("no worker does that"), which
356
+ // was wrong every time. Measured before deleting it: delegation costs ~1.6x on a 512KB body
357
+ // (128ms -> 202ms) and nothing measurable under 16KB, at author time. That is a fair price for a
358
+ // decoder whose behaviour is the host's by construction rather than by my recollection of the
359
+ // Encoding Standard.
360
+ //
361
+ // A no-input 'decode()' is NOT a no-op: it is the final flush of a stream, so it must reach the
362
+ // host too. Returning early left pending bytes undelivered and _bomSeen latched, where node
363
+ // emits the replacement for the truncated sequence and resets.
364
+ TextDecoderCtor.prototype.decode = function (input, options) {
365
+ var stream = !!(options && options.stream);
366
+ // ONLY 'undefined' is an omitted input. 'decode(null)' throws TypeError on the host, and
367
+ // treating it as a zero-byte flush turned a decode failure into a successful path here \u2014
368
+ // the same invalid-input gap as the plain-array case, one value over.
369
+ var arr = [];
370
+ if (input !== undefined) {
371
+ var view = viewOf(input);
372
+ for (var vi = 0; vi < view.length; vi++) arr.push(view[vi]);
373
+ }
374
+ var res = $parse(DD($String(this._id), this._encoding, this._fatal ? "1" : "",
375
+ this._ignoreBOM ? "1" : "", stream ? "1" : "", stringifyArr(arr)));
376
+ if (res.error) throw new $TypeError(res.error);
377
+ return res.v;
378
+ };
379
+
380
+ // \u2500\u2500 AbortController \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
381
+ //
382
+ // A flag plus listeners. No DOM event machinery: what a worker actually uses is .signal,
383
+ // .aborted, .abort(), addEventListener("abort") and throwIfAborted.
384
+ // Getter-only, so a write is ignored in sloppy mode and throws in strict \u2014 which is what the
385
+ // host's readonly accessors do.
386
+ // Readonly, as node's is. It was a writable data property, so 'e.encoding = "x"' reported "x"
387
+ // here and "utf-8" there \u2014 the same defect already fixed on TextDecoder, missed on its sibling.
388
+ $defineProperty(TextEncoderCtor.prototype, "encoding", {
389
+ configurable: true, get: function () { return "utf-8"; },
390
+ });
391
+
392
+ $defineProperty(TextDecoderCtor.prototype, "encoding", {
393
+ configurable: true, get: function () { return this._encoding; },
394
+ });
395
+ $defineProperty(TextDecoderCtor.prototype, "fatal", {
396
+ configurable: true, get: function () { return this._fatal; },
397
+ });
398
+ $defineProperty(TextDecoderCtor.prototype, "ignoreBOM", {
399
+ configurable: true, get: function () { return this._ignoreBOM; },
400
+ });
401
+
402
+ function AbortSignalCtor() { this.aborted = false; this.reason = undefined; this._l = []; this.onabort = null; }
403
+ AbortSignalCtor.prototype.addEventListener = function (type, fn) { if (type === "abort" && fn) this._l.push(fn); };
404
+ AbortSignalCtor.prototype.removeEventListener = function (type, fn) {
405
+ if (type !== "abort") return;
406
+ var out = []; for (var i = 0; i < this._l.length; i++) if (this._l[i] !== fn) out.push(this._l[i]);
407
+ this._l = out;
408
+ };
409
+ AbortSignalCtor.prototype.throwIfAborted = function () { if (this.aborted) throw this.reason; };
410
+ function AbortControllerCtor() { this.signal = new AbortSignalCtor(); }
411
+ AbortControllerCtor.prototype.abort = function (reason) {
412
+ var s = this.signal;
413
+ if (s.aborted) return;
414
+ s.aborted = true;
415
+ // The host's default reason is an AbortError DOMException; there is no DOMException here, so
416
+ // an Error carrying the same name is the closest honest stand-in and is what code checking
417
+ // err.name === "AbortError" expects.
418
+ if (reason === undefined) { var e = new $Error("This operation was aborted"); e.name = "AbortError"; s.reason = e; }
419
+ else s.reason = reason;
420
+ var ev = { type: "abort", target: s };
421
+ if (typeof s.onabort === "function") s.onabort(ev);
422
+ for (var i = 0; i < s._l.length; i++) s._l[i](ev);
423
+ };
424
+
425
+ globalThis.URLSearchParams = USP;
426
+ globalThis.URL = URLCtor;
427
+ globalThis.TextEncoder = TextEncoderCtor;
428
+ globalThis.TextDecoder = TextDecoderCtor;
429
+ globalThis.AbortController = AbortControllerCtor;
430
+ globalThis.AbortSignal = AbortSignalCtor;
431
+ })();
432
+ `;
433
+ function urlComponents(u) {
434
+ return {
435
+ href: u.href,
436
+ origin: u.origin,
437
+ protocol: u.protocol,
438
+ username: u.username,
439
+ password: u.password,
440
+ host: u.host,
441
+ hostname: u.hostname,
442
+ port: u.port,
443
+ pathname: u.pathname,
444
+ search: u.search,
445
+ hash: u.hash
446
+ };
447
+ }
448
+ function installWebGlobals(ctx) {
449
+ const setPart = ctx.newFunction("__himiSetUrlPart", (hrefH, partH, valueH) => {
450
+ const href = ctx.getString(hrefH);
451
+ const part = ctx.getString(partH);
452
+ const value = ctx.getString(valueH);
453
+ try {
454
+ const u = new URL(href);
455
+ u[part] = value;
456
+ return ctx.newString(JSON.stringify(urlComponents(u)));
457
+ } catch (err) {
458
+ return ctx.newString(JSON.stringify({ error: err?.message ?? "Invalid URL" }));
459
+ }
460
+ });
461
+ ctx.setProp(ctx.global, "__himiSetUrlPart", setPart);
462
+ setPart.dispose();
463
+ const decoderInfo = ctx.newFunction("__himiDecoderInfo", (labelH) => {
464
+ const label = ctx.getString(labelH);
465
+ try {
466
+ const d = new TextDecoder(label);
467
+ return ctx.newString(JSON.stringify({ encoding: d.encoding }));
468
+ } catch (err) {
469
+ return ctx.newString(JSON.stringify({ error: err?.message ?? `Invalid label: ${label}` }));
470
+ }
471
+ });
472
+ ctx.setProp(ctx.global, "__himiDecoderInfo", decoderInfo);
473
+ decoderInfo.dispose();
474
+ const decoders = /* @__PURE__ */ new Map();
475
+ const MAX_DECODERS = 256;
476
+ const decodeBytes = ctx.newFunction(
477
+ "__himiDecodeBytes",
478
+ (idH, encH, fatalH, bomH, streamH, bytesH) => {
479
+ try {
480
+ const id = ctx.getString(idH);
481
+ const encoding = ctx.getString(encH);
482
+ const fatal = ctx.getString(fatalH) === "1";
483
+ const ignoreBOM = ctx.getString(bomH) === "1";
484
+ const stream = ctx.getString(streamH) === "1";
485
+ const bytes = JSON.parse(ctx.getString(bytesH));
486
+ let dec = decoders.get(id);
487
+ if (!dec) {
488
+ if (decoders.size >= MAX_DECODERS) {
489
+ return ctx.newString(JSON.stringify({ error: `too many TextDecoder instances (cap ${MAX_DECODERS})` }));
490
+ }
491
+ dec = new TextDecoder(encoding, { fatal, ignoreBOM });
492
+ decoders.set(id, dec);
493
+ }
494
+ const v = dec.decode(new Uint8Array(bytes), { stream });
495
+ if (!stream) decoders.delete(id);
496
+ return ctx.newString(JSON.stringify({ v }));
497
+ } catch (err) {
498
+ return ctx.newString(JSON.stringify({ error: err?.message ?? "decode failed" }));
499
+ }
500
+ }
501
+ );
502
+ ctx.setProp(ctx.global, "__himiDecodeBytes", decodeBytes);
503
+ decodeBytes.dispose();
504
+ const queryDecode = ctx.newFunction("__himiQueryDecode", (strH) => {
505
+ const usp = new URLSearchParams(ctx.getString(strH));
506
+ return ctx.newString(JSON.stringify([...usp.entries()]));
507
+ });
508
+ ctx.setProp(ctx.global, "__himiQueryDecode", queryDecode);
509
+ queryDecode.dispose();
510
+ const queryEncode = ctx.newFunction("__himiQueryEncode", (pairsH) => {
511
+ const flat = JSON.parse(ctx.getString(pairsH));
512
+ const usp = new URLSearchParams();
513
+ for (let i = 0; i + 1 < flat.length; i += 2) usp.append(String(flat[i]), String(flat[i + 1]));
514
+ return ctx.newString(usp.toString());
515
+ });
516
+ ctx.setProp(ctx.global, "__himiQueryEncode", queryEncode);
517
+ queryEncode.dispose();
518
+ const parse = ctx.newFunction("__himiParseUrl", (hrefH, baseH) => {
519
+ const href = ctx.getString(hrefH);
520
+ const base = ctx.getString(baseH);
521
+ try {
522
+ const u = base ? new URL(href, base) : new URL(href);
523
+ return ctx.newString(JSON.stringify(urlComponents(u)));
524
+ } catch (err) {
525
+ return ctx.newString(JSON.stringify({ error: err?.message ?? "Invalid URL" }));
526
+ }
527
+ });
528
+ ctx.setProp(ctx.global, "__himiParseUrl", parse);
529
+ parse.dispose();
530
+ const res = ctx.evalCode(WEB_GLOBALS_SHIM, "himi-web-globals.js");
531
+ if (res.error) {
532
+ const detail = ctx.dump(res.error);
533
+ res.error.dispose();
534
+ throw new Error(`web globals shim failed: ${String(detail?.message ?? detail)}`);
535
+ }
536
+ res.value.dispose();
537
+ }
538
+ export {
539
+ installWebGlobals
540
+ };