@fluid-app/widget-runtime 0.1.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/README.md +77 -0
- package/dist/Thread-0eUyc0Hw.cjs +591 -0
- package/dist/Thread-0eUyc0Hw.cjs.map +1 -0
- package/dist/Thread-BiW7rXts.mjs +574 -0
- package/dist/Thread-BiW7rXts.mjs.map +1 -0
- package/dist/index.cjs +6 -0
- package/dist/index.d.cts +3 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.mjs +3 -0
- package/dist/remote-dom-renderer-BU-73KvK.d.mts +90 -0
- package/dist/remote-dom-renderer-BU-73KvK.d.mts.map +1 -0
- package/dist/remote-dom-renderer-DSHFetvm.d.cts +90 -0
- package/dist/remote-dom-renderer-DSHFetvm.d.cts.map +1 -0
- package/dist/remote-dom-renderer-DUQf80Nu.cjs +2116 -0
- package/dist/remote-dom-renderer-DUQf80Nu.cjs.map +1 -0
- package/dist/remote-dom-renderer-DcwcNPsu.mjs +2081 -0
- package/dist/remote-dom-renderer-DcwcNPsu.mjs.map +1 -0
- package/dist/remote-dom-values-BSAxrOE7.mjs +238 -0
- package/dist/remote-dom-values-BSAxrOE7.mjs.map +1 -0
- package/dist/remote-dom-values-D4AgBNWr.d.cts +32 -0
- package/dist/remote-dom-values-D4AgBNWr.d.cts.map +1 -0
- package/dist/remote-dom-values-DbgIedSg.cjs +297 -0
- package/dist/remote-dom-values-DbgIedSg.cjs.map +1 -0
- package/dist/remote-dom-values-EwoLXnSn.d.mts +32 -0
- package/dist/remote-dom-values-EwoLXnSn.d.mts.map +1 -0
- package/dist/remote-dom.cjs +6 -0
- package/dist/remote-dom.d.cts +3 -0
- package/dist/remote-dom.d.mts +3 -0
- package/dist/remote-dom.mjs +3 -0
- package/dist/worker-react-bootstrap-C7tCMYGA.mjs +13 -0
- package/dist/worker-react-bootstrap-C7tCMYGA.mjs.map +1 -0
- package/dist/worker-react-bootstrap-N8jcWZ3L.cjs +13 -0
- package/dist/worker-react-bootstrap-N8jcWZ3L.cjs.map +1 -0
- package/dist/worker-react-renderer-BKzig_Vy.mjs +185 -0
- package/dist/worker-react-renderer-BKzig_Vy.mjs.map +1 -0
- package/dist/worker-react-renderer-BSFxMMf7.cjs +186 -0
- package/dist/worker-react-renderer-BSFxMMf7.cjs.map +1 -0
- package/dist/worker.cjs +325 -0
- package/dist/worker.cjs.map +1 -0
- package/dist/worker.d.cts +46 -0
- package/dist/worker.d.cts.map +1 -0
- package/dist/worker.d.mts +46 -0
- package/dist/worker.d.mts.map +1 -0
- package/dist/worker.mjs +319 -0
- package/dist/worker.mjs.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,2116 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
22
|
+
//#endregion
|
|
23
|
+
const require_Thread = require("./Thread-0eUyc0Hw.cjs");
|
|
24
|
+
const require_remote_dom_values = require("./remote-dom-values-DbgIedSg.cjs");
|
|
25
|
+
let _remote_dom_core = require("@remote-dom/core");
|
|
26
|
+
let _remote_dom_core_elements = require("@remote-dom/core/elements");
|
|
27
|
+
let _remote_dom_core_receivers = require("@remote-dom/core/receivers");
|
|
28
|
+
let postcss_lib_parse = require("postcss/lib/parse");
|
|
29
|
+
postcss_lib_parse = __toESM(postcss_lib_parse);
|
|
30
|
+
let postcss_value_parser = require("postcss-value-parser");
|
|
31
|
+
postcss_value_parser = __toESM(postcss_value_parser);
|
|
32
|
+
//#region src/remote-dom-sanitizer.ts
|
|
33
|
+
const REMOTE_DOM_DENIED_TAG_NAMES = new Set([
|
|
34
|
+
"applet",
|
|
35
|
+
"base",
|
|
36
|
+
"body",
|
|
37
|
+
"embed",
|
|
38
|
+
"frame",
|
|
39
|
+
"frameset",
|
|
40
|
+
"head",
|
|
41
|
+
"html",
|
|
42
|
+
"iframe",
|
|
43
|
+
"link",
|
|
44
|
+
"meta",
|
|
45
|
+
"noscript",
|
|
46
|
+
"object",
|
|
47
|
+
"portal",
|
|
48
|
+
"script",
|
|
49
|
+
"slot",
|
|
50
|
+
"style",
|
|
51
|
+
"template",
|
|
52
|
+
"title"
|
|
53
|
+
]);
|
|
54
|
+
const REMOTE_DOM_ALLOWED_TAG_NAME_SET = new Set(require_remote_dom_values.REMOTE_DOM_ALLOWED_TAG_NAMES);
|
|
55
|
+
const GLOBAL_ALLOWED_ATTRIBUTES = new Set([
|
|
56
|
+
"aria-activedescendant",
|
|
57
|
+
"aria-atomic",
|
|
58
|
+
"aria-autocomplete",
|
|
59
|
+
"aria-braillelabel",
|
|
60
|
+
"aria-brailleroledescription",
|
|
61
|
+
"aria-busy",
|
|
62
|
+
"aria-checked",
|
|
63
|
+
"aria-colcount",
|
|
64
|
+
"aria-colindex",
|
|
65
|
+
"aria-colindextext",
|
|
66
|
+
"aria-colspan",
|
|
67
|
+
"aria-controls",
|
|
68
|
+
"aria-current",
|
|
69
|
+
"aria-describedby",
|
|
70
|
+
"aria-description",
|
|
71
|
+
"aria-details",
|
|
72
|
+
"aria-disabled",
|
|
73
|
+
"aria-errormessage",
|
|
74
|
+
"aria-expanded",
|
|
75
|
+
"aria-haspopup",
|
|
76
|
+
"aria-hidden",
|
|
77
|
+
"aria-invalid",
|
|
78
|
+
"aria-keyshortcuts",
|
|
79
|
+
"aria-label",
|
|
80
|
+
"aria-labelledby",
|
|
81
|
+
"aria-level",
|
|
82
|
+
"aria-live",
|
|
83
|
+
"aria-modal",
|
|
84
|
+
"aria-multiline",
|
|
85
|
+
"aria-multiselectable",
|
|
86
|
+
"aria-orientation",
|
|
87
|
+
"aria-owns",
|
|
88
|
+
"aria-placeholder",
|
|
89
|
+
"aria-posinset",
|
|
90
|
+
"aria-pressed",
|
|
91
|
+
"aria-readonly",
|
|
92
|
+
"aria-required",
|
|
93
|
+
"aria-roledescription",
|
|
94
|
+
"aria-rowcount",
|
|
95
|
+
"aria-rowindex",
|
|
96
|
+
"aria-rowindextext",
|
|
97
|
+
"aria-rowspan",
|
|
98
|
+
"aria-selected",
|
|
99
|
+
"aria-setsize",
|
|
100
|
+
"aria-sort",
|
|
101
|
+
"aria-valuemax",
|
|
102
|
+
"aria-valuemin",
|
|
103
|
+
"aria-valuenow",
|
|
104
|
+
"aria-valuetext",
|
|
105
|
+
"class",
|
|
106
|
+
"dir",
|
|
107
|
+
"hidden",
|
|
108
|
+
"id",
|
|
109
|
+
"inert",
|
|
110
|
+
"lang",
|
|
111
|
+
"role",
|
|
112
|
+
"tabindex",
|
|
113
|
+
"title",
|
|
114
|
+
"translate"
|
|
115
|
+
]);
|
|
116
|
+
const TAG_ALLOWED_ATTRIBUTES = {
|
|
117
|
+
a: new Set([
|
|
118
|
+
"download",
|
|
119
|
+
"href",
|
|
120
|
+
"hreflang",
|
|
121
|
+
"rel",
|
|
122
|
+
"target",
|
|
123
|
+
"type"
|
|
124
|
+
]),
|
|
125
|
+
audio: new Set([
|
|
126
|
+
"autoplay",
|
|
127
|
+
"controls",
|
|
128
|
+
"loop",
|
|
129
|
+
"muted",
|
|
130
|
+
"preload",
|
|
131
|
+
"src"
|
|
132
|
+
]),
|
|
133
|
+
blockquote: new Set(["cite"]),
|
|
134
|
+
button: new Set([
|
|
135
|
+
"disabled",
|
|
136
|
+
"name",
|
|
137
|
+
"type",
|
|
138
|
+
"value"
|
|
139
|
+
]),
|
|
140
|
+
col: new Set(["span"]),
|
|
141
|
+
colgroup: new Set(["span"]),
|
|
142
|
+
data: new Set(["value"]),
|
|
143
|
+
del: new Set(["cite", "datetime"]),
|
|
144
|
+
details: new Set(["open"]),
|
|
145
|
+
dialog: new Set(["open"]),
|
|
146
|
+
form: new Set(["autocomplete", "name"]),
|
|
147
|
+
img: new Set([
|
|
148
|
+
"alt",
|
|
149
|
+
"decoding",
|
|
150
|
+
"height",
|
|
151
|
+
"loading",
|
|
152
|
+
"src",
|
|
153
|
+
"width"
|
|
154
|
+
]),
|
|
155
|
+
input: new Set([
|
|
156
|
+
"accept",
|
|
157
|
+
"autocomplete",
|
|
158
|
+
"checked",
|
|
159
|
+
"disabled",
|
|
160
|
+
"max",
|
|
161
|
+
"maxlength",
|
|
162
|
+
"min",
|
|
163
|
+
"minlength",
|
|
164
|
+
"name",
|
|
165
|
+
"pattern",
|
|
166
|
+
"placeholder",
|
|
167
|
+
"readonly",
|
|
168
|
+
"required",
|
|
169
|
+
"step",
|
|
170
|
+
"type",
|
|
171
|
+
"value"
|
|
172
|
+
]),
|
|
173
|
+
ins: new Set(["cite", "datetime"]),
|
|
174
|
+
label: new Set(["for"]),
|
|
175
|
+
meter: new Set([
|
|
176
|
+
"high",
|
|
177
|
+
"low",
|
|
178
|
+
"max",
|
|
179
|
+
"min",
|
|
180
|
+
"optimum",
|
|
181
|
+
"value"
|
|
182
|
+
]),
|
|
183
|
+
optgroup: new Set(["disabled", "label"]),
|
|
184
|
+
option: new Set([
|
|
185
|
+
"disabled",
|
|
186
|
+
"label",
|
|
187
|
+
"selected",
|
|
188
|
+
"value"
|
|
189
|
+
]),
|
|
190
|
+
output: new Set(["for", "name"]),
|
|
191
|
+
progress: new Set(["max", "value"]),
|
|
192
|
+
q: new Set(["cite"]),
|
|
193
|
+
select: new Set([
|
|
194
|
+
"autocomplete",
|
|
195
|
+
"disabled",
|
|
196
|
+
"multiple",
|
|
197
|
+
"name",
|
|
198
|
+
"required",
|
|
199
|
+
"size"
|
|
200
|
+
]),
|
|
201
|
+
source: new Set([
|
|
202
|
+
"height",
|
|
203
|
+
"media",
|
|
204
|
+
"sizes",
|
|
205
|
+
"src",
|
|
206
|
+
"type",
|
|
207
|
+
"width"
|
|
208
|
+
]),
|
|
209
|
+
td: new Set([
|
|
210
|
+
"colspan",
|
|
211
|
+
"headers",
|
|
212
|
+
"rowspan"
|
|
213
|
+
]),
|
|
214
|
+
textarea: new Set([
|
|
215
|
+
"autocomplete",
|
|
216
|
+
"cols",
|
|
217
|
+
"disabled",
|
|
218
|
+
"maxlength",
|
|
219
|
+
"minlength",
|
|
220
|
+
"name",
|
|
221
|
+
"placeholder",
|
|
222
|
+
"readonly",
|
|
223
|
+
"required",
|
|
224
|
+
"rows",
|
|
225
|
+
"value",
|
|
226
|
+
"wrap"
|
|
227
|
+
]),
|
|
228
|
+
th: new Set([
|
|
229
|
+
"abbr",
|
|
230
|
+
"colspan",
|
|
231
|
+
"headers",
|
|
232
|
+
"rowspan",
|
|
233
|
+
"scope"
|
|
234
|
+
]),
|
|
235
|
+
time: new Set(["datetime"]),
|
|
236
|
+
track: new Set([
|
|
237
|
+
"default",
|
|
238
|
+
"kind",
|
|
239
|
+
"label",
|
|
240
|
+
"src",
|
|
241
|
+
"srclang"
|
|
242
|
+
]),
|
|
243
|
+
video: new Set([
|
|
244
|
+
"autoplay",
|
|
245
|
+
"controls",
|
|
246
|
+
"height",
|
|
247
|
+
"loop",
|
|
248
|
+
"muted",
|
|
249
|
+
"playsinline",
|
|
250
|
+
"poster",
|
|
251
|
+
"preload",
|
|
252
|
+
"src",
|
|
253
|
+
"width"
|
|
254
|
+
])
|
|
255
|
+
};
|
|
256
|
+
const BOOLEAN_ATTRIBUTES = new Set([
|
|
257
|
+
"autoplay",
|
|
258
|
+
"checked",
|
|
259
|
+
"controls",
|
|
260
|
+
"default",
|
|
261
|
+
"disabled",
|
|
262
|
+
"hidden",
|
|
263
|
+
"inert",
|
|
264
|
+
"loop",
|
|
265
|
+
"multiple",
|
|
266
|
+
"muted",
|
|
267
|
+
"open",
|
|
268
|
+
"playsinline",
|
|
269
|
+
"readonly",
|
|
270
|
+
"required",
|
|
271
|
+
"selected"
|
|
272
|
+
]);
|
|
273
|
+
const SAFE_INPUT_TYPES = new Set([
|
|
274
|
+
"button",
|
|
275
|
+
"checkbox",
|
|
276
|
+
"color",
|
|
277
|
+
"date",
|
|
278
|
+
"datetime-local",
|
|
279
|
+
"email",
|
|
280
|
+
"file",
|
|
281
|
+
"hidden",
|
|
282
|
+
"month",
|
|
283
|
+
"number",
|
|
284
|
+
"password",
|
|
285
|
+
"radio",
|
|
286
|
+
"range",
|
|
287
|
+
"reset",
|
|
288
|
+
"search",
|
|
289
|
+
"submit",
|
|
290
|
+
"tel",
|
|
291
|
+
"text",
|
|
292
|
+
"time",
|
|
293
|
+
"url",
|
|
294
|
+
"week"
|
|
295
|
+
]);
|
|
296
|
+
const SAFE_BUTTON_TYPES = new Set([
|
|
297
|
+
"button",
|
|
298
|
+
"reset",
|
|
299
|
+
"submit"
|
|
300
|
+
]);
|
|
301
|
+
const SAFE_LOADING_VALUES = new Set(["eager", "lazy"]);
|
|
302
|
+
const SAFE_DECODING_VALUES = new Set([
|
|
303
|
+
"async",
|
|
304
|
+
"auto",
|
|
305
|
+
"sync"
|
|
306
|
+
]);
|
|
307
|
+
const SAFE_PRELOAD_VALUES = new Set([
|
|
308
|
+
"auto",
|
|
309
|
+
"metadata",
|
|
310
|
+
"none"
|
|
311
|
+
]);
|
|
312
|
+
const SAFE_TRACK_KIND_VALUES = new Set([
|
|
313
|
+
"captions",
|
|
314
|
+
"chapters",
|
|
315
|
+
"descriptions",
|
|
316
|
+
"metadata",
|
|
317
|
+
"subtitles"
|
|
318
|
+
]);
|
|
319
|
+
const URL_VALUED_ATTRIBUTES = new Set([
|
|
320
|
+
"cite",
|
|
321
|
+
"href",
|
|
322
|
+
"poster",
|
|
323
|
+
"src"
|
|
324
|
+
]);
|
|
325
|
+
const MEDIA_SOURCE_TAGS = new Set([
|
|
326
|
+
"audio",
|
|
327
|
+
"img",
|
|
328
|
+
"source",
|
|
329
|
+
"track",
|
|
330
|
+
"video"
|
|
331
|
+
]);
|
|
332
|
+
const SUPPORTED_REMOTE_DOM_EVENT_SET = new Set(require_remote_dom_values.SUPPORTED_REMOTE_DOM_EVENTS);
|
|
333
|
+
const REMOTE_DOM_SEARCH_SORT_EVENT_SET = new Set(require_remote_dom_values.REMOTE_DOM_SEARCH_SORT_EVENTS);
|
|
334
|
+
function sanitizeRemoteDomTagName(tagName) {
|
|
335
|
+
if (typeof tagName !== "string") return void 0;
|
|
336
|
+
const normalizedTagName = tagName.trim().toLowerCase();
|
|
337
|
+
if (normalizedTagName.length === 0 || REMOTE_DOM_DENIED_TAG_NAMES.has(normalizedTagName) || !REMOTE_DOM_ALLOWED_TAG_NAME_SET.has(normalizedTagName)) return;
|
|
338
|
+
return normalizedTagName;
|
|
339
|
+
}
|
|
340
|
+
function sanitizeRemoteDomAttributes(tagName, attributes, options = {}) {
|
|
341
|
+
if (!isObjectRecord$1(attributes)) return [];
|
|
342
|
+
const sanitizedAttributes = [];
|
|
343
|
+
for (const [rawName, rawValue] of Object.entries(attributes)) {
|
|
344
|
+
const attribute = sanitizeRemoteDomAttribute(tagName, rawName, rawValue, options);
|
|
345
|
+
if (attribute) sanitizedAttributes.push(attribute);
|
|
346
|
+
}
|
|
347
|
+
return sanitizedAttributes;
|
|
348
|
+
}
|
|
349
|
+
function sanitizeRemoteDomProperty(tagName, rawName, rawValue) {
|
|
350
|
+
if (typeof rawName !== "string") return void 0;
|
|
351
|
+
const normalizedTagName = tagName.trim().toLowerCase();
|
|
352
|
+
const name = rawName.trim().toLowerCase();
|
|
353
|
+
if (!require_remote_dom_values.isSafeRemoteDomPropertyKey(name)) return;
|
|
354
|
+
if (normalizedTagName === "input") {
|
|
355
|
+
if (name === "checked" && typeof rawValue === "boolean") return {
|
|
356
|
+
name,
|
|
357
|
+
value: rawValue
|
|
358
|
+
};
|
|
359
|
+
if (name === "value" && typeof rawValue === "string") return {
|
|
360
|
+
name,
|
|
361
|
+
value: rawValue
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
if (normalizedTagName === "fluid-ui-search-sort") {
|
|
365
|
+
if (name === "searchvalue" && typeof rawValue === "string") return {
|
|
366
|
+
name: "searchValue",
|
|
367
|
+
value: rawValue
|
|
368
|
+
};
|
|
369
|
+
if (name === "placeholder") return typeof rawValue === "string" || rawValue === void 0 ? {
|
|
370
|
+
name: "placeholder",
|
|
371
|
+
value: rawValue
|
|
372
|
+
} : void 0;
|
|
373
|
+
if (name === "sortoptions") {
|
|
374
|
+
const value = sanitizeSearchSortOptions(rawValue);
|
|
375
|
+
return value === void 0 && rawValue !== void 0 ? void 0 : {
|
|
376
|
+
name: "sortOptions",
|
|
377
|
+
value
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
if (name === "sortvalue") return typeof rawValue === "string" || rawValue === void 0 ? {
|
|
381
|
+
name: "sortValue",
|
|
382
|
+
value: rawValue
|
|
383
|
+
} : void 0;
|
|
384
|
+
}
|
|
385
|
+
if (normalizedTagName === "fluid-spacer-widget") {
|
|
386
|
+
if (name === "customheight") return typeof rawValue === "string" || rawValue === void 0 ? {
|
|
387
|
+
name: "customHeight",
|
|
388
|
+
value: rawValue
|
|
389
|
+
} : void 0;
|
|
390
|
+
if (name === "previewmode" && typeof rawValue === "boolean") return {
|
|
391
|
+
name: "previewMode",
|
|
392
|
+
value: rawValue
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
function isRemoteDomPropertyName(tagName, rawName) {
|
|
397
|
+
const normalizedTagName = tagName.trim().toLowerCase();
|
|
398
|
+
const name = rawName.trim().toLowerCase();
|
|
399
|
+
if (normalizedTagName === "input") return name === "checked" || name === "value";
|
|
400
|
+
if (normalizedTagName === "fluid-ui-search-sort") return name === "searchvalue" || name === "placeholder" || name === "sortoptions" || name === "sortvalue";
|
|
401
|
+
if (normalizedTagName === "fluid-spacer-widget") return name === "customheight" || name === "previewmode";
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
404
|
+
function sanitizeRemoteDomAttribute(tagName, rawName, rawValue, options = {}) {
|
|
405
|
+
if (typeof rawName !== "string") return void 0;
|
|
406
|
+
const normalizedTagName = tagName.trim().toLowerCase();
|
|
407
|
+
const name = rawName.trim().toLowerCase();
|
|
408
|
+
if (!require_remote_dom_values.isSafeRemoteDomPropertyKey(name)) return void 0;
|
|
409
|
+
if (!isAllowedAttributeName(normalizedTagName, name)) return void 0;
|
|
410
|
+
if (name === "type" && normalizedTagName === "input") {
|
|
411
|
+
const value = stringifyAttributeValue(rawValue).toLowerCase();
|
|
412
|
+
return SAFE_INPUT_TYPES.has(value) ? {
|
|
413
|
+
name,
|
|
414
|
+
value
|
|
415
|
+
} : void 0;
|
|
416
|
+
}
|
|
417
|
+
if (name === "type" && normalizedTagName === "button") {
|
|
418
|
+
const value = stringifyAttributeValue(rawValue).toLowerCase();
|
|
419
|
+
return SAFE_BUTTON_TYPES.has(value) ? {
|
|
420
|
+
name,
|
|
421
|
+
value
|
|
422
|
+
} : void 0;
|
|
423
|
+
}
|
|
424
|
+
if (URL_VALUED_ATTRIBUTES.has(name)) {
|
|
425
|
+
const value = sanitizeUrlValuedAttribute(normalizedTagName, name, rawValue, options.urlOriginPolicy);
|
|
426
|
+
return value ? {
|
|
427
|
+
name,
|
|
428
|
+
value
|
|
429
|
+
} : void 0;
|
|
430
|
+
}
|
|
431
|
+
if (name === "target") {
|
|
432
|
+
const value = stringifyAttributeValue(rawValue);
|
|
433
|
+
return value === "_blank" || value === "_self" ? {
|
|
434
|
+
name,
|
|
435
|
+
value
|
|
436
|
+
} : void 0;
|
|
437
|
+
}
|
|
438
|
+
if (name === "rel") {
|
|
439
|
+
const value = sanitizeTokenList(rawValue);
|
|
440
|
+
return value.length > 0 ? {
|
|
441
|
+
name,
|
|
442
|
+
value
|
|
443
|
+
} : void 0;
|
|
444
|
+
}
|
|
445
|
+
if (name === "loading") return sanitizeEnumAttribute(name, rawValue, SAFE_LOADING_VALUES);
|
|
446
|
+
if (name === "decoding") return sanitizeEnumAttribute(name, rawValue, SAFE_DECODING_VALUES);
|
|
447
|
+
if (name === "preload") return sanitizeEnumAttribute(name, rawValue, SAFE_PRELOAD_VALUES);
|
|
448
|
+
if (name === "kind" && normalizedTagName === "track") return sanitizeEnumAttribute(name, rawValue, SAFE_TRACK_KIND_VALUES);
|
|
449
|
+
if (BOOLEAN_ATTRIBUTES.has(name)) return rawValue === true || rawValue === "" || rawValue === name ? {
|
|
450
|
+
name,
|
|
451
|
+
value: ""
|
|
452
|
+
} : void 0;
|
|
453
|
+
const value = stringifyAttributeValue(rawValue);
|
|
454
|
+
if (value.length === 0 && rawValue !== "") return void 0;
|
|
455
|
+
const sanitizedValue = sanitizeCssComponentValueUrlReferences(value, options.urlOriginPolicy);
|
|
456
|
+
if (sanitizedValue === void 0) return;
|
|
457
|
+
return {
|
|
458
|
+
name,
|
|
459
|
+
value: sanitizedValue
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
function sanitizeRemoteDomUrl(value, options) {
|
|
463
|
+
if (typeof value !== "string") return void 0;
|
|
464
|
+
const trimmedValue = value.trim();
|
|
465
|
+
if (trimmedValue.length === 0 || trimmedValue !== value || hasControlCharacter(trimmedValue) || trimmedValue.includes("\\") || trimmedValue.startsWith("//")) return;
|
|
466
|
+
if (trimmedValue.startsWith("#")) return options.allowHashOnly === true ? trimmedValue : void 0;
|
|
467
|
+
if (isRelativeUrl(trimmedValue)) {
|
|
468
|
+
if (!options.allowRelative) return void 0;
|
|
469
|
+
const parsedRelativeUrl = resolveRemoteDomRelativeUrl(trimmedValue, options.originPolicy, options.relativeUrlBase ?? "artifact");
|
|
470
|
+
if (!parsedRelativeUrl) return void 0;
|
|
471
|
+
return isAllowedHttpOrigin(parsedRelativeUrl.origin, options.originPolicy, options.allowedHttpOriginGroups ?? []) ? parsedRelativeUrl.href : void 0;
|
|
472
|
+
}
|
|
473
|
+
let parsedUrl;
|
|
474
|
+
try {
|
|
475
|
+
parsedUrl = new URL(trimmedValue);
|
|
476
|
+
} catch {
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
if (parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:") return isAllowedHttpOrigin(parsedUrl.origin, options.originPolicy, options.allowedHttpOriginGroups ?? []) ? trimmedValue : void 0;
|
|
480
|
+
if (options.allowMailTo && parsedUrl.protocol === "mailto:") return trimmedValue;
|
|
481
|
+
if (options.allowTel && parsedUrl.protocol === "tel:") return trimmedValue;
|
|
482
|
+
}
|
|
483
|
+
function sanitizeRemoteDomCssUrlReferences(value, options = {}) {
|
|
484
|
+
if (typeof value !== "string") return void 0;
|
|
485
|
+
return sanitizeCssTextUrlReferences(value, options.urlOriginPolicy);
|
|
486
|
+
}
|
|
487
|
+
function isSupportedRemoteDomEventName(eventName, tagName) {
|
|
488
|
+
if (SUPPORTED_REMOTE_DOM_EVENT_SET.has(eventName)) return true;
|
|
489
|
+
return tagName?.trim().toLowerCase() === "fluid-ui-search-sort" && REMOTE_DOM_SEARCH_SORT_EVENT_SET.has(eventName);
|
|
490
|
+
}
|
|
491
|
+
function serializeRemoteDomEvent(event, targetId, currentTargetId, currentTargetTagName) {
|
|
492
|
+
if (!isSupportedRemoteDomEventName(event.type, currentTargetTagName)) return;
|
|
493
|
+
const inputState = readInputState(event.target);
|
|
494
|
+
return {
|
|
495
|
+
type: event.type,
|
|
496
|
+
targetId,
|
|
497
|
+
currentTargetId,
|
|
498
|
+
bubbles: event.bubbles,
|
|
499
|
+
cancelable: event.cancelable,
|
|
500
|
+
defaultPrevented: event.defaultPrevented,
|
|
501
|
+
...inputState,
|
|
502
|
+
...readKeyboardState(event),
|
|
503
|
+
...readPointerState(event),
|
|
504
|
+
...readMouseState(event),
|
|
505
|
+
...readCustomEventDetail(event)
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
function sanitizeSearchSortOptions(value) {
|
|
509
|
+
if (!Array.isArray(value)) return void 0;
|
|
510
|
+
const options = [];
|
|
511
|
+
for (const option of value) {
|
|
512
|
+
if (!isObjectRecord$1(option) || typeof option.label !== "string" || typeof option.value !== "string") return;
|
|
513
|
+
options.push({
|
|
514
|
+
label: option.label,
|
|
515
|
+
value: option.value
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
return options;
|
|
519
|
+
}
|
|
520
|
+
function readCustomEventDetail(event) {
|
|
521
|
+
if (!(event instanceof CustomEvent) || !REMOTE_DOM_SEARCH_SORT_EVENT_SET.has(event.type)) return {};
|
|
522
|
+
if (!require_remote_dom_values.isRemoteDomSerializableValue(event.detail)) return {};
|
|
523
|
+
try {
|
|
524
|
+
const detailJson = JSON.stringify(event.detail);
|
|
525
|
+
return typeof detailJson === "string" ? { detailJson } : {};
|
|
526
|
+
} catch {
|
|
527
|
+
return {};
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
function sanitizeUrlValuedAttribute(tagName, name, value, originPolicy) {
|
|
531
|
+
if (name === "href") return sanitizeRemoteDomUrl(value, {
|
|
532
|
+
allowHashOnly: true,
|
|
533
|
+
allowMailTo: true,
|
|
534
|
+
allowRelative: true,
|
|
535
|
+
allowTel: true,
|
|
536
|
+
allowedHttpOriginGroups: [
|
|
537
|
+
"artifact",
|
|
538
|
+
"media",
|
|
539
|
+
"navigation"
|
|
540
|
+
],
|
|
541
|
+
originPolicy,
|
|
542
|
+
relativeUrlBase: "navigation"
|
|
543
|
+
});
|
|
544
|
+
if (name === "src" && MEDIA_SOURCE_TAGS.has(tagName)) return sanitizeRemoteDomUrl(value, {
|
|
545
|
+
allowHashOnly: false,
|
|
546
|
+
allowMailTo: false,
|
|
547
|
+
allowRelative: true,
|
|
548
|
+
allowTel: false,
|
|
549
|
+
allowedHttpOriginGroups: ["artifact", "media"],
|
|
550
|
+
originPolicy,
|
|
551
|
+
relativeUrlBase: "artifact"
|
|
552
|
+
});
|
|
553
|
+
if (name === "poster" && tagName === "video") return sanitizeRemoteDomUrl(value, {
|
|
554
|
+
allowHashOnly: false,
|
|
555
|
+
allowMailTo: false,
|
|
556
|
+
allowRelative: true,
|
|
557
|
+
allowTel: false,
|
|
558
|
+
allowedHttpOriginGroups: ["artifact", "media"],
|
|
559
|
+
originPolicy,
|
|
560
|
+
relativeUrlBase: "artifact"
|
|
561
|
+
});
|
|
562
|
+
return sanitizeRemoteDomUrl(value, {
|
|
563
|
+
allowHashOnly: false,
|
|
564
|
+
allowMailTo: false,
|
|
565
|
+
allowRelative: true,
|
|
566
|
+
allowTel: false,
|
|
567
|
+
allowedHttpOriginGroups: ["artifact", "media"],
|
|
568
|
+
originPolicy,
|
|
569
|
+
relativeUrlBase: "artifact"
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
function sanitizeEnumAttribute(name, rawValue, safeValues) {
|
|
573
|
+
const value = stringifyAttributeValue(rawValue).toLowerCase();
|
|
574
|
+
return safeValues.has(value) ? {
|
|
575
|
+
name,
|
|
576
|
+
value
|
|
577
|
+
} : void 0;
|
|
578
|
+
}
|
|
579
|
+
function hasControlCharacter(value) {
|
|
580
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
581
|
+
const codePoint = value.charCodeAt(index);
|
|
582
|
+
if (codePoint < 32 || codePoint >= 127 && codePoint <= 159) return true;
|
|
583
|
+
}
|
|
584
|
+
return false;
|
|
585
|
+
}
|
|
586
|
+
function isAllowedAttributeName(tagName, name) {
|
|
587
|
+
if (name.length === 0 || name.startsWith("on") || name === "style" || name === "srcdoc" || name.includes(":") || !/^[a-z][a-z0-9_.-]*$/u.test(name)) return false;
|
|
588
|
+
if (name.startsWith("data-")) return true;
|
|
589
|
+
if (GLOBAL_ALLOWED_ATTRIBUTES.has(name)) return true;
|
|
590
|
+
return TAG_ALLOWED_ATTRIBUTES[tagName]?.has(name) === true;
|
|
591
|
+
}
|
|
592
|
+
function stringifyAttributeValue(value) {
|
|
593
|
+
if (typeof value === "string") return value;
|
|
594
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
595
|
+
return "";
|
|
596
|
+
}
|
|
597
|
+
function sanitizeTokenList(value) {
|
|
598
|
+
return stringifyAttributeValue(value).split(/\s+/u).filter((token) => /^[a-z0-9_-]+$/iu.test(token)).join(" ");
|
|
599
|
+
}
|
|
600
|
+
function escapeCssString(value) {
|
|
601
|
+
return value.replace(/\\/gu, "\\\\").replace(/"/gu, "\\\"");
|
|
602
|
+
}
|
|
603
|
+
const CSS_URL_FUNCTION_NAME = "url";
|
|
604
|
+
const CSS_IMPORT_RULE_NAME = "import";
|
|
605
|
+
const CSS_REJECTED_URL_FUNCTION_NAMES = new Set(["image-set", "-webkit-image-set"]);
|
|
606
|
+
function sanitizeCssTextUrlReferences(cssText, originPolicy) {
|
|
607
|
+
let stylesheet;
|
|
608
|
+
try {
|
|
609
|
+
stylesheet = (0, postcss_lib_parse.default)(cssText);
|
|
610
|
+
} catch {
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
let valid = true;
|
|
614
|
+
stylesheet.walkAtRules((atRule) => {
|
|
615
|
+
if (!valid) return;
|
|
616
|
+
const decodedName = decodeCssEscapes(atRule.name)?.toLowerCase();
|
|
617
|
+
if (!decodedName) {
|
|
618
|
+
valid = false;
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
const sanitizedParams = decodedName === CSS_IMPORT_RULE_NAME ? sanitizeCssImportParameters(atRule.params, originPolicy) : sanitizeCssComponentValueUrlReferences(atRule.params, originPolicy);
|
|
622
|
+
if (sanitizedParams === void 0) {
|
|
623
|
+
valid = false;
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
if (decodedName === CSS_IMPORT_RULE_NAME) atRule.name = decodedName;
|
|
627
|
+
atRule.params = sanitizedParams;
|
|
628
|
+
});
|
|
629
|
+
stylesheet.walkDecls((declaration) => {
|
|
630
|
+
if (!valid) return;
|
|
631
|
+
const sanitizedValue = sanitizeCssComponentValueUrlReferences(declaration.value, originPolicy);
|
|
632
|
+
if (sanitizedValue === void 0) {
|
|
633
|
+
valid = false;
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
declaration.value = sanitizedValue;
|
|
637
|
+
});
|
|
638
|
+
return valid ? stylesheet.toString() : void 0;
|
|
639
|
+
}
|
|
640
|
+
function sanitizeCssImportParameters(params, originPolicy) {
|
|
641
|
+
const parsed = (0, postcss_value_parser.default)(params);
|
|
642
|
+
const firstToken = parsed.nodes.find((node) => node.type !== "space" && node.type !== "comment");
|
|
643
|
+
if (!firstToken) return void 0;
|
|
644
|
+
if (firstToken.type === "string") {
|
|
645
|
+
const decodedUrl = decodeCssEscapes(firstToken.value);
|
|
646
|
+
const sanitizedUrl = decodedUrl === void 0 ? void 0 : sanitizeCssUrlToken(decodedUrl, originPolicy);
|
|
647
|
+
if (!sanitizedUrl) return void 0;
|
|
648
|
+
firstToken.quote = "\"";
|
|
649
|
+
firstToken.value = escapeCssString(sanitizedUrl);
|
|
650
|
+
} else if (firstToken.type !== "function" || decodeCssEscapes(firstToken.value)?.toLowerCase() !== CSS_URL_FUNCTION_NAME) return;
|
|
651
|
+
return sanitizeParsedCssValue(parsed.nodes, originPolicy) ? postcss_value_parser.default.stringify(parsed.nodes) : void 0;
|
|
652
|
+
}
|
|
653
|
+
function sanitizeCssComponentValueUrlReferences(cssValue, originPolicy) {
|
|
654
|
+
const parsed = (0, postcss_value_parser.default)(cssValue);
|
|
655
|
+
return sanitizeParsedCssValue(parsed.nodes, originPolicy) ? postcss_value_parser.default.stringify(parsed.nodes) : void 0;
|
|
656
|
+
}
|
|
657
|
+
function sanitizeParsedCssValue(nodes, originPolicy) {
|
|
658
|
+
for (const node of nodes) {
|
|
659
|
+
if ("unclosed" in node && node.unclosed === true) return false;
|
|
660
|
+
if (node.type !== "function") continue;
|
|
661
|
+
const decodedFunctionName = decodeCssEscapes(node.value);
|
|
662
|
+
if (decodedFunctionName === void 0) return false;
|
|
663
|
+
const functionName = decodedFunctionName.toLowerCase();
|
|
664
|
+
if (CSS_REJECTED_URL_FUNCTION_NAMES.has(functionName)) return false;
|
|
665
|
+
if (functionName === CSS_URL_FUNCTION_NAME) {
|
|
666
|
+
if (!sanitizeCssUrlFunctionNode(node, originPolicy)) return false;
|
|
667
|
+
continue;
|
|
668
|
+
}
|
|
669
|
+
if (!sanitizeParsedCssValue(node.nodes, originPolicy)) return false;
|
|
670
|
+
}
|
|
671
|
+
return true;
|
|
672
|
+
}
|
|
673
|
+
function sanitizeCssUrlFunctionNode(node, originPolicy) {
|
|
674
|
+
const tokens = node.nodes.filter((child) => child.type !== "space" && child.type !== "comment");
|
|
675
|
+
if (tokens.length !== 1) return false;
|
|
676
|
+
const token = tokens[0];
|
|
677
|
+
if (!token || token.type !== "word" && token.type !== "string") return false;
|
|
678
|
+
if ("unclosed" in token && token.unclosed === true) return false;
|
|
679
|
+
const decodedUrl = decodeCssEscapes(token.value);
|
|
680
|
+
const sanitizedUrl = decodedUrl === void 0 ? void 0 : sanitizeCssUrlToken(decodedUrl, originPolicy);
|
|
681
|
+
if (!sanitizedUrl) return false;
|
|
682
|
+
node.value = CSS_URL_FUNCTION_NAME;
|
|
683
|
+
node.before = "";
|
|
684
|
+
node.after = "";
|
|
685
|
+
node.nodes = [{
|
|
686
|
+
type: "string",
|
|
687
|
+
quote: "\"",
|
|
688
|
+
value: escapeCssString(sanitizedUrl),
|
|
689
|
+
sourceIndex: token.sourceIndex,
|
|
690
|
+
sourceEndIndex: token.sourceEndIndex
|
|
691
|
+
}];
|
|
692
|
+
return true;
|
|
693
|
+
}
|
|
694
|
+
/** Decodes CSS escapes after the maintained parser has identified a token. */
|
|
695
|
+
function decodeCssEscapes(value) {
|
|
696
|
+
let decoded = "";
|
|
697
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
698
|
+
const codeUnit = value[index];
|
|
699
|
+
if (codeUnit !== "\\") {
|
|
700
|
+
decoded += codeUnit;
|
|
701
|
+
continue;
|
|
702
|
+
}
|
|
703
|
+
index += 1;
|
|
704
|
+
const escaped = value[index];
|
|
705
|
+
if (escaped === void 0 || escaped === "\n" || escaped === "\r" || escaped === "\f") return;
|
|
706
|
+
if (!/^[0-9a-f]$/iu.test(escaped)) {
|
|
707
|
+
decoded += escaped;
|
|
708
|
+
continue;
|
|
709
|
+
}
|
|
710
|
+
const hexStart = index;
|
|
711
|
+
while (index + 1 < value.length && index + 1 - hexStart < 6 && /^[0-9a-f]$/iu.test(value[index + 1] ?? "")) index += 1;
|
|
712
|
+
const codePoint = Number.parseInt(value.slice(hexStart, index + 1), 16);
|
|
713
|
+
decoded += codePoint === 0 || codePoint > 1114111 || codePoint >= 55296 && codePoint <= 57343 ? "�" : String.fromCodePoint(codePoint);
|
|
714
|
+
if (/^[ \n\r\t\f]$/u.test(value[index + 1] ?? "")) index += 1;
|
|
715
|
+
}
|
|
716
|
+
return decoded;
|
|
717
|
+
}
|
|
718
|
+
function sanitizeCssUrlToken(rawUrl, originPolicy) {
|
|
719
|
+
return sanitizeRemoteDomUrl(rawUrl.trim().replace(/^(["'])(.*)\1$/u, "$2"), {
|
|
720
|
+
allowHashOnly: false,
|
|
721
|
+
allowMailTo: false,
|
|
722
|
+
allowRelative: true,
|
|
723
|
+
allowTel: false,
|
|
724
|
+
allowedHttpOriginGroups: ["artifact", "media"],
|
|
725
|
+
originPolicy,
|
|
726
|
+
relativeUrlBase: "artifact"
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
function resolveRemoteDomRelativeUrl(value, originPolicy, base) {
|
|
730
|
+
const baseUrl = base === "navigation" ? originPolicy?.navigationOrigin : originPolicy?.artifactBaseUrl;
|
|
731
|
+
if (!baseUrl) return void 0;
|
|
732
|
+
try {
|
|
733
|
+
const resolvedUrl = new URL(value, baseUrl);
|
|
734
|
+
return resolvedUrl.protocol === "http:" || resolvedUrl.protocol === "https:" ? resolvedUrl : void 0;
|
|
735
|
+
} catch {
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
function isAllowedHttpOrigin(origin, originPolicy, allowedGroups) {
|
|
740
|
+
if (allowedGroups.length === 0 || !originPolicy) return false;
|
|
741
|
+
for (const group of allowedGroups) {
|
|
742
|
+
if (group === "artifact" && originPolicy.artifactOrigins.includes(origin)) return true;
|
|
743
|
+
if (group === "media" && originPolicy.mediaOrigins.includes(origin)) return true;
|
|
744
|
+
if (group === "navigation" && originPolicy.navigationOrigin === origin) return true;
|
|
745
|
+
}
|
|
746
|
+
return false;
|
|
747
|
+
}
|
|
748
|
+
function isRelativeUrl(value) {
|
|
749
|
+
return !/^[a-z][a-z0-9+.-]*:/iu.test(value);
|
|
750
|
+
}
|
|
751
|
+
function readInputState(target) {
|
|
752
|
+
if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target instanceof HTMLSelectElement) {
|
|
753
|
+
const inputState = { value: target.value };
|
|
754
|
+
if (target instanceof HTMLInputElement) inputState.checked = target.checked;
|
|
755
|
+
return inputState;
|
|
756
|
+
}
|
|
757
|
+
return {};
|
|
758
|
+
}
|
|
759
|
+
function readKeyboardState(event) {
|
|
760
|
+
if (!(event instanceof KeyboardEvent)) return {};
|
|
761
|
+
return {
|
|
762
|
+
altKey: event.altKey,
|
|
763
|
+
code: event.code,
|
|
764
|
+
ctrlKey: event.ctrlKey,
|
|
765
|
+
key: event.key,
|
|
766
|
+
metaKey: event.metaKey,
|
|
767
|
+
shiftKey: event.shiftKey
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
function readMouseState(event) {
|
|
771
|
+
if (!(event instanceof MouseEvent)) return {};
|
|
772
|
+
return {
|
|
773
|
+
altKey: event.altKey,
|
|
774
|
+
button: event.button,
|
|
775
|
+
buttons: event.buttons,
|
|
776
|
+
clientX: event.clientX,
|
|
777
|
+
clientY: event.clientY,
|
|
778
|
+
ctrlKey: event.ctrlKey,
|
|
779
|
+
metaKey: event.metaKey,
|
|
780
|
+
shiftKey: event.shiftKey
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
function readPointerState(event) {
|
|
784
|
+
if (!isObjectRecord$1(event) || typeof PointerEvent === "undefined") return {};
|
|
785
|
+
if (!(event instanceof PointerEvent)) return {};
|
|
786
|
+
return {
|
|
787
|
+
isPrimary: event.isPrimary,
|
|
788
|
+
pointerId: event.pointerId,
|
|
789
|
+
pointerType: event.pointerType
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
function isObjectRecord$1(value) {
|
|
793
|
+
return typeof value === "object" && value !== null;
|
|
794
|
+
}
|
|
795
|
+
//#endregion
|
|
796
|
+
//#region src/remote-dom-sanitizing-connection.ts
|
|
797
|
+
var RemoteDomConnectionCallDeniedError = class extends Error {
|
|
798
|
+
constructor(method) {
|
|
799
|
+
super(`Remote DOM element method "${method}" was blocked; host method calls are denied.`);
|
|
800
|
+
this.name = "RemoteDomConnectionCallDeniedError";
|
|
801
|
+
}
|
|
802
|
+
};
|
|
803
|
+
function createSanitizingRemoteConnection(options) {
|
|
804
|
+
const state = { nodes: new Map([[_remote_dom_core.ROOT_ID, {
|
|
805
|
+
kind: "element",
|
|
806
|
+
localName: "",
|
|
807
|
+
childIds: []
|
|
808
|
+
}]]) };
|
|
809
|
+
function reset() {
|
|
810
|
+
state.nodes.clear();
|
|
811
|
+
state.nodes.set(_remote_dom_core.ROOT_ID, {
|
|
812
|
+
kind: "element",
|
|
813
|
+
localName: "",
|
|
814
|
+
childIds: []
|
|
815
|
+
});
|
|
816
|
+
}
|
|
817
|
+
function mutate(records) {
|
|
818
|
+
if (records.length > options.maxMutationBatchSize) {
|
|
819
|
+
options.onInvalidRecord?.("Remote DOM mutation batch exceeded maxMutationBatchSize");
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
const normalizedRecords = [];
|
|
823
|
+
const pendingEventListenerUpdates = [];
|
|
824
|
+
const workingState = cloneSanitizingState(state);
|
|
825
|
+
for (const rawRecord of records) {
|
|
826
|
+
const record = parseRemoteMutationRecord(rawRecord);
|
|
827
|
+
if (!record) {
|
|
828
|
+
options.onInvalidRecord?.("Remote DOM worker sent an invalid upstream mutation record");
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
831
|
+
const normalized = normalizeMutationRecordForHost(options, workingState, record, pendingEventListenerUpdates);
|
|
832
|
+
if (!normalized.ok) {
|
|
833
|
+
if (normalized.message === NODE_LIMIT_MESSAGE) options.onNodeLimitExceeded?.();
|
|
834
|
+
else options.onInvalidRecord?.(normalized.message);
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
if (normalized.record) normalizedRecords.push(normalized.record);
|
|
838
|
+
}
|
|
839
|
+
try {
|
|
840
|
+
if (normalizedRecords.length > 0) options.connection.mutate(normalizedRecords);
|
|
841
|
+
} catch (error) {
|
|
842
|
+
options.onMutateError?.(error);
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
commitSanitizingState(state, workingState);
|
|
846
|
+
for (const update of pendingEventListenerUpdates) options.onEventListenerUpdate?.(update.targetId, update.eventName, update.listener);
|
|
847
|
+
}
|
|
848
|
+
return {
|
|
849
|
+
mutate,
|
|
850
|
+
call(_id, method) {
|
|
851
|
+
throw new RemoteDomConnectionCallDeniedError(method);
|
|
852
|
+
},
|
|
853
|
+
reset
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
function cloneSanitizingState(state) {
|
|
857
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
858
|
+
for (const [id, node] of state.nodes) nodes.set(id, node.kind === "element" ? {
|
|
859
|
+
...node,
|
|
860
|
+
childIds: [...node.childIds]
|
|
861
|
+
} : { kind: "text" });
|
|
862
|
+
return { nodes };
|
|
863
|
+
}
|
|
864
|
+
function commitSanitizingState(state, workingState) {
|
|
865
|
+
state.nodes.clear();
|
|
866
|
+
for (const [id, node] of workingState.nodes) state.nodes.set(id, node);
|
|
867
|
+
}
|
|
868
|
+
const NODE_LIMIT_MESSAGE = "Remote DOM mutation exceeded node limit.";
|
|
869
|
+
function normalizeMutationRecordForHost(options, state, mutation, pendingEventListenerUpdates) {
|
|
870
|
+
switch (mutation[0]) {
|
|
871
|
+
case _remote_dom_core.MUTATION_TYPE_INSERT_CHILD: {
|
|
872
|
+
const [, parentId, child, index] = mutation;
|
|
873
|
+
const parent = state.nodes.get(parentId);
|
|
874
|
+
if (!parent || parent.kind !== "element") return {
|
|
875
|
+
ok: false,
|
|
876
|
+
message: `Remote DOM mutation referenced missing insertChild parent node "${parentId}".`
|
|
877
|
+
};
|
|
878
|
+
if (!Number.isInteger(index) || index < 0 || index > parent.childIds.length) return {
|
|
879
|
+
ok: false,
|
|
880
|
+
message: "Remote DOM insertChild index was invalid."
|
|
881
|
+
};
|
|
882
|
+
const normalized = normalizeRemoteNodeForHost(options, state, child, new Set(state.nodes.keys()), pendingEventListenerUpdates);
|
|
883
|
+
if (!normalized.ok) return normalized;
|
|
884
|
+
if (Math.max(0, state.nodes.size - 1) + normalized.nodeCount > options.maxDomNodeCount) return {
|
|
885
|
+
ok: false,
|
|
886
|
+
message: NODE_LIMIT_MESSAGE
|
|
887
|
+
};
|
|
888
|
+
registerSimulatedRemoteNode(state, normalized.node);
|
|
889
|
+
parent.childIds.splice(index, 0, normalized.node.id);
|
|
890
|
+
return {
|
|
891
|
+
ok: true,
|
|
892
|
+
record: [
|
|
893
|
+
_remote_dom_core.MUTATION_TYPE_INSERT_CHILD,
|
|
894
|
+
parentId,
|
|
895
|
+
normalized.node,
|
|
896
|
+
index
|
|
897
|
+
]
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
case _remote_dom_core.MUTATION_TYPE_REMOVE_CHILD: {
|
|
901
|
+
const [, parentId, index] = mutation;
|
|
902
|
+
const parent = state.nodes.get(parentId);
|
|
903
|
+
if (!parent || parent.kind !== "element") return {
|
|
904
|
+
ok: false,
|
|
905
|
+
message: `Remote DOM mutation referenced missing removeChild parent node "${parentId}".`
|
|
906
|
+
};
|
|
907
|
+
if (!Number.isInteger(index) || index < 0 || index >= parent.childIds.length) return {
|
|
908
|
+
ok: false,
|
|
909
|
+
message: "Remote DOM removeChild index was invalid."
|
|
910
|
+
};
|
|
911
|
+
const [removedId] = parent.childIds.splice(index, 1);
|
|
912
|
+
if (!removedId) return {
|
|
913
|
+
ok: false,
|
|
914
|
+
message: "Remote DOM removeChild index was invalid."
|
|
915
|
+
};
|
|
916
|
+
removeSimulatedRemoteNode(state, removedId);
|
|
917
|
+
return {
|
|
918
|
+
ok: true,
|
|
919
|
+
record: mutation
|
|
920
|
+
};
|
|
921
|
+
}
|
|
922
|
+
case _remote_dom_core.MUTATION_TYPE_UPDATE_TEXT: {
|
|
923
|
+
const [, id] = mutation;
|
|
924
|
+
const target = state.nodes.get(id);
|
|
925
|
+
if (!target || target.kind !== "text") return {
|
|
926
|
+
ok: false,
|
|
927
|
+
message: `Remote DOM mutation referenced missing updateText target node "${id}".`
|
|
928
|
+
};
|
|
929
|
+
return {
|
|
930
|
+
ok: true,
|
|
931
|
+
record: mutation
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
case _remote_dom_core.MUTATION_TYPE_UPDATE_PROPERTY: return normalizeUpdatePropertyRecordForHost(options, state, mutation, pendingEventListenerUpdates);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
function normalizeUpdatePropertyRecordForHost(options, state, mutation, pendingEventListenerUpdates) {
|
|
938
|
+
const [, id, property, value, updateType] = mutation;
|
|
939
|
+
if (!require_remote_dom_values.isSafeRemoteDomPropertyKey(property)) return {
|
|
940
|
+
ok: false,
|
|
941
|
+
message: `Remote DOM mutation used an unsafe property key "${property}".`
|
|
942
|
+
};
|
|
943
|
+
const node = state.nodes.get(id);
|
|
944
|
+
if (!node || node.kind !== "element") return {
|
|
945
|
+
ok: false,
|
|
946
|
+
message: `Remote DOM mutation referenced missing updateProperty target node "${id}".`
|
|
947
|
+
};
|
|
948
|
+
if (updateType === _remote_dom_core.UPDATE_PROPERTY_TYPE_EVENT_LISTENER) {
|
|
949
|
+
if (!isSupportedRemoteDomEventName(property, node.localName)) return { ok: true };
|
|
950
|
+
const listener = typeof value === "function" ? value : null;
|
|
951
|
+
pendingEventListenerUpdates.push({
|
|
952
|
+
targetId: id,
|
|
953
|
+
eventName: property,
|
|
954
|
+
listener
|
|
955
|
+
});
|
|
956
|
+
return { ok: true };
|
|
957
|
+
}
|
|
958
|
+
if (value !== void 0 && !require_remote_dom_values.isRemoteDomSerializableValue(value)) return {
|
|
959
|
+
ok: false,
|
|
960
|
+
message: `Remote DOM mutation property "${property}" was not serializable.`
|
|
961
|
+
};
|
|
962
|
+
if (updateType === _remote_dom_core.UPDATE_PROPERTY_TYPE_PROPERTY) {
|
|
963
|
+
const sanitizedProperty = sanitizeRemoteDomProperty(node.localName, property, value);
|
|
964
|
+
if (sanitizedProperty) return {
|
|
965
|
+
ok: true,
|
|
966
|
+
record: [
|
|
967
|
+
_remote_dom_core.MUTATION_TYPE_UPDATE_PROPERTY,
|
|
968
|
+
id,
|
|
969
|
+
sanitizedProperty.name,
|
|
970
|
+
sanitizedProperty.value,
|
|
971
|
+
_remote_dom_core.UPDATE_PROPERTY_TYPE_PROPERTY
|
|
972
|
+
]
|
|
973
|
+
};
|
|
974
|
+
if (isRemoteDomPropertyName(node.localName, property)) return {
|
|
975
|
+
ok: false,
|
|
976
|
+
message: `Remote DOM property "${property}" had an invalid value for "${node.localName}".`
|
|
977
|
+
};
|
|
978
|
+
}
|
|
979
|
+
const [attribute] = sanitizeRemoteDomAttributes(node.localName, { [property]: value }, { urlOriginPolicy: options.urlOriginPolicy });
|
|
980
|
+
if (attribute) return {
|
|
981
|
+
ok: true,
|
|
982
|
+
record: [
|
|
983
|
+
_remote_dom_core.MUTATION_TYPE_UPDATE_PROPERTY,
|
|
984
|
+
id,
|
|
985
|
+
attribute.name,
|
|
986
|
+
attribute.value,
|
|
987
|
+
_remote_dom_core.UPDATE_PROPERTY_TYPE_ATTRIBUTE
|
|
988
|
+
]
|
|
989
|
+
};
|
|
990
|
+
const normalizedAttributeName = property.trim().toLowerCase();
|
|
991
|
+
if (!/^[a-z][a-z0-9_.-]*$/u.test(normalizedAttributeName)) return {
|
|
992
|
+
ok: false,
|
|
993
|
+
message: `Remote DOM mutation used an invalid attribute removal name "${property}".`
|
|
994
|
+
};
|
|
995
|
+
return {
|
|
996
|
+
ok: true,
|
|
997
|
+
record: [
|
|
998
|
+
_remote_dom_core.MUTATION_TYPE_UPDATE_PROPERTY,
|
|
999
|
+
id,
|
|
1000
|
+
normalizedAttributeName,
|
|
1001
|
+
void 0,
|
|
1002
|
+
_remote_dom_core.UPDATE_PROPERTY_TYPE_ATTRIBUTE
|
|
1003
|
+
]
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
1006
|
+
function normalizeRemoteNodeForHost(options, state, value, seen, pendingEventListenerUpdates) {
|
|
1007
|
+
if (!isObjectRecord(value)) return {
|
|
1008
|
+
ok: false,
|
|
1009
|
+
message: "Remote DOM render payload was not a node."
|
|
1010
|
+
};
|
|
1011
|
+
if (value.type === _remote_dom_core.NODE_TYPE_TEXT && typeof value.id === "string" && typeof value.data === "string") {
|
|
1012
|
+
const idValidation = validateRemoteNodeId(value.id, seen);
|
|
1013
|
+
if (!idValidation.ok) return idValidation;
|
|
1014
|
+
return {
|
|
1015
|
+
ok: true,
|
|
1016
|
+
node: {
|
|
1017
|
+
id: value.id,
|
|
1018
|
+
type: _remote_dom_core.NODE_TYPE_TEXT,
|
|
1019
|
+
data: value.data
|
|
1020
|
+
},
|
|
1021
|
+
nodeCount: 1
|
|
1022
|
+
};
|
|
1023
|
+
}
|
|
1024
|
+
if (value.type !== _remote_dom_core.NODE_TYPE_ELEMENT || typeof value.id !== "string" || typeof value.element !== "string") return {
|
|
1025
|
+
ok: false,
|
|
1026
|
+
message: "Remote DOM render payload was not a valid node."
|
|
1027
|
+
};
|
|
1028
|
+
const idValidation = validateRemoteNodeId(value.id, seen);
|
|
1029
|
+
if (!idValidation.ok) return idValidation;
|
|
1030
|
+
const properties = readRemoteNodeProperties(value);
|
|
1031
|
+
if (!properties) return {
|
|
1032
|
+
ok: false,
|
|
1033
|
+
message: `Remote DOM element "${value.id}" contained non-serializable properties.`
|
|
1034
|
+
};
|
|
1035
|
+
const tagName = sanitizeRemoteDomTagName(value.element);
|
|
1036
|
+
if (!tagName) return {
|
|
1037
|
+
ok: false,
|
|
1038
|
+
message: `Remote DOM element "${value.id}" used an unsupported tag name.`
|
|
1039
|
+
};
|
|
1040
|
+
queueRemoteNodeEventListeners(value.id, tagName, value.eventListeners, pendingEventListenerUpdates);
|
|
1041
|
+
if (!Array.isArray(value.children)) return {
|
|
1042
|
+
ok: false,
|
|
1043
|
+
message: `Remote DOM element "${value.id}" did not contain a valid children array.`
|
|
1044
|
+
};
|
|
1045
|
+
const children = [];
|
|
1046
|
+
let nodeCount = 1;
|
|
1047
|
+
for (const child of value.children) {
|
|
1048
|
+
const normalized = normalizeRemoteNodeForHost(options, state, child, seen, pendingEventListenerUpdates);
|
|
1049
|
+
if (!normalized.ok) return normalized;
|
|
1050
|
+
children.push(normalized.node);
|
|
1051
|
+
nodeCount += normalized.nodeCount;
|
|
1052
|
+
}
|
|
1053
|
+
const remoteProperties = {};
|
|
1054
|
+
let attributeProperties = properties;
|
|
1055
|
+
if (isObjectRecord(value.properties)) {
|
|
1056
|
+
const mutableAttributeProperties = { ...properties };
|
|
1057
|
+
attributeProperties = mutableAttributeProperties;
|
|
1058
|
+
for (const [rawName, rawValue] of Object.entries(value.properties)) {
|
|
1059
|
+
const property = sanitizeRemoteDomProperty(tagName, rawName, rawValue);
|
|
1060
|
+
if (property) {
|
|
1061
|
+
remoteProperties[property.name] = property.value;
|
|
1062
|
+
delete mutableAttributeProperties[rawName];
|
|
1063
|
+
continue;
|
|
1064
|
+
}
|
|
1065
|
+
if (isRemoteDomPropertyName(tagName, rawName)) return {
|
|
1066
|
+
ok: false,
|
|
1067
|
+
message: `Remote DOM property "${rawName}" had an invalid value for "${tagName}".`
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
const attributes = sanitizeRemoteDomAttributes(tagName, attributeProperties, { urlOriginPolicy: options.urlOriginPolicy });
|
|
1072
|
+
const remoteAttributes = {};
|
|
1073
|
+
for (const attribute of attributes) remoteAttributes[attribute.name] = attribute.value;
|
|
1074
|
+
if (tagName === "button" && remoteAttributes.type === void 0) remoteAttributes.type = "button";
|
|
1075
|
+
return {
|
|
1076
|
+
ok: true,
|
|
1077
|
+
node: {
|
|
1078
|
+
id: value.id,
|
|
1079
|
+
type: _remote_dom_core.NODE_TYPE_ELEMENT,
|
|
1080
|
+
element: tagName,
|
|
1081
|
+
attributes: remoteAttributes,
|
|
1082
|
+
properties: remoteProperties,
|
|
1083
|
+
children
|
|
1084
|
+
},
|
|
1085
|
+
nodeCount
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1088
|
+
function queueRemoteNodeEventListeners(id, tagName, eventListeners, pendingEventListenerUpdates) {
|
|
1089
|
+
if (!isObjectRecord(eventListeners)) return;
|
|
1090
|
+
for (const [eventName, listener] of Object.entries(eventListeners)) {
|
|
1091
|
+
if (!require_remote_dom_values.isSafeRemoteDomPropertyKey(eventName) || !isSupportedRemoteDomEventName(eventName, tagName)) continue;
|
|
1092
|
+
pendingEventListenerUpdates.push({
|
|
1093
|
+
targetId: id,
|
|
1094
|
+
eventName,
|
|
1095
|
+
listener: typeof listener === "function" ? listener : null
|
|
1096
|
+
});
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
function validateRemoteNodeId(id, seen) {
|
|
1100
|
+
if (id === _remote_dom_core.ROOT_ID) return {
|
|
1101
|
+
ok: false,
|
|
1102
|
+
message: `Remote DOM node id "${id}" is reserved`
|
|
1103
|
+
};
|
|
1104
|
+
if (seen.has(id)) return {
|
|
1105
|
+
ok: false,
|
|
1106
|
+
message: `Remote DOM render payload contained duplicate node id "${id}"`
|
|
1107
|
+
};
|
|
1108
|
+
seen.add(id);
|
|
1109
|
+
return { ok: true };
|
|
1110
|
+
}
|
|
1111
|
+
function readRemoteNodeProperties(value) {
|
|
1112
|
+
const properties = {};
|
|
1113
|
+
for (const source of [value.attributes, value.properties]) {
|
|
1114
|
+
if (source === void 0) continue;
|
|
1115
|
+
if (!isObjectRecord(source)) return void 0;
|
|
1116
|
+
for (const [key, item] of Object.entries(source)) {
|
|
1117
|
+
if (!require_remote_dom_values.isSafeRemoteDomPropertyKey(key)) return void 0;
|
|
1118
|
+
if (item !== void 0 && !require_remote_dom_values.isRemoteDomSerializableValue(item)) return;
|
|
1119
|
+
properties[key] = item;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
return properties;
|
|
1123
|
+
}
|
|
1124
|
+
function registerSimulatedRemoteNode(state, node) {
|
|
1125
|
+
if (node.type === _remote_dom_core.NODE_TYPE_TEXT) {
|
|
1126
|
+
state.nodes.set(node.id, { kind: "text" });
|
|
1127
|
+
return;
|
|
1128
|
+
}
|
|
1129
|
+
if (node.type !== _remote_dom_core.NODE_TYPE_ELEMENT) return;
|
|
1130
|
+
state.nodes.set(node.id, {
|
|
1131
|
+
kind: "element",
|
|
1132
|
+
localName: node.element,
|
|
1133
|
+
childIds: node.children.map((child) => child.id)
|
|
1134
|
+
});
|
|
1135
|
+
for (const child of node.children) registerSimulatedRemoteNode(state, child);
|
|
1136
|
+
}
|
|
1137
|
+
function removeSimulatedRemoteNode(state, id) {
|
|
1138
|
+
const node = state.nodes.get(id);
|
|
1139
|
+
if (!node) return;
|
|
1140
|
+
state.nodes.delete(id);
|
|
1141
|
+
if (node.kind === "element") for (const childId of node.childIds) removeSimulatedRemoteNode(state, childId);
|
|
1142
|
+
}
|
|
1143
|
+
function parseRemoteMutationRecord(value) {
|
|
1144
|
+
if (!Array.isArray(value)) return void 0;
|
|
1145
|
+
switch (value[0]) {
|
|
1146
|
+
case _remote_dom_core.MUTATION_TYPE_INSERT_CHILD: return value.length === 4 && typeof value[1] === "string" && isObjectRecord(value[2]) && typeof value[3] === "number" ? value : void 0;
|
|
1147
|
+
case _remote_dom_core.MUTATION_TYPE_REMOVE_CHILD: return value.length === 3 && typeof value[1] === "string" && typeof value[2] === "number" ? value : void 0;
|
|
1148
|
+
case _remote_dom_core.MUTATION_TYPE_UPDATE_TEXT: return value.length === 3 && typeof value[1] === "string" && typeof value[2] === "string" ? value : void 0;
|
|
1149
|
+
case _remote_dom_core.MUTATION_TYPE_UPDATE_PROPERTY: return (value.length === 4 || value.length === 5) && typeof value[1] === "string" && typeof value[2] === "string" ? value : void 0;
|
|
1150
|
+
default: return;
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
function isObjectRecord(value) {
|
|
1154
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1155
|
+
}
|
|
1156
|
+
//#endregion
|
|
1157
|
+
//#region src/remote-dom-styles.ts
|
|
1158
|
+
const remoteDomCssArtifactCache = /* @__PURE__ */ new Map();
|
|
1159
|
+
const DEFAULT_THEME_DATA_ATTRIBUTES = [
|
|
1160
|
+
"data-theme",
|
|
1161
|
+
"data-mode",
|
|
1162
|
+
"data-color-mode",
|
|
1163
|
+
"data-fluid-theme",
|
|
1164
|
+
"data-fluid-color-scheme"
|
|
1165
|
+
];
|
|
1166
|
+
const REMOTE_DOM_WIDGET_STYLE_ATTRIBUTE = "data-fluid-widget-style";
|
|
1167
|
+
function attachRemoteDomStyles({ artifact, root, cssText, widgetCssText, cssUrls, fluidComponentCssText, fluidComponentCssUrls, themeBridgeCssText, urlOriginPolicy, useConstructableStylesheets = true, fetchCss, onFailure, themeBridge }) {
|
|
1168
|
+
const styleElements = [];
|
|
1169
|
+
const adoptedSheets = /* @__PURE__ */ new Set();
|
|
1170
|
+
const acquiredArtifacts = [];
|
|
1171
|
+
let disposed = false;
|
|
1172
|
+
let failureReported = false;
|
|
1173
|
+
const resolvedUrlOriginPolicy = urlOriginPolicy ?? require_remote_dom_values.createRemoteDomUrlOriginPolicy({ artifactUrls: collectArtifactUrls$1(artifact) });
|
|
1174
|
+
const { sources, failedSourceCount: rejectedSourceCount } = createStyleSources({
|
|
1175
|
+
artifact,
|
|
1176
|
+
cssText,
|
|
1177
|
+
widgetCssText,
|
|
1178
|
+
cssUrls,
|
|
1179
|
+
fluidComponentCssText,
|
|
1180
|
+
fluidComponentCssUrls,
|
|
1181
|
+
themeBridgeCssText,
|
|
1182
|
+
urlOriginPolicy: resolvedUrlOriginPolicy
|
|
1183
|
+
});
|
|
1184
|
+
const declaredSourceCount = sources.length + rejectedSourceCount;
|
|
1185
|
+
const bridge = themeBridge === false ? void 0 : createRemoteDomThemeBridge({
|
|
1186
|
+
root,
|
|
1187
|
+
...themeBridge
|
|
1188
|
+
});
|
|
1189
|
+
const reportFailures = (failedSourceCount) => {
|
|
1190
|
+
if (disposed || failureReported || failedSourceCount === 0) return;
|
|
1191
|
+
failureReported = true;
|
|
1192
|
+
try {
|
|
1193
|
+
onFailure?.(failedSourceCount);
|
|
1194
|
+
} catch {}
|
|
1195
|
+
};
|
|
1196
|
+
return {
|
|
1197
|
+
ready: Promise.resolve().then(async () => {
|
|
1198
|
+
const sourceResults = await Promise.all(sources.map(async (source) => {
|
|
1199
|
+
if (disposed) return void 0;
|
|
1200
|
+
if (source.kind === "text") return source;
|
|
1201
|
+
let artifact;
|
|
1202
|
+
try {
|
|
1203
|
+
artifact = acquireCssArtifact(source, root, fetchCss);
|
|
1204
|
+
acquiredArtifacts.push(artifact);
|
|
1205
|
+
const sanitizedCssText = sanitizeRemoteDomCssUrlReferences(await artifact.entry.promise, { urlOriginPolicy: resolvedUrlOriginPolicy });
|
|
1206
|
+
if (!sanitizedCssText) {
|
|
1207
|
+
releaseCssArtifact(artifact);
|
|
1208
|
+
if (artifact.entry.refCount === 0) remoteDomCssArtifactCache.delete(artifact.entry.key);
|
|
1209
|
+
return null;
|
|
1210
|
+
}
|
|
1211
|
+
if (disposed) {
|
|
1212
|
+
releaseCssArtifact(artifact);
|
|
1213
|
+
return;
|
|
1214
|
+
}
|
|
1215
|
+
return {
|
|
1216
|
+
kind: "text",
|
|
1217
|
+
label: source.label,
|
|
1218
|
+
cssText: sanitizedCssText,
|
|
1219
|
+
artifact: artifact.entry
|
|
1220
|
+
};
|
|
1221
|
+
} catch {
|
|
1222
|
+
if (artifact) {
|
|
1223
|
+
releaseCssArtifact(artifact);
|
|
1224
|
+
if (artifact.entry.refCount === 0) remoteDomCssArtifactCache.delete(artifact.entry.key);
|
|
1225
|
+
}
|
|
1226
|
+
return null;
|
|
1227
|
+
}
|
|
1228
|
+
}));
|
|
1229
|
+
if (disposed) return;
|
|
1230
|
+
const resolvedSources = [];
|
|
1231
|
+
let resolutionFailureCount = 0;
|
|
1232
|
+
for (const source of sourceResults) if (source === null) resolutionFailureCount += 1;
|
|
1233
|
+
else if (source !== void 0) resolvedSources.push(source);
|
|
1234
|
+
const installationFailureCount = installResolvedStyleSources({
|
|
1235
|
+
root,
|
|
1236
|
+
sources: resolvedSources,
|
|
1237
|
+
styleElements,
|
|
1238
|
+
adoptedSheets,
|
|
1239
|
+
useConstructableStylesheets
|
|
1240
|
+
});
|
|
1241
|
+
reportFailures(rejectedSourceCount + resolutionFailureCount + installationFailureCount);
|
|
1242
|
+
}).catch(() => {
|
|
1243
|
+
reportFailures(declaredSourceCount);
|
|
1244
|
+
}),
|
|
1245
|
+
dispose: () => {
|
|
1246
|
+
if (disposed) return;
|
|
1247
|
+
disposed = true;
|
|
1248
|
+
const cleanupErrors = [];
|
|
1249
|
+
runStyleCleanupStep(cleanupErrors, () => bridge?.dispose());
|
|
1250
|
+
runStyleCleanupStep(cleanupErrors, () => removeAdoptedSheets(root, adoptedSheets));
|
|
1251
|
+
for (const styleElement of styleElements) runStyleCleanupStep(cleanupErrors, () => styleElement.remove());
|
|
1252
|
+
for (const artifact of acquiredArtifacts) runStyleCleanupStep(cleanupErrors, () => releaseCssArtifact(artifact));
|
|
1253
|
+
throwStyleCleanupErrors(cleanupErrors, "Remote DOM style disposal encountered cleanup failures");
|
|
1254
|
+
}
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1257
|
+
function createRemoteDomThemeBridge(options) {
|
|
1258
|
+
const sourceElement = options.sourceElement ?? options.root.ownerDocument.documentElement;
|
|
1259
|
+
const host = options.root.host;
|
|
1260
|
+
const managedVariables = /* @__PURE__ */ new Set();
|
|
1261
|
+
const managedAttributes = /* @__PURE__ */ new Set();
|
|
1262
|
+
const managedClasses = /* @__PURE__ */ new Set();
|
|
1263
|
+
const originalVariables = host instanceof HTMLElement ? snapshotCssVariables(host) : /* @__PURE__ */ new Map();
|
|
1264
|
+
const originalAttributes = host instanceof HTMLElement ? snapshotDataAttributes(host) : /* @__PURE__ */ new Map();
|
|
1265
|
+
const originalClasses = host instanceof HTMLElement ? new Set(host.classList) : /* @__PURE__ */ new Set();
|
|
1266
|
+
let disposed = false;
|
|
1267
|
+
let observer;
|
|
1268
|
+
const restore = () => {
|
|
1269
|
+
if (!(host instanceof HTMLElement)) return;
|
|
1270
|
+
restoreThemeBridgeState({
|
|
1271
|
+
host,
|
|
1272
|
+
managedVariables,
|
|
1273
|
+
managedAttributes,
|
|
1274
|
+
managedClasses,
|
|
1275
|
+
originalVariables,
|
|
1276
|
+
originalAttributes,
|
|
1277
|
+
originalClasses
|
|
1278
|
+
});
|
|
1279
|
+
};
|
|
1280
|
+
const update = () => {
|
|
1281
|
+
if (disposed || !(host instanceof HTMLElement)) return;
|
|
1282
|
+
try {
|
|
1283
|
+
mirrorCssVariables({
|
|
1284
|
+
host,
|
|
1285
|
+
sourceElement,
|
|
1286
|
+
variableNames: options.cssVariableNames,
|
|
1287
|
+
managedVariables,
|
|
1288
|
+
originalVariables
|
|
1289
|
+
});
|
|
1290
|
+
mirrorDataAttributes({
|
|
1291
|
+
host,
|
|
1292
|
+
sourceElement,
|
|
1293
|
+
dataAttributes: options.dataAttributes,
|
|
1294
|
+
copyAllDataAttributes: options.copyAllDataAttributes ?? true,
|
|
1295
|
+
managedAttributes,
|
|
1296
|
+
originalAttributes
|
|
1297
|
+
});
|
|
1298
|
+
mirrorClasses({
|
|
1299
|
+
host,
|
|
1300
|
+
sourceElement,
|
|
1301
|
+
classNames: options.classNames ?? "all",
|
|
1302
|
+
managedClasses,
|
|
1303
|
+
originalClasses
|
|
1304
|
+
});
|
|
1305
|
+
} catch (error) {
|
|
1306
|
+
throw rollbackThemeBridge(error);
|
|
1307
|
+
}
|
|
1308
|
+
};
|
|
1309
|
+
const rollbackThemeBridge = (error) => {
|
|
1310
|
+
disposed = true;
|
|
1311
|
+
const cleanupErrors = [];
|
|
1312
|
+
runStyleCleanupStep(cleanupErrors, () => observer?.disconnect());
|
|
1313
|
+
runStyleCleanupStep(cleanupErrors, restore);
|
|
1314
|
+
return cleanupErrors.length === 0 ? error : new AggregateError([error, ...cleanupErrors], "Remote DOM theme update failed and rollback encountered cleanup failures");
|
|
1315
|
+
};
|
|
1316
|
+
try {
|
|
1317
|
+
update();
|
|
1318
|
+
if (options.observe !== false && typeof MutationObserver !== "undefined") {
|
|
1319
|
+
observer = new MutationObserver(() => update());
|
|
1320
|
+
observer.observe(options.observeTarget ?? sourceElement, {
|
|
1321
|
+
attributes: true,
|
|
1322
|
+
childList: options.observeTarget ? true : false,
|
|
1323
|
+
subtree: options.observeTarget ? true : false
|
|
1324
|
+
});
|
|
1325
|
+
}
|
|
1326
|
+
} catch (error) {
|
|
1327
|
+
if (disposed) throw error;
|
|
1328
|
+
throw rollbackThemeBridge(error);
|
|
1329
|
+
}
|
|
1330
|
+
return {
|
|
1331
|
+
update,
|
|
1332
|
+
dispose: () => {
|
|
1333
|
+
if (disposed) return;
|
|
1334
|
+
disposed = true;
|
|
1335
|
+
const cleanupErrors = [];
|
|
1336
|
+
runStyleCleanupStep(cleanupErrors, () => observer?.disconnect());
|
|
1337
|
+
runStyleCleanupStep(cleanupErrors, restore);
|
|
1338
|
+
throwStyleCleanupErrors(cleanupErrors, "Remote DOM theme bridge disposal encountered cleanup failures");
|
|
1339
|
+
}
|
|
1340
|
+
};
|
|
1341
|
+
}
|
|
1342
|
+
function collectArtifactUrls$1(artifact) {
|
|
1343
|
+
return [
|
|
1344
|
+
artifact.workerEntryUrl,
|
|
1345
|
+
...artifact.cssUrls,
|
|
1346
|
+
...artifact.assetUrls
|
|
1347
|
+
];
|
|
1348
|
+
}
|
|
1349
|
+
function createStyleSources({ artifact, cssText, widgetCssText, cssUrls, fluidComponentCssText, fluidComponentCssUrls, themeBridgeCssText, urlOriginPolicy }) {
|
|
1350
|
+
const sources = [];
|
|
1351
|
+
const defaultVersion = `${artifact.packageId}@${artifact.version}`;
|
|
1352
|
+
let failedSourceCount = 0;
|
|
1353
|
+
failedSourceCount += addTextSource(sources, "fluid-components", fluidComponentCssText, urlOriginPolicy);
|
|
1354
|
+
failedSourceCount += addUrlSources(sources, "fluid-components", fluidComponentCssUrls ?? [], defaultVersion, urlOriginPolicy);
|
|
1355
|
+
failedSourceCount += addTextSource(sources, "theme-bridge", themeBridgeCssText, urlOriginPolicy);
|
|
1356
|
+
failedSourceCount += addTextSource(sources, "widget", widgetCssText ?? cssText, urlOriginPolicy);
|
|
1357
|
+
failedSourceCount += addUrlSources(sources, "widget", cssUrls ?? artifact.cssUrls, defaultVersion, urlOriginPolicy);
|
|
1358
|
+
return {
|
|
1359
|
+
sources,
|
|
1360
|
+
failedSourceCount
|
|
1361
|
+
};
|
|
1362
|
+
}
|
|
1363
|
+
function addTextSource(sources, label, cssText, urlOriginPolicy) {
|
|
1364
|
+
if (!cssText || cssText.length === 0) return 0;
|
|
1365
|
+
try {
|
|
1366
|
+
const sanitizedCssText = sanitizeRemoteDomCssUrlReferences(cssText, { urlOriginPolicy });
|
|
1367
|
+
if (!sanitizedCssText) return 1;
|
|
1368
|
+
sources.push({
|
|
1369
|
+
kind: "text",
|
|
1370
|
+
label,
|
|
1371
|
+
cssText: sanitizedCssText
|
|
1372
|
+
});
|
|
1373
|
+
return 0;
|
|
1374
|
+
} catch {
|
|
1375
|
+
return 1;
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
function addUrlSources(sources, label, cssUrls, defaultVersion, urlOriginPolicy) {
|
|
1379
|
+
let failedSourceCount = 0;
|
|
1380
|
+
for (const cssUrl of cssUrls) try {
|
|
1381
|
+
const sanitizedUrl = sanitizeRemoteDomUrl(typeof cssUrl === "string" ? cssUrl : cssUrl.url, {
|
|
1382
|
+
allowHashOnly: false,
|
|
1383
|
+
allowMailTo: false,
|
|
1384
|
+
allowRelative: false,
|
|
1385
|
+
allowTel: false,
|
|
1386
|
+
allowedHttpOriginGroups: ["artifact"],
|
|
1387
|
+
originPolicy: urlOriginPolicy
|
|
1388
|
+
});
|
|
1389
|
+
if (!sanitizedUrl) {
|
|
1390
|
+
failedSourceCount += 1;
|
|
1391
|
+
continue;
|
|
1392
|
+
}
|
|
1393
|
+
sources.push({
|
|
1394
|
+
kind: "url",
|
|
1395
|
+
label,
|
|
1396
|
+
url: sanitizedUrl,
|
|
1397
|
+
version: typeof cssUrl === "string" ? defaultVersion : cssUrl.version ?? defaultVersion
|
|
1398
|
+
});
|
|
1399
|
+
} catch {
|
|
1400
|
+
failedSourceCount += 1;
|
|
1401
|
+
}
|
|
1402
|
+
return failedSourceCount;
|
|
1403
|
+
}
|
|
1404
|
+
function acquireCssArtifact(source, root, fetchCss) {
|
|
1405
|
+
const key = createCssArtifactCacheKey(source.url, source.version);
|
|
1406
|
+
const existingEntry = remoteDomCssArtifactCache.get(key);
|
|
1407
|
+
if (existingEntry) {
|
|
1408
|
+
existingEntry.refCount += 1;
|
|
1409
|
+
return {
|
|
1410
|
+
entry: existingEntry,
|
|
1411
|
+
released: false
|
|
1412
|
+
};
|
|
1413
|
+
}
|
|
1414
|
+
const entry = {
|
|
1415
|
+
key,
|
|
1416
|
+
url: source.url,
|
|
1417
|
+
version: source.version,
|
|
1418
|
+
promise: resolveFetchCss(root, fetchCss)(source.url),
|
|
1419
|
+
sheet: void 0,
|
|
1420
|
+
refCount: 1
|
|
1421
|
+
};
|
|
1422
|
+
remoteDomCssArtifactCache.set(key, entry);
|
|
1423
|
+
return {
|
|
1424
|
+
entry,
|
|
1425
|
+
released: false
|
|
1426
|
+
};
|
|
1427
|
+
}
|
|
1428
|
+
function releaseCssArtifact(artifact) {
|
|
1429
|
+
if (artifact.released) return;
|
|
1430
|
+
artifact.released = true;
|
|
1431
|
+
artifact.entry.refCount = Math.max(0, artifact.entry.refCount - 1);
|
|
1432
|
+
}
|
|
1433
|
+
function runStyleCleanupStep(errors, cleanup) {
|
|
1434
|
+
try {
|
|
1435
|
+
cleanup();
|
|
1436
|
+
} catch (error) {
|
|
1437
|
+
errors.push(error);
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
function throwStyleCleanupErrors(errors, message) {
|
|
1441
|
+
if (errors.length > 0) throw new AggregateError(errors, message);
|
|
1442
|
+
}
|
|
1443
|
+
function installResolvedStyleSources({ root, sources, styleElements, adoptedSheets, useConstructableStylesheets }) {
|
|
1444
|
+
const canAdoptStylesheets = useConstructableStylesheets && readAdoptedStyleSheets(root) !== void 0;
|
|
1445
|
+
let failedSourceCount = 0;
|
|
1446
|
+
let adoptedSourceCount = 0;
|
|
1447
|
+
for (const source of sources) {
|
|
1448
|
+
let sheet;
|
|
1449
|
+
if (canAdoptStylesheets) try {
|
|
1450
|
+
sheet = getOrCreateConstructableStyleSheet(source.cssText, source.artifact);
|
|
1451
|
+
} catch {
|
|
1452
|
+
sheet = void 0;
|
|
1453
|
+
}
|
|
1454
|
+
if (sheet) {
|
|
1455
|
+
adoptedSheets.add(sheet);
|
|
1456
|
+
adoptedSourceCount += 1;
|
|
1457
|
+
continue;
|
|
1458
|
+
}
|
|
1459
|
+
let styleElement;
|
|
1460
|
+
try {
|
|
1461
|
+
styleElement = root.ownerDocument.createElement("style");
|
|
1462
|
+
styleElement.setAttribute(REMOTE_DOM_WIDGET_STYLE_ATTRIBUTE, source.label);
|
|
1463
|
+
styleElement.textContent = source.cssText;
|
|
1464
|
+
root.append(styleElement);
|
|
1465
|
+
styleElements.push(styleElement);
|
|
1466
|
+
} catch {
|
|
1467
|
+
styleElement?.remove();
|
|
1468
|
+
failedSourceCount += 1;
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
if (adoptedSheets.size > 0) try {
|
|
1472
|
+
appendAdoptedSheets(root, Array.from(adoptedSheets));
|
|
1473
|
+
} catch {
|
|
1474
|
+
let removalFailed = false;
|
|
1475
|
+
try {
|
|
1476
|
+
removeAdoptedSheets(root, adoptedSheets);
|
|
1477
|
+
} catch {
|
|
1478
|
+
removalFailed = true;
|
|
1479
|
+
}
|
|
1480
|
+
if (!removalFailed) adoptedSheets.clear();
|
|
1481
|
+
failedSourceCount += adoptedSourceCount;
|
|
1482
|
+
}
|
|
1483
|
+
return failedSourceCount;
|
|
1484
|
+
}
|
|
1485
|
+
function getOrCreateConstructableStyleSheet(cssText, cachedArtifact) {
|
|
1486
|
+
if (cachedArtifact?.sheet) return cachedArtifact.sheet;
|
|
1487
|
+
const sheet = createConstructableStyleSheet(cssText);
|
|
1488
|
+
if (cachedArtifact) cachedArtifact.sheet = sheet;
|
|
1489
|
+
return sheet;
|
|
1490
|
+
}
|
|
1491
|
+
function createConstructableStyleSheet(cssText) {
|
|
1492
|
+
if (typeof CSSStyleSheet === "undefined") return void 0;
|
|
1493
|
+
const sheet = new CSSStyleSheet();
|
|
1494
|
+
if (typeof sheet.replaceSync !== "function") return void 0;
|
|
1495
|
+
try {
|
|
1496
|
+
sheet.replaceSync(cssText);
|
|
1497
|
+
return sheet;
|
|
1498
|
+
} catch {
|
|
1499
|
+
return;
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
function appendAdoptedSheets(root, sheets) {
|
|
1503
|
+
const previousAdoptedStyleSheets = readAdoptedStyleSheets(root);
|
|
1504
|
+
if (!previousAdoptedStyleSheets) return;
|
|
1505
|
+
root.adoptedStyleSheets = [...previousAdoptedStyleSheets, ...sheets];
|
|
1506
|
+
}
|
|
1507
|
+
function removeAdoptedSheets(root, adoptedSheets) {
|
|
1508
|
+
if (adoptedSheets.size === 0) return;
|
|
1509
|
+
const currentAdoptedStyleSheets = readAdoptedStyleSheets(root);
|
|
1510
|
+
if (!currentAdoptedStyleSheets) return;
|
|
1511
|
+
root.adoptedStyleSheets = currentAdoptedStyleSheets.filter((sheet) => !adoptedSheets.has(sheet));
|
|
1512
|
+
}
|
|
1513
|
+
function readAdoptedStyleSheets(root) {
|
|
1514
|
+
if (!("adoptedStyleSheets" in root)) return void 0;
|
|
1515
|
+
return [...root.adoptedStyleSheets];
|
|
1516
|
+
}
|
|
1517
|
+
function resolveFetchCss(root, fetchCss) {
|
|
1518
|
+
if (fetchCss) return fetchCss;
|
|
1519
|
+
const windowFetch = root.ownerDocument.defaultView?.fetch;
|
|
1520
|
+
if (typeof windowFetch === "function") return async (url) => {
|
|
1521
|
+
const response = await windowFetch(url);
|
|
1522
|
+
if (!response.ok) throw new Error(`Failed to fetch Remote DOM CSS: ${url}`);
|
|
1523
|
+
return response.text();
|
|
1524
|
+
};
|
|
1525
|
+
return async () => "";
|
|
1526
|
+
}
|
|
1527
|
+
function createCssArtifactCacheKey(url, version) {
|
|
1528
|
+
return `${version}:${url}`;
|
|
1529
|
+
}
|
|
1530
|
+
function snapshotCssVariables(host) {
|
|
1531
|
+
const declaredVariableNames = /* @__PURE__ */ new Set();
|
|
1532
|
+
collectCssVariableNamesFromDeclaration(declaredVariableNames, host.style);
|
|
1533
|
+
const snapshots = /* @__PURE__ */ new Map();
|
|
1534
|
+
for (const variableName of declaredVariableNames) snapshots.set(variableName, {
|
|
1535
|
+
value: host.style.getPropertyValue(variableName),
|
|
1536
|
+
priority: host.style.getPropertyPriority(variableName)
|
|
1537
|
+
});
|
|
1538
|
+
return snapshots;
|
|
1539
|
+
}
|
|
1540
|
+
function snapshotDataAttributes(host) {
|
|
1541
|
+
const snapshots = /* @__PURE__ */ new Map();
|
|
1542
|
+
for (const attributeName of host.getAttributeNames()) {
|
|
1543
|
+
if (!attributeName.startsWith("data-")) continue;
|
|
1544
|
+
const value = host.getAttribute(attributeName);
|
|
1545
|
+
if (value !== null) snapshots.set(attributeName, value);
|
|
1546
|
+
}
|
|
1547
|
+
return snapshots;
|
|
1548
|
+
}
|
|
1549
|
+
function restoreThemeBridgeState({ host, managedVariables, managedAttributes, managedClasses, originalVariables, originalAttributes, originalClasses }) {
|
|
1550
|
+
const restorationErrors = [];
|
|
1551
|
+
for (const variableName of Array.from(managedVariables)) runStyleCleanupStep(restorationErrors, () => {
|
|
1552
|
+
restoreCssVariable(host, variableName, originalVariables);
|
|
1553
|
+
managedVariables.delete(variableName);
|
|
1554
|
+
});
|
|
1555
|
+
for (const attributeName of Array.from(managedAttributes)) runStyleCleanupStep(restorationErrors, () => {
|
|
1556
|
+
const originalValue = originalAttributes.get(attributeName);
|
|
1557
|
+
if (originalValue === void 0) host.removeAttribute(attributeName);
|
|
1558
|
+
else host.setAttribute(attributeName, originalValue);
|
|
1559
|
+
managedAttributes.delete(attributeName);
|
|
1560
|
+
});
|
|
1561
|
+
for (const className of Array.from(managedClasses)) runStyleCleanupStep(restorationErrors, () => {
|
|
1562
|
+
host.classList.toggle(className, originalClasses.has(className));
|
|
1563
|
+
managedClasses.delete(className);
|
|
1564
|
+
});
|
|
1565
|
+
throwStyleCleanupErrors(restorationErrors, "Remote DOM theme restoration encountered cleanup failures");
|
|
1566
|
+
}
|
|
1567
|
+
function restoreCssVariable(host, variableName, originalVariables) {
|
|
1568
|
+
const original = originalVariables.get(variableName);
|
|
1569
|
+
if (original) host.style.setProperty(variableName, original.value, original.priority);
|
|
1570
|
+
else host.style.removeProperty(variableName);
|
|
1571
|
+
}
|
|
1572
|
+
function mirrorCssVariables({ host, sourceElement, variableNames, managedVariables, originalVariables }) {
|
|
1573
|
+
const computedStyle = sourceElement.ownerDocument.defaultView?.getComputedStyle(sourceElement);
|
|
1574
|
+
const nextVariables = new Set((variableNames ?? collectCssVariableNames(sourceElement, computedStyle)).filter((variableName) => variableName.startsWith("--")));
|
|
1575
|
+
for (const variableName of managedVariables) if (!nextVariables.has(variableName)) {
|
|
1576
|
+
restoreCssVariable(host, variableName, originalVariables);
|
|
1577
|
+
managedVariables.delete(variableName);
|
|
1578
|
+
}
|
|
1579
|
+
for (const variableName of nextVariables) {
|
|
1580
|
+
const value = computedStyle?.getPropertyValue(variableName) ?? "";
|
|
1581
|
+
if (value.length > 0) {
|
|
1582
|
+
managedVariables.add(variableName);
|
|
1583
|
+
host.style.setProperty(variableName, value.trim());
|
|
1584
|
+
} else {
|
|
1585
|
+
restoreCssVariable(host, variableName, originalVariables);
|
|
1586
|
+
managedVariables.delete(variableName);
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
function collectCssVariableNames(sourceElement, computedStyle) {
|
|
1591
|
+
const variableNames = /* @__PURE__ */ new Set();
|
|
1592
|
+
collectCssVariableNamesFromDeclaration(variableNames, computedStyle);
|
|
1593
|
+
if (sourceElement instanceof HTMLElement || sourceElement instanceof SVGElement) collectCssVariableNamesFromDeclaration(variableNames, sourceElement.style);
|
|
1594
|
+
return Array.from(variableNames);
|
|
1595
|
+
}
|
|
1596
|
+
function collectCssVariableNamesFromDeclaration(variableNames, declaration) {
|
|
1597
|
+
if (!declaration) return;
|
|
1598
|
+
for (let index = 0; index < declaration.length; index += 1) {
|
|
1599
|
+
const propertyName = declaration.item(index);
|
|
1600
|
+
if (propertyName.startsWith("--")) variableNames.add(propertyName);
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
function mirrorDataAttributes({ host, sourceElement, dataAttributes, copyAllDataAttributes, managedAttributes, originalAttributes }) {
|
|
1604
|
+
const nextAttributes = /* @__PURE__ */ new Map();
|
|
1605
|
+
const attributeNames = (dataAttributes ?? (copyAllDataAttributes ? sourceElement.getAttributeNames() : DEFAULT_THEME_DATA_ATTRIBUTES)).filter((attributeName) => attributeName.startsWith("data-"));
|
|
1606
|
+
for (const attributeName of attributeNames) {
|
|
1607
|
+
const value = sourceElement.getAttribute(attributeName);
|
|
1608
|
+
if (value !== null) nextAttributes.set(attributeName, value);
|
|
1609
|
+
}
|
|
1610
|
+
for (const attributeName of managedAttributes) if (!nextAttributes.has(attributeName)) {
|
|
1611
|
+
const originalValue = originalAttributes.get(attributeName);
|
|
1612
|
+
if (originalValue === void 0) host.removeAttribute(attributeName);
|
|
1613
|
+
else host.setAttribute(attributeName, originalValue);
|
|
1614
|
+
managedAttributes.delete(attributeName);
|
|
1615
|
+
}
|
|
1616
|
+
for (const [attributeName, value] of nextAttributes) {
|
|
1617
|
+
managedAttributes.add(attributeName);
|
|
1618
|
+
host.setAttribute(attributeName, value);
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
function mirrorClasses({ host, sourceElement, classNames, managedClasses, originalClasses }) {
|
|
1622
|
+
const sourceClasses = new Set(sourceElement.classList);
|
|
1623
|
+
const nextClasses = classNames === "all" ? sourceClasses : new Set(classNames.filter((className) => sourceClasses.has(className)));
|
|
1624
|
+
for (const className of managedClasses) if (!nextClasses.has(className)) {
|
|
1625
|
+
host.classList.toggle(className, originalClasses.has(className));
|
|
1626
|
+
managedClasses.delete(className);
|
|
1627
|
+
}
|
|
1628
|
+
for (const className of nextClasses) {
|
|
1629
|
+
managedClasses.add(className);
|
|
1630
|
+
host.classList.add(className);
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
//#endregion
|
|
1634
|
+
//#region src/remote-dom-renderer.ts
|
|
1635
|
+
const DEFAULT_MAX_MUTATION_BATCH_SIZE = 100;
|
|
1636
|
+
const DEFAULT_MAX_DOM_NODE_COUNT = 1e3;
|
|
1637
|
+
function mountRemoteDomWidget(options) {
|
|
1638
|
+
const initialProps = options.props ?? null;
|
|
1639
|
+
assertSerializable(initialProps, "Initial widget props");
|
|
1640
|
+
const shadowRoot = createShadowRoot(options.host);
|
|
1641
|
+
const navigationOrigin = normalizeNavigationOrigin(options.hostOrigin);
|
|
1642
|
+
const urlOriginPolicy = require_remote_dom_values.createRemoteDomUrlOriginPolicy({
|
|
1643
|
+
artifactUrls: collectArtifactUrls(options.artifact),
|
|
1644
|
+
...options.mediaOrigins === void 0 ? {} : { mediaOrigins: options.mediaOrigins },
|
|
1645
|
+
...navigationOrigin === void 0 ? {} : { navigationOrigin }
|
|
1646
|
+
});
|
|
1647
|
+
const styles = attachRemoteDomStyles({
|
|
1648
|
+
artifact: options.artifact,
|
|
1649
|
+
root: shadowRoot,
|
|
1650
|
+
urlOriginPolicy,
|
|
1651
|
+
onFailure: (count) => {
|
|
1652
|
+
reportError(options, `${count} Remote DOM widget styles failed to load`);
|
|
1653
|
+
},
|
|
1654
|
+
...options.cssText === void 0 ? {} : { cssText: options.cssText },
|
|
1655
|
+
...options.widgetCssText === void 0 ? {} : { widgetCssText: options.widgetCssText },
|
|
1656
|
+
...options.cssUrls === void 0 ? {} : { cssUrls: options.cssUrls },
|
|
1657
|
+
...options.fluidComponentCssText === void 0 ? {} : { fluidComponentCssText: options.fluidComponentCssText },
|
|
1658
|
+
...options.fluidComponentCssUrls === void 0 ? {} : { fluidComponentCssUrls: options.fluidComponentCssUrls },
|
|
1659
|
+
...options.themeBridgeCssText === void 0 ? {} : { themeBridgeCssText: options.themeBridgeCssText },
|
|
1660
|
+
...options.themeBridge === void 0 ? {} : { themeBridge: options.themeBridge },
|
|
1661
|
+
...options.fetchCss === void 0 ? {} : { fetchCss: options.fetchCss },
|
|
1662
|
+
...options.useConstructableStylesheets === void 0 ? {} : { useConstructableStylesheets: options.useConstructableStylesheets }
|
|
1663
|
+
});
|
|
1664
|
+
let worker;
|
|
1665
|
+
try {
|
|
1666
|
+
worker = (options.workerFactory ?? createDefaultWorker)(options.artifact.workerEntryUrl, { type: "module" });
|
|
1667
|
+
} catch (error) {
|
|
1668
|
+
reportCleanupErrors(options, "Remote DOM widget setup cleanup failed", collectCleanupErrors([() => styles.dispose(), () => clearRenderedRemoteDomNodes(shadowRoot)]));
|
|
1669
|
+
throw error;
|
|
1670
|
+
}
|
|
1671
|
+
let thread;
|
|
1672
|
+
try {
|
|
1673
|
+
thread = new require_Thread.Thread(createWorkerMessageTarget(worker));
|
|
1674
|
+
} catch (error) {
|
|
1675
|
+
reportCleanupErrors(options, "Remote DOM widget setup cleanup failed", collectCleanupErrors([
|
|
1676
|
+
() => styles.dispose(),
|
|
1677
|
+
() => worker.terminate(),
|
|
1678
|
+
() => clearRenderedRemoteDomNodes(shadowRoot)
|
|
1679
|
+
]));
|
|
1680
|
+
throw error;
|
|
1681
|
+
}
|
|
1682
|
+
let state;
|
|
1683
|
+
const pendingListenerUpdates = /* @__PURE__ */ new Map();
|
|
1684
|
+
const connection = createSanitizingRemoteConnection({
|
|
1685
|
+
connection: new _remote_dom_core_receivers.DOMRemoteReceiver({
|
|
1686
|
+
root: shadowRoot,
|
|
1687
|
+
call: () => {
|
|
1688
|
+
throw new RemoteDomConnectionCallDeniedError("remote element method");
|
|
1689
|
+
}
|
|
1690
|
+
}).connection,
|
|
1691
|
+
urlOriginPolicy,
|
|
1692
|
+
maxMutationBatchSize: options.maxMutationBatchSize ?? DEFAULT_MAX_MUTATION_BATCH_SIZE,
|
|
1693
|
+
maxDomNodeCount: options.maxDomNodeCount ?? DEFAULT_MAX_DOM_NODE_COUNT,
|
|
1694
|
+
onEventListenerUpdate: (targetId, eventName, listener) => {
|
|
1695
|
+
pendingListenerUpdates.set(subscriptionKey(targetId, eventName), {
|
|
1696
|
+
targetId,
|
|
1697
|
+
eventName,
|
|
1698
|
+
listener
|
|
1699
|
+
});
|
|
1700
|
+
},
|
|
1701
|
+
onNodeLimitExceeded: () => {
|
|
1702
|
+
reportError(options, "Remote DOM widget exceeded its DOM node limit");
|
|
1703
|
+
},
|
|
1704
|
+
onInvalidRecord: (message) => reportError(options, message),
|
|
1705
|
+
onMutateError: (error) => reportError(options, "Remote DOM mutation could not be applied", error)
|
|
1706
|
+
});
|
|
1707
|
+
const submitListener = createSubmitPreventionListener();
|
|
1708
|
+
const navigationListener = (event) => {
|
|
1709
|
+
handleNavigationIntent(state, event);
|
|
1710
|
+
};
|
|
1711
|
+
state = {
|
|
1712
|
+
options,
|
|
1713
|
+
shadowRoot,
|
|
1714
|
+
worker,
|
|
1715
|
+
thread,
|
|
1716
|
+
styles,
|
|
1717
|
+
urlOriginPolicy,
|
|
1718
|
+
navigationOrigin,
|
|
1719
|
+
nodesById: new Map([[_remote_dom_core.ROOT_ID, shadowRoot]]),
|
|
1720
|
+
subscriptions: /* @__PURE__ */ new Map(),
|
|
1721
|
+
pendingListenerUpdates,
|
|
1722
|
+
submitListener,
|
|
1723
|
+
navigationListener,
|
|
1724
|
+
disposed: false,
|
|
1725
|
+
cleanupStarted: false
|
|
1726
|
+
};
|
|
1727
|
+
shadowRoot.addEventListener("submit", submitListener, { capture: true });
|
|
1728
|
+
shadowRoot.addEventListener("click", navigationListener, { capture: true });
|
|
1729
|
+
worker.onerror = (event) => {
|
|
1730
|
+
if (state.disposed) return;
|
|
1731
|
+
reportError(options, event.message || "Remote DOM widget worker failed", event.error);
|
|
1732
|
+
disposeAfterFailure(state, false);
|
|
1733
|
+
};
|
|
1734
|
+
const ready = Promise.all([styles.ready, thread.imports.mount({
|
|
1735
|
+
widgetType: options.artifact.widgetType,
|
|
1736
|
+
props: initialProps
|
|
1737
|
+
}, {
|
|
1738
|
+
mutate(records) {
|
|
1739
|
+
if (state.disposed) return;
|
|
1740
|
+
connection.mutate(records);
|
|
1741
|
+
rebuildNodeIndex(state);
|
|
1742
|
+
flushPendingListenerUpdates(state);
|
|
1743
|
+
},
|
|
1744
|
+
callCapability(capability, method, payload) {
|
|
1745
|
+
return callCapability(state, capability, method, payload);
|
|
1746
|
+
},
|
|
1747
|
+
reportError(error) {
|
|
1748
|
+
reportError(options, error.message);
|
|
1749
|
+
}
|
|
1750
|
+
})]).then(() => void 0);
|
|
1751
|
+
ready.catch((error) => {
|
|
1752
|
+
if (state.disposed) return;
|
|
1753
|
+
reportError(options, "Remote DOM widget failed to mount", error);
|
|
1754
|
+
disposeAfterFailure(state);
|
|
1755
|
+
});
|
|
1756
|
+
return {
|
|
1757
|
+
shadowRoot,
|
|
1758
|
+
styles,
|
|
1759
|
+
ready,
|
|
1760
|
+
updateProps(props) {
|
|
1761
|
+
if (state.disposed) return;
|
|
1762
|
+
assertSerializable(props, "Widget props");
|
|
1763
|
+
state.thread.imports.updateProps(props).catch((error) => {
|
|
1764
|
+
if (!state.disposed) reportError(options, "Remote DOM widget props update failed", error);
|
|
1765
|
+
});
|
|
1766
|
+
},
|
|
1767
|
+
dispose() {
|
|
1768
|
+
disposeMount(state);
|
|
1769
|
+
}
|
|
1770
|
+
};
|
|
1771
|
+
}
|
|
1772
|
+
function callCapability(state, capability, method, payload) {
|
|
1773
|
+
if (state.disposed) return Promise.reject(/* @__PURE__ */ new Error("Remote DOM widget has been disposed"));
|
|
1774
|
+
if (!state.options.artifact.capabilities.some((declaration) => declaration.name === capability)) return Promise.reject(/* @__PURE__ */ new Error(`Remote DOM capability "${capability}" was not declared`));
|
|
1775
|
+
if (payload !== void 0 && !require_remote_dom_values.isRemoteDomSerializableValue(payload)) return Promise.reject(/* @__PURE__ */ new Error("Remote DOM capability payload was not serializable"));
|
|
1776
|
+
if (capability === "fullscreen" && state.options.onFullscreen) return Promise.resolve().then(() => state.options.onFullscreen?.({
|
|
1777
|
+
method,
|
|
1778
|
+
...payload === void 0 ? {} : { payload },
|
|
1779
|
+
host: state.options.host,
|
|
1780
|
+
shadowRoot: state.shadowRoot
|
|
1781
|
+
})).then((result) => {
|
|
1782
|
+
if (result === void 0) throw new Error("Remote DOM fullscreen handler returned no result");
|
|
1783
|
+
return assertSerializableCapabilityResult(result);
|
|
1784
|
+
});
|
|
1785
|
+
if (!state.options.callCapability) return Promise.reject(/* @__PURE__ */ new Error(`No host handler is configured for capability "${capability}"`));
|
|
1786
|
+
return Promise.resolve().then(() => state.options.callCapability?.(capability, method, payload)).then((result) => {
|
|
1787
|
+
if (result === void 0) throw new Error(`Capability handler for "${capability}" returned no result`);
|
|
1788
|
+
return assertSerializableCapabilityResult(result);
|
|
1789
|
+
});
|
|
1790
|
+
}
|
|
1791
|
+
function assertSerializableCapabilityResult(result) {
|
|
1792
|
+
if (!require_remote_dom_values.isRemoteDomSerializableValue(result)) throw new Error("Remote DOM capability result was not serializable");
|
|
1793
|
+
return result;
|
|
1794
|
+
}
|
|
1795
|
+
function rebuildNodeIndex(state) {
|
|
1796
|
+
state.nodesById.clear();
|
|
1797
|
+
state.nodesById.set(_remote_dom_core.ROOT_ID, state.shadowRoot);
|
|
1798
|
+
const visit = (node) => {
|
|
1799
|
+
state.nodesById.set((0, _remote_dom_core_elements.remoteId)(node), node);
|
|
1800
|
+
for (const child of node.childNodes) visit(child);
|
|
1801
|
+
};
|
|
1802
|
+
for (const child of state.shadowRoot.childNodes) if (!isWidgetStyleNode(child)) visit(child);
|
|
1803
|
+
for (const subscription of Array.from(state.subscriptions.values())) if (!state.nodesById.has(subscription.targetId)) unsubscribe(state, subscription.targetId, subscription.eventName);
|
|
1804
|
+
}
|
|
1805
|
+
function flushPendingListenerUpdates(state) {
|
|
1806
|
+
for (const update of state.pendingListenerUpdates.values()) if (update.listener === null) unsubscribe(state, update.targetId, update.eventName);
|
|
1807
|
+
else subscribe(state, update.targetId, update.eventName, update.listener);
|
|
1808
|
+
state.pendingListenerUpdates.clear();
|
|
1809
|
+
}
|
|
1810
|
+
function subscribe(state, targetId, eventName, proxy) {
|
|
1811
|
+
const target = state.nodesById.get(targetId);
|
|
1812
|
+
const tagName = target instanceof Element ? target.localName : void 0;
|
|
1813
|
+
if (!target || !isSupportedRemoteDomEventName(eventName, tagName)) return;
|
|
1814
|
+
unsubscribe(state, targetId, eventName);
|
|
1815
|
+
const capture = targetId === _remote_dom_core.ROOT_ID;
|
|
1816
|
+
const listener = (event) => {
|
|
1817
|
+
if (!capture && hasCloserEventSubscription(state, event, target, eventName)) return;
|
|
1818
|
+
if (eventName === "submit" && event.cancelable) event.preventDefault();
|
|
1819
|
+
const actualTargetId = resolveEventTargetId(state, event);
|
|
1820
|
+
if (!actualTargetId) return;
|
|
1821
|
+
const eventPayload = serializeRemoteDomEvent(event, actualTargetId, targetId, tagName);
|
|
1822
|
+
if (!eventPayload) return;
|
|
1823
|
+
try {
|
|
1824
|
+
const result = proxy({
|
|
1825
|
+
targetId: actualTargetId,
|
|
1826
|
+
detail: toSerializableEventPayload(eventPayload)
|
|
1827
|
+
});
|
|
1828
|
+
if (isPromiseLike(result)) result.catch((error) => {
|
|
1829
|
+
reportEventDeliveryFailure(state, error);
|
|
1830
|
+
});
|
|
1831
|
+
} catch (error) {
|
|
1832
|
+
reportEventDeliveryFailure(state, error);
|
|
1833
|
+
}
|
|
1834
|
+
};
|
|
1835
|
+
target.addEventListener(eventName, listener, { capture });
|
|
1836
|
+
require_Thread.retain(proxy);
|
|
1837
|
+
state.subscriptions.set(subscriptionKey(targetId, eventName), {
|
|
1838
|
+
targetId,
|
|
1839
|
+
eventName,
|
|
1840
|
+
target,
|
|
1841
|
+
listener,
|
|
1842
|
+
capture,
|
|
1843
|
+
proxy
|
|
1844
|
+
});
|
|
1845
|
+
}
|
|
1846
|
+
function hasCloserEventSubscription(state, event, subscriptionTarget, eventName) {
|
|
1847
|
+
for (const pathTarget of event.composedPath()) {
|
|
1848
|
+
if (pathTarget === subscriptionTarget) return false;
|
|
1849
|
+
if (!(pathTarget instanceof Node)) continue;
|
|
1850
|
+
const pathTargetId = (0, _remote_dom_core_elements.remoteId)(pathTarget);
|
|
1851
|
+
if (state.nodesById.get(pathTargetId) === pathTarget && state.subscriptions.has(subscriptionKey(pathTargetId, eventName))) return true;
|
|
1852
|
+
}
|
|
1853
|
+
return false;
|
|
1854
|
+
}
|
|
1855
|
+
function unsubscribe(state, targetId, eventName) {
|
|
1856
|
+
const key = subscriptionKey(targetId, eventName);
|
|
1857
|
+
const subscription = state.subscriptions.get(key);
|
|
1858
|
+
if (!subscription) return;
|
|
1859
|
+
subscription.target.removeEventListener(eventName, subscription.listener, { capture: subscription.capture });
|
|
1860
|
+
require_Thread.release(subscription.proxy);
|
|
1861
|
+
state.subscriptions.delete(key);
|
|
1862
|
+
}
|
|
1863
|
+
function resolveEventTargetId(state, event) {
|
|
1864
|
+
for (const target of event.composedPath()) {
|
|
1865
|
+
if (target === state.shadowRoot) return _remote_dom_core.ROOT_ID;
|
|
1866
|
+
if (!(target instanceof Node)) continue;
|
|
1867
|
+
const id = (0, _remote_dom_core_elements.remoteId)(target);
|
|
1868
|
+
if (state.nodesById.get(id) === target) return id;
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
function handleNavigationIntent(state, event) {
|
|
1872
|
+
if (!(event instanceof MouseEvent)) return;
|
|
1873
|
+
const anchor = (event.target instanceof Element ? event.target : event.target instanceof Text ? event.target.parentElement : null)?.closest("a[href]");
|
|
1874
|
+
if (!(anchor instanceof HTMLAnchorElement)) return;
|
|
1875
|
+
if (!state.shadowRoot.contains(anchor)) return;
|
|
1876
|
+
if (event.cancelable) event.preventDefault();
|
|
1877
|
+
const href = sanitizeRemoteDomUrl(anchor.getAttribute("href"), {
|
|
1878
|
+
allowHashOnly: true,
|
|
1879
|
+
allowMailTo: false,
|
|
1880
|
+
allowRelative: true,
|
|
1881
|
+
allowTel: false,
|
|
1882
|
+
allowedHttpOriginGroups: ["navigation"],
|
|
1883
|
+
originPolicy: state.urlOriginPolicy,
|
|
1884
|
+
relativeUrlBase: "navigation"
|
|
1885
|
+
});
|
|
1886
|
+
const url = href ? resolveInternalNavigationUrl(href, state.navigationOrigin) : void 0;
|
|
1887
|
+
if (!href || !url || !state.options.onNavigate) {
|
|
1888
|
+
reportError(state.options, "Remote DOM navigation was blocked because no allowed internal route handler was available");
|
|
1889
|
+
return;
|
|
1890
|
+
}
|
|
1891
|
+
const targetId = findNodeId(state, anchor);
|
|
1892
|
+
Promise.resolve(state.options.onNavigate({
|
|
1893
|
+
href,
|
|
1894
|
+
url,
|
|
1895
|
+
source: "anchor",
|
|
1896
|
+
...targetId === void 0 ? {} : { targetId },
|
|
1897
|
+
altKey: event.altKey,
|
|
1898
|
+
button: event.button,
|
|
1899
|
+
ctrlKey: event.ctrlKey,
|
|
1900
|
+
metaKey: event.metaKey,
|
|
1901
|
+
shiftKey: event.shiftKey
|
|
1902
|
+
})).catch((error) => {
|
|
1903
|
+
if (!state.disposed) reportError(state.options, "Remote DOM navigation handler failed", error);
|
|
1904
|
+
});
|
|
1905
|
+
}
|
|
1906
|
+
function disposeMount(state, notifyWorker = true) {
|
|
1907
|
+
if (state.cleanupStarted) return;
|
|
1908
|
+
state.cleanupStarted = true;
|
|
1909
|
+
state.disposed = true;
|
|
1910
|
+
const cleanupSteps = [
|
|
1911
|
+
() => {
|
|
1912
|
+
state.worker.onerror = null;
|
|
1913
|
+
},
|
|
1914
|
+
() => {
|
|
1915
|
+
state.shadowRoot.removeEventListener("submit", state.submitListener, { capture: true });
|
|
1916
|
+
},
|
|
1917
|
+
() => {
|
|
1918
|
+
state.shadowRoot.removeEventListener("click", state.navigationListener, { capture: true });
|
|
1919
|
+
}
|
|
1920
|
+
];
|
|
1921
|
+
for (const subscription of Array.from(state.subscriptions.values())) cleanupSteps.push(() => {
|
|
1922
|
+
unsubscribe(state, subscription.targetId, subscription.eventName);
|
|
1923
|
+
});
|
|
1924
|
+
cleanupSteps.push(() => state.pendingListenerUpdates.clear(), () => state.styles.dispose(), () => clearRenderedRemoteDomNodes(state.shadowRoot), () => state.nodesById.clear());
|
|
1925
|
+
const cleanupErrors = collectCleanupErrors(cleanupSteps);
|
|
1926
|
+
if (notifyWorker) Promise.resolve(state.thread.imports.dispose()).catch(() => void 0);
|
|
1927
|
+
queueMicrotask(() => {
|
|
1928
|
+
reportCleanupErrors(state.options, "Remote DOM widget asynchronous cleanup failed", collectCleanupErrors([() => state.thread.close(), () => state.worker.terminate()]));
|
|
1929
|
+
});
|
|
1930
|
+
if (cleanupErrors.length > 0) throw new AggregateError(cleanupErrors, "Remote DOM widget cleanup failed");
|
|
1931
|
+
}
|
|
1932
|
+
function disposeAfterFailure(state, notifyWorker = true) {
|
|
1933
|
+
try {
|
|
1934
|
+
disposeMount(state, notifyWorker);
|
|
1935
|
+
} catch (cleanupError) {
|
|
1936
|
+
reportError(state.options, "Remote DOM widget cleanup failed after an earlier error", cleanupError);
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1939
|
+
function reportEventDeliveryFailure(state, error) {
|
|
1940
|
+
if (state.disposed) return;
|
|
1941
|
+
reportError(state.options, "Remote DOM event delivery failed", error);
|
|
1942
|
+
}
|
|
1943
|
+
function createShadowRoot(host) {
|
|
1944
|
+
if (host.shadowRoot) {
|
|
1945
|
+
host.shadowRoot.replaceChildren();
|
|
1946
|
+
return host.shadowRoot;
|
|
1947
|
+
}
|
|
1948
|
+
return host.attachShadow({ mode: "open" });
|
|
1949
|
+
}
|
|
1950
|
+
function createSubmitPreventionListener() {
|
|
1951
|
+
return (event) => {
|
|
1952
|
+
if (event.cancelable) event.preventDefault();
|
|
1953
|
+
};
|
|
1954
|
+
}
|
|
1955
|
+
function collectArtifactUrls(artifact) {
|
|
1956
|
+
return [
|
|
1957
|
+
artifact.workerEntryUrl,
|
|
1958
|
+
...artifact.cssUrls,
|
|
1959
|
+
...artifact.assetUrls
|
|
1960
|
+
];
|
|
1961
|
+
}
|
|
1962
|
+
function normalizeNavigationOrigin(value) {
|
|
1963
|
+
if (!value) return void 0;
|
|
1964
|
+
try {
|
|
1965
|
+
const url = new URL(value);
|
|
1966
|
+
return url.protocol === "http:" || url.protocol === "https:" ? url.origin : void 0;
|
|
1967
|
+
} catch {
|
|
1968
|
+
return;
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
function resolveInternalNavigationUrl(href, navigationOrigin) {
|
|
1972
|
+
if (href.startsWith("#")) return href;
|
|
1973
|
+
if (href.startsWith("//") || /^https?:(?!\/\/)/iu.test(href)) return;
|
|
1974
|
+
try {
|
|
1975
|
+
const url = new URL(href, navigationOrigin ?? "https://fluid.local");
|
|
1976
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return;
|
|
1977
|
+
if (/^[a-z][a-z\d+.-]*:/iu.test(href) && (!navigationOrigin || url.origin !== navigationOrigin)) return;
|
|
1978
|
+
return `${url.pathname}${url.search}${url.hash}`;
|
|
1979
|
+
} catch {
|
|
1980
|
+
return;
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
function findNodeId(state, node) {
|
|
1984
|
+
for (const [id, candidate] of state.nodesById) if (candidate === node) return id;
|
|
1985
|
+
}
|
|
1986
|
+
function isWidgetStyleNode(node) {
|
|
1987
|
+
return node instanceof HTMLStyleElement && node.hasAttribute("data-fluid-widget-style");
|
|
1988
|
+
}
|
|
1989
|
+
function clearRenderedRemoteDomNodes(shadowRoot) {
|
|
1990
|
+
for (const child of Array.from(shadowRoot.childNodes)) if (!isWidgetStyleNode(child)) child.remove();
|
|
1991
|
+
}
|
|
1992
|
+
function toSerializableEventPayload(payload) {
|
|
1993
|
+
const result = {
|
|
1994
|
+
bubbles: payload.bubbles,
|
|
1995
|
+
cancelable: payload.cancelable,
|
|
1996
|
+
currentTargetId: payload.currentTargetId,
|
|
1997
|
+
defaultPrevented: payload.defaultPrevented,
|
|
1998
|
+
targetId: payload.targetId,
|
|
1999
|
+
type: payload.type
|
|
2000
|
+
};
|
|
2001
|
+
for (const key of [
|
|
2002
|
+
"altKey",
|
|
2003
|
+
"button",
|
|
2004
|
+
"buttons",
|
|
2005
|
+
"checked",
|
|
2006
|
+
"clientX",
|
|
2007
|
+
"clientY",
|
|
2008
|
+
"code",
|
|
2009
|
+
"ctrlKey",
|
|
2010
|
+
"detailJson",
|
|
2011
|
+
"isPrimary",
|
|
2012
|
+
"key",
|
|
2013
|
+
"metaKey",
|
|
2014
|
+
"pointerId",
|
|
2015
|
+
"pointerType",
|
|
2016
|
+
"shiftKey",
|
|
2017
|
+
"value"
|
|
2018
|
+
]) {
|
|
2019
|
+
const value = payload[key];
|
|
2020
|
+
if (value !== void 0) result[key] = value;
|
|
2021
|
+
}
|
|
2022
|
+
return result;
|
|
2023
|
+
}
|
|
2024
|
+
function assertSerializable(value, description) {
|
|
2025
|
+
if (!require_remote_dom_values.isRemoteDomSerializableValue(value)) throw new TypeError(`${description} must be serializable`);
|
|
2026
|
+
}
|
|
2027
|
+
function createWorkerMessageTarget(worker) {
|
|
2028
|
+
return {
|
|
2029
|
+
send(message, transferables) {
|
|
2030
|
+
worker.postMessage(message, transferables ?? []);
|
|
2031
|
+
},
|
|
2032
|
+
listen(listener, { signal }) {
|
|
2033
|
+
const onMessage = (event) => {
|
|
2034
|
+
listener(event.data);
|
|
2035
|
+
};
|
|
2036
|
+
if (worker.addEventListener) worker.addEventListener("message", onMessage, { signal });
|
|
2037
|
+
else {
|
|
2038
|
+
worker.onmessage = onMessage;
|
|
2039
|
+
signal?.addEventListener("abort", () => {
|
|
2040
|
+
worker.onmessage = null;
|
|
2041
|
+
}, { once: true });
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
};
|
|
2045
|
+
}
|
|
2046
|
+
function createDefaultWorker(workerEntryUrl, options) {
|
|
2047
|
+
if (typeof Worker === "undefined") throw new Error("Remote DOM Worker is not available in this environment");
|
|
2048
|
+
if (!shouldWrapWorkerEntryUrl(workerEntryUrl)) return new Worker(workerEntryUrl, options);
|
|
2049
|
+
return createBlobWrappedWorker(workerEntryUrl, options);
|
|
2050
|
+
}
|
|
2051
|
+
function shouldWrapWorkerEntryUrl(workerEntryUrl) {
|
|
2052
|
+
if (typeof location === "undefined" || typeof Blob === "undefined" || typeof URL.createObjectURL !== "function") return false;
|
|
2053
|
+
try {
|
|
2054
|
+
return new URL(workerEntryUrl, location.href).origin !== location.origin;
|
|
2055
|
+
} catch {
|
|
2056
|
+
return false;
|
|
2057
|
+
}
|
|
2058
|
+
}
|
|
2059
|
+
function createBlobWrappedWorker(workerEntryUrl, options) {
|
|
2060
|
+
const blobUrl = URL.createObjectURL(new Blob([`import ${JSON.stringify(workerEntryUrl)};\n`], { type: "application/javascript" }));
|
|
2061
|
+
let worker;
|
|
2062
|
+
try {
|
|
2063
|
+
worker = new Worker(blobUrl, options);
|
|
2064
|
+
} catch (error) {
|
|
2065
|
+
URL.revokeObjectURL(blobUrl);
|
|
2066
|
+
throw error;
|
|
2067
|
+
}
|
|
2068
|
+
const terminate = worker.terminate.bind(worker);
|
|
2069
|
+
worker.terminate = () => {
|
|
2070
|
+
try {
|
|
2071
|
+
terminate();
|
|
2072
|
+
} finally {
|
|
2073
|
+
URL.revokeObjectURL(blobUrl);
|
|
2074
|
+
}
|
|
2075
|
+
};
|
|
2076
|
+
return worker;
|
|
2077
|
+
}
|
|
2078
|
+
function reportError(options, message, cause) {
|
|
2079
|
+
try {
|
|
2080
|
+
options.onError?.(new Error(message, cause === void 0 ? {} : { cause }));
|
|
2081
|
+
} catch {}
|
|
2082
|
+
}
|
|
2083
|
+
function collectCleanupErrors(cleanupSteps) {
|
|
2084
|
+
const errors = [];
|
|
2085
|
+
for (const cleanup of cleanupSteps) try {
|
|
2086
|
+
cleanup();
|
|
2087
|
+
} catch (error) {
|
|
2088
|
+
errors.push(error);
|
|
2089
|
+
}
|
|
2090
|
+
return errors;
|
|
2091
|
+
}
|
|
2092
|
+
function reportCleanupErrors(options, message, errors) {
|
|
2093
|
+
if (errors.length === 0) return;
|
|
2094
|
+
reportError(options, message, errors.length === 1 ? errors[0] : new AggregateError(errors, "Multiple cleanup operations failed"));
|
|
2095
|
+
}
|
|
2096
|
+
function subscriptionKey(targetId, eventName) {
|
|
2097
|
+
return `${targetId}:${eventName}`;
|
|
2098
|
+
}
|
|
2099
|
+
function isPromiseLike(value) {
|
|
2100
|
+
return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
|
|
2101
|
+
}
|
|
2102
|
+
//#endregion
|
|
2103
|
+
Object.defineProperty(exports, "__toESM", {
|
|
2104
|
+
enumerable: true,
|
|
2105
|
+
get: function() {
|
|
2106
|
+
return __toESM;
|
|
2107
|
+
}
|
|
2108
|
+
});
|
|
2109
|
+
Object.defineProperty(exports, "mountRemoteDomWidget", {
|
|
2110
|
+
enumerable: true,
|
|
2111
|
+
get: function() {
|
|
2112
|
+
return mountRemoteDomWidget;
|
|
2113
|
+
}
|
|
2114
|
+
});
|
|
2115
|
+
|
|
2116
|
+
//# sourceMappingURL=remote-dom-renderer-DUQf80Nu.cjs.map
|