@atolljs/islands 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,446 @@
1
+ /**
2
+ * React-reconciler host adapter for the worker DOM backend.
3
+ *
4
+ * The generic instance state (op queues, instance ids, handler registry,
5
+ * doorbell, geometry) lives in `instance.ts`. This file only wires the
6
+ * reconciler's create/append/update/remove/commit hooks to that backend.
7
+ *
8
+ * react-reconciler@0.34 reads ~150 fields off the config object. Most are
9
+ * stubs for features this renderer doesn't implement (hydration,
10
+ * persistence, resources, singletons, view transitions, test selectors,
11
+ * scope/hydratable APIs) — they exist so nothing throws when the reconciler
12
+ * destructures them; they are never invoked behind the `supports*` flags.
13
+ */
14
+
15
+ import { createContext } from 'react';
16
+ import {
17
+ bumpOpsVersion,
18
+ getActiveInstance,
19
+ getLastActiveInstance,
20
+ instances,
21
+ pushOp,
22
+ serializeProps,
23
+ unregisterHandler,
24
+ type ElementInstance,
25
+ type HostInstance,
26
+ type RootContainer,
27
+ type TextInstance,
28
+ } from './instance';
29
+ import { newElement, newText } from './instance';
30
+ import { docForInstance, type ProxyNode } from './proxyDom';
31
+
32
+ /* ── Event-priority plumbing ────────────────────────────────────────────── */
33
+ /*
34
+ * React 19 expresses event priorities as lane numbers: 2 = discrete
35
+ * (click/keydown → SyncLane), 8 = continuous, 32 = default, 0 = none. The
36
+ * reconciler calls setCurrentUpdatePriority around its own flushes
37
+ * (flushSyncFromReconciler sets 2), so honoring the set/get pair and echoing
38
+ * the value back from resolveUpdatePriority is all that's needed.
39
+ */
40
+ let currentUpdatePriority = 0;
41
+ const DEFAULT_EVENT_PRIORITY = 32;
42
+
43
+ /* ── React-19 transition context (must be real React objects) ───────────── */
44
+
45
+ const NotPendingTransition = Object.freeze({ pending: false, data: null, method: null, action: null });
46
+ const HostTransitionContext = createContext(NotPendingTransition);
47
+
48
+ const noop = (): void => {};
49
+ const NULL = (): null => null;
50
+ const FALSE = (): boolean => false;
51
+ const TRUE = (): boolean => true;
52
+
53
+ /* ── Refs & portals ───────────────────────────────────────────────────────
54
+ *
55
+ * React refs must receive an object the COMPONENT treats as "the element" —
56
+ * for React DOM that's the real DOM node, for us the closest truthful thing
57
+ * is the proxy DOM's facade (it navigates the shadow tree, mutates via ops,
58
+ * and reports `nodeType === 1`). getPublicInstance therefore adopts the
59
+ * host instance into a per-instance proxy document, created lazily so React
60
+ * mounts only pay for it when something actually holds a ref.
61
+ *
62
+ * This is what makes react-dom's `createPortal(children, ref.current)` work
63
+ * here: isValidContainer() only checks nodeType, the portal fiber then feeds
64
+ * the facade back as `containerInfo`, and the container-level methods below
65
+ * unwrap `.instance` so portal children land inside the real target node —
66
+ * that is the entire recharts <Tooltip>/<Legend> path.
67
+ */
68
+ const publicInstanceFor = (instance: HostInstance): ProxyNode | HostInstance =>
69
+ docForInstance(instance.instance).adopt(instance);
70
+
71
+ /**
72
+ * Portal `containerInfo` is the public instance (a ProxyElement) the caller
73
+ * passed to createPortal; the ROOT_CONTAINER sentinel and raw instances keep
74
+ * their own `id`. Anything unrecognizable falls back to the island root.
75
+ */
76
+ const containerParentId = (container: unknown): number => {
77
+ const inst = (container as { instance?: { id?: unknown } } | null)?.instance;
78
+ if (inst && typeof inst.id === 'number') return inst.id;
79
+ const id = (container as { id?: unknown } | null)?.id;
80
+ return typeof id === 'number' ? id : 0;
81
+ };
82
+
83
+ /**
84
+ * The instance a create should bind to — read off the root container for
85
+ * ordinary renders, off the portal container's wrapped instance for portal
86
+ * subtrees (a ProxyElement, whose `.instance` field doesn't exist but whose
87
+ * `.instance.instance` does), finally falling back to ambient instance state.
88
+ */
89
+ const containerInstance = (container: unknown): string => {
90
+ // `.instance` is the instance KEY on a RootContainer/raw host record and
91
+ // the host RECORD on a ProxyElement (portal containers) — disambiguate
92
+ // by shape: a string IS the key; a record holds `.instance.instance`.
93
+ const inner = (container as { instance?: unknown } | null)?.instance;
94
+ if (typeof inner === 'string') return inner;
95
+ return (inner as { instance?: string } | undefined)?.instance ??
96
+ (getActiveInstance() !== '' ? getActiveInstance() : getLastActiveInstance());
97
+ };
98
+
99
+ /* Host context = DOM namespace tracking, same role it plays in React DOM:
100
+ * `getChildHostContext` flips the namespace when the element type requires
101
+ * it, and `createInstance` stamps the result on the instance so the `create`
102
+ * op can tell the driver to createElementNS. Recharts-style SVG trees need
103
+ * this — without it every <svg>/<path> would arrive as an HTMLUnknownElement. */
104
+ interface HostContext {
105
+ ns?: string;
106
+ }
107
+ const SVG_NS = 'http://www.w3.org/2000/svg';
108
+ const MATH_NS = 'http://www.w3.org/1998/Math/MathML';
109
+ const HTML_CTX: HostContext = Object.freeze({});
110
+ const SVG_CTX: HostContext = Object.freeze({ ns: SVG_NS });
111
+ const MATH_CTX: HostContext = Object.freeze({ ns: MATH_NS });
112
+
113
+ /** The namespace context a host element gives its children — and the
114
+ * namespace the element itself belongs to (getChildNamespace semantics:
115
+ * <svg> in HTML is SVG, foreignObject/desc/title flip back to HTML). */
116
+ const childHostContextFor = (parent: HostContext, type: string): HostContext => {
117
+ if (type === 'svg') return SVG_CTX;
118
+ if (type === 'math') return MATH_CTX;
119
+ if (type === 'foreignObject' || type === 'desc' || type === 'title') return HTML_CTX;
120
+ return parent;
121
+ };
122
+
123
+ /* ── The host config ────────────────────────────────────────────────────── */
124
+
125
+ export const hostConfig = {
126
+ // Identity / capabilities
127
+ rendererVersion: '0.34.0',
128
+ rendererPackageName: '@atolljs/islands',
129
+ extraDevToolsConfig: null,
130
+ isPrimaryRenderer: true,
131
+ warnsIfNotActing: false,
132
+ supportsMutation: true,
133
+ supportsPersistence: false,
134
+ supportsHydration: false,
135
+ supportsResources: false,
136
+ supportsSingletons: false,
137
+ supportsMicrotasks: false,
138
+ supportsTestSelectors: false,
139
+
140
+ getPublicInstance: (instance: HostInstance): unknown => publicInstanceFor(instance),
141
+ // Host contexts must be non-null objects (the reconciler pushes them on a
142
+ // context stack and warns "Expected host context to exist" on null). This
143
+ // renderer carries no per-subtree context — echo a single frozen sentinel.
144
+ // Host contexts must be non-null objects (the reconciler warns on null).
145
+ // Ours carries only the element namespace: <svg>/<math> enter their
146
+ // namespaces; foreignObject/desc/title are HTML-integration points that
147
+ // flip children back to HTML; everything else inherits the parent's.
148
+ // For portals, this becomes the context the portal subtree renders under —
149
+ // derived from the container's own namespace so children of an SVG portal
150
+ // target (recharts zIndex <g> layers) stay in the SVG namespace.
151
+ getRootHostContext: (container: unknown): HostContext => {
152
+ const ns = (container as { instance?: { ns?: string } } | null)?.instance?.ns;
153
+ if (ns === SVG_NS) return SVG_CTX;
154
+ if (ns === MATH_NS) return MATH_CTX;
155
+ return HTML_CTX;
156
+ },
157
+ getChildHostContext: (parent: HostContext, type: string): HostContext =>
158
+ childHostContextFor(parent, type),
159
+ prepareForCommit: NULL,
160
+ // The doorbell: every commit bumps opsVersion once — the main thread's
161
+ // observe() wakes (Atomics.waitAsync) and flushes the op queue, so commits
162
+ // made outside task calls (effects, timers, async setState) arrive as a
163
+ // push instead of waiting on a poll. Task-returned ops bump too; the
164
+ // follow-up flush just finds an empty queue.
165
+ resetAfterCommit: bumpOpsVersion,
166
+
167
+ // Creation — emit ops
168
+ createInstance: (
169
+ type: string,
170
+ props: Record<string, unknown>,
171
+ rootContainer: unknown,
172
+ hostContext: unknown,
173
+ _internalHandle: unknown,
174
+ ): ElementInstance => {
175
+ // The element's own namespace = the child context its TYPE produces
176
+ // under the parent's context — the same computation React DOM runs
177
+ // (getChildNamespace): <svg> in HTML is itself SVG, <foreignObject> in
178
+ // SVG is itself HTML. Instance comes from the container (see RootContainer).
179
+ const ctx = childHostContextFor(hostContext as HostContext, type);
180
+ const instance = newElement(type, props, ctx.ns, containerInstance(rootContainer));
181
+ pushOp(instance.instance, {
182
+ t: 'create',
183
+ id: instance.id,
184
+ type,
185
+ props: instance.props,
186
+ ns: instance.ns,
187
+ });
188
+ return instance;
189
+ },
190
+ createTextInstance: (
191
+ text: string,
192
+ rootContainer: unknown,
193
+ _hostContext: unknown,
194
+ _internalHandle: unknown,
195
+ ): TextInstance => {
196
+ const instance = newText(text, containerInstance(rootContainer));
197
+ pushOp(instance.instance, { t: 'text', id: instance.id, text });
198
+ return instance;
199
+ },
200
+ finalizeInitialChildren: FALSE,
201
+ // Always false: string/number children become real text instances, so the
202
+ // tree arrives as linear ops and `utext` handles every text update. (The
203
+ // `true` path would expect commitUpdate to set textContent from
204
+ // props.children — which we deliberately never serialize.)
205
+ shouldSetTextContent: FALSE,
206
+
207
+ // Tree wiring — emit ops
208
+ appendInitialChild: (parent: HostInstance, child: HostInstance): void => {
209
+ pushOp(parent.instance, { t: 'append', parent: parent.id, child: child.id });
210
+ },
211
+ appendChild: (parent: HostInstance, child: HostInstance): void => {
212
+ pushOp(parent.instance, { t: 'append', parent: parent.id, child: child.id });
213
+ },
214
+ appendChildToContainer: (container: unknown, child: HostInstance): void => {
215
+ pushOp(child.instance, { t: 'append', parent: containerParentId(container), child: child.id });
216
+ },
217
+ insertBefore: (parent: HostInstance, child: HostInstance, before: HostInstance): void => {
218
+ pushOp(parent.instance, { t: 'append', parent: parent.id, child: child.id, before: before.id });
219
+ },
220
+ insertInContainerBefore: (container: unknown, child: HostInstance, before: HostInstance): void => {
221
+ pushOp(child.instance, {
222
+ t: 'append',
223
+ parent: containerParentId(container),
224
+ child: child.id,
225
+ before: before.id,
226
+ });
227
+ },
228
+ removeChild: (_parent: HostInstance, child: HostInstance): void => {
229
+ pushOp(child.instance, { t: 'remove', child: child.id });
230
+ },
231
+ removeChildFromContainer: (_container: unknown, child: HostInstance): void => {
232
+ pushOp(child.instance, { t: 'remove', child: child.id });
233
+ },
234
+ // No instance argument — routed by the task's active instance (only reached
235
+ // inside mount/remount's syncCommit).
236
+ clearContainer: (): void => {
237
+ pushOp(getActiveInstance(), { t: 'clear' });
238
+ },
239
+
240
+ // Updates — emit ops
241
+ commitUpdate: (
242
+ instance: ElementInstance,
243
+ _type: string,
244
+ _oldProps: Record<string, unknown>,
245
+ newProps: Record<string, unknown>,
246
+ _internalHandle: unknown,
247
+ ): void => {
248
+ // Serialize first so the op carries the latest props; re-serialization
249
+ // also re-registers event handlers against the current closure.
250
+ instance.props = serializeProps(instance, newProps);
251
+ pushOp(instance.instance, { t: 'update', id: instance.id, props: instance.props });
252
+ },
253
+ commitTextUpdate: (instance: TextInstance, _oldText: string, newText: string): void => {
254
+ instance.text = newText;
255
+ pushOp(instance.instance, { t: 'utext', id: instance.id, text: newText });
256
+ },
257
+ commitMount: noop,
258
+ // Unreachable while shouldSetTextContent is always false; still emit the
259
+ // spec'd op for completeness.
260
+ resetTextContent: (instance: ElementInstance): void => {
261
+ instance.props = {};
262
+ pushOp(instance.instance, { t: 'update', id: instance.id, props: {} });
263
+ },
264
+
265
+ // Suspense visibility — `hidden` is a global HTML attribute the main
266
+ // thread applies like any other prop.
267
+ hideInstance: (instance: ElementInstance): void => {
268
+ pushOp(instance.instance, { t: 'update', id: instance.id, props: { ...instance.props, hidden: true } });
269
+ },
270
+ unhideInstance: (instance: ElementInstance): void => {
271
+ pushOp(instance.instance, { t: 'update', id: instance.id, props: { ...instance.props } });
272
+ },
273
+ hideTextInstance: (instance: TextInstance): void => {
274
+ pushOp(instance.instance, { t: 'utext', id: instance.id, text: '' });
275
+ },
276
+ unhideTextInstance: (instance: TextInstance, text: string): void => {
277
+ pushOp(instance.instance, { t: 'utext', id: instance.id, text });
278
+ },
279
+
280
+ // GC hook — drop the record and its handler slots.
281
+ detachDeletedInstance: (instance: HostInstance): void => {
282
+ instances.delete(instance.id);
283
+ if (instance.kind === 'element') {
284
+ for (const hid of Object.values(instance.listenerSlots)) unregisterHandler(hid);
285
+ }
286
+ },
287
+
288
+ // Scheduler
289
+ scheduleTimeout: setTimeout,
290
+ cancelTimeout: clearTimeout,
291
+ noTimeout: -1,
292
+ // supportsMicrotasks is false, so the reconciler schedules root work via
293
+ // the `scheduler` package (MessageChannel in a worker). This export is
294
+ // still destructured — provide a real one for completeness.
295
+ scheduleMicrotask: (fn: () => void): void => queueMicrotask(fn),
296
+
297
+ // Event priorities (see note above — values are lane numbers).
298
+ setCurrentUpdatePriority: (p: number): void => {
299
+ currentUpdatePriority = p;
300
+ },
301
+ getCurrentUpdatePriority: (): number => currentUpdatePriority,
302
+ resolveUpdatePriority: (): number =>
303
+ currentUpdatePriority !== 0 ? currentUpdatePriority : DEFAULT_EVENT_PRIORITY,
304
+ resolveEventType: NULL,
305
+ resolveEventTimeStamp: (): number => -1.1,
306
+ trackSchedulerEvent: noop,
307
+ shouldAttemptEagerTransition: FALSE,
308
+
309
+ // Events/portals/scopes — no DOM event system exists worker-side.
310
+ getInstanceFromNode: NULL,
311
+ beforeActiveInstanceBlur: noop,
312
+ afterActiveInstanceBlur: noop,
313
+ preparePortalMount: noop,
314
+ prepareScopeUpdate: noop,
315
+ getInstanceFromScope: NULL,
316
+
317
+ // React 19 "suspend on commit" — never suspend.
318
+ requestPostPaintCallback: noop,
319
+ maySuspendCommit: FALSE,
320
+ maySuspendCommitOnUpdate: FALSE,
321
+ maySuspendCommitInSyncRender: FALSE,
322
+ preloadInstance: TRUE,
323
+ startSuspendingCommit: noop,
324
+ suspendInstance: noop,
325
+ suspendOnActiveViewTransition: noop,
326
+ waitForCommitToBeReady: NULL,
327
+ getSuspendedCommitReason: () => 0,
328
+
329
+ // Transitions / forms / console
330
+ NotPendingTransition,
331
+ HostTransitionContext,
332
+ resetFormInstance: noop,
333
+ bindToConsole: (methodName: string, args: unknown[]) =>
334
+ (console as unknown as Record<string, (...a: unknown[]) => void>)[methodName]?.bind(console, ...args) ??
335
+ noop,
336
+
337
+ // Persistence (supportsPersistence: false — destructured, never called)
338
+ createContainerChildSet: () => [],
339
+ appendChildToContainerChildSet: noop,
340
+ finalizeContainerChildren: noop,
341
+ replaceContainerChildren: noop,
342
+ cloneInstance: NULL,
343
+ cloneMutableInstance: (instance: HostInstance) => instance,
344
+ cloneMutableTextInstance: (instance: HostInstance) => instance,
345
+ cloneHiddenInstance: (instance: HostInstance) => instance,
346
+ cloneHiddenTextInstance: (instance: HostInstance) => instance,
347
+
348
+ // Fragment instances (only used for `<Fragment ref={…}>` — unimplemented)
349
+ createFragmentInstance: () => ({}),
350
+ updateFragmentInstanceFiber: noop,
351
+ commitNewChildToFragmentInstance: noop,
352
+ deleteChildFromFragmentInstance: noop,
353
+
354
+ // View transitions (React 19) — all stubs
355
+ createViewTransitionInstance: (name: string) => ({ name, autoName: null }),
356
+ applyViewTransitionName: noop,
357
+ restoreViewTransitionName: noop,
358
+ cancelViewTransitionName: noop,
359
+ cancelRootViewTransitionName: noop,
360
+ restoreRootViewTransitionName: noop,
361
+ cloneRootViewTransitionContainer: noop,
362
+ removeRootViewTransitionClone: noop,
363
+ measureInstance: NULL,
364
+ measureClonedInstance: NULL,
365
+ wasInstanceInViewport: FALSE,
366
+ hasInstanceChanged: FALSE,
367
+ hasInstanceAffectedParent: FALSE,
368
+ startViewTransition: NULL,
369
+ startGestureTransition: NULL,
370
+ stopViewTransition: noop,
371
+ addViewTransitionFinishedListener: noop,
372
+ getCurrentGestureOffset: () => 0,
373
+
374
+ // Hydration (supportsHydration: false — destructured, never called)
375
+ isSuspenseInstancePending: FALSE,
376
+ isSuspenseInstanceFallback: FALSE,
377
+ getSuspenseInstanceFallbackErrorDetails: () => ({}),
378
+ registerSuspenseInstanceRetry: noop,
379
+ getNextHydratableSibling: NULL,
380
+ getNextHydratableSiblingAfterSingleton: NULL,
381
+ getFirstHydratableChild: NULL,
382
+ getFirstHydratableChildWithinContainer: NULL,
383
+ getFirstHydratableChildWithinActivityInstance: NULL,
384
+ getFirstHydratableChildWithinSingleton: NULL,
385
+ getFirstHydratableChildWithinSuspenseInstance: NULL,
386
+ canHydrateInstance: NULL,
387
+ canHydrateTextInstance: NULL,
388
+ canHydrateActivityInstance: NULL,
389
+ canHydrateSuspenseInstance: NULL,
390
+ canHydrateFormStateMarker: NULL,
391
+ isFormStateMarkerMatching: FALSE,
392
+ hydrateInstance: noop,
393
+ hydrateTextInstance: noop,
394
+ hydrateActivityInstance: noop,
395
+ hydrateSuspenseInstance: noop,
396
+ getNextHydratableInstanceAfterActivityInstance: NULL,
397
+ getNextHydratableInstanceAfterSuspenseInstance: NULL,
398
+ commitHydratedInstance: noop,
399
+ commitHydratedContainer: noop,
400
+ commitHydratedSuspenseInstance: noop,
401
+ finalizeHydratedChildren: FALSE,
402
+ flushHydrationEvents: noop,
403
+ clearActivityBoundary: FALSE,
404
+ clearSuspenseBoundary: FALSE,
405
+ clearActivityBoundaryFromContainer: FALSE,
406
+ clearSuspenseBoundaryFromContainer: FALSE,
407
+ hideDehydratedBoundary: noop,
408
+ unhideDehydratedBoundary: noop,
409
+ shouldDeleteUnhydratedTailInstances: FALSE,
410
+ diffHydratedPropsForDevWarnings: NULL,
411
+ diffHydratedTextForDevWarnings: NULL,
412
+ describeHydratableInstanceForDevWarnings: NULL,
413
+ validateHydratableInstance: TRUE,
414
+ validateHydratableTextInstance: TRUE,
415
+
416
+ // Host resources (stylesheets/scripts — supportsResources: false)
417
+ isHostHoistableType: FALSE,
418
+ getHoistableRoot: NULL,
419
+ getResource: NULL,
420
+ acquireResource: noop,
421
+ releaseResource: noop,
422
+ hydrateHoistable: noop,
423
+ mountHoistable: noop,
424
+ unmountHoistable: noop,
425
+ createHoistableInstance: NULL,
426
+ prepareToCommitHoistables: noop,
427
+ mayResourceSuspendCommit: FALSE,
428
+ preloadResource: TRUE,
429
+ suspendResource: noop,
430
+
431
+ // Singletons (supportsSingletons: false)
432
+ resolveSingletonInstance: NULL,
433
+ acquireSingletonInstance: noop,
434
+ releaseSingletonInstance: noop,
435
+ isHostSingletonType: FALSE,
436
+ isSingletonScope: FALSE,
437
+
438
+ // Test selectors (supportsTestSelectors: false)
439
+ findFiberRoot: NULL,
440
+ getBoundingRect: NULL,
441
+ getTextContent: NULL,
442
+ isHiddenSubtree: FALSE,
443
+ matchAccessibilityRole: FALSE,
444
+ setFocusIfFocusable: FALSE,
445
+ setupIntersectionObserver: noop,
446
+ };
@@ -0,0 +1,78 @@
1
+ /**
2
+ * The worker-side surface of @atolljs/islands — import from
3
+ * '@atolljs/islands/worker' inside the worker entry:
4
+ *
5
+ * import { definePolyWorker } from '@atolljs/islands/worker';
6
+ * export const renderWorker = definePolyWorker({ apps: { ... } });
7
+ *
8
+ * Apps (React or `{ imperative }`) also use from here: `emit` (island→shell
9
+ * channel), `runInInstance` (instance scoping for worker-initiated work), `Slot`
10
+ * (transclusion), `createProxyDocument`/`installDomShim` (imperative DOM).
11
+ */
12
+ export { definePolyWorker, defineMonoWorker } from './defineWorkers';
13
+ export type {
14
+ ImperativeIslandApp,
15
+ Instance,
16
+ IslandApp,
17
+ PolyWorkerRegistry,
18
+ ReactIslandApp,
19
+ RenderContext,
20
+ RenderedHandle,
21
+ RenderedIslandApp,
22
+ } from './defineWorkers';
23
+
24
+ export { islandApp, islandAppNameOf } from '../app';
25
+
26
+ // hostConfig is deliberately NOT exported — a static re-export would pull
27
+ // react + react-reconciler into every /worker bundle. The reconciler is
28
+ // reachable only through definePolyWorker's lazy import of reactInstance.
29
+
30
+ export {
31
+ allocId,
32
+ bumpOpsVersion,
33
+ emit,
34
+ getActiveInstance,
35
+ getHandler,
36
+ getLastActiveInstance,
37
+ getLastTouchedInstance,
38
+ getInstanceSize,
39
+ instances,
40
+ pushOp,
41
+ registerHandler,
42
+ ROOT_CONTAINER,
43
+ runInInstance,
44
+ setActiveInstance,
45
+ setDoorbellContract,
46
+ setInstanceSize,
47
+ takeOps,
48
+ unregisterHandler,
49
+ } from './instance';
50
+ export type { ElementInstance, HostInstance, TextInstance } from './instance';
51
+
52
+ export {
53
+ createProxyDocument,
54
+ installDomShim,
55
+ installInstanceDispatcher,
56
+ ProxyComment,
57
+ ProxyElement,
58
+ ProxyFragment,
59
+ ProxyNode,
60
+ ProxyText,
61
+ docForInstance,
62
+ } from './proxyDom';
63
+ export type {
64
+ AdjacentPosition,
65
+ InternalDocument,
66
+ ProxyClassList,
67
+ ProxyDocument,
68
+ ProxyEventHandler,
69
+ WindowShim,
70
+ WireListenerOpts,
71
+ } from './proxyDom';
72
+
73
+ export { Slot } from './slot';
74
+
75
+ export type { EventPayload, IslandWorkerMethods, Op, WireProps } from '../ops';
76
+ export { isEventRef } from '../ops';
77
+ export { renderMemory } from '../memory';
78
+ export type { DoorbellSpec } from '../memory';