@ai-matrx/summon 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.
Files changed (54) hide show
  1. package/CHANGELOG.md +21 -2
  2. package/dist/gate-DUvE-Cc1.d.cts +399 -0
  3. package/dist/gate-DUvE-Cc1.d.ts +399 -0
  4. package/dist/handles.cjs +1 -0
  5. package/dist/handles.cjs.map +1 -1
  6. package/dist/handles.d.cts +3 -61
  7. package/dist/handles.d.ts +3 -61
  8. package/dist/handles.js +1 -0
  9. package/dist/handles.js.map +1 -1
  10. package/dist/helpers-2NY1ha0V.d.cts +63 -0
  11. package/dist/helpers-2NY1ha0V.d.ts +63 -0
  12. package/dist/index.cjs +194 -159
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.cts +9 -355
  15. package/dist/index.d.ts +9 -355
  16. package/dist/index.js +200 -165
  17. package/dist/index.js.map +1 -1
  18. package/dist/instanceBody-CgZAFnic.d.cts +23 -0
  19. package/dist/instanceBody-CgZAFnic.d.ts +23 -0
  20. package/dist/open.cjs +408 -0
  21. package/dist/open.cjs.map +1 -0
  22. package/dist/open.d.cts +22 -0
  23. package/dist/open.d.ts +22 -0
  24. package/dist/open.js +375 -0
  25. package/dist/open.js.map +1 -0
  26. package/dist/persistence.cjs +27 -2
  27. package/dist/persistence.cjs.map +1 -1
  28. package/dist/persistence.js +28 -3
  29. package/dist/persistence.js.map +1 -1
  30. package/dist/react.cjs +249 -352
  31. package/dist/react.cjs.map +1 -1
  32. package/dist/react.d.cts +11 -151
  33. package/dist/react.d.ts +11 -151
  34. package/dist/react.js +210 -306
  35. package/dist/react.js.map +1 -1
  36. package/dist/root.cjs +277 -0
  37. package/dist/root.cjs.map +1 -0
  38. package/dist/root.d.cts +175 -0
  39. package/dist/root.d.ts +175 -0
  40. package/dist/root.js +254 -0
  41. package/dist/root.js.map +1 -0
  42. package/dist/window-host.cjs +11 -2
  43. package/dist/window-host.cjs.map +1 -1
  44. package/dist/window-host.d.cts +1 -0
  45. package/dist/window-host.d.ts +1 -0
  46. package/dist/window-host.js +11 -2
  47. package/dist/window-host.js.map +1 -1
  48. package/dist/window.cjs +2 -1
  49. package/dist/window.cjs.map +1 -1
  50. package/dist/window.d.cts +3 -2
  51. package/dist/window.d.ts +3 -2
  52. package/dist/window.js +2 -1
  53. package/dist/window.js.map +1 -1
  54. package/package.json +26 -3
package/dist/react.js CHANGED
@@ -8,10 +8,7 @@ import { createSummonStore } from "@ai-matrx/summon";
8
8
 
9
9
  // src/react/context.ts
10
10
  import { createContext } from "react";
11
- var SummonStoreContext = createContext(null);
12
- SummonStoreContext.displayName = "SummonStoreContext";
13
- var SummonPortsContext = createContext(null);
14
- SummonPortsContext.displayName = "SummonPortsContext";
11
+ import { SummonStoreContext, SummonPortsContext } from "@ai-matrx/summon/root";
15
12
  var SummonConfigContext = createContext(null);
16
13
  SummonConfigContext.displayName = "SummonConfigContext";
17
14
 
@@ -21,114 +18,8 @@ import { Button } from "@ai-matrx/design-system";
21
18
 
22
19
  // src/react/storeHooks.ts
23
20
  import { useContext } from "react";
24
- import {
25
- createDispatchHook,
26
- createSelectorHook,
27
- createStoreHook
28
- } from "react-redux";
29
- import { DEFAULT_PORTS } from "@ai-matrx/summon";
30
- var useSummonSelector = createSelectorHook(SummonStoreContext).withTypes();
31
- var useSummonDispatch = createDispatchHook(SummonStoreContext).withTypes();
32
- var useSummonStore = createStoreHook(SummonStoreContext).withTypes();
33
- var MISSING_PROVIDER = "[summon] No <SummonProvider> above this component. Wrap the app (or the part that opens overlays) in <SummonProvider>.";
34
- function useSummonPorts() {
35
- const ports = useContext(SummonPortsContext);
36
- if (!ports) throw new Error(MISSING_PROVIDER);
37
- return ports;
38
- }
39
- function useOptionalSummonPorts() {
40
- return useContext(SummonPortsContext) ?? DEFAULT_PORTS;
41
- }
42
- function useOptionalSummonStore() {
43
- const context = useContext(SummonStoreContext);
44
- return context ? context.store : null;
45
- }
46
- function useSummonConfig() {
47
- const config = useContext(SummonConfigContext);
48
- if (!config) throw new Error(MISSING_PROVIDER);
49
- return config;
50
- }
51
-
52
- // src/react/fallbacks.tsx
53
- import { jsx, jsxs } from "react/jsx-runtime";
54
- function normalizeOverlayError(error) {
55
- if (error instanceof Error) {
56
- const isChunkLoadError = error.name === "ChunkLoadError" || /Loading chunk [\w-]+ failed|Failed to fetch dynamically imported module|Importing a module script failed/i.test(
57
- error.message
58
- );
59
- return { name: error.name, message: error.message, stack: error.stack ?? null, isChunkLoadError };
60
- }
61
- return { name: "Error", message: typeof error === "string" ? error : String(error), stack: null, isChunkLoadError: false };
62
- }
63
- function OverlayLoadingFallback({ overlayId, label }) {
64
- const ports = useSummonPorts();
65
- const { stallWarnMs } = useSummonConfig();
66
- useEffect(() => {
67
- const timer = setTimeout(() => {
68
- ports.errors.capture(new Error(`Overlay "${overlayId}" still loading after ${stallWarnMs}ms`), {
69
- stage: "overlay-load-stall",
70
- overlayId,
71
- level: "warning"
72
- });
73
- }, stallWarnMs);
74
- return () => clearTimeout(timer);
75
- }, [ports, overlayId, stallWarnMs]);
76
- return /* @__PURE__ */ jsx("div", { className: "pointer-events-none fixed inset-0 z-[2147483000] flex items-center justify-center p-4", children: /* @__PURE__ */ jsxs(
77
- "div",
78
- {
79
- role: "status",
80
- "aria-label": `Loading ${label}`,
81
- className: "pointer-events-auto flex items-center gap-3 rounded-xl border border-border bg-card px-5 py-4 text-sm text-muted-foreground shadow-[var(--elevation-2)]",
82
- children: [
83
- /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "size-4 animate-spin rounded-full border-2 border-border border-t-primary" }),
84
- /* @__PURE__ */ jsx("span", { children: "Loading\u2026" })
85
- ]
86
- }
87
- ) });
88
- }
89
- function OverlayErrorFallback({ label, error, retry, close, extras }) {
90
- const e = normalizeOverlayError(error);
91
- return /* @__PURE__ */ jsx("div", { className: "pointer-events-none fixed inset-0 z-[2147483001] flex items-center justify-center p-4", children: /* @__PURE__ */ jsxs(
92
- "div",
93
- {
94
- role: "alertdialog",
95
- "aria-label": `${label} failed to load`,
96
- className: "pointer-events-auto flex max-h-[85dvh] w-full max-w-lg flex-col overflow-hidden rounded-xl border border-destructive bg-card shadow-[var(--elevation-3)]",
97
- children: [
98
- /* @__PURE__ */ jsxs("div", { className: "border-b border-border px-5 py-4", children: [
99
- /* @__PURE__ */ jsxs("h2", { className: "text-sm font-semibold text-foreground", children: [
100
- label,
101
- " failed to load"
102
- ] }),
103
- /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: e.isChunkLoadError ? "Part of it did not finish loading." : "It hit an error while rendering." })
104
- ] }),
105
- /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-auto px-5 py-4", children: /* @__PURE__ */ jsxs("div", { className: "rounded-lg bg-muted px-3 py-2 font-mono text-xs text-foreground", children: [
106
- /* @__PURE__ */ jsx("span", { className: "text-destructive", children: e.name }),
107
- ": ",
108
- e.message
109
- ] }) }),
110
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 border-t border-border px-5 py-3", children: [
111
- /* @__PURE__ */ jsx("div", { children: extras }),
112
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
113
- /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: close, children: "Close" }),
114
- /* @__PURE__ */ jsx(Button, { variant: "primary", size: "sm", onClick: retry, children: "Try again" }),
115
- /* @__PURE__ */ jsx(
116
- Button,
117
- {
118
- variant: "outline",
119
- size: "sm",
120
- onClick: () => {
121
- if (typeof window !== "undefined") window.location.reload();
122
- },
123
- children: "Reload page"
124
- }
125
- )
126
- ] })
127
- ] })
128
- ]
129
- }
130
- ) });
131
- }
21
+ import { getSummonHostConfig, getSummonHostVersion } from "@ai-matrx/summon/root";
22
+ import { globalSlot } from "@ai-matrx/kit/global-slot";
132
23
 
133
24
  // src/react/keepAlive.ts
134
25
  var KeepAliveRegistry = class {
@@ -221,11 +112,126 @@ var LoaderCache = class {
221
112
  }
222
113
  };
223
114
 
224
- // src/react/SummonProvider.tsx
225
- import { jsx as jsx2 } from "react/jsx-runtime";
115
+ // src/react/storeHooks.ts
116
+ import {
117
+ useSummonSelector,
118
+ useSummonDispatch,
119
+ useSummonStore,
120
+ useSummonPorts,
121
+ useOptionalSummonPorts,
122
+ useOptionalSummonStore
123
+ } from "@ai-matrx/summon/root";
226
124
  var DEFAULT_KEEP_ALIVE_LIMIT = 8;
227
125
  var DEFAULT_IMPORT_TIMEOUT_MS = 12e3;
228
126
  var DEFAULT_STALL_WARN_MS = 1e4;
127
+ var hostConfigSlot = () => globalSlot("ai-matrx.summon.hostReactConfig", () => ({ version: -1, config: null, keepAlive: null, loaders: null }));
128
+ function hostReactConfig() {
129
+ const s = hostConfigSlot();
130
+ const version = getSummonHostVersion();
131
+ if (s.config && s.version === version) return s.config;
132
+ const host = getSummonHostConfig();
133
+ s.keepAlive ??= new KeepAliveRegistry(DEFAULT_KEEP_ALIVE_LIMIT);
134
+ s.loaders ??= new LoaderCache({ timeoutMs: () => DEFAULT_IMPORT_TIMEOUT_MS });
135
+ s.config = {
136
+ loadingFallback: OverlayLoadingFallback,
137
+ errorFallback: OverlayErrorFallback,
138
+ errorReportExtras: host.errorReportExtras ?? null,
139
+ renderWrapper: host.renderWrapper ?? null,
140
+ importTimeoutMs: DEFAULT_IMPORT_TIMEOUT_MS,
141
+ stallWarnMs: DEFAULT_STALL_WARN_MS,
142
+ keepAlive: s.keepAlive,
143
+ loaders: s.loaders
144
+ };
145
+ s.version = version;
146
+ return s.config;
147
+ }
148
+ function useSummonConfig() {
149
+ return useContext(SummonConfigContext) ?? hostReactConfig();
150
+ }
151
+
152
+ // src/react/fallbacks.tsx
153
+ import { jsx, jsxs } from "react/jsx-runtime";
154
+ function normalizeOverlayError(error) {
155
+ if (error instanceof Error) {
156
+ const isChunkLoadError = error.name === "ChunkLoadError" || /Loading chunk [\w-]+ failed|Failed to fetch dynamically imported module|Importing a module script failed/i.test(
157
+ error.message
158
+ );
159
+ return { name: error.name, message: error.message, stack: error.stack ?? null, isChunkLoadError };
160
+ }
161
+ return { name: "Error", message: typeof error === "string" ? error : String(error), stack: null, isChunkLoadError: false };
162
+ }
163
+ function OverlayLoadingFallback({ overlayId, label }) {
164
+ const ports = useSummonPorts();
165
+ const { stallWarnMs } = useSummonConfig();
166
+ useEffect(() => {
167
+ const timer = setTimeout(() => {
168
+ ports.errors.capture(new Error(`Overlay "${overlayId}" still loading after ${stallWarnMs}ms`), {
169
+ stage: "overlay-load-stall",
170
+ overlayId,
171
+ level: "warning"
172
+ });
173
+ }, stallWarnMs);
174
+ return () => clearTimeout(timer);
175
+ }, [ports, overlayId, stallWarnMs]);
176
+ return /* @__PURE__ */ jsx("div", { className: "pointer-events-none fixed inset-0 z-[2147483000] flex items-center justify-center p-4", children: /* @__PURE__ */ jsxs(
177
+ "div",
178
+ {
179
+ role: "status",
180
+ "aria-label": `Loading ${label}`,
181
+ className: "pointer-events-auto flex items-center gap-3 rounded-xl border border-border bg-card px-5 py-4 text-sm text-muted-foreground shadow-[var(--elevation-2)]",
182
+ children: [
183
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "size-4 animate-spin rounded-full border-2 border-border border-t-primary" }),
184
+ /* @__PURE__ */ jsx("span", { children: "Loading\u2026" })
185
+ ]
186
+ }
187
+ ) });
188
+ }
189
+ function OverlayErrorFallback({ label, error, retry, close, extras }) {
190
+ const e = normalizeOverlayError(error);
191
+ return /* @__PURE__ */ jsx("div", { className: "pointer-events-none fixed inset-0 z-[2147483001] flex items-center justify-center p-4", children: /* @__PURE__ */ jsxs(
192
+ "div",
193
+ {
194
+ role: "alertdialog",
195
+ "aria-label": `${label} failed to load`,
196
+ className: "pointer-events-auto flex max-h-[85dvh] w-full max-w-lg flex-col overflow-hidden rounded-xl border border-destructive bg-card shadow-[var(--elevation-3)]",
197
+ children: [
198
+ /* @__PURE__ */ jsxs("div", { className: "border-b border-border px-5 py-4", children: [
199
+ /* @__PURE__ */ jsxs("h2", { className: "text-sm font-semibold text-foreground", children: [
200
+ label,
201
+ " failed to load"
202
+ ] }),
203
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: e.isChunkLoadError ? "Part of it did not finish loading." : "It hit an error while rendering." })
204
+ ] }),
205
+ /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-auto px-5 py-4", children: /* @__PURE__ */ jsxs("div", { className: "rounded-lg bg-muted px-3 py-2 font-mono text-xs text-foreground", children: [
206
+ /* @__PURE__ */ jsx("span", { className: "text-destructive", children: e.name }),
207
+ ": ",
208
+ e.message
209
+ ] }) }),
210
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 border-t border-border px-5 py-3", children: [
211
+ /* @__PURE__ */ jsx("div", { children: extras }),
212
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
213
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: close, children: "Close" }),
214
+ /* @__PURE__ */ jsx(Button, { variant: "primary", size: "sm", onClick: retry, children: "Try again" }),
215
+ /* @__PURE__ */ jsx(
216
+ Button,
217
+ {
218
+ variant: "outline",
219
+ size: "sm",
220
+ onClick: () => {
221
+ if (typeof window !== "undefined") window.location.reload();
222
+ },
223
+ children: "Reload page"
224
+ }
225
+ )
226
+ ] })
227
+ ] })
228
+ ]
229
+ }
230
+ ) });
231
+ }
232
+
233
+ // src/react/SummonProvider.tsx
234
+ import { jsx as jsx2 } from "react/jsx-runtime";
229
235
  function SummonProvider({
230
236
  store,
231
237
  ports,
@@ -263,49 +269,52 @@ function SummonProvider({
263
269
  return /* @__PURE__ */ jsx2(Provider, { store: activeStore, context: SummonStoreContext, children: /* @__PURE__ */ jsx2(SummonPortsContext.Provider, { value: resolvedPorts, children: /* @__PURE__ */ jsx2(SummonConfigContext.Provider, { value: config, children }) }) });
264
270
  }
265
271
 
266
- // src/react/defineOverlay.tsx
267
- import { useCallback as useCallback2, useEffect as useEffect4, useMemo as useMemo3, useRef as useRef3, useState as useState2 } from "react";
272
+ // src/react.ts
268
273
  import {
269
- DEFAULT_INSTANCE_ID as DEFAULT_INSTANCE_ID2,
270
- instanceKey as toInstanceKey
271
- } from "@ai-matrx/summon";
272
- import { selectIsOverlayOpen } from "@ai-matrx/summon";
273
-
274
- // src/react/dispatchers.ts
275
- import { closeOverlay, openOverlay } from "@ai-matrx/summon";
276
- import { DEFAULT_INSTANCE_ID } from "@ai-matrx/summon";
277
- function newInstanceId(overlayId) {
278
- return `${overlayId}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
279
- }
280
- function dispatchOpen(dispatch, overlayId, instanceId, data) {
281
- dispatch(
282
- openOverlay({
283
- overlayId,
284
- instanceId,
285
- data: data ?? null
286
- })
287
- );
288
- }
289
- function dispatchClose(dispatch, overlayId, instanceId = DEFAULT_INSTANCE_ID) {
290
- dispatch(closeOverlay({ overlayId, instanceId }));
291
- }
274
+ defineOverlay,
275
+ CALLBACK_GROUP_KEY
276
+ } from "@ai-matrx/summon/root";
292
277
 
293
278
  // src/react/events.ts
294
279
  import { createEventChannel, getEventChannel } from "@ai-matrx/summon/handles";
295
- function openOverlayEventChannel(owner, getHandlers) {
296
- const channel = createEventChannel({ owner });
297
- channel.subscribe((message) => {
298
- const handlers = getHandlers();
299
- handlers?.[message.type]?.(message.payload);
300
- });
301
- return channel.id;
302
- }
280
+ import { materializePendingChannels } from "@ai-matrx/summon/open";
281
+ import { registerOverlayEmitter } from "@ai-matrx/summon/root";
303
282
  function emitOverlayEvent(channelId, type, payload) {
283
+ materializePendingChannels(createEventChannel);
304
284
  getEventChannel(channelId)?.emit({ type, payload });
305
285
  }
286
+ registerOverlayEmitter(emitOverlayEvent);
287
+
288
+ // src/react/SummonHost.tsx
289
+ import { Activity, memo as memo2, useCallback as useCallback2, useEffect as useEffect4, useRef as useRef3, useState as useState2 } from "react";
290
+ import { releaseOverlayInstance } from "@ai-matrx/summon";
291
+ import { registerOverlayMeta } from "@ai-matrx/summon";
292
+ import { closeOverlaysBoundToPage, overlayIdsBoundToPage, selectOpenInstances } from "@ai-matrx/summon";
293
+ import { instanceKey as toInstanceKey } from "@ai-matrx/summon";
294
+ import { dispatchClose } from "@ai-matrx/summon/root";
295
+
296
+ // src/react/hostRenders.ts
297
+ import { createContext as createContext2 } from "react";
298
+ var HostRendersContext = createContext2(null);
299
+ var MISSING_RENDER_ERROR = "OverlayRenderMissingError";
300
+ var missing = /* @__PURE__ */ new Map();
301
+ function missingRenderLoader(overlayId) {
302
+ let loader = missing.get(overlayId);
303
+ if (!loader) {
304
+ const message = `Overlay "${overlayId}" is open but has no render module: its definition has no \`render\` and <SummonHost renders> has no "${overlayId}" entry.`;
305
+ loader = () => {
306
+ if (process.env.NODE_ENV !== "production") console.error(`[summon] ${message}`);
307
+ const error = new Error(message);
308
+ error.name = MISSING_RENDER_ERROR;
309
+ return Promise.reject(error);
310
+ };
311
+ missing.set(overlayId, loader);
312
+ }
313
+ return loader;
314
+ }
306
315
 
307
316
  // src/react/instanceBody.tsx
308
- import { Suspense, memo, useContext as useContext3, useEffect as useEffect3, useMemo as useMemo2, useRef as useRef2 } from "react";
317
+ import { Suspense, memo, useContext as useContext2, useEffect as useEffect3, useMemo as useMemo2, useRef as useRef2 } from "react";
309
318
 
310
319
  // src/react/OverlayErrorBoundary.tsx
311
320
  import { Component } from "react";
@@ -356,20 +365,14 @@ var OverlayErrorBoundary = class extends Component {
356
365
  };
357
366
 
358
367
  // src/react/instance.tsx
359
- import { createContext as createContext2, useCallback, useContext as useContext2 } from "react";
368
+ import { useCallback } from "react";
360
369
  import { selectOverlayStateValue, setOverlayStateValue } from "@ai-matrx/summon";
361
- var OverlayInstanceContext = createContext2(null);
362
- OverlayInstanceContext.displayName = "OverlayInstanceContext";
363
- function useOverlayInstance() {
364
- const value = useContext2(OverlayInstanceContext);
365
- if (!value) {
366
- throw new Error("[summon] useOverlayInstance() was called outside a rendered overlay.");
367
- }
368
- return value;
369
- }
370
- function useOptionalOverlayInstance() {
371
- return useContext2(OverlayInstanceContext);
372
- }
370
+ import { useOverlayInstance } from "@ai-matrx/summon/root";
371
+ import {
372
+ OverlayInstanceContext,
373
+ useOverlayInstance as useOverlayInstance2,
374
+ useOptionalOverlayInstance
375
+ } from "@ai-matrx/summon/root";
373
376
  function useOverlayState(name, initial) {
374
377
  const { instanceKey } = useOverlayInstance();
375
378
  const dispatch = useSummonDispatch();
@@ -390,26 +393,6 @@ function useOverlayState(name, initial) {
390
393
  return [value, setValue];
391
394
  }
392
395
 
393
- // src/react/hostRenders.ts
394
- import { createContext as createContext3 } from "react";
395
- var HostRendersContext = createContext3(null);
396
- var MISSING_RENDER_ERROR = "OverlayRenderMissingError";
397
- var missing = /* @__PURE__ */ new Map();
398
- function missingRenderLoader(overlayId) {
399
- let loader = missing.get(overlayId);
400
- if (!loader) {
401
- const message = `Overlay "${overlayId}" is open but has no render module: its definition has no \`render\` and <SummonHost renders> has no "${overlayId}" entry.`;
402
- loader = () => {
403
- if (process.env.NODE_ENV !== "production") console.error(`[summon] ${message}`);
404
- const error = new Error(message);
405
- error.name = MISSING_RENDER_ERROR;
406
- return Promise.reject(error);
407
- };
408
- missing.set(overlayId, loader);
409
- }
410
- return loader;
411
- }
412
-
413
396
  // src/react/instanceBody.tsx
414
397
  import { jsx as jsx4 } from "react/jsx-runtime";
415
398
  function LazyRender({ overlayId, instanceId, data, hidden, close, render, attemptRef }) {
@@ -423,7 +406,7 @@ function createInstanceBody(overlayId, label, ownRender, parse, refusable) {
423
406
  function OverlayInstanceBody({ instanceId, instanceKey, data, hidden, close }) {
424
407
  const config = useSummonConfig();
425
408
  const ports = useSummonPorts();
426
- const hostRenders = useContext3(HostRendersContext);
409
+ const hostRenders = useContext2(HostRendersContext);
427
410
  const hostRender = ownRender ? void 0 : hostRenders?.[overlayId];
428
411
  const render = ownRender ?? hostRender ?? missingRenderLoader(overlayId);
429
412
  const attemptRef = useRef2(0);
@@ -476,104 +459,7 @@ function createInstanceBody(overlayId, label, ownRender, parse, refusable) {
476
459
  return memo(OverlayInstanceBody);
477
460
  }
478
461
 
479
- // src/react/defineOverlay.tsx
480
- var CALLBACK_GROUP_KEY = "callbackGroupId";
481
- function openWith(dispatch, id, multi, options) {
482
- const instanceId = options?.instanceId ?? (multi ? newInstanceId(id) : DEFAULT_INSTANCE_ID2);
483
- const key = toInstanceKey(id, instanceId);
484
- const data = {};
485
- const given = options?.data;
486
- if (typeof given === "object" && given !== null) Object.assign(data, given);
487
- const handlers = options?.handlers;
488
- if (handlers) data[CALLBACK_GROUP_KEY] = openOverlayEventChannel(key, () => handlers);
489
- dispatchOpen(dispatch, id, instanceId, data);
490
- return { overlayId: id, instanceId, close: () => dispatchClose(dispatch, id, instanceId) };
491
- }
492
- function dataSignature(data) {
493
- try {
494
- return JSON.stringify(data, (_key, value) => typeof value === "function" ? void 0 : value);
495
- } catch {
496
- return String(Date.now());
497
- }
498
- }
499
- function defineOverlay() {
500
- return function define(spec) {
501
- const id = spec.id;
502
- const multi = spec.instance === "multi";
503
- const parse = spec.parse ?? ((raw) => raw);
504
- const Body = createInstanceBody(id, spec.label, spec.render, parse, spec.parse !== void 0);
505
- const meta = spec;
506
- function useSummon() {
507
- const dispatch = useSummonDispatch();
508
- return useCallback2((options) => openWith(dispatch, id, multi, options), [dispatch]);
509
- }
510
- function useIsOpen(instanceId = DEFAULT_INSTANCE_ID2) {
511
- return useSummonSelector((state) => selectIsOverlayOpen(state, id, instanceId));
512
- }
513
- function useClose() {
514
- const dispatch = useSummonDispatch();
515
- return useCallback2((instanceId) => dispatchClose(dispatch, id, instanceId ?? DEFAULT_INSTANCE_ID2), [dispatch]);
516
- }
517
- function useEmit() {
518
- const instance = useOptionalOverlayInstance();
519
- const channelId = instance?.overlayId === id ? instance.rawData?.[CALLBACK_GROUP_KEY] : void 0;
520
- return useCallback2(
521
- (event, payload) => {
522
- if (typeof channelId === "string") emitOverlayEvent(channelId, event, payload);
523
- },
524
- [channelId]
525
- );
526
- }
527
- function Controller(props) {
528
- const dispatch = useSummonDispatch();
529
- const [ownInstanceId] = useState2(() => multi ? newInstanceId(id) : DEFAULT_INSTANCE_ID2);
530
- const instanceId = props.instanceId ?? ownInstanceId;
531
- const handlersRef = useRef3(props.handlers);
532
- handlersRef.current = props.handlers;
533
- const hasHandlers = props.handlers !== void 0;
534
- const data = useMemo3(() => {
535
- const out = {};
536
- for (const [key, value] of Object.entries(props)) {
537
- if (key !== "instanceId" && key !== "handlers") out[key] = value;
538
- }
539
- return out;
540
- }, [props]);
541
- const signature = dataSignature(data);
542
- const dataRef = useRef3(data);
543
- dataRef.current = data;
544
- useEffect4(() => {
545
- const key = toInstanceKey(id, instanceId);
546
- const open = { ...dataRef.current };
547
- if (hasHandlers) open[CALLBACK_GROUP_KEY] = openOverlayEventChannel(key, () => handlersRef.current);
548
- dispatchOpen(dispatch, id, instanceId, open);
549
- return () => dispatchClose(dispatch, id, instanceId);
550
- }, [dispatch, instanceId, signature, hasHandlers]);
551
- return null;
552
- }
553
- Controller.displayName = `${id}Controller`;
554
- return {
555
- ...spec,
556
- id,
557
- label: spec.label,
558
- instance: multi ? "multi" : "single",
559
- keepAlive: spec.keepAlive ?? "none",
560
- meta,
561
- Body,
562
- useSummon,
563
- Controller,
564
- useIsOpen,
565
- useClose,
566
- useEmit
567
- };
568
- };
569
- }
570
-
571
462
  // src/react/SummonHost.tsx
572
- import { Activity, memo as memo2, useCallback as useCallback3, useEffect as useEffect5, useRef as useRef4, useState as useState3 } from "react";
573
- import { releaseOverlayInstance } from "@ai-matrx/summon";
574
- import { registerOverlayMeta } from "@ai-matrx/summon";
575
- import { closeOverlaysBoundToPage, overlayIdsBoundToPage, selectOpenInstances } from "@ai-matrx/summon";
576
- import { instanceKey as toInstanceKey2 } from "@ai-matrx/summon";
577
463
  import { Fragment, jsx as jsx5 } from "react/jsx-runtime";
578
464
  function asRawData(data) {
579
465
  return typeof data === "object" && data !== null && !Array.isArray(data) ? data : null;
@@ -588,11 +474,22 @@ function sameInstances(a, b) {
588
474
  }
589
475
  return true;
590
476
  }
477
+ var bodies = /* @__PURE__ */ new WeakMap();
478
+ function bodyOf(definition) {
479
+ let body = bodies.get(definition);
480
+ if (!body) {
481
+ const parse = definition.parse ?? ((raw) => raw);
482
+ const render = definition.render;
483
+ body = createInstanceBody(definition.id, definition.label, render, parse, definition.parse !== void 0);
484
+ bodies.set(definition, body);
485
+ }
486
+ return body;
487
+ }
591
488
  var NO_RETAINED = /* @__PURE__ */ new Map();
592
489
  function useCloseOnNavigation() {
593
490
  const ports = useSummonPorts();
594
491
  const dispatch = useSummonDispatch();
595
- useEffect5(() => {
492
+ useEffect4(() => {
596
493
  const router = ports.router;
597
494
  let previous = router.pathname();
598
495
  return router.subscribe(() => {
@@ -606,17 +503,17 @@ function useCloseOnNavigation() {
606
503
  }
607
504
  var InstanceSlot = memo2(function InstanceSlot2({ definition, instanceId, data, hidden }) {
608
505
  const dispatch = useSummonDispatch();
609
- const close = useCallback3(() => dispatchClose(dispatch, definition.id, instanceId), [dispatch, definition.id, instanceId]);
610
- const Body = definition.Body;
611
- return /* @__PURE__ */ jsx5(Body, { instanceId, instanceKey: toInstanceKey2(definition.id, instanceId), data, hidden, close });
506
+ const close = useCallback2(() => dispatchClose(dispatch, definition.id, instanceId), [dispatch, definition.id, instanceId]);
507
+ const Body = bodyOf(definition);
508
+ return /* @__PURE__ */ jsx5(Body, { instanceId, instanceKey: toInstanceKey(definition.id, instanceId), data, hidden, close });
612
509
  });
613
510
  var DefinitionSlot = memo2(function DefinitionSlot2({ definition }) {
614
511
  const { keepAlive } = useSummonConfig();
615
512
  const dispatch = useSummonDispatch();
616
513
  const open = useSummonSelector((state) => selectOpenInstances(state, definition.id), sameInstances);
617
514
  const keepHidden = definition.keepAlive === "hidden";
618
- const [retained, setRetained] = useState3(NO_RETAINED);
619
- const [previousOpen, setPreviousOpen] = useState3(open);
515
+ const [retained, setRetained] = useState2(NO_RETAINED);
516
+ const [previousOpen, setPreviousOpen] = useState2(open);
620
517
  if (previousOpen !== open) {
621
518
  setPreviousOpen(open);
622
519
  if (keepHidden) {
@@ -629,13 +526,13 @@ var DefinitionSlot = memo2(function DefinitionSlot2({ definition }) {
629
526
  setRetained(next);
630
527
  }
631
528
  }
632
- const registered = useRef4(/* @__PURE__ */ new Set());
633
- useEffect5(() => {
529
+ const registered = useRef3(/* @__PURE__ */ new Set());
530
+ useEffect4(() => {
634
531
  const seen = registered.current;
635
532
  for (const instanceId of retained.keys()) {
636
533
  if (seen.has(instanceId)) continue;
637
534
  seen.add(instanceId);
638
- const key = toInstanceKey2(definition.id, instanceId);
535
+ const key = toInstanceKey(definition.id, instanceId);
639
536
  keepAlive.retain(key, () => {
640
537
  seen.delete(instanceId);
641
538
  releaseOverlayInstance(dispatch, key);
@@ -650,14 +547,14 @@ var DefinitionSlot = memo2(function DefinitionSlot2({ definition }) {
650
547
  for (const instanceId of [...seen]) {
651
548
  if (retained.has(instanceId)) continue;
652
549
  seen.delete(instanceId);
653
- keepAlive.release(toInstanceKey2(definition.id, instanceId));
550
+ keepAlive.release(toInstanceKey(definition.id, instanceId));
654
551
  }
655
552
  }, [retained, keepAlive, definition.id, dispatch]);
656
- useEffect5(() => {
553
+ useEffect4(() => {
657
554
  const seen = registered.current;
658
555
  return () => {
659
556
  for (const instanceId of seen) {
660
- const key = toInstanceKey2(definition.id, instanceId);
557
+ const key = toInstanceKey(definition.id, instanceId);
661
558
  keepAlive.release(key);
662
559
  releaseOverlayInstance(dispatch, key);
663
560
  }
@@ -682,7 +579,7 @@ var DefinitionSlot = memo2(function DefinitionSlot2({ definition }) {
682
579
  return /* @__PURE__ */ jsx5(Fragment, { children: nodes });
683
580
  });
684
581
  function SummonHost({ definitions, renders }) {
685
- const registeredFor = useRef4(null);
582
+ const registeredFor = useRef3(null);
686
583
  if (registeredFor.current !== definitions) {
687
584
  registerOverlayMeta(definitions.map((definition) => definition.meta));
688
585
  registeredFor.current = definitions;
@@ -691,41 +588,45 @@ function SummonHost({ definitions, renders }) {
691
588
  return /* @__PURE__ */ jsx5(HostRendersContext.Provider, { value: renders ?? null, children: definitions.map((definition) => /* @__PURE__ */ jsx5(DefinitionSlot, { definition }, definition.id)) });
692
589
  }
693
590
 
591
+ // src/react.ts
592
+ import { SummonRoot, configureSummonHost } from "@ai-matrx/summon/root";
593
+
694
594
  // src/react/hooks.ts
695
- import { useCallback as useCallback4 } from "react";
595
+ import { useCallback as useCallback3 } from "react";
696
596
  import { getOverlayMeta } from "@ai-matrx/summon";
697
- import { selectIsOverlayOpen as selectIsOverlayOpen2 } from "@ai-matrx/summon";
698
- import { DEFAULT_INSTANCE_ID as DEFAULT_INSTANCE_ID3 } from "@ai-matrx/summon";
699
- function useIsOverlayOpen(overlayId, instanceId = DEFAULT_INSTANCE_ID3) {
700
- return useSummonSelector((state) => selectIsOverlayOpen2(state, overlayId, instanceId));
597
+ import { selectIsOverlayOpen } from "@ai-matrx/summon";
598
+ import { DEFAULT_INSTANCE_ID } from "@ai-matrx/summon";
599
+ import { dispatchClose as dispatchClose2, dispatchOpen, newInstanceId } from "@ai-matrx/summon/root";
600
+ function useIsOverlayOpen(overlayId, instanceId = DEFAULT_INSTANCE_ID) {
601
+ return useSummonSelector((state) => selectIsOverlayOpen(state, overlayId, instanceId));
701
602
  }
702
603
  function useOpenOverlay(overlayId) {
703
604
  const dispatch = useSummonDispatch();
704
- return useCallback4(
605
+ return useCallback3(
705
606
  (options) => {
706
607
  const multi = getOverlayMeta(overlayId)?.instance === "multi";
707
- const instanceId = options?.instanceId ?? (multi ? newInstanceId(overlayId) : DEFAULT_INSTANCE_ID3);
608
+ const instanceId = options?.instanceId ?? (multi ? newInstanceId(overlayId) : DEFAULT_INSTANCE_ID);
708
609
  dispatchOpen(dispatch, overlayId, instanceId, options?.data ?? null);
709
- return { overlayId, instanceId, close: () => dispatchClose(dispatch, overlayId, instanceId) };
610
+ return { overlayId, instanceId, close: () => dispatchClose2(dispatch, overlayId, instanceId) };
710
611
  },
711
612
  [dispatch, overlayId]
712
613
  );
713
614
  }
714
- function useCloseOverlay(overlayId, instanceId = DEFAULT_INSTANCE_ID3) {
615
+ function useCloseOverlay(overlayId, instanceId = DEFAULT_INSTANCE_ID) {
715
616
  const dispatch = useSummonDispatch();
716
- return useCallback4(() => dispatchClose(dispatch, overlayId, instanceId), [dispatch, overlayId, instanceId]);
617
+ return useCallback3(() => dispatchClose2(dispatch, overlayId, instanceId), [dispatch, overlayId, instanceId]);
717
618
  }
718
619
 
719
620
  // src/react/useOverlayLink.ts
720
- import { useEffect as useEffect6, useMemo as useMemo4 } from "react";
621
+ import { useEffect as useEffect5, useMemo as useMemo3 } from "react";
721
622
  import { registerSyncEntry, unregisterSyncEntry } from "@ai-matrx/summon";
722
623
  function useOverlayLink(linkKey, id, args) {
723
624
  const dispatch = useSummonDispatch();
724
625
  const argsKey = args ? JSON.stringify(
725
626
  Object.keys(args).sort().map((k) => [k, args[k]])
726
627
  ) : "";
727
- const stableArgs = useMemo4(() => args ? { ...args } : void 0, [argsKey]);
728
- useEffect6(() => {
628
+ const stableArgs = useMemo3(() => args ? { ...args } : void 0, [argsKey]);
629
+ useEffect5(() => {
729
630
  if (!linkKey || !id) return void 0;
730
631
  dispatch(registerSyncEntry(stableArgs ? { typeKey: linkKey, instanceId: id, args: stableArgs } : { typeKey: linkKey, instanceId: id }));
731
632
  return () => {
@@ -744,9 +645,12 @@ export {
744
645
  OverlayLoadingFallback,
745
646
  SummonHost,
746
647
  SummonProvider,
648
+ SummonRoot,
747
649
  SummonStoreContext,
748
650
  chunkTimeoutError,
651
+ configureSummonHost,
749
652
  defineOverlay,
653
+ emitOverlayEvent,
750
654
  normalizeOverlayError,
751
655
  useCloseOnNavigation,
752
656
  useCloseOverlay,
@@ -755,7 +659,7 @@ export {
755
659
  useOptionalOverlayInstance,
756
660
  useOptionalSummonPorts,
757
661
  useOptionalSummonStore,
758
- useOverlayInstance,
662
+ useOverlayInstance2 as useOverlayInstance,
759
663
  useOverlayLink,
760
664
  useOverlayState,
761
665
  useSummonDispatch,