@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.
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/motion/src/index.d.ts +51 -5
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/media/src/index.d.ts +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/media/src/rendition.d.ts +42 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/motion.mjs +22 -2
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-media.mjs +78 -0
- package/dist/cli.mjs +9019 -7448
- package/dist/preview-assets.generated.bin +0 -0
- package/dist/quickjs-intl.js +462 -0
- package/dist/quickjs-web-globals.js +540 -0
- package/dist/quickjs-worker-entry.js +313 -0
- package/guides/himi-json-output.md +30 -1
- package/guides/one-app-section-mappings.md +4 -5
- package/guides/one-app-to-himi-app.md +214 -6
- package/guides/one-app-viewer.md +2 -2
- package/guides/sdk-reference.json +36 -6
- package/package.json +3 -2
|
@@ -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
|
+
};
|