@graview/guest 0.1.6 → 0.1.8
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 +86 -0
- package/dist/build.d.ts +43 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +117 -0
- package/dist/build.js.map +1 -0
- package/dist/channel.d.ts +51 -0
- package/dist/channel.d.ts.map +1 -0
- package/dist/channel.js +105 -0
- package/dist/channel.js.map +1 -0
- package/dist/guest.d.ts +2 -22
- package/dist/guest.d.ts.map +1 -1
- package/dist/guest.js +8 -89
- package/dist/guest.js.map +1 -1
- package/dist/host/frame.d.ts.map +1 -1
- package/dist/host/frame.js +1 -6
- package/dist/host/frame.js.map +1 -1
- package/dist/host/index.d.ts +3 -0
- package/dist/host/index.d.ts.map +1 -1
- package/dist/host/index.js.map +1 -1
- package/dist/host/kit.d.ts +85 -0
- package/dist/host/kit.d.ts.map +1 -0
- package/dist/host/kit.js +344 -0
- package/dist/host/kit.js.map +1 -0
- package/dist/host/nonce.d.ts +3 -0
- package/dist/host/nonce.d.ts.map +1 -0
- package/dist/host/nonce.js +7 -0
- package/dist/host/nonce.js.map +1 -0
- package/dist/host/react.d.ts +16 -5
- package/dist/host/react.d.ts.map +1 -1
- package/dist/host/react.js +31 -3
- package/dist/host/react.js.map +1 -1
- package/dist/host/session.d.ts +6 -0
- package/dist/host/session.d.ts.map +1 -1
- package/dist/host/session.js +4 -0
- package/dist/host/session.js.map +1 -1
- package/dist/host/worker.d.ts +96 -0
- package/dist/host/worker.d.ts.map +1 -0
- package/dist/host/worker.js +195 -0
- package/dist/host/worker.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/kit.d.ts +202 -0
- package/dist/kit.d.ts.map +1 -0
- package/dist/kit.js +69 -0
- package/dist/kit.js.map +1 -0
- package/dist/protocol.d.ts +48 -1
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +20 -0
- package/dist/protocol.js.map +1 -1
- package/dist/worker/elements.d.ts +11 -0
- package/dist/worker/elements.d.ts.map +1 -0
- package/dist/worker/elements.js +28 -0
- package/dist/worker/elements.js.map +1 -0
- package/dist/worker/harden.d.ts +39 -0
- package/dist/worker/harden.d.ts.map +1 -0
- package/dist/worker/harden.js +175 -0
- package/dist/worker/harden.js.map +1 -0
- package/dist/worker/index.d.ts +32 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker/index.js +92 -0
- package/dist/worker/index.js.map +1 -0
- package/dist/worker/listeners.d.ts +19 -0
- package/dist/worker/listeners.d.ts.map +1 -0
- package/dist/worker/listeners.js +157 -0
- package/dist/worker/listeners.js.map +1 -0
- package/dist/worker/natives.d.ts +7 -0
- package/dist/worker/natives.d.ts.map +1 -0
- package/dist/worker/natives.js +12 -0
- package/dist/worker/natives.js.map +1 -0
- package/package.json +30 -7
package/dist/kit.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE COMPONENT KIT A WORKER GUEST DRAWS WITH (FR-69), declared once.
|
|
3
|
+
*
|
|
4
|
+
* A guest in a worker has no DOM of its own: it builds a tree of these
|
|
5
|
+
* elements with Remote DOM, and the host draws it in its own document. The
|
|
6
|
+
* kit is Tier 1's closed set of blocks (FR-03: title, text, badge, field,
|
|
7
|
+
* progress, group, divider), plus the few a view that asks for acts needs —
|
|
8
|
+
* a card to hold them, a button, an input, and a link.
|
|
9
|
+
*
|
|
10
|
+
* Each component says, once, its typed properties and its events. The
|
|
11
|
+
* worker side defines one `RemoteElement` per component from it
|
|
12
|
+
* (worker/elements.ts), and the host side draws from it (host/kit.ts): only
|
|
13
|
+
* a component in the kit, only a property or event it declares, only a
|
|
14
|
+
* value of the declared type, and a `url` only when it is `https:`. Adding
|
|
15
|
+
* a property here makes it a property on both sides; nothing else changes.
|
|
16
|
+
*
|
|
17
|
+
* This module has no imports: a guest bundle carries it and nothing of the
|
|
18
|
+
* framework.
|
|
19
|
+
*/
|
|
20
|
+
/** The tones a block may take: FR-03's own (`VIEW_TONES` in @graview/core/document, held to it by a test). */
|
|
21
|
+
export const KIT_TONES = ["good", "warn", "bad", "neutral", "accent"];
|
|
22
|
+
/**
|
|
23
|
+
* The host attributes a property may be drawn as, besides the default
|
|
24
|
+
* `data-gv-<name>`. A closed list: never an event handler, a style, a
|
|
25
|
+
* source or a frame.
|
|
26
|
+
*/
|
|
27
|
+
export const KIT_HOST_ATTRIBUTES = ["value", "max", "aria-label", "placeholder", "disabled"];
|
|
28
|
+
/** The DOM events a kit event may come from, on the element the host drew. */
|
|
29
|
+
export const KIT_HOST_EVENTS = ["click", "change"];
|
|
30
|
+
/**
|
|
31
|
+
* Where a link may open. A new tab (`_blank`) unless the kit says
|
|
32
|
+
* otherwise; never `_top` or `_parent`, which would take the host's page.
|
|
33
|
+
*/
|
|
34
|
+
export const KIT_LINK_TARGETS = ["_blank", "_self"];
|
|
35
|
+
/** The host elements a component may be drawn as. */
|
|
36
|
+
export const KIT_HOST_TAGS = ["section", "div", "span", "strong", "p", "hr", "a", "button", "input", "progress"];
|
|
37
|
+
const tone = { type: { oneOf: KIT_TONES } };
|
|
38
|
+
/** The kit, by element name. Every name starts `gv-`. */
|
|
39
|
+
export const GUEST_KIT = {
|
|
40
|
+
"gv-card": { host: "section", properties: { tone }, events: {}, children: "any" },
|
|
41
|
+
"gv-group": { host: "div", properties: { direction: { type: { oneOf: ["row", "column"] } } }, events: {}, children: "any" },
|
|
42
|
+
"gv-title": { host: "strong", properties: {}, events: {}, children: "text" },
|
|
43
|
+
"gv-text": { host: "p", properties: { tone }, events: {}, children: "text" },
|
|
44
|
+
"gv-badge": { host: "span", properties: { tone }, events: {}, children: "text" },
|
|
45
|
+
"gv-field": { host: "div", properties: { label: { type: "string" } }, events: {}, children: "text" },
|
|
46
|
+
"gv-progress": {
|
|
47
|
+
host: "progress",
|
|
48
|
+
properties: { value: { type: "number", as: "value" }, max: { type: "number", as: "max" }, label: { type: "string", as: "aria-label" } },
|
|
49
|
+
events: {},
|
|
50
|
+
children: "none",
|
|
51
|
+
},
|
|
52
|
+
"gv-divider": { host: "hr", properties: {}, events: {}, children: "none" },
|
|
53
|
+
"gv-link": { host: "a", properties: { href: { type: "url" } }, events: {}, children: "text" },
|
|
54
|
+
"gv-button": {
|
|
55
|
+
host: "button",
|
|
56
|
+
properties: { tone, disabled: { type: "boolean", as: "disabled" } },
|
|
57
|
+
events: { press: { from: "click" } },
|
|
58
|
+
children: "text",
|
|
59
|
+
},
|
|
60
|
+
"gv-input": {
|
|
61
|
+
host: "input",
|
|
62
|
+
properties: { label: { type: "string", as: "aria-label" }, value: { type: "string", as: "value" }, placeholder: { type: "string", as: "placeholder" } },
|
|
63
|
+
events: { change: { from: "change", detail: "value" } },
|
|
64
|
+
children: "none",
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
/** The longest text a kit node may hold, in characters; longer is cut. */
|
|
68
|
+
export const KIT_MAX_TEXT = 10_000;
|
|
69
|
+
//# sourceMappingURL=kit.js.map
|
package/dist/kit.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kit.js","sourceRoot":"","sources":["../src/kit.ts"],"names":[],"mappings":"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"}
|
package/dist/protocol.d.ts
CHANGED
|
@@ -15,6 +15,26 @@
|
|
|
15
15
|
* guest → host { type: "size", nonce, height } (over the port: the height it wants)
|
|
16
16
|
* host → guest { type: "answer", id, ok, … } (over the port: what became of an act)
|
|
17
17
|
*
|
|
18
|
+
* A GUEST IN A WORKER (FR-68) says the same things. Its `guest-ready` goes
|
|
19
|
+
* to the worker's owner (`self.postMessage`), which is the host by
|
|
20
|
+
* construction, and the hello comes back the same way with the port. A
|
|
21
|
+
* worker has no DOM of its own to draw in, so it draws in the host's, from
|
|
22
|
+
* the component kit alone (kit.ts):
|
|
23
|
+
*
|
|
24
|
+
* guest → host { type: "render", nonce, records } (over the port: Remote DOM mutation records)
|
|
25
|
+
* host → guest { type: "event", listener, detail } (over the port: a kit event the viewer raised)
|
|
26
|
+
*
|
|
27
|
+
* A frame guest never sends `render`; a host that is not drawing a worker
|
|
28
|
+
* drops it unread.
|
|
29
|
+
*
|
|
30
|
+
* A worker's host also watches that the worker is alive. Its runtime — not
|
|
31
|
+
* the guest's code, which can stop it only by blocking its own event loop —
|
|
32
|
+
* answers each heartbeat with the beat it was asked, and a worker that goes
|
|
33
|
+
* `limits.silentMs` without an answer is stopped:
|
|
34
|
+
*
|
|
35
|
+
* host → guest { type: "heartbeat", beat } (over the port, on an interval)
|
|
36
|
+
* guest → host { type: "heartbeat", nonce, beat } (over the port: the runtime's answer)
|
|
37
|
+
*
|
|
18
38
|
* The host answers a `guest-ready` only from its own frame's window and
|
|
19
39
|
* only from the opaque origin, and every request over the port carries the
|
|
20
40
|
* nonce of that hello. What the guest is pushed is the store as the viewer
|
|
@@ -112,10 +132,25 @@ export interface HostHello {
|
|
|
112
132
|
readonly nonce: string;
|
|
113
133
|
readonly view: string;
|
|
114
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* A kit event the viewer raised on something a worker guest drew: which of
|
|
137
|
+
* the guest's listeners to call, and the one plain value the kit declares
|
|
138
|
+
* for it (an input's text), if any.
|
|
139
|
+
*/
|
|
140
|
+
export interface GuestEvent {
|
|
141
|
+
readonly type: "event";
|
|
142
|
+
readonly listener: number;
|
|
143
|
+
readonly detail?: string | number | boolean | null;
|
|
144
|
+
}
|
|
145
|
+
/** The host asking a worker guest's runtime whether it is still answering. */
|
|
146
|
+
export interface HostHeartbeat {
|
|
147
|
+
readonly type: "heartbeat";
|
|
148
|
+
readonly beat: number;
|
|
149
|
+
}
|
|
115
150
|
export type HostMessage = {
|
|
116
151
|
readonly type: "props";
|
|
117
152
|
readonly props: GuestProps;
|
|
118
|
-
} | GuestAnswer;
|
|
153
|
+
} | GuestAnswer | GuestEvent | HostHeartbeat;
|
|
119
154
|
export type GuestRequest = {
|
|
120
155
|
readonly type: "act";
|
|
121
156
|
readonly nonce: string;
|
|
@@ -130,6 +165,18 @@ export type GuestRequest = {
|
|
|
130
165
|
readonly type: "size";
|
|
131
166
|
readonly nonce: string;
|
|
132
167
|
readonly height: number;
|
|
168
|
+
}
|
|
169
|
+
/** A worker guest's drawing: Remote DOM mutation records, with each listener sent as `{ listener: id }`. */
|
|
170
|
+
| {
|
|
171
|
+
readonly type: "render";
|
|
172
|
+
readonly nonce: string;
|
|
173
|
+
readonly records: readonly unknown[];
|
|
174
|
+
}
|
|
175
|
+
/** The runtime's answer to a heartbeat, with the beat it was asked. */
|
|
176
|
+
| {
|
|
177
|
+
readonly type: "heartbeat";
|
|
178
|
+
readonly nonce: string;
|
|
179
|
+
readonly beat: number;
|
|
133
180
|
};
|
|
134
181
|
/** Whether a window message is a guest saying it is ready. */
|
|
135
182
|
export declare function isGuestReady(data: unknown): data is GuestReady;
|
package/dist/protocol.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
|
package/dist/protocol.js
CHANGED
|
@@ -15,6 +15,26 @@
|
|
|
15
15
|
* guest → host { type: "size", nonce, height } (over the port: the height it wants)
|
|
16
16
|
* host → guest { type: "answer", id, ok, … } (over the port: what became of an act)
|
|
17
17
|
*
|
|
18
|
+
* A GUEST IN A WORKER (FR-68) says the same things. Its `guest-ready` goes
|
|
19
|
+
* to the worker's owner (`self.postMessage`), which is the host by
|
|
20
|
+
* construction, and the hello comes back the same way with the port. A
|
|
21
|
+
* worker has no DOM of its own to draw in, so it draws in the host's, from
|
|
22
|
+
* the component kit alone (kit.ts):
|
|
23
|
+
*
|
|
24
|
+
* guest → host { type: "render", nonce, records } (over the port: Remote DOM mutation records)
|
|
25
|
+
* host → guest { type: "event", listener, detail } (over the port: a kit event the viewer raised)
|
|
26
|
+
*
|
|
27
|
+
* A frame guest never sends `render`; a host that is not drawing a worker
|
|
28
|
+
* drops it unread.
|
|
29
|
+
*
|
|
30
|
+
* A worker's host also watches that the worker is alive. Its runtime — not
|
|
31
|
+
* the guest's code, which can stop it only by blocking its own event loop —
|
|
32
|
+
* answers each heartbeat with the beat it was asked, and a worker that goes
|
|
33
|
+
* `limits.silentMs` without an answer is stopped:
|
|
34
|
+
*
|
|
35
|
+
* host → guest { type: "heartbeat", beat } (over the port, on an interval)
|
|
36
|
+
* guest → host { type: "heartbeat", nonce, beat } (over the port: the runtime's answer)
|
|
37
|
+
*
|
|
18
38
|
* The host answers a `guest-ready` only from its own frame's window and
|
|
19
39
|
* only from the opaque origin, and every request over the port carries the
|
|
20
40
|
* nonce of that hello. What the guest is pushed is the store as the viewer
|
package/dist/protocol.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,gFAAgF;AAChF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;AAEhC,gFAAgF;AAChF,MAAM,CAAC,MAAM,aAAa,GAAG,eAAe,CAAC;AAE7C,2EAA2E;AAC3E,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC;AA4GpC,8DAA8D;AAC9D,MAAM,UAAU,YAAY,CAAC,IAAa;IACxC,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAK,IAAmB,CAAC,OAAO,KAAK,aAAa,CAAC;AACrG,CAAC;AAED,oDAAoD;AACpD,MAAM,UAAU,WAAW,CAAC,IAAa;IACvC,MAAM,KAAK,GAAG,IAAiB,CAAC;IAChC,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,KAAK,YAAY,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,CAAC;AACxH,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Kit, KitComponent } from "../kit.js";
|
|
2
|
+
/**
|
|
3
|
+
* ONE COMPONENT OF THE KIT, AS A REMOTE ELEMENT: its declared properties
|
|
4
|
+
* (each also settable as an attribute of the same name) and its declared
|
|
5
|
+
* events, and nothing else. What it says goes to the host as mutation
|
|
6
|
+
* records, and the host draws only what the same declaration allows.
|
|
7
|
+
*/
|
|
8
|
+
export declare function kitElement(component: KitComponent): CustomElementConstructor;
|
|
9
|
+
/** Define every component of a kit in a registry, by its element name. */
|
|
10
|
+
export declare function defineKit(kit: Kit, registry?: CustomElementRegistry): void;
|
|
11
|
+
//# sourceMappingURL=elements.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elements.d.ts","sourceRoot":"","sources":["../../src/worker/elements.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,YAAY,EAAmB,MAAM,WAAW,CAAC;AAKpE;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,YAAY,GAAG,wBAAwB,CAU5E;AAED,0EAA0E;AAC1E,wBAAgB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,GAAE,qBAAsC,GAAG,IAAI,CAI1F"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { RemoteElement } from "@remote-dom/core/elements";
|
|
2
|
+
/** The Remote DOM type a kit property is kept as on the worker's side. */
|
|
3
|
+
const remoteType = (type) => (type === "number" ? Number : type === "boolean" ? Boolean : String);
|
|
4
|
+
/**
|
|
5
|
+
* ONE COMPONENT OF THE KIT, AS A REMOTE ELEMENT: its declared properties
|
|
6
|
+
* (each also settable as an attribute of the same name) and its declared
|
|
7
|
+
* events, and nothing else. What it says goes to the host as mutation
|
|
8
|
+
* records, and the host draws only what the same declaration allows.
|
|
9
|
+
*/
|
|
10
|
+
export function kitElement(component) {
|
|
11
|
+
const properties = Object.fromEntries(Object.entries(component.properties).map(([name, property]) => [name, { type: remoteType(property.type), attribute: true }]));
|
|
12
|
+
const events = Object.keys(component.events);
|
|
13
|
+
class KitElement extends RemoteElement {
|
|
14
|
+
/* A kit element is never slotted: the host has no slots to put it in. */
|
|
15
|
+
static slottable = false;
|
|
16
|
+
static remoteProperties = properties;
|
|
17
|
+
static remoteEvents = events;
|
|
18
|
+
}
|
|
19
|
+
return KitElement;
|
|
20
|
+
}
|
|
21
|
+
/** Define every component of a kit in a registry, by its element name. */
|
|
22
|
+
export function defineKit(kit, registry = customElements) {
|
|
23
|
+
for (const [name, component] of Object.entries(kit)) {
|
|
24
|
+
if (!registry.get(name))
|
|
25
|
+
registry.define(name, kitElement(component));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=elements.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elements.js","sourceRoot":"","sources":["../../src/worker/elements.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAG1D,0EAA0E;AAC1E,MAAM,UAAU,GAAG,CAAC,IAAqB,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnH;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,SAAuB;IAChD,MAAM,UAAU,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACpK,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC7C,MAAM,UAAW,SAAQ,aAAa;QACpC,yEAAyE;QACzE,MAAM,CAAmB,SAAS,GAAG,KAAc,CAAC;QACpD,MAAM,CAAmB,gBAAgB,GAAG,UAAU,CAAC;QACvD,MAAM,CAAmB,YAAY,GAAG,MAAM,CAAC;;IAEjD,OAAO,UAAiD,CAAC;AAC3D,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,SAAS,CAAC,GAAQ,EAAE,WAAkC,cAAc;IAClF,KAAK,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACpD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;IACxE,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** The language's own globals: ECMAScript, ES2025 and the proposals engines already ship. */
|
|
2
|
+
export declare const LANGUAGE: readonly ["globalThis", "Infinity", "NaN", "undefined", "isFinite", "isNaN", "parseFloat", "parseInt", "decodeURI", "decodeURIComponent", "encodeURI", "encodeURIComponent", "escape", "unescape", "Object", "Function", "Array", "Number", "Boolean", "String", "Symbol", "BigInt", "Date", "Promise", "RegExp", "Math", "JSON", "Reflect", "Proxy", "Intl", "Error", "AggregateError", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", "URIError", "SuppressedError", "Map", "Set", "WeakMap", "WeakSet", "WeakRef", "FinalizationRegistry", "Iterator", "AsyncIterator", "DisposableStack", "AsyncDisposableStack", "ArrayBuffer", "SharedArrayBuffer", "DataView", "Atomics", "Int8Array", "Uint8Array", "Uint8ClampedArray", "Int16Array", "Uint16Array", "Int32Array", "Uint32Array", "Float16Array", "Float32Array", "Float64Array", "BigInt64Array", "BigUint64Array"];
|
|
3
|
+
/** What Remote DOM's polyfill puts on the global: a document to build in, and the classes of what it builds. */
|
|
4
|
+
export declare const POLYFILLED_DOM: readonly ["window", "parent", "top", "document", "customElements", "Event", "ErrorEvent", "PromiseRejectionEvent", "ToggleEvent", "FocusEvent", "ClipboardEvent", "CustomEvent", "EventTarget", "Node", "ParentNode", "ChildNode", "DocumentFragment", "Document", "CharacterData", "Comment", "Text", "Element", "HTMLElement", "SVGElement", "HTMLTemplateElement", "MutationObserver"];
|
|
5
|
+
/** The platform's few that stay (see the top of this module for why each). */
|
|
6
|
+
export declare const PLATFORM: readonly ["self", "postMessage", "setTimeout", "clearTimeout", "setInterval", "clearInterval", "queueMicrotask", "structuredClone", "crypto", "console", "DOMException"];
|
|
7
|
+
/**
|
|
8
|
+
* Numbers an engine will not let go: Chromium's worker global defines
|
|
9
|
+
* `TEMPORARY` (0) and `PERSISTENT` (1), the constants of the FileSystem API
|
|
10
|
+
* it no longer ships, as non-configurable. They are numbers and hand back
|
|
11
|
+
* nothing, so they may stay — only while they are numbers; anything else
|
|
12
|
+
* by these names is removed or stops the worker.
|
|
13
|
+
*/
|
|
14
|
+
export declare const INERT: readonly ["TEMPORARY", "PERSISTENT"];
|
|
15
|
+
/**
|
|
16
|
+
* EVERY NAME A GUEST'S WORKER GLOBAL MAY HAVE, on the global or any
|
|
17
|
+
* prototype on its chain before `Object.prototype` (where a prototype's
|
|
18
|
+
* `constructor` and `Symbol.toStringTag` stay too). Anything else is
|
|
19
|
+
* removed before the guest runs.
|
|
20
|
+
*/
|
|
21
|
+
export declare const GUEST_GLOBALS: readonly string[];
|
|
22
|
+
/** What `Object.prototype` holds in every engine; it is the language's, and the walk does not touch it. */
|
|
23
|
+
export declare const OBJECT_PROTOTYPE: readonly string[];
|
|
24
|
+
/** What hardening did: every name it took, and any it could not. */
|
|
25
|
+
export interface Hardening {
|
|
26
|
+
readonly removed: readonly string[];
|
|
27
|
+
/** Names outside the allowlist that could not be removed. Empty, or the worker is not hardened. */
|
|
28
|
+
readonly stuck: readonly string[];
|
|
29
|
+
/** Whether the global takes no new names. Where the engine refuses, a guest can add its own, which reach nothing removed. */
|
|
30
|
+
readonly sealed: boolean;
|
|
31
|
+
/** False when the runtime is not in a worker, and so hardened nothing. */
|
|
32
|
+
readonly worker?: false;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* HARDEN A WORKER'S GLOBAL before guest code runs. Called once by the
|
|
36
|
+
* worker entry, after Remote DOM's polyfill and the kit are in place.
|
|
37
|
+
*/
|
|
38
|
+
export declare function harden(scope?: typeof globalThis): Hardening;
|
|
39
|
+
//# sourceMappingURL=harden.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harden.d.ts","sourceRoot":"","sources":["../../src/worker/harden.ts"],"names":[],"mappings":"AA0CA,6FAA6F;AAC7F,eAAO,MAAM,QAAQ,y2BAQX,CAAC;AAEX,gHAAgH;AAChH,eAAO,MAAM,cAAc,2XAIjB,CAAC;AAEX,8EAA8E;AAC9E,eAAO,MAAM,QAAQ,0KAA2K,CAAC;AAEjM;;;;;;GAMG;AACH,eAAO,MAAM,KAAK,sCAAuC,CAAC;AAE1D;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,MAAM,EAA2E,CAAC;AAEvH,2GAA2G;AAC3G,eAAO,MAAM,gBAAgB,EAAE,SAAS,MAAM,EAG5C,CAAC;AAEH,oEAAoE;AACpE,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,mGAAmG;IACnG,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,6HAA6H;IAC7H,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,0EAA0E;IAC1E,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC;CACzB;AAID;;;GAGG;AACH,wBAAgB,MAAM,CAAC,KAAK,GAAE,OAAO,UAAuB,GAAG,SAAS,CAoFvE"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* A HARDENED WORKER (FR-70).
|
|
3
|
+
*
|
|
4
|
+
* A worker's policy and origin are the host's to set, and on ChatGPT the
|
|
5
|
+
* origin is shared by every widget an app's connector shows: Graview
|
|
6
|
+
* Cloud's spike watched one view's worker plant IndexedDB and Cache Storage
|
|
7
|
+
* data that a second view's worker read, and ChatGPT's `connect-src` always
|
|
8
|
+
* names a list of public CDNs. So before any guest code runs, the runtime
|
|
9
|
+
* takes from the worker's global everything outside a short allowlist —
|
|
10
|
+
* the network, storage, channels, nested workers, more code — from the
|
|
11
|
+
* global itself and from every prototype on its chain, so no reference is
|
|
12
|
+
* left to recover them by, and makes what is left stay as it is.
|
|
13
|
+
*
|
|
14
|
+
* What stays, and why:
|
|
15
|
+
*
|
|
16
|
+
* the language Object, Array, Promise, JSON, Intl, the typed arrays, … (LANGUAGE)
|
|
17
|
+
* postMessage it reaches only the worker's owner, the host, which drops all but one ready
|
|
18
|
+
* timers setTimeout and setInterval refuse a string, which would be code from text
|
|
19
|
+
* queueMicrotask, structuredClone
|
|
20
|
+
* crypto as an object with getRandomValues alone
|
|
21
|
+
* console it reaches the developer's tools, nothing else; a guest's errors stay readable
|
|
22
|
+
* DOMException an error class, which the polyfill throws
|
|
23
|
+
* the polyfilled DOM Remote DOM's document, window and node classes (POLYFILLED_DOM)
|
|
24
|
+
*
|
|
25
|
+
* And what goes that a reader might expect to stay:
|
|
26
|
+
*
|
|
27
|
+
* eval, Function code from text could write `import()`, which no global's removal can take
|
|
28
|
+
* away and which reaches every origin script-src allows (ChatGPT's CDNs, or in
|
|
29
|
+
* WebKit under Claude's policy any https origin). Without them a guest's code is
|
|
30
|
+
* the bundle it was built as, and the build refuses one with `import()` in it
|
|
31
|
+
* (FR-71). `Function` stays as a name, for `instanceof`, but makes nothing, and
|
|
32
|
+
* so do the async and generator function constructors.
|
|
33
|
+
* performance a fine clock, which is a side channel and draws nothing
|
|
34
|
+
* addEventListener, onmessage, onerror, close, name, location, navigator, self.fonts, WebAssembly, …
|
|
35
|
+
*
|
|
36
|
+
* The removal is deletion in the same realm, so it holds only while no
|
|
37
|
+
* remaining API can hand back what was removed. The allowlist is what keeps
|
|
38
|
+
* that true as browsers add APIs: a name not on it goes, whatever it is.
|
|
39
|
+
* `scripts/guest-sandbox.mjs` enumerates the worker's global in Chromium and
|
|
40
|
+
* WebKit and fails on any name outside it, and tries the ways back.
|
|
41
|
+
*/
|
|
42
|
+
/** The language's own globals: ECMAScript, ES2025 and the proposals engines already ship. */
|
|
43
|
+
export const LANGUAGE = [
|
|
44
|
+
"globalThis", "Infinity", "NaN", "undefined", "isFinite", "isNaN", "parseFloat", "parseInt",
|
|
45
|
+
"decodeURI", "decodeURIComponent", "encodeURI", "encodeURIComponent", "escape", "unescape",
|
|
46
|
+
"Object", "Function", "Array", "Number", "Boolean", "String", "Symbol", "BigInt", "Date", "Promise", "RegExp", "Math", "JSON", "Reflect", "Proxy", "Intl",
|
|
47
|
+
"Error", "AggregateError", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", "URIError", "SuppressedError",
|
|
48
|
+
"Map", "Set", "WeakMap", "WeakSet", "WeakRef", "FinalizationRegistry", "Iterator", "AsyncIterator", "DisposableStack", "AsyncDisposableStack",
|
|
49
|
+
"ArrayBuffer", "SharedArrayBuffer", "DataView", "Atomics",
|
|
50
|
+
"Int8Array", "Uint8Array", "Uint8ClampedArray", "Int16Array", "Uint16Array", "Int32Array", "Uint32Array", "Float16Array", "Float32Array", "Float64Array", "BigInt64Array", "BigUint64Array",
|
|
51
|
+
];
|
|
52
|
+
/** What Remote DOM's polyfill puts on the global: a document to build in, and the classes of what it builds. */
|
|
53
|
+
export const POLYFILLED_DOM = [
|
|
54
|
+
"window", "parent", "top", "document", "customElements",
|
|
55
|
+
"Event", "ErrorEvent", "PromiseRejectionEvent", "ToggleEvent", "FocusEvent", "ClipboardEvent", "CustomEvent", "EventTarget",
|
|
56
|
+
"Node", "ParentNode", "ChildNode", "DocumentFragment", "Document", "CharacterData", "Comment", "Text", "Element", "HTMLElement", "SVGElement", "HTMLTemplateElement", "MutationObserver",
|
|
57
|
+
];
|
|
58
|
+
/** The platform's few that stay (see the top of this module for why each). */
|
|
59
|
+
export const PLATFORM = ["self", "postMessage", "setTimeout", "clearTimeout", "setInterval", "clearInterval", "queueMicrotask", "structuredClone", "crypto", "console", "DOMException"];
|
|
60
|
+
/**
|
|
61
|
+
* Numbers an engine will not let go: Chromium's worker global defines
|
|
62
|
+
* `TEMPORARY` (0) and `PERSISTENT` (1), the constants of the FileSystem API
|
|
63
|
+
* it no longer ships, as non-configurable. They are numbers and hand back
|
|
64
|
+
* nothing, so they may stay — only while they are numbers; anything else
|
|
65
|
+
* by these names is removed or stops the worker.
|
|
66
|
+
*/
|
|
67
|
+
export const INERT = ["TEMPORARY", "PERSISTENT"];
|
|
68
|
+
/**
|
|
69
|
+
* EVERY NAME A GUEST'S WORKER GLOBAL MAY HAVE, on the global or any
|
|
70
|
+
* prototype on its chain before `Object.prototype` (where a prototype's
|
|
71
|
+
* `constructor` and `Symbol.toStringTag` stay too). Anything else is
|
|
72
|
+
* removed before the guest runs.
|
|
73
|
+
*/
|
|
74
|
+
export const GUEST_GLOBALS = Object.freeze([...LANGUAGE, ...POLYFILLED_DOM, ...PLATFORM, ...INERT]);
|
|
75
|
+
/** What `Object.prototype` holds in every engine; it is the language's, and the walk does not touch it. */
|
|
76
|
+
export const OBJECT_PROTOTYPE = Object.freeze([
|
|
77
|
+
"constructor", "__defineGetter__", "__defineSetter__", "hasOwnProperty", "__lookupGetter__", "__lookupSetter__",
|
|
78
|
+
"isPrototypeOf", "propertyIsEnumerable", "toString", "valueOf", "__proto__", "toLocaleString",
|
|
79
|
+
]);
|
|
80
|
+
const nameOf = (key) => (typeof key === "symbol" ? `[${key.description ?? "symbol"}]` : key);
|
|
81
|
+
/**
|
|
82
|
+
* HARDEN A WORKER'S GLOBAL before guest code runs. Called once by the
|
|
83
|
+
* worker entry, after Remote DOM's polyfill and the kit are in place.
|
|
84
|
+
*/
|
|
85
|
+
export function harden(scope = globalThis) {
|
|
86
|
+
const removed = [];
|
|
87
|
+
const stuck = [];
|
|
88
|
+
const allowed = new Set([...LANGUAGE, ...POLYFILLED_DOM, ...PLATFORM, "constructor", Symbol.toStringTag]);
|
|
89
|
+
/* A name on the inert list stays only if it will not go and holds a number that cannot be changed. */
|
|
90
|
+
const inert = (at, key) => {
|
|
91
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(at, key);
|
|
92
|
+
return INERT.includes(key) && descriptor !== undefined && "value" in descriptor && typeof descriptor.value === "number" && !descriptor.writable && !descriptor.configurable;
|
|
93
|
+
};
|
|
94
|
+
const global = scope;
|
|
95
|
+
/* Kept, but narrowed: what the guest is handed in place of the platform's own. */
|
|
96
|
+
const nativeSetTimeout = global["setTimeout"];
|
|
97
|
+
const nativeSetInterval = global["setInterval"];
|
|
98
|
+
const nativeCrypto = global["crypto"];
|
|
99
|
+
const timer = (native, name) => function (handler, ms, ...args) {
|
|
100
|
+
if (typeof handler !== "function")
|
|
101
|
+
throw new TypeError(`${name} takes a function: a guest view cannot run code from text`);
|
|
102
|
+
return native.call(scope, handler, ms, ...args);
|
|
103
|
+
};
|
|
104
|
+
const crypto = nativeCrypto ? Object.freeze({ getRandomValues: (array) => nativeCrypto.getRandomValues(array) }) : undefined;
|
|
105
|
+
/*
|
|
106
|
+
* THE POLYFILL'S WINDOW. Remote DOM's `window` (and `document.defaultView`)
|
|
107
|
+
* is an object of its own, which took the platform's `navigator` and
|
|
108
|
+
* `location` when it was made; they go from it as from the global.
|
|
109
|
+
*/
|
|
110
|
+
const view = global["document"]?.defaultView;
|
|
111
|
+
if (view && view !== global) {
|
|
112
|
+
for (const key of Reflect.ownKeys(view)) {
|
|
113
|
+
if (typeof key === "symbol" || allowed.has(key))
|
|
114
|
+
continue;
|
|
115
|
+
if (!Reflect.deleteProperty(view, key))
|
|
116
|
+
stuck.push(`window.${key}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/* THE CHAIN: the global, and every prototype up to Object.prototype. */
|
|
120
|
+
const chain = [];
|
|
121
|
+
for (let at = scope; at && at !== Object.prototype; at = Object.getPrototypeOf(at))
|
|
122
|
+
chain.push(at);
|
|
123
|
+
for (const at of chain) {
|
|
124
|
+
for (const key of Reflect.ownKeys(at)) {
|
|
125
|
+
if (allowed.has(key))
|
|
126
|
+
continue;
|
|
127
|
+
if (Reflect.deleteProperty(at, key))
|
|
128
|
+
removed.push(nameOf(key));
|
|
129
|
+
else if (!inert(at, key))
|
|
130
|
+
stuck.push(nameOf(key));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/* CODE FROM TEXT: eval went with the rest; every function constructor now refuses. */
|
|
134
|
+
const refuse = () => function Function() {
|
|
135
|
+
throw new EvalError("A guest view cannot make code from text.");
|
|
136
|
+
};
|
|
137
|
+
const prototypes = [Function.prototype, Object.getPrototypeOf(async function () { }), Object.getPrototypeOf(function* () { }), Object.getPrototypeOf(async function* () { })];
|
|
138
|
+
for (const prototype of prototypes) {
|
|
139
|
+
const stand = refuse();
|
|
140
|
+
Object.defineProperty(stand, "prototype", { value: prototype, writable: false, enumerable: false, configurable: false });
|
|
141
|
+
if (!Reflect.defineProperty(prototype, "constructor", { value: stand, writable: false, enumerable: false, configurable: false }))
|
|
142
|
+
stuck.push("Function.prototype.constructor");
|
|
143
|
+
if (prototype === Function.prototype)
|
|
144
|
+
Reflect.defineProperty(scope, "Function", { value: stand, writable: true, enumerable: false, configurable: true });
|
|
145
|
+
}
|
|
146
|
+
const keep = (name, value) => {
|
|
147
|
+
if (!Reflect.defineProperty(scope, name, { value, writable: true, enumerable: true, configurable: true }))
|
|
148
|
+
stuck.push(name);
|
|
149
|
+
};
|
|
150
|
+
keep("setTimeout", timer(nativeSetTimeout, "setTimeout"));
|
|
151
|
+
keep("setInterval", timer(nativeSetInterval, "setInterval"));
|
|
152
|
+
if (crypto)
|
|
153
|
+
keep("crypto", crypto);
|
|
154
|
+
/*
|
|
155
|
+
* MAKE IT STICK. Every prototype on the chain is frozen, every property
|
|
156
|
+
* left on the global is made non-configurable and read-only, and the
|
|
157
|
+
* global takes no new ones: what a guest finds is what stays.
|
|
158
|
+
*/
|
|
159
|
+
for (const at of chain.slice(1))
|
|
160
|
+
Object.freeze(at);
|
|
161
|
+
for (const key of Reflect.ownKeys(scope)) {
|
|
162
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(scope, key);
|
|
163
|
+
Reflect.defineProperty(scope, key, "value" in descriptor ? { ...descriptor, writable: false, configurable: false } : { ...descriptor, configurable: false });
|
|
164
|
+
}
|
|
165
|
+
/* Where an engine will not have a global made inextensible, a guest can add its own names: nothing it adds reaches anything removed. */
|
|
166
|
+
let sealed;
|
|
167
|
+
try {
|
|
168
|
+
sealed = Reflect.preventExtensions(scope);
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
sealed = false;
|
|
172
|
+
}
|
|
173
|
+
return { removed, stuck, sealed };
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=harden.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harden.js","sourceRoot":"","sources":["../../src/worker/harden.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import "@remote-dom/core/polyfill";
|
|
2
|
+
import { type Guest } from "../channel.js";
|
|
3
|
+
import { type Hardening } from "./harden.js";
|
|
4
|
+
/** The element a worker guest draws into; the host's container stands for it. */
|
|
5
|
+
export declare const GUEST_ROOT = "graview-root";
|
|
6
|
+
/**
|
|
7
|
+
* WHAT HARDENING TOOK (FR-70), before any guest code ran. Should a name
|
|
8
|
+
* outside the allowlist refuse to go, the runtime stops here: no guest
|
|
9
|
+
* code runs in a worker that is not hardened, and the host hears it fail
|
|
10
|
+
* to start rather than a guest that is not held. Outside a worker (a test
|
|
11
|
+
* of the runtime in Node) there is no worker's global to harden, and
|
|
12
|
+
* `worker` says so.
|
|
13
|
+
*/
|
|
14
|
+
export declare const hardening: Hardening;
|
|
15
|
+
/** A guest in a worker: a frame guest's channel, and the root its kit elements go in. */
|
|
16
|
+
export interface WorkerGuest extends Guest {
|
|
17
|
+
/** Append kit elements here (`document.createElement("gv-card")`, …); the host draws them. */
|
|
18
|
+
readonly root: Element;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Connect a worker guest to its host: say ready to the worker's owner,
|
|
22
|
+
* take its hello, and draw from then on through the port. One connection
|
|
23
|
+
* per worker; asking again returns it.
|
|
24
|
+
*/
|
|
25
|
+
export declare function connectGuest(): WorkerGuest;
|
|
26
|
+
export { GUEST_GLOBALS, INERT, LANGUAGE, OBJECT_PROTOTYPE, PLATFORM, POLYFILLED_DOM } from "./harden.js";
|
|
27
|
+
export type { Hardening } from "./harden.js";
|
|
28
|
+
export { GUEST_KIT, KIT_LINK_TARGETS, KIT_TONES } from "../kit.js";
|
|
29
|
+
export type { GuestKitElement, Kit, KitComponent, KitEvent, KitProperty, KitPropertyType, KitTone } from "../kit.js";
|
|
30
|
+
export type { Guest } from "../channel.js";
|
|
31
|
+
export type { GuestAct, GuestAnswer, GuestEdge, GuestNode, GuestProps, GuestRefusal } from "../protocol.js";
|
|
32
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/worker/index.ts"],"names":[],"mappings":"AAqBA,OAAO,2BAA2B,CAAC;AAEnC,OAAO,EAAa,KAAK,KAAK,EAAE,MAAM,eAAe,CAAC;AAGtD,OAAO,EAAU,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAGrD,iFAAiF;AACjF,eAAO,MAAM,UAAU,iBAAiB,CAAC;AAKzC;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,EAAE,SAAmH,CAAC;AAG5I,yFAAyF;AACzF,MAAM,WAAW,WAAY,SAAQ,KAAK;IACxC,8FAA8F;IAC9F,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB;AAID;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,WAAW,CA6C1C;AAED,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACzG,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACnE,YAAY,EAAE,eAAe,EAAE,GAAG,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACrH,YAAY,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* A GUEST VIEW IN A WORKER (FR-68): `@graview/guest/worker`.
|
|
3
|
+
*
|
|
4
|
+
* Where a frame cannot be nested — a chat's widget, whose own sandbox will
|
|
5
|
+
* not frame another origin — a view somebody else wrote runs in a classic
|
|
6
|
+
* Web Worker the host starts from a `blob:` URL. This entry is the guest's
|
|
7
|
+
* whole runtime there, and it must be the first thing the worker runs:
|
|
8
|
+
*
|
|
9
|
+
* 1. it keeps, for itself, how to hear the host and say ready (natives.ts);
|
|
10
|
+
* 2. it boots Remote DOM's DOM polyfill, so the guest has a `document`;
|
|
11
|
+
* 3. it defines the component kit as remote elements (kit.ts, elements.ts);
|
|
12
|
+
* 4. it hardens the worker's global before guest code runs (harden.ts),
|
|
13
|
+
* and stops if it cannot;
|
|
14
|
+
* 5. it offers the guest the same API a frame guest has — props in,
|
|
15
|
+
* `act`, `navigate`, `size` — and a `root` to draw the kit into.
|
|
16
|
+
*
|
|
17
|
+
* The protocol is FR-04's (protocol.ts): ready, a hello with a nonce and a
|
|
18
|
+
* port, and everything after over the port. What the guest draws goes to
|
|
19
|
+
* the host as Remote DOM mutation records, and the host draws only the kit.
|
|
20
|
+
*/
|
|
21
|
+
import { natives } from "./natives.js";
|
|
22
|
+
import "@remote-dom/core/polyfill";
|
|
23
|
+
import { RemoteRootElement } from "@remote-dom/core/elements";
|
|
24
|
+
import { openGuest } from "../channel.js";
|
|
25
|
+
import { GUEST_KIT } from "../kit.js";
|
|
26
|
+
import { defineKit } from "./elements.js";
|
|
27
|
+
import { harden } from "./harden.js";
|
|
28
|
+
import { createListenerLedger } from "./listeners.js";
|
|
29
|
+
/** The element a worker guest draws into; the host's container stands for it. */
|
|
30
|
+
export const GUEST_ROOT = "graview-root";
|
|
31
|
+
defineKit(GUEST_KIT);
|
|
32
|
+
customElements.define(GUEST_ROOT, RemoteRootElement);
|
|
33
|
+
/**
|
|
34
|
+
* WHAT HARDENING TOOK (FR-70), before any guest code ran. Should a name
|
|
35
|
+
* outside the allowlist refuse to go, the runtime stops here: no guest
|
|
36
|
+
* code runs in a worker that is not hardened, and the host hears it fail
|
|
37
|
+
* to start rather than a guest that is not held. Outside a worker (a test
|
|
38
|
+
* of the runtime in Node) there is no worker's global to harden, and
|
|
39
|
+
* `worker` says so.
|
|
40
|
+
*/
|
|
41
|
+
export const hardening = "WorkerGlobalScope" in globalThis ? harden() : { removed: [], stuck: [], sealed: false, worker: false };
|
|
42
|
+
if (hardening.stuck.length > 0)
|
|
43
|
+
throw new Error(`The guest's worker could not be hardened: ${hardening.stuck.join(", ")} would not go.`);
|
|
44
|
+
let shared;
|
|
45
|
+
/**
|
|
46
|
+
* Connect a worker guest to its host: say ready to the worker's owner,
|
|
47
|
+
* take its hello, and draw from then on through the port. One connection
|
|
48
|
+
* per worker; asking again returns it.
|
|
49
|
+
*/
|
|
50
|
+
export function connectGuest() {
|
|
51
|
+
if (shared)
|
|
52
|
+
return shared;
|
|
53
|
+
/*
|
|
54
|
+
* A listener cannot be cloned into a message, so it crosses as an id the
|
|
55
|
+
* host hands back when the viewer raises the event, and is let go when
|
|
56
|
+
* what it was on leaves the tree (listeners.ts).
|
|
57
|
+
*/
|
|
58
|
+
const ledger = createListenerLedger();
|
|
59
|
+
const opened = openGuest({
|
|
60
|
+
listen(heard) {
|
|
61
|
+
natives.listen(heard);
|
|
62
|
+
return () => natives.unlisten(heard);
|
|
63
|
+
},
|
|
64
|
+
/* A dedicated worker hears only its owner: whoever posts to it is the host that started it. */
|
|
65
|
+
fromHost: () => true,
|
|
66
|
+
ready: (message) => natives.post(message),
|
|
67
|
+
}, { onEvent: (event) => void ledger.listener(event.listener)?.(event.detail) });
|
|
68
|
+
/* A microtask's mutations go as one message: building a card is one render, not one per node. */
|
|
69
|
+
let pending;
|
|
70
|
+
const connection = {
|
|
71
|
+
mutate(records) {
|
|
72
|
+
if (!pending) {
|
|
73
|
+
pending = [];
|
|
74
|
+
natives.microtask(() => {
|
|
75
|
+
const records = pending ?? [];
|
|
76
|
+
pending = undefined;
|
|
77
|
+
opened.send({ type: "render", records: ledger.encode(records) });
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
pending.push(...records);
|
|
81
|
+
},
|
|
82
|
+
/* The kit declares no methods, so there is nothing of the host's to call. */
|
|
83
|
+
call: () => undefined,
|
|
84
|
+
};
|
|
85
|
+
const root = document.createElement(GUEST_ROOT);
|
|
86
|
+
root.connect(connection);
|
|
87
|
+
shared = Object.defineProperty(opened.guest, "root", { value: root, enumerable: true });
|
|
88
|
+
return shared;
|
|
89
|
+
}
|
|
90
|
+
export { GUEST_GLOBALS, INERT, LANGUAGE, OBJECT_PROTOTYPE, PLATFORM, POLYFILLED_DOM } from "./harden.js";
|
|
91
|
+
export { GUEST_KIT, KIT_LINK_TARGETS, KIT_TONES } from "../kit.js";
|
|
92
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/worker/index.ts"],"names":[],"mappings":"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"}
|