@fluid-app/widget-runtime 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -0
- package/dist/index.cjs +3 -2
- package/dist/index.d.cts +3 -2
- package/dist/index.d.mts +3 -2
- package/dist/index.mjs +3 -3
- package/dist/{remote-dom-renderer-CKvnUH8G.d.mts → remote-dom-renderer-BGIZ0FRi.d.mts} +35 -1
- package/dist/remote-dom-renderer-BGIZ0FRi.d.mts.map +1 -0
- package/dist/{remote-dom-renderer-f7OWlvvv.cjs → remote-dom-renderer-BlZKfMAA.cjs} +340 -172
- package/dist/remote-dom-renderer-BlZKfMAA.cjs.map +1 -0
- package/dist/{remote-dom-renderer-CeYSItkU.d.cts → remote-dom-renderer-BoB9jd3B.d.cts} +35 -1
- package/dist/remote-dom-renderer-BoB9jd3B.d.cts.map +1 -0
- package/dist/{remote-dom-renderer-CpdKWANy.mjs → remote-dom-renderer-Dn3pfVsl.mjs} +340 -172
- package/dist/remote-dom-renderer-Dn3pfVsl.mjs.map +1 -0
- package/dist/remote-dom-ui-contract-B140dMly.d.mts +632 -0
- package/dist/remote-dom-ui-contract-B140dMly.d.mts.map +1 -0
- package/dist/remote-dom-ui-contract-BLOyWbT2.d.cts +632 -0
- package/dist/remote-dom-ui-contract-BLOyWbT2.d.cts.map +1 -0
- package/dist/remote-dom-values-B5UZPDRy.cjs +849 -0
- package/dist/remote-dom-values-B5UZPDRy.cjs.map +1 -0
- package/dist/remote-dom-values-D4AgBNWr.d.cts.map +1 -1
- package/dist/remote-dom-values-EwoLXnSn.d.mts.map +1 -1
- package/dist/remote-dom-values-wEbrw5iW.mjs +790 -0
- package/dist/remote-dom-values-wEbrw5iW.mjs.map +1 -0
- package/dist/remote-dom.cjs +2 -2
- package/dist/remote-dom.d.cts +1 -1
- package/dist/remote-dom.d.mts +1 -1
- package/dist/remote-dom.mjs +2 -2
- package/dist/{worker-react-renderer-BKzig_Vy.mjs → worker-react-renderer-BV6ExKCS.mjs} +17 -40
- package/dist/worker-react-renderer-BV6ExKCS.mjs.map +1 -0
- package/dist/{worker-react-renderer-BvHZ2o0B.cjs → worker-react-renderer-CR-TvErh.cjs} +18 -41
- package/dist/worker-react-renderer-CR-TvErh.cjs.map +1 -0
- package/dist/worker.cjs +18 -3
- package/dist/worker.cjs.map +1 -1
- package/dist/worker.d.cts +17 -2
- package/dist/worker.d.cts.map +1 -1
- package/dist/worker.d.mts +17 -1
- package/dist/worker.d.mts.map +1 -1
- package/dist/worker.mjs +17 -3
- package/dist/worker.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/remote-dom-renderer-CKvnUH8G.d.mts.map +0 -1
- package/dist/remote-dom-renderer-CeYSItkU.d.cts.map +0 -1
- package/dist/remote-dom-renderer-CpdKWANy.mjs.map +0 -1
- package/dist/remote-dom-renderer-f7OWlvvv.cjs.map +0 -1
- package/dist/remote-dom-values-BSAxrOE7.mjs +0 -238
- package/dist/remote-dom-values-BSAxrOE7.mjs.map +0 -1
- package/dist/remote-dom-values-DbgIedSg.cjs +0 -297
- package/dist/remote-dom-values-DbgIedSg.cjs.map +0 -1
- package/dist/worker-react-renderer-BKzig_Vy.mjs.map +0 -1
- package/dist/worker-react-renderer-BvHZ2o0B.cjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"remote-dom-values-BSAxrOE7.mjs","names":[],"sources":["../src/remote-dom-values.ts"],"sourcesContent":["import type {\n RemoteMutationRecord,\n RemoteNodeSerialization,\n} from \"@remote-dom/core\";\n\nexport const REMOTE_DOM_FULLSCREEN_CAPABILITY = \"fullscreen\";\nexport const FLUID_SEARCH_SORT_TAG_NAME = \"fluid-ui-search-sort\";\nexport const FLUID_SPACER_WIDGET_TAG_NAME = \"fluid-spacer-widget\";\n\n/** Canonical element allowlist shared by the worker registration and host sanitizer. */\nexport const REMOTE_DOM_ALLOWED_TAG_NAMES = [\n \"a\",\n \"abbr\",\n \"address\",\n \"article\",\n \"aside\",\n \"audio\",\n \"b\",\n \"bdi\",\n \"bdo\",\n \"blockquote\",\n \"br\",\n \"button\",\n \"caption\",\n \"cite\",\n \"code\",\n \"col\",\n \"colgroup\",\n \"data\",\n \"dd\",\n \"del\",\n \"details\",\n \"dfn\",\n \"dialog\",\n \"div\",\n \"dl\",\n \"dt\",\n \"em\",\n \"fieldset\",\n \"figcaption\",\n \"figure\",\n \"footer\",\n \"form\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"header\",\n \"hr\",\n \"i\",\n \"img\",\n \"input\",\n \"ins\",\n \"kbd\",\n \"label\",\n \"legend\",\n \"li\",\n \"main\",\n \"mark\",\n \"meter\",\n \"nav\",\n \"ol\",\n \"optgroup\",\n \"option\",\n \"output\",\n \"p\",\n \"picture\",\n \"pre\",\n \"progress\",\n \"q\",\n \"rp\",\n \"rt\",\n \"ruby\",\n \"s\",\n \"samp\",\n \"section\",\n \"select\",\n \"small\",\n \"source\",\n \"span\",\n \"strong\",\n \"sub\",\n \"summary\",\n \"sup\",\n \"table\",\n \"tbody\",\n \"td\",\n \"textarea\",\n \"tfoot\",\n \"th\",\n \"thead\",\n \"time\",\n \"tr\",\n \"track\",\n \"u\",\n \"ul\",\n \"var\",\n \"video\",\n \"wbr\",\n FLUID_SEARCH_SORT_TAG_NAME,\n FLUID_SPACER_WIDGET_TAG_NAME,\n] as const;\n\n/** Canonical event allowlist shared by worker elements and host forwarding. */\nexport const SUPPORTED_REMOTE_DOM_EVENTS = [\n \"blur\",\n \"change\",\n \"click\",\n \"contextmenu\",\n \"dblclick\",\n \"focus\",\n \"input\",\n \"keydown\",\n \"keypress\",\n \"keyup\",\n \"mousedown\",\n \"mouseenter\",\n \"mouseleave\",\n \"mousemove\",\n \"mouseout\",\n \"mouseover\",\n \"mouseup\",\n \"pointercancel\",\n \"pointerdown\",\n \"pointerenter\",\n \"pointerleave\",\n \"pointermove\",\n \"pointerout\",\n \"pointerover\",\n \"pointerup\",\n \"submit\",\n] as const;\nexport const REMOTE_DOM_SEARCH_SORT_EVENTS = [\n \"search-change\",\n \"sort-change\",\n] as const;\n\nexport type RemoteDomRemoteNode = RemoteNodeSerialization;\nexport type RemoteDomRemoteMutationRecord = RemoteMutationRecord;\n\nexport type RemoteDomSerializableValue =\n | null\n | boolean\n | number\n | string\n | readonly RemoteDomSerializableValue[]\n | { readonly [key: string]: RemoteDomSerializableValue };\n\nconst REMOTE_DOM_UNSAFE_PROPERTY_KEYS = new Set([\n \"__proto__\",\n \"constructor\",\n \"prototype\",\n]);\nconst MAX_REMOTE_DOM_SERIALIZATION_DEPTH = 50;\n\nexport function isSafeRemoteDomPropertyKey(key: string): boolean {\n return !REMOTE_DOM_UNSAFE_PROPERTY_KEYS.has(key);\n}\n\n/** Converts an arbitrary value into a structured-clone-safe Remote DOM value. */\nexport function toRemoteDomSerializableValue(\n value: unknown,\n): RemoteDomSerializableValue | undefined {\n return serializeRemoteDomValue(value, new WeakSet<object>(), 0);\n}\n\nfunction serializeRemoteDomValue(\n value: unknown,\n ancestors: WeakSet<object>,\n depth: number,\n): RemoteDomSerializableValue | undefined {\n if (\n value === undefined ||\n typeof value === \"function\" ||\n typeof value === \"symbol\"\n ) {\n return undefined;\n }\n if (typeof value === \"bigint\") return value.toString();\n if (\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"boolean\"\n ) {\n return value;\n }\n if (typeof value === \"number\") {\n return Number.isFinite(value) ? value : null;\n }\n if (typeof value !== \"object\") return null;\n if (depth > MAX_REMOTE_DOM_SERIALIZATION_DEPTH || ancestors.has(value)) {\n return null;\n }\n if (value instanceof Date) {\n return Number.isFinite(value.getTime()) ? value.toISOString() : null;\n }\n if (value instanceof Error) {\n return { name: value.name, message: value.message };\n }\n\n ancestors.add(value);\n try {\n if (Array.isArray(value)) {\n return value.map(\n (item) => serializeRemoteDomValue(item, ancestors, depth + 1) ?? null,\n );\n }\n\n const prototype = Object.getPrototypeOf(value);\n if (prototype !== Object.prototype && prototype !== null) return null;\n\n const serialized: Record<string, RemoteDomSerializableValue> = {};\n for (const [key, item] of Object.entries(value)) {\n if (!isSafeRemoteDomPropertyKey(key)) continue;\n\n const serializedItem = serializeRemoteDomValue(\n item,\n ancestors,\n depth + 1,\n );\n if (serializedItem !== undefined) serialized[key] = serializedItem;\n }\n return serialized;\n } finally {\n ancestors.delete(value);\n }\n}\n\nexport function isRemoteDomSerializableValue(\n value: unknown,\n): value is RemoteDomSerializableValue {\n return isRemoteDomSerializableValueInternal(value, new WeakSet<object>(), 0);\n}\n\nfunction isRemoteDomSerializableValueInternal(\n value: unknown,\n seen: WeakSet<object>,\n depth: number,\n): value is RemoteDomSerializableValue {\n if (value === null) return true;\n\n switch (typeof value) {\n case \"boolean\":\n case \"string\":\n return true;\n case \"number\":\n return Number.isFinite(value);\n case \"object\":\n return isRemoteDomSerializableObject(value, seen, depth);\n default:\n return false;\n }\n}\n\nfunction isRemoteDomSerializableObject(\n value: object,\n ancestors: WeakSet<object>,\n depth: number,\n): value is\n | readonly RemoteDomSerializableValue[]\n | { readonly [key: string]: RemoteDomSerializableValue } {\n if (depth > 50 || ancestors.has(value)) return false;\n\n const prototype = Object.getPrototypeOf(value);\n if (\n !Array.isArray(value) &&\n prototype !== Object.prototype &&\n prototype !== null\n ) {\n return false;\n }\n\n ancestors.add(value);\n try {\n if (Array.isArray(value)) {\n return value.every((item) =>\n isRemoteDomSerializableValueInternal(item, ancestors, depth + 1),\n );\n }\n\n return Object.entries(value).every(\n ([key, item]) =>\n isSafeRemoteDomPropertyKey(key) &&\n isRemoteDomSerializableValueInternal(item, ancestors, depth + 1),\n );\n } finally {\n ancestors.delete(value);\n }\n}\n\nexport type RemoteDomNodeProperties = Readonly<\n Record<string, RemoteDomSerializableValue | undefined>\n>;\n\nexport interface RemoteDomNavigationIntent {\n readonly href: string;\n readonly url: string;\n readonly targetId?: string;\n readonly source: \"anchor\";\n readonly altKey: boolean;\n readonly ctrlKey: boolean;\n readonly metaKey: boolean;\n readonly shiftKey: boolean;\n readonly button: number;\n}\n\nexport const DEFAULT_REMOTE_DOM_MEDIA_ORIGINS = [\n \"https://assets.fluid.app\",\n \"https://cdn.fluid.app\",\n \"https://ik.imagekit.io\",\n \"https://media.fluid.app\",\n] as const;\n\nexport interface RemoteDomUrlOriginPolicy {\n readonly artifactOrigins: readonly string[];\n readonly artifactBaseUrl?: string;\n readonly mediaOrigins: readonly string[];\n readonly navigationOrigin?: string;\n}\n\nexport interface RemoteDomUrlOriginPolicyInput {\n readonly artifactUrls: readonly string[];\n readonly mediaOrigins?: readonly string[];\n readonly navigationOrigin?: string;\n}\n\nexport function createRemoteDomUrlOriginPolicy({\n artifactUrls,\n mediaOrigins = DEFAULT_REMOTE_DOM_MEDIA_ORIGINS,\n navigationOrigin,\n}: RemoteDomUrlOriginPolicyInput): RemoteDomUrlOriginPolicy {\n const artifactOriginSet = new Set<string>();\n let artifactBaseUrl: string | undefined;\n for (const artifactUrl of artifactUrls) {\n const normalizedUrl = normalizeRemoteDomHttpUrl(artifactUrl);\n if (!normalizedUrl) continue;\n artifactOriginSet.add(normalizedUrl.origin);\n artifactBaseUrl ??= normalizedUrl.href;\n }\n\n const mediaOriginSet = new Set<string>();\n for (const mediaOrigin of mediaOrigins) {\n const origin = normalizeRemoteDomHttpOrigin(mediaOrigin);\n if (origin) mediaOriginSet.add(origin);\n }\n\n const navigationHttpOrigin = navigationOrigin\n ? normalizeRemoteDomHttpOrigin(navigationOrigin)\n : undefined;\n\n return {\n artifactOrigins: Array.from(artifactOriginSet),\n ...(artifactBaseUrl ? { artifactBaseUrl } : {}),\n mediaOrigins: Array.from(mediaOriginSet),\n ...(navigationHttpOrigin === undefined\n ? {}\n : { navigationOrigin: navigationHttpOrigin }),\n };\n}\n\nfunction normalizeRemoteDomHttpOrigin(value: string): string | undefined {\n return normalizeRemoteDomHttpUrl(value)?.origin;\n}\n\nfunction normalizeRemoteDomHttpUrl(value: string): URL | undefined {\n try {\n const parsedUrl = new URL(value);\n return parsedUrl.protocol === \"http:\" || parsedUrl.protocol === \"https:\"\n ? parsedUrl\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport interface RemoteDomProtocolError {\n readonly code: string;\n readonly message: string;\n readonly details?: RemoteDomSerializableValue;\n}\n"],"mappings":";AAKA,MAAa,mCAAmC;AAChD,MAAa,6BAA6B;AAC1C,MAAa,+BAA+B;;AAG5C,MAAa,+BAA+B;CAC1C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;AAGD,MAAa,8BAA8B;CACzC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AACD,MAAa,gCAAgC,CAC3C,iBACA,cACD;AAaD,MAAM,kCAAkC,IAAI,IAAI;CAC9C;CACA;CACA;CACD,CAAC;AACF,MAAM,qCAAqC;AAE3C,SAAgB,2BAA2B,KAAsB;AAC/D,QAAO,CAAC,gCAAgC,IAAI,IAAI;;;AAIlD,SAAgB,6BACd,OACwC;AACxC,QAAO,wBAAwB,uBAAO,IAAI,SAAiB,EAAE,EAAE;;AAGjE,SAAS,wBACP,OACA,WACA,OACwC;AACxC,KACE,UAAU,KAAA,KACV,OAAO,UAAU,cACjB,OAAO,UAAU,SAEjB;AAEF,KAAI,OAAO,UAAU,SAAU,QAAO,MAAM,UAAU;AACtD,KACE,UAAU,QACV,OAAO,UAAU,YACjB,OAAO,UAAU,UAEjB,QAAO;AAET,KAAI,OAAO,UAAU,SACnB,QAAO,OAAO,SAAS,MAAM,GAAG,QAAQ;AAE1C,KAAI,OAAO,UAAU,SAAU,QA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"}
|
|
@@ -1,297 +0,0 @@
|
|
|
1
|
-
//#region src/remote-dom-values.ts
|
|
2
|
-
const REMOTE_DOM_FULLSCREEN_CAPABILITY = "fullscreen";
|
|
3
|
-
const FLUID_SEARCH_SORT_TAG_NAME = "fluid-ui-search-sort";
|
|
4
|
-
const FLUID_SPACER_WIDGET_TAG_NAME = "fluid-spacer-widget";
|
|
5
|
-
/** Canonical element allowlist shared by the worker registration and host sanitizer. */
|
|
6
|
-
const REMOTE_DOM_ALLOWED_TAG_NAMES = [
|
|
7
|
-
"a",
|
|
8
|
-
"abbr",
|
|
9
|
-
"address",
|
|
10
|
-
"article",
|
|
11
|
-
"aside",
|
|
12
|
-
"audio",
|
|
13
|
-
"b",
|
|
14
|
-
"bdi",
|
|
15
|
-
"bdo",
|
|
16
|
-
"blockquote",
|
|
17
|
-
"br",
|
|
18
|
-
"button",
|
|
19
|
-
"caption",
|
|
20
|
-
"cite",
|
|
21
|
-
"code",
|
|
22
|
-
"col",
|
|
23
|
-
"colgroup",
|
|
24
|
-
"data",
|
|
25
|
-
"dd",
|
|
26
|
-
"del",
|
|
27
|
-
"details",
|
|
28
|
-
"dfn",
|
|
29
|
-
"dialog",
|
|
30
|
-
"div",
|
|
31
|
-
"dl",
|
|
32
|
-
"dt",
|
|
33
|
-
"em",
|
|
34
|
-
"fieldset",
|
|
35
|
-
"figcaption",
|
|
36
|
-
"figure",
|
|
37
|
-
"footer",
|
|
38
|
-
"form",
|
|
39
|
-
"h1",
|
|
40
|
-
"h2",
|
|
41
|
-
"h3",
|
|
42
|
-
"h4",
|
|
43
|
-
"h5",
|
|
44
|
-
"h6",
|
|
45
|
-
"header",
|
|
46
|
-
"hr",
|
|
47
|
-
"i",
|
|
48
|
-
"img",
|
|
49
|
-
"input",
|
|
50
|
-
"ins",
|
|
51
|
-
"kbd",
|
|
52
|
-
"label",
|
|
53
|
-
"legend",
|
|
54
|
-
"li",
|
|
55
|
-
"main",
|
|
56
|
-
"mark",
|
|
57
|
-
"meter",
|
|
58
|
-
"nav",
|
|
59
|
-
"ol",
|
|
60
|
-
"optgroup",
|
|
61
|
-
"option",
|
|
62
|
-
"output",
|
|
63
|
-
"p",
|
|
64
|
-
"picture",
|
|
65
|
-
"pre",
|
|
66
|
-
"progress",
|
|
67
|
-
"q",
|
|
68
|
-
"rp",
|
|
69
|
-
"rt",
|
|
70
|
-
"ruby",
|
|
71
|
-
"s",
|
|
72
|
-
"samp",
|
|
73
|
-
"section",
|
|
74
|
-
"select",
|
|
75
|
-
"small",
|
|
76
|
-
"source",
|
|
77
|
-
"span",
|
|
78
|
-
"strong",
|
|
79
|
-
"sub",
|
|
80
|
-
"summary",
|
|
81
|
-
"sup",
|
|
82
|
-
"table",
|
|
83
|
-
"tbody",
|
|
84
|
-
"td",
|
|
85
|
-
"textarea",
|
|
86
|
-
"tfoot",
|
|
87
|
-
"th",
|
|
88
|
-
"thead",
|
|
89
|
-
"time",
|
|
90
|
-
"tr",
|
|
91
|
-
"track",
|
|
92
|
-
"u",
|
|
93
|
-
"ul",
|
|
94
|
-
"var",
|
|
95
|
-
"video",
|
|
96
|
-
"wbr",
|
|
97
|
-
FLUID_SEARCH_SORT_TAG_NAME,
|
|
98
|
-
FLUID_SPACER_WIDGET_TAG_NAME
|
|
99
|
-
];
|
|
100
|
-
/** Canonical event allowlist shared by worker elements and host forwarding. */
|
|
101
|
-
const SUPPORTED_REMOTE_DOM_EVENTS = [
|
|
102
|
-
"blur",
|
|
103
|
-
"change",
|
|
104
|
-
"click",
|
|
105
|
-
"contextmenu",
|
|
106
|
-
"dblclick",
|
|
107
|
-
"focus",
|
|
108
|
-
"input",
|
|
109
|
-
"keydown",
|
|
110
|
-
"keypress",
|
|
111
|
-
"keyup",
|
|
112
|
-
"mousedown",
|
|
113
|
-
"mouseenter",
|
|
114
|
-
"mouseleave",
|
|
115
|
-
"mousemove",
|
|
116
|
-
"mouseout",
|
|
117
|
-
"mouseover",
|
|
118
|
-
"mouseup",
|
|
119
|
-
"pointercancel",
|
|
120
|
-
"pointerdown",
|
|
121
|
-
"pointerenter",
|
|
122
|
-
"pointerleave",
|
|
123
|
-
"pointermove",
|
|
124
|
-
"pointerout",
|
|
125
|
-
"pointerover",
|
|
126
|
-
"pointerup",
|
|
127
|
-
"submit"
|
|
128
|
-
];
|
|
129
|
-
const REMOTE_DOM_SEARCH_SORT_EVENTS = ["search-change", "sort-change"];
|
|
130
|
-
const REMOTE_DOM_UNSAFE_PROPERTY_KEYS = new Set([
|
|
131
|
-
"__proto__",
|
|
132
|
-
"constructor",
|
|
133
|
-
"prototype"
|
|
134
|
-
]);
|
|
135
|
-
const MAX_REMOTE_DOM_SERIALIZATION_DEPTH = 50;
|
|
136
|
-
function isSafeRemoteDomPropertyKey(key) {
|
|
137
|
-
return !REMOTE_DOM_UNSAFE_PROPERTY_KEYS.has(key);
|
|
138
|
-
}
|
|
139
|
-
/** Converts an arbitrary value into a structured-clone-safe Remote DOM value. */
|
|
140
|
-
function toRemoteDomSerializableValue(value) {
|
|
141
|
-
return serializeRemoteDomValue(value, /* @__PURE__ */ new WeakSet(), 0);
|
|
142
|
-
}
|
|
143
|
-
function serializeRemoteDomValue(value, ancestors, depth) {
|
|
144
|
-
if (value === void 0 || typeof value === "function" || typeof value === "symbol") return;
|
|
145
|
-
if (typeof value === "bigint") return value.toString();
|
|
146
|
-
if (value === null || typeof value === "string" || typeof value === "boolean") return value;
|
|
147
|
-
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
148
|
-
if (typeof value !== "object") return null;
|
|
149
|
-
if (depth > MAX_REMOTE_DOM_SERIALIZATION_DEPTH || ancestors.has(value)) return null;
|
|
150
|
-
if (value instanceof Date) return Number.isFinite(value.getTime()) ? value.toISOString() : null;
|
|
151
|
-
if (value instanceof Error) return {
|
|
152
|
-
name: value.name,
|
|
153
|
-
message: value.message
|
|
154
|
-
};
|
|
155
|
-
ancestors.add(value);
|
|
156
|
-
try {
|
|
157
|
-
if (Array.isArray(value)) return value.map((item) => serializeRemoteDomValue(item, ancestors, depth + 1) ?? null);
|
|
158
|
-
const prototype = Object.getPrototypeOf(value);
|
|
159
|
-
if (prototype !== Object.prototype && prototype !== null) return null;
|
|
160
|
-
const serialized = {};
|
|
161
|
-
for (const [key, item] of Object.entries(value)) {
|
|
162
|
-
if (!isSafeRemoteDomPropertyKey(key)) continue;
|
|
163
|
-
const serializedItem = serializeRemoteDomValue(item, ancestors, depth + 1);
|
|
164
|
-
if (serializedItem !== void 0) serialized[key] = serializedItem;
|
|
165
|
-
}
|
|
166
|
-
return serialized;
|
|
167
|
-
} finally {
|
|
168
|
-
ancestors.delete(value);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
function isRemoteDomSerializableValue(value) {
|
|
172
|
-
return isRemoteDomSerializableValueInternal(value, /* @__PURE__ */ new WeakSet(), 0);
|
|
173
|
-
}
|
|
174
|
-
function isRemoteDomSerializableValueInternal(value, seen, depth) {
|
|
175
|
-
if (value === null) return true;
|
|
176
|
-
switch (typeof value) {
|
|
177
|
-
case "boolean":
|
|
178
|
-
case "string": return true;
|
|
179
|
-
case "number": return Number.isFinite(value);
|
|
180
|
-
case "object": return isRemoteDomSerializableObject(value, seen, depth);
|
|
181
|
-
default: return false;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
function isRemoteDomSerializableObject(value, ancestors, depth) {
|
|
185
|
-
if (depth > 50 || ancestors.has(value)) return false;
|
|
186
|
-
const prototype = Object.getPrototypeOf(value);
|
|
187
|
-
if (!Array.isArray(value) && prototype !== Object.prototype && prototype !== null) return false;
|
|
188
|
-
ancestors.add(value);
|
|
189
|
-
try {
|
|
190
|
-
if (Array.isArray(value)) return value.every((item) => isRemoteDomSerializableValueInternal(item, ancestors, depth + 1));
|
|
191
|
-
return Object.entries(value).every(([key, item]) => isSafeRemoteDomPropertyKey(key) && isRemoteDomSerializableValueInternal(item, ancestors, depth + 1));
|
|
192
|
-
} finally {
|
|
193
|
-
ancestors.delete(value);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
const DEFAULT_REMOTE_DOM_MEDIA_ORIGINS = [
|
|
197
|
-
"https://assets.fluid.app",
|
|
198
|
-
"https://cdn.fluid.app",
|
|
199
|
-
"https://ik.imagekit.io",
|
|
200
|
-
"https://media.fluid.app"
|
|
201
|
-
];
|
|
202
|
-
function createRemoteDomUrlOriginPolicy({ artifactUrls, mediaOrigins = DEFAULT_REMOTE_DOM_MEDIA_ORIGINS, navigationOrigin }) {
|
|
203
|
-
const artifactOriginSet = /* @__PURE__ */ new Set();
|
|
204
|
-
let artifactBaseUrl;
|
|
205
|
-
for (const artifactUrl of artifactUrls) {
|
|
206
|
-
const normalizedUrl = normalizeRemoteDomHttpUrl(artifactUrl);
|
|
207
|
-
if (!normalizedUrl) continue;
|
|
208
|
-
artifactOriginSet.add(normalizedUrl.origin);
|
|
209
|
-
artifactBaseUrl ??= normalizedUrl.href;
|
|
210
|
-
}
|
|
211
|
-
const mediaOriginSet = /* @__PURE__ */ new Set();
|
|
212
|
-
for (const mediaOrigin of mediaOrigins) {
|
|
213
|
-
const origin = normalizeRemoteDomHttpOrigin(mediaOrigin);
|
|
214
|
-
if (origin) mediaOriginSet.add(origin);
|
|
215
|
-
}
|
|
216
|
-
const navigationHttpOrigin = navigationOrigin ? normalizeRemoteDomHttpOrigin(navigationOrigin) : void 0;
|
|
217
|
-
return {
|
|
218
|
-
artifactOrigins: Array.from(artifactOriginSet),
|
|
219
|
-
...artifactBaseUrl ? { artifactBaseUrl } : {},
|
|
220
|
-
mediaOrigins: Array.from(mediaOriginSet),
|
|
221
|
-
...navigationHttpOrigin === void 0 ? {} : { navigationOrigin: navigationHttpOrigin }
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
function normalizeRemoteDomHttpOrigin(value) {
|
|
225
|
-
return normalizeRemoteDomHttpUrl(value)?.origin;
|
|
226
|
-
}
|
|
227
|
-
function normalizeRemoteDomHttpUrl(value) {
|
|
228
|
-
try {
|
|
229
|
-
const parsedUrl = new URL(value);
|
|
230
|
-
return parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:" ? parsedUrl : void 0;
|
|
231
|
-
} catch {
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
//#endregion
|
|
236
|
-
Object.defineProperty(exports, "FLUID_SEARCH_SORT_TAG_NAME", {
|
|
237
|
-
enumerable: true,
|
|
238
|
-
get: function() {
|
|
239
|
-
return FLUID_SEARCH_SORT_TAG_NAME;
|
|
240
|
-
}
|
|
241
|
-
});
|
|
242
|
-
Object.defineProperty(exports, "FLUID_SPACER_WIDGET_TAG_NAME", {
|
|
243
|
-
enumerable: true,
|
|
244
|
-
get: function() {
|
|
245
|
-
return FLUID_SPACER_WIDGET_TAG_NAME;
|
|
246
|
-
}
|
|
247
|
-
});
|
|
248
|
-
Object.defineProperty(exports, "REMOTE_DOM_ALLOWED_TAG_NAMES", {
|
|
249
|
-
enumerable: true,
|
|
250
|
-
get: function() {
|
|
251
|
-
return REMOTE_DOM_ALLOWED_TAG_NAMES;
|
|
252
|
-
}
|
|
253
|
-
});
|
|
254
|
-
Object.defineProperty(exports, "REMOTE_DOM_FULLSCREEN_CAPABILITY", {
|
|
255
|
-
enumerable: true,
|
|
256
|
-
get: function() {
|
|
257
|
-
return REMOTE_DOM_FULLSCREEN_CAPABILITY;
|
|
258
|
-
}
|
|
259
|
-
});
|
|
260
|
-
Object.defineProperty(exports, "REMOTE_DOM_SEARCH_SORT_EVENTS", {
|
|
261
|
-
enumerable: true,
|
|
262
|
-
get: function() {
|
|
263
|
-
return REMOTE_DOM_SEARCH_SORT_EVENTS;
|
|
264
|
-
}
|
|
265
|
-
});
|
|
266
|
-
Object.defineProperty(exports, "SUPPORTED_REMOTE_DOM_EVENTS", {
|
|
267
|
-
enumerable: true,
|
|
268
|
-
get: function() {
|
|
269
|
-
return SUPPORTED_REMOTE_DOM_EVENTS;
|
|
270
|
-
}
|
|
271
|
-
});
|
|
272
|
-
Object.defineProperty(exports, "createRemoteDomUrlOriginPolicy", {
|
|
273
|
-
enumerable: true,
|
|
274
|
-
get: function() {
|
|
275
|
-
return createRemoteDomUrlOriginPolicy;
|
|
276
|
-
}
|
|
277
|
-
});
|
|
278
|
-
Object.defineProperty(exports, "isRemoteDomSerializableValue", {
|
|
279
|
-
enumerable: true,
|
|
280
|
-
get: function() {
|
|
281
|
-
return isRemoteDomSerializableValue;
|
|
282
|
-
}
|
|
283
|
-
});
|
|
284
|
-
Object.defineProperty(exports, "isSafeRemoteDomPropertyKey", {
|
|
285
|
-
enumerable: true,
|
|
286
|
-
get: function() {
|
|
287
|
-
return isSafeRemoteDomPropertyKey;
|
|
288
|
-
}
|
|
289
|
-
});
|
|
290
|
-
Object.defineProperty(exports, "toRemoteDomSerializableValue", {
|
|
291
|
-
enumerable: true,
|
|
292
|
-
get: function() {
|
|
293
|
-
return toRemoteDomSerializableValue;
|
|
294
|
-
}
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
//# sourceMappingURL=remote-dom-values-DbgIedSg.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"remote-dom-values-DbgIedSg.cjs","names":[],"sources":["../src/remote-dom-values.ts"],"sourcesContent":["import type {\n RemoteMutationRecord,\n RemoteNodeSerialization,\n} from \"@remote-dom/core\";\n\nexport const REMOTE_DOM_FULLSCREEN_CAPABILITY = \"fullscreen\";\nexport const FLUID_SEARCH_SORT_TAG_NAME = \"fluid-ui-search-sort\";\nexport const FLUID_SPACER_WIDGET_TAG_NAME = \"fluid-spacer-widget\";\n\n/** Canonical element allowlist shared by the worker registration and host sanitizer. */\nexport const REMOTE_DOM_ALLOWED_TAG_NAMES = [\n \"a\",\n \"abbr\",\n \"address\",\n \"article\",\n \"aside\",\n \"audio\",\n \"b\",\n \"bdi\",\n \"bdo\",\n \"blockquote\",\n \"br\",\n \"button\",\n \"caption\",\n \"cite\",\n \"code\",\n \"col\",\n \"colgroup\",\n \"data\",\n \"dd\",\n \"del\",\n \"details\",\n \"dfn\",\n \"dialog\",\n \"div\",\n \"dl\",\n \"dt\",\n \"em\",\n \"fieldset\",\n \"figcaption\",\n \"figure\",\n \"footer\",\n \"form\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"header\",\n \"hr\",\n \"i\",\n \"img\",\n \"input\",\n \"ins\",\n \"kbd\",\n \"label\",\n \"legend\",\n \"li\",\n \"main\",\n \"mark\",\n \"meter\",\n \"nav\",\n \"ol\",\n \"optgroup\",\n \"option\",\n \"output\",\n \"p\",\n \"picture\",\n \"pre\",\n \"progress\",\n \"q\",\n \"rp\",\n \"rt\",\n \"ruby\",\n \"s\",\n \"samp\",\n \"section\",\n \"select\",\n \"small\",\n \"source\",\n \"span\",\n \"strong\",\n \"sub\",\n \"summary\",\n \"sup\",\n \"table\",\n \"tbody\",\n \"td\",\n \"textarea\",\n \"tfoot\",\n \"th\",\n \"thead\",\n \"time\",\n \"tr\",\n \"track\",\n \"u\",\n \"ul\",\n \"var\",\n \"video\",\n \"wbr\",\n FLUID_SEARCH_SORT_TAG_NAME,\n FLUID_SPACER_WIDGET_TAG_NAME,\n] as const;\n\n/** Canonical event allowlist shared by worker elements and host forwarding. */\nexport const SUPPORTED_REMOTE_DOM_EVENTS = [\n \"blur\",\n \"change\",\n \"click\",\n \"contextmenu\",\n \"dblclick\",\n \"focus\",\n \"input\",\n \"keydown\",\n \"keypress\",\n \"keyup\",\n \"mousedown\",\n \"mouseenter\",\n \"mouseleave\",\n \"mousemove\",\n \"mouseout\",\n \"mouseover\",\n \"mouseup\",\n \"pointercancel\",\n \"pointerdown\",\n \"pointerenter\",\n \"pointerleave\",\n \"pointermove\",\n \"pointerout\",\n \"pointerover\",\n \"pointerup\",\n \"submit\",\n] as const;\nexport const REMOTE_DOM_SEARCH_SORT_EVENTS = [\n \"search-change\",\n \"sort-change\",\n] as const;\n\nexport type RemoteDomRemoteNode = RemoteNodeSerialization;\nexport type RemoteDomRemoteMutationRecord = RemoteMutationRecord;\n\nexport type RemoteDomSerializableValue =\n | null\n | boolean\n | number\n | string\n | readonly RemoteDomSerializableValue[]\n | { readonly [key: string]: RemoteDomSerializableValue };\n\nconst REMOTE_DOM_UNSAFE_PROPERTY_KEYS = new Set([\n \"__proto__\",\n \"constructor\",\n \"prototype\",\n]);\nconst MAX_REMOTE_DOM_SERIALIZATION_DEPTH = 50;\n\nexport function isSafeRemoteDomPropertyKey(key: string): boolean {\n return !REMOTE_DOM_UNSAFE_PROPERTY_KEYS.has(key);\n}\n\n/** Converts an arbitrary value into a structured-clone-safe Remote DOM value. */\nexport function toRemoteDomSerializableValue(\n value: unknown,\n): RemoteDomSerializableValue | undefined {\n return serializeRemoteDomValue(value, new WeakSet<object>(), 0);\n}\n\nfunction serializeRemoteDomValue(\n value: unknown,\n ancestors: WeakSet<object>,\n depth: number,\n): RemoteDomSerializableValue | undefined {\n if (\n value === undefined ||\n typeof value === \"function\" ||\n typeof value === \"symbol\"\n ) {\n return undefined;\n }\n if (typeof value === \"bigint\") return value.toString();\n if (\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"boolean\"\n ) {\n return value;\n }\n if (typeof value === \"number\") {\n return Number.isFinite(value) ? value : null;\n }\n if (typeof value !== \"object\") return null;\n if (depth > MAX_REMOTE_DOM_SERIALIZATION_DEPTH || ancestors.has(value)) {\n return null;\n }\n if (value instanceof Date) {\n return Number.isFinite(value.getTime()) ? value.toISOString() : null;\n }\n if (value instanceof Error) {\n return { name: value.name, message: value.message };\n }\n\n ancestors.add(value);\n try {\n if (Array.isArray(value)) {\n return value.map(\n (item) => serializeRemoteDomValue(item, ancestors, depth + 1) ?? null,\n );\n }\n\n const prototype = Object.getPrototypeOf(value);\n if (prototype !== Object.prototype && prototype !== null) return null;\n\n const serialized: Record<string, RemoteDomSerializableValue> = {};\n for (const [key, item] of Object.entries(value)) {\n if (!isSafeRemoteDomPropertyKey(key)) continue;\n\n const serializedItem = serializeRemoteDomValue(\n item,\n ancestors,\n depth + 1,\n );\n if (serializedItem !== undefined) serialized[key] = serializedItem;\n }\n return serialized;\n } finally {\n ancestors.delete(value);\n }\n}\n\nexport function isRemoteDomSerializableValue(\n value: unknown,\n): value is RemoteDomSerializableValue {\n return isRemoteDomSerializableValueInternal(value, new WeakSet<object>(), 0);\n}\n\nfunction isRemoteDomSerializableValueInternal(\n value: unknown,\n seen: WeakSet<object>,\n depth: number,\n): value is RemoteDomSerializableValue {\n if (value === null) return true;\n\n switch (typeof value) {\n case \"boolean\":\n case \"string\":\n return true;\n case \"number\":\n return Number.isFinite(value);\n case \"object\":\n return isRemoteDomSerializableObject(value, seen, depth);\n default:\n return false;\n }\n}\n\nfunction isRemoteDomSerializableObject(\n value: object,\n ancestors: WeakSet<object>,\n depth: number,\n): value is\n | readonly RemoteDomSerializableValue[]\n | { readonly [key: string]: RemoteDomSerializableValue } {\n if (depth > 50 || ancestors.has(value)) return false;\n\n const prototype = Object.getPrototypeOf(value);\n if (\n !Array.isArray(value) &&\n prototype !== Object.prototype &&\n prototype !== null\n ) {\n return false;\n }\n\n ancestors.add(value);\n try {\n if (Array.isArray(value)) {\n return value.every((item) =>\n isRemoteDomSerializableValueInternal(item, ancestors, depth + 1),\n );\n }\n\n return Object.entries(value).every(\n ([key, item]) =>\n isSafeRemoteDomPropertyKey(key) &&\n isRemoteDomSerializableValueInternal(item, ancestors, depth + 1),\n );\n } finally {\n ancestors.delete(value);\n }\n}\n\nexport type RemoteDomNodeProperties = Readonly<\n Record<string, RemoteDomSerializableValue | undefined>\n>;\n\nexport interface RemoteDomNavigationIntent {\n readonly href: string;\n readonly url: string;\n readonly targetId?: string;\n readonly source: \"anchor\";\n readonly altKey: boolean;\n readonly ctrlKey: boolean;\n readonly metaKey: boolean;\n readonly shiftKey: boolean;\n readonly button: number;\n}\n\nexport const DEFAULT_REMOTE_DOM_MEDIA_ORIGINS = [\n \"https://assets.fluid.app\",\n \"https://cdn.fluid.app\",\n \"https://ik.imagekit.io\",\n \"https://media.fluid.app\",\n] as const;\n\nexport interface RemoteDomUrlOriginPolicy {\n readonly artifactOrigins: readonly string[];\n readonly artifactBaseUrl?: string;\n readonly mediaOrigins: readonly string[];\n readonly navigationOrigin?: string;\n}\n\nexport interface RemoteDomUrlOriginPolicyInput {\n readonly artifactUrls: readonly string[];\n readonly mediaOrigins?: readonly string[];\n readonly navigationOrigin?: string;\n}\n\nexport function createRemoteDomUrlOriginPolicy({\n artifactUrls,\n mediaOrigins = DEFAULT_REMOTE_DOM_MEDIA_ORIGINS,\n navigationOrigin,\n}: RemoteDomUrlOriginPolicyInput): RemoteDomUrlOriginPolicy {\n const artifactOriginSet = new Set<string>();\n let artifactBaseUrl: string | undefined;\n for (const artifactUrl of artifactUrls) {\n const normalizedUrl = normalizeRemoteDomHttpUrl(artifactUrl);\n if (!normalizedUrl) continue;\n artifactOriginSet.add(normalizedUrl.origin);\n artifactBaseUrl ??= normalizedUrl.href;\n }\n\n const mediaOriginSet = new Set<string>();\n for (const mediaOrigin of mediaOrigins) {\n const origin = normalizeRemoteDomHttpOrigin(mediaOrigin);\n if (origin) mediaOriginSet.add(origin);\n }\n\n const navigationHttpOrigin = navigationOrigin\n ? normalizeRemoteDomHttpOrigin(navigationOrigin)\n : undefined;\n\n return {\n artifactOrigins: Array.from(artifactOriginSet),\n ...(artifactBaseUrl ? { artifactBaseUrl } : {}),\n mediaOrigins: Array.from(mediaOriginSet),\n ...(navigationHttpOrigin === undefined\n ? {}\n : { navigationOrigin: navigationHttpOrigin }),\n };\n}\n\nfunction normalizeRemoteDomHttpOrigin(value: string): string | undefined {\n return normalizeRemoteDomHttpUrl(value)?.origin;\n}\n\nfunction normalizeRemoteDomHttpUrl(value: string): URL | undefined {\n try {\n const parsedUrl = new URL(value);\n return parsedUrl.protocol === \"http:\" || parsedUrl.protocol === \"https:\"\n ? parsedUrl\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport interface RemoteDomProtocolError {\n readonly code: string;\n readonly message: string;\n readonly details?: RemoteDomSerializableValue;\n}\n"],"mappings":";AAKA,MAAa,mCAAmC;AAChD,MAAa,6BAA6B;AAC1C,MAAa,+BAA+B;;AAG5C,MAAa,+BAA+B;CAC1C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;AAGD,MAAa,8BAA8B;CACzC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AACD,MAAa,gCAAgC,CAC3C,iBACA,cACD;AAaD,MAAM,kCAAkC,IAAI,IAAI;CAC9C;CACA;CACA;CACD,CAAC;AACF,MAAM,qCAAqC;AAE3C,SAAgB,2BAA2B,KAAsB;AAC/D,QAAO,CAAC,gCAAgC,IAAI,IAAI;;;AAIlD,SAAgB,6BACd,OACwC;AACxC,QAAO,wBAAwB,uBAAO,IAAI,SAAiB,EAAE,EAAE;;AAGjE,SAAS,wBACP,OACA,WACA,OACwC;AACxC,KACE,UAAU,KAAA,KACV,OAAO,UAAU,cACjB,OAAO,UAAU,SAEjB;AAEF,KAAI,OAAO,UAAU,SAAU,QAAO,MAAM,UAAU;AACtD,KACE,UAAU,QACV,OAAO,UAAU,YACjB,OAAO,UAAU,UAEjB,QAAO;AAET,KAAI,OAAO,UAAU,SACnB,QAAO,OAAO,SAAS,MAAM,GAAG,QAAQ;AAE1C,KAAI,OAAO,UAAU,SAAU,QA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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"worker-react-renderer-BKzig_Vy.mjs","names":[],"sources":["../src/worker-react-renderer.ts"],"sourcesContent":["import {\n BatchingRemoteConnection,\n createRemoteElement,\n RemoteRootElement,\n type RemoteElementEventListenerDefinition,\n type RemoteConnection,\n} from \"@remote-dom/core/elements\";\nimport type { ReactNode } from \"react\";\nimport { flushSync } from \"react-dom\";\nimport { createRoot, type Root } from \"react-dom/client\";\n\nimport {\n FLUID_SEARCH_SORT_TAG_NAME,\n FLUID_SPACER_WIDGET_TAG_NAME,\n isRemoteDomSerializableValue,\n REMOTE_DOM_ALLOWED_TAG_NAMES,\n REMOTE_DOM_SEARCH_SORT_EVENTS,\n SUPPORTED_REMOTE_DOM_EVENTS,\n type RemoteDomSerializableValue,\n} from \"./remote-dom-values\";\n\nexport interface RemoteDomReactWorkerRendererOptions {\n /**\n * The host-backed connection ({@link RemoteConnection}); its `mutate` is the\n * threads-proxied `host.mutate`. The renderer wraps it in a\n * `BatchingRemoteConnection` and flushes explicitly after every commit.\n */\n readonly connection: RemoteConnection;\n}\n\nexport interface RemoteDomReactWorkerRenderer {\n readonly render: (node: ReactNode) => void;\n readonly dispose: () => void;\n}\n\nconst REMOTE_ROOT_TAG_NAME = \"remote-root\";\n\ntype NoRemoteMembers = Record<never, never>;\ntype RemoteEventListeners = Record<string, (payload?: unknown) => unknown>;\n\nconst standardEventDefinitions = createRemoteEventDefinitions(\n SUPPORTED_REMOTE_DOM_EVENTS,\n);\nconst searchSortEventDefinitions = {\n ...standardEventDefinitions,\n ...createRemoteEventDefinitions(REMOTE_DOM_SEARCH_SORT_EVENTS),\n};\n\nconst FluidRemoteElement = createRemoteElement<\n NoRemoteMembers,\n NoRemoteMembers,\n NoRemoteMembers,\n RemoteEventListeners\n>({ events: standardEventDefinitions });\n\ninterface RemoteInputProperties {\n readonly checked: boolean;\n readonly type: string;\n readonly value: string;\n}\n\nconst RemoteInputElement = createRemoteElement<\n RemoteInputProperties,\n NoRemoteMembers,\n NoRemoteMembers,\n RemoteEventListeners\n>({\n events: standardEventDefinitions,\n properties: {\n checked: { attribute: false, default: false },\n type: { attribute: true, default: \"text\" },\n value: { attribute: false, default: \"\" },\n },\n});\n\nclass FluidRemoteInputElement extends RemoteInputElement {\n applyHostState(detail: Readonly<Record<string, unknown>>): void {\n // React wraps public input setters with its value tracker. Update Remote\n // DOM's upstream property cache directly so the following native event is\n // extracted, while still synchronizing the host-controlled value.\n const value = readSerializableString(detail, \"value\");\n if (value !== undefined) this.updateRemoteProperty(\"value\", value);\n\n const checked = detail.checked;\n if (typeof checked === \"boolean\") {\n this.updateRemoteProperty(\"checked\", checked);\n }\n }\n}\n\ninterface RemoteSearchSortOption {\n readonly label: string;\n readonly value: string;\n}\n\ninterface RemoteSearchSortProperties {\n readonly placeholder: string | undefined;\n readonly searchValue: string;\n readonly sortOptions: readonly RemoteSearchSortOption[] | undefined;\n readonly sortValue: string | undefined;\n}\n\nconst FluidRemoteSearchSortElement = createRemoteElement<\n RemoteSearchSortProperties,\n NoRemoteMembers,\n NoRemoteMembers,\n RemoteEventListeners\n>({\n events: searchSortEventDefinitions,\n properties: {\n placeholder: { attribute: false },\n searchValue: { attribute: false, default: \"\" },\n sortOptions: { attribute: false },\n sortValue: { attribute: false },\n },\n});\n\ninterface RemoteSpacerProperties {\n readonly customHeight: string | undefined;\n readonly previewMode: boolean;\n}\n\nconst FluidRemoteSpacerWidgetElement = createRemoteElement<\n RemoteSpacerProperties,\n NoRemoteMembers,\n NoRemoteMembers,\n RemoteEventListeners\n>({\n events: standardEventDefinitions,\n properties: {\n customHeight: { attribute: false },\n previewMode: { attribute: false, default: false },\n },\n});\n\nlet remoteElementsRegistered = false;\n\nexport function createRemoteDomReactWorkerRenderer({\n connection,\n}: RemoteDomReactWorkerRendererOptions): RemoteDomReactWorkerRenderer {\n registerRemoteElements();\n\n const remoteRoot = document.createElement(\n REMOTE_ROOT_TAG_NAME,\n ) as RemoteRootElement;\n const batchedConnection = new BatchingRemoteConnection(connection);\n remoteRoot.connect(batchedConnection);\n const reactRoot: Root = createRoot(remoteRoot);\n // Remote DOM installs bubbling event proxies from custom-element lifecycle\n // callbacks. Keep the remote tree connected to its synthetic document so\n // those callbacks run for every element React mounts.\n try {\n document.body.append(remoteRoot);\n } catch (error) {\n reactRoot.unmount();\n throw error;\n }\n let disposed = false;\n\n return {\n render(node) {\n flushSync(() => {\n reactRoot.render(node);\n });\n // The host must never observe a capability/event side effect before the\n // DOM it references, so force mutations out immediately after commit.\n batchedConnection.flush();\n },\n dispose() {\n if (disposed) return;\n disposed = true;\n const cleanupErrors: unknown[] = [];\n\n try {\n flushSync(() => {\n reactRoot.unmount();\n });\n } catch (error) {\n cleanupErrors.push(error);\n }\n try {\n remoteRoot.remove();\n } catch (error) {\n cleanupErrors.push(error);\n }\n try {\n batchedConnection.flush();\n } catch (error) {\n cleanupErrors.push(error);\n }\n\n if (cleanupErrors.length > 0) {\n throw new AggregateError(\n cleanupErrors,\n \"Remote DOM React session cleanup failed.\",\n );\n }\n },\n };\n}\n\nfunction registerRemoteElements(): void {\n if (remoteElementsRegistered) return;\n remoteElementsRegistered = true;\n\n defineRemoteElement(REMOTE_ROOT_TAG_NAME, RemoteRootElement);\n for (const tagName of REMOTE_DOM_ALLOWED_TAG_NAMES) {\n if (\n tagName === FLUID_SEARCH_SORT_TAG_NAME ||\n tagName === FLUID_SPACER_WIDGET_TAG_NAME\n ) {\n continue;\n }\n defineRemoteElement(\n tagName,\n tagName === \"input\" ? FluidRemoteInputElement : FluidRemoteElement,\n );\n }\n defineRemoteElement(FLUID_SEARCH_SORT_TAG_NAME, FluidRemoteSearchSortElement);\n defineRemoteElement(\n FLUID_SPACER_WIDGET_TAG_NAME,\n FluidRemoteSpacerWidgetElement,\n );\n}\n\nfunction defineRemoteElement(\n tagName: string,\n constructor: CustomElementConstructor,\n): void {\n if (customElements.get(tagName)) return;\n customElements.define(tagName, constructor);\n}\n\nfunction createRemoteEventDefinitions(\n eventNames: readonly string[],\n): Readonly<Record<string, RemoteElementEventListenerDefinition>> {\n return Object.fromEntries(\n eventNames.map((eventName) => [\n eventName,\n {\n bubbles: true,\n dispatchEvent(this: Element, payload?: unknown) {\n const detail = readHostEventDetail(payload);\n if (\n this instanceof FluidRemoteInputElement &&\n isObjectRecord(detail)\n ) {\n this.applyHostState(detail);\n }\n return createRemoteDomReactEvent(eventName, detail);\n },\n },\n ]),\n );\n}\n\nfunction readHostEventDetail(\n payload: unknown,\n): RemoteDomSerializableValue | undefined {\n if (!isObjectRecord(payload)) return undefined;\n const detail = payload.detail;\n return isRemoteDomSerializableValue(detail) ? detail : undefined;\n}\n\nfunction createRemoteDomReactEvent(\n eventName: string,\n detail: RemoteDomSerializableValue | undefined,\n): Event {\n const customDetail = parseCustomEventDetail(eventName, detail);\n const event = new CustomEvent(eventName, {\n bubbles: true,\n cancelable: true,\n detail: customDetail.ok ? customDetail.value : detail,\n });\n if (!isObjectRecord(detail)) return event;\n\n const key = readSerializableString(detail, \"key\");\n if (key !== undefined) setObjectProperty(event, \"key\", key);\n\n const eventType = readSerializableString(detail, \"type\");\n if (eventType !== undefined) setObjectProperty(event, \"inputType\", eventType);\n\n return event;\n}\n\nfunction parseCustomEventDetail(\n eventName: string,\n detail: RemoteDomSerializableValue | undefined,\n):\n | { readonly ok: true; readonly value: RemoteDomSerializableValue }\n | { readonly ok: false } {\n if (!isSearchSortEvent(eventName) || !isObjectRecord(detail)) {\n return { ok: false };\n }\n const detailJson = detail.detailJson;\n if (typeof detailJson !== \"string\") return { ok: false };\n\n try {\n const value: unknown = JSON.parse(detailJson);\n return isRemoteDomSerializableValue(value)\n ? { ok: true, value }\n : { ok: false };\n } catch {\n return { ok: false };\n }\n}\n\nfunction isSearchSortEvent(eventName: string): boolean {\n return REMOTE_DOM_SEARCH_SORT_EVENTS.some(\n (candidate) => candidate === eventName,\n );\n}\n\nfunction readSerializableString(\n detail: Readonly<Record<string, unknown>>,\n key: string,\n): string | undefined {\n const value = detail[key];\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction setObjectProperty(target: object, key: string, value: unknown): void {\n Object.defineProperty(target, key, {\n configurable: true,\n enumerable: true,\n value,\n writable: true,\n });\n}\n\nfunction isObjectRecord(\n value: unknown,\n): value is Readonly<Record<string, unknown>> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"worker-react-renderer-BvHZ2o0B.cjs","names":["SUPPORTED_REMOTE_DOM_EVENTS","REMOTE_DOM_SEARCH_SORT_EVENTS","BatchingRemoteConnection","RemoteRootElement","REMOTE_DOM_ALLOWED_TAG_NAMES","FLUID_SEARCH_SORT_TAG_NAME","FLUID_SPACER_WIDGET_TAG_NAME","isRemoteDomSerializableValue"],"sources":["../src/worker-react-renderer.ts"],"sourcesContent":["import {\n BatchingRemoteConnection,\n createRemoteElement,\n RemoteRootElement,\n type RemoteElementEventListenerDefinition,\n type RemoteConnection,\n} from \"@remote-dom/core/elements\";\nimport type { ReactNode } from \"react\";\nimport { flushSync } from \"react-dom\";\nimport { createRoot, type Root } from \"react-dom/client\";\n\nimport {\n FLUID_SEARCH_SORT_TAG_NAME,\n FLUID_SPACER_WIDGET_TAG_NAME,\n isRemoteDomSerializableValue,\n REMOTE_DOM_ALLOWED_TAG_NAMES,\n REMOTE_DOM_SEARCH_SORT_EVENTS,\n SUPPORTED_REMOTE_DOM_EVENTS,\n type RemoteDomSerializableValue,\n} from \"./remote-dom-values\";\n\nexport interface RemoteDomReactWorkerRendererOptions {\n /**\n * The host-backed connection ({@link RemoteConnection}); its `mutate` is the\n * threads-proxied `host.mutate`. The renderer wraps it in a\n * `BatchingRemoteConnection` and flushes explicitly after every commit.\n */\n readonly connection: RemoteConnection;\n}\n\nexport interface RemoteDomReactWorkerRenderer {\n readonly render: (node: ReactNode) => void;\n readonly dispose: () => void;\n}\n\nconst REMOTE_ROOT_TAG_NAME = \"remote-root\";\n\ntype NoRemoteMembers = Record<never, never>;\ntype RemoteEventListeners = Record<string, (payload?: unknown) => unknown>;\n\nconst standardEventDefinitions = createRemoteEventDefinitions(\n SUPPORTED_REMOTE_DOM_EVENTS,\n);\nconst searchSortEventDefinitions = {\n ...standardEventDefinitions,\n ...createRemoteEventDefinitions(REMOTE_DOM_SEARCH_SORT_EVENTS),\n};\n\nconst FluidRemoteElement = createRemoteElement<\n NoRemoteMembers,\n NoRemoteMembers,\n NoRemoteMembers,\n RemoteEventListeners\n>({ events: standardEventDefinitions });\n\ninterface RemoteInputProperties {\n readonly checked: boolean;\n readonly type: string;\n readonly value: string;\n}\n\nconst RemoteInputElement = createRemoteElement<\n RemoteInputProperties,\n NoRemoteMembers,\n NoRemoteMembers,\n RemoteEventListeners\n>({\n events: standardEventDefinitions,\n properties: {\n checked: { attribute: false, default: false },\n type: { attribute: true, default: \"text\" },\n value: { attribute: false, default: \"\" },\n },\n});\n\nclass FluidRemoteInputElement extends RemoteInputElement {\n applyHostState(detail: Readonly<Record<string, unknown>>): void {\n // React wraps public input setters with its value tracker. Update Remote\n // DOM's upstream property cache directly so the following native event is\n // extracted, while still synchronizing the host-controlled value.\n const value = readSerializableString(detail, \"value\");\n if (value !== undefined) this.updateRemoteProperty(\"value\", value);\n\n const checked = detail.checked;\n if (typeof checked === \"boolean\") {\n this.updateRemoteProperty(\"checked\", checked);\n }\n }\n}\n\ninterface RemoteSearchSortOption {\n readonly label: string;\n readonly value: string;\n}\n\ninterface RemoteSearchSortProperties {\n readonly placeholder: string | undefined;\n readonly searchValue: string;\n readonly sortOptions: readonly RemoteSearchSortOption[] | undefined;\n readonly sortValue: string | undefined;\n}\n\nconst FluidRemoteSearchSortElement = createRemoteElement<\n RemoteSearchSortProperties,\n NoRemoteMembers,\n NoRemoteMembers,\n RemoteEventListeners\n>({\n events: searchSortEventDefinitions,\n properties: {\n placeholder: { attribute: false },\n searchValue: { attribute: false, default: \"\" },\n sortOptions: { attribute: false },\n sortValue: { attribute: false },\n },\n});\n\ninterface RemoteSpacerProperties {\n readonly customHeight: string | undefined;\n readonly previewMode: boolean;\n}\n\nconst FluidRemoteSpacerWidgetElement = createRemoteElement<\n RemoteSpacerProperties,\n NoRemoteMembers,\n NoRemoteMembers,\n RemoteEventListeners\n>({\n events: standardEventDefinitions,\n properties: {\n customHeight: { attribute: false },\n previewMode: { attribute: false, default: false },\n },\n});\n\nlet remoteElementsRegistered = false;\n\nexport function createRemoteDomReactWorkerRenderer({\n connection,\n}: RemoteDomReactWorkerRendererOptions): RemoteDomReactWorkerRenderer {\n registerRemoteElements();\n\n const remoteRoot = document.createElement(\n REMOTE_ROOT_TAG_NAME,\n ) as RemoteRootElement;\n const batchedConnection = new BatchingRemoteConnection(connection);\n remoteRoot.connect(batchedConnection);\n const reactRoot: Root = createRoot(remoteRoot);\n // Remote DOM installs bubbling event proxies from custom-element lifecycle\n // callbacks. Keep the remote tree connected to its synthetic document so\n // those callbacks run for every element React mounts.\n try {\n document.body.append(remoteRoot);\n } catch (error) {\n reactRoot.unmount();\n throw error;\n }\n let disposed = false;\n\n return {\n render(node) {\n flushSync(() => {\n reactRoot.render(node);\n });\n // The host must never observe a capability/event side effect before the\n // DOM it references, so force mutations out immediately after commit.\n batchedConnection.flush();\n },\n dispose() {\n if (disposed) return;\n disposed = true;\n const cleanupErrors: unknown[] = [];\n\n try {\n flushSync(() => {\n reactRoot.unmount();\n });\n } catch (error) {\n cleanupErrors.push(error);\n }\n try {\n remoteRoot.remove();\n } catch (error) {\n cleanupErrors.push(error);\n }\n try {\n batchedConnection.flush();\n } catch (error) {\n cleanupErrors.push(error);\n }\n\n if (cleanupErrors.length > 0) {\n throw new AggregateError(\n cleanupErrors,\n \"Remote DOM React session cleanup failed.\",\n );\n }\n },\n };\n}\n\nfunction registerRemoteElements(): void {\n if (remoteElementsRegistered) return;\n remoteElementsRegistered = true;\n\n defineRemoteElement(REMOTE_ROOT_TAG_NAME, RemoteRootElement);\n for (const tagName of REMOTE_DOM_ALLOWED_TAG_NAMES) {\n if (\n tagName === FLUID_SEARCH_SORT_TAG_NAME ||\n tagName === FLUID_SPACER_WIDGET_TAG_NAME\n ) {\n continue;\n }\n defineRemoteElement(\n tagName,\n tagName === \"input\" ? FluidRemoteInputElement : FluidRemoteElement,\n );\n }\n defineRemoteElement(FLUID_SEARCH_SORT_TAG_NAME, FluidRemoteSearchSortElement);\n defineRemoteElement(\n FLUID_SPACER_WIDGET_TAG_NAME,\n FluidRemoteSpacerWidgetElement,\n );\n}\n\nfunction defineRemoteElement(\n tagName: string,\n constructor: CustomElementConstructor,\n): void {\n if (customElements.get(tagName)) return;\n customElements.define(tagName, constructor);\n}\n\nfunction createRemoteEventDefinitions(\n eventNames: readonly string[],\n): Readonly<Record<string, RemoteElementEventListenerDefinition>> {\n return Object.fromEntries(\n eventNames.map((eventName) => [\n eventName,\n {\n bubbles: true,\n dispatchEvent(this: Element, payload?: unknown) {\n const detail = readHostEventDetail(payload);\n if (\n this instanceof FluidRemoteInputElement &&\n isObjectRecord(detail)\n ) {\n this.applyHostState(detail);\n }\n return createRemoteDomReactEvent(eventName, detail);\n },\n },\n ]),\n );\n}\n\nfunction readHostEventDetail(\n payload: unknown,\n): RemoteDomSerializableValue | undefined {\n if (!isObjectRecord(payload)) return undefined;\n const detail = payload.detail;\n return isRemoteDomSerializableValue(detail) ? detail : undefined;\n}\n\nfunction createRemoteDomReactEvent(\n eventName: string,\n detail: RemoteDomSerializableValue | undefined,\n): Event {\n const customDetail = parseCustomEventDetail(eventName, detail);\n const event = new CustomEvent(eventName, {\n bubbles: true,\n cancelable: true,\n detail: customDetail.ok ? customDetail.value : detail,\n });\n if (!isObjectRecord(detail)) return event;\n\n const key = readSerializableString(detail, \"key\");\n if (key !== undefined) setObjectProperty(event, \"key\", key);\n\n const eventType = readSerializableString(detail, \"type\");\n if (eventType !== undefined) setObjectProperty(event, \"inputType\", eventType);\n\n return event;\n}\n\nfunction parseCustomEventDetail(\n eventName: string,\n detail: RemoteDomSerializableValue | undefined,\n):\n | { readonly ok: true; readonly value: RemoteDomSerializableValue }\n | { readonly ok: false } {\n if (!isSearchSortEvent(eventName) || !isObjectRecord(detail)) {\n return { ok: false };\n }\n const detailJson = detail.detailJson;\n if (typeof detailJson !== \"string\") return { ok: false };\n\n try {\n const value: unknown = JSON.parse(detailJson);\n return isRemoteDomSerializableValue(value)\n ? { ok: true, value }\n : { ok: false };\n } catch {\n return { ok: false };\n }\n}\n\nfunction isSearchSortEvent(eventName: string): boolean {\n return REMOTE_DOM_SEARCH_SORT_EVENTS.some(\n (candidate) => candidate === eventName,\n );\n}\n\nfunction readSerializableString(\n detail: Readonly<Record<string, unknown>>,\n key: string,\n): string | undefined {\n const value = detail[key];\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction setObjectProperty(target: object, key: string, value: unknown): void {\n Object.defineProperty(target, key, {\n configurable: true,\n enumerable: true,\n value,\n writable: true,\n });\n}\n\nfunction isObjectRecord(\n value: unknown,\n): value is Readonly<Record<string, unknown>> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n"],"mappings":"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"}
|