@ai-matrx/summon 0.1.16 → 0.1.18

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/dist/open.js CHANGED
@@ -1,185 +1,74 @@
1
- // src/core/types.ts
2
- var DEFAULT_INSTANCE_ID = "default";
3
- function instanceKey(overlayId, instanceId = DEFAULT_INSTANCE_ID) {
4
- return `${overlayId}:${instanceId}`;
5
- }
6
- function parseInstanceKey(key) {
7
- const at = key.indexOf(":");
8
- if (at <= 0 || at === key.length - 1) return null;
9
- return { overlayId: key.slice(0, at), instanceId: key.slice(at + 1) };
10
- }
11
- function defaultWindowIdFor(meta) {
12
- return meta.window?.windowId ?? meta.id;
13
- }
14
-
15
- // src/core/ports.ts
16
- var noop = () => {
17
- };
18
- var anonymousIdentity = {
19
- current: () => ({ key: "anonymous", ready: true }),
20
- subscribe: () => noop
21
- };
22
- var locationRouter = {
23
- pathname: () => typeof window === "undefined" ? "/" : window.location.pathname,
24
- search: () => typeof window === "undefined" ? "" : window.location.search,
25
- replaceSearch: (nextSearch) => {
26
- if (typeof window === "undefined") return;
27
- const query = nextSearch && !nextSearch.startsWith("?") ? `?${nextSearch}` : nextSearch;
28
- const url = `${window.location.pathname}${query}${window.location.hash}`;
29
- window.history.replaceState(window.history.state, "", url);
30
- },
31
- subscribe: (listener) => {
32
- if (typeof window === "undefined") return noop;
33
- window.addEventListener("popstate", listener);
34
- return () => window.removeEventListener("popstate", listener);
35
- }
36
- };
37
- var consoleNotify = {
38
- info: (message) => console.info(`[summon] ${message}`),
39
- warn: (message) => console.warn(`[summon] ${message}`),
40
- error: (message) => console.error(`[summon] ${message}`)
41
- };
42
- var consoleErrorSink = {
43
- capture: (error, context) => console.error("[summon]", error, context)
44
- };
45
- var debugOff = { enabled: () => false };
46
- var DEFAULT_PORTS = {
47
- identity: anonymousIdentity,
48
- router: locationRouter,
49
- notify: consoleNotify,
50
- errors: consoleErrorSink,
51
- debug: debugOff,
52
- persistence: null
53
- };
54
- function resolvePorts(overrides) {
55
- return { ...DEFAULT_PORTS, ...overrides };
56
- }
57
-
58
- // src/core/registry.ts
59
- import { globalSlot } from "@ai-matrx/kit/global-slot";
60
- var state = () => globalSlot("ai-matrx.summon.registry", () => ({
61
- byId: /* @__PURE__ */ new Map(),
62
- byLinkKey: /* @__PURE__ */ new Map(),
63
- listeners: /* @__PURE__ */ new Set()
64
- }));
65
- function registerOverlayMeta(definitions) {
66
- const s = state();
67
- for (const def of definitions) {
68
- s.byId.set(def.id, def);
69
- const keys = def.link ? [def.link.key, ...def.link.aliases ?? []] : [];
70
- for (const key of keys) {
71
- const holder = s.byLinkKey.get(key);
72
- if (holder && holder.id !== def.id) {
73
- throw new Error(`[summon] link key "${key}" is claimed by both "${holder.id}" and "${def.id}"`);
74
- }
75
- s.byLinkKey.set(key, def);
76
- }
77
- }
78
- for (const listener of s.listeners) listener();
79
- }
80
- function getOverlayMeta(overlayId) {
81
- return state().byId.get(overlayId);
82
- }
83
- function getOverlayMetaByLinkKey(linkKey) {
84
- return state().byLinkKey.get(linkKey);
85
- }
86
- function allOverlayMeta() {
87
- return [...state().byId.values()];
88
- }
89
- function isRegisteredOverlay(overlayId) {
90
- return state().byId.has(overlayId);
91
- }
92
- function subscribeToOverlayRegistry(listener) {
93
- const s = state();
94
- s.listeners.add(listener);
95
- return () => s.listeners.delete(listener);
96
- }
97
- function resetOverlayRegistry() {
98
- const s = state();
99
- s.byId.clear();
100
- s.byLinkKey.clear();
101
- }
102
-
103
- // src/open/actions.ts
104
- function creator(type, build) {
105
- const create = (...args) => ({ type, payload: build(...args) });
106
- return Object.assign(create, {
107
- type,
108
- toString: () => type,
109
- match: (action) => typeof action === "object" && action !== null && action.type === type
110
- });
111
- }
112
- function isPlainRecord(value) {
113
- return typeof value === "object" && value !== null && !Array.isArray(value);
114
- }
115
- function stripFunctions(overlayId, data) {
116
- if (!isPlainRecord(data)) return data;
117
- const offenders = Object.keys(data).filter((key) => typeof data[key] === "function");
118
- if (offenders.length === 0) return data;
119
- console.error(
120
- `[summon] BUG: function value(s) in openOverlay data for "${overlayId}" (keys: ${offenders.join(", ")}). Functions cannot travel through Redux \u2014 the handler would NEVER fire. Register a handle (@ai-matrx/summon/handles) and pass its id string instead. The offending key(s) were stripped from state.`
121
- );
122
- const cleaned = { ...data };
123
- for (const key of offenders) delete cleaned[key];
124
- return cleaned;
125
- }
126
- function rawOpen(payload) {
127
- const raw = { overlayId: payload.overlayId };
128
- if (payload.instanceId !== void 0) raw.instanceId = payload.instanceId;
129
- if (payload.data !== void 0) raw.data = stripFunctions(payload.overlayId, payload.data);
130
- const defaults = getOverlayMeta(payload.overlayId)?.defaults;
131
- if (isPlainRecord(defaults)) raw.defaults = stripFunctions(payload.overlayId, defaults);
132
- return raw;
133
- }
134
- var O = "overlays/";
135
- var openOverlay = creator(O + "openOverlay", (payload) => rawOpen(payload));
136
- var closeOverlay = creator(
137
- O + "closeOverlay",
138
- (payload) => payload.instanceId === void 0 ? { overlayId: payload.overlayId } : { overlayId: payload.overlayId, instanceId: payload.instanceId }
139
- );
140
- var toggleOverlay = creator(O + "toggleOverlay", (payload) => rawOpen(payload));
141
- var closeAllInstancesOfOverlay = creator(O + "closeAllInstancesOfOverlay", (payload) => ({
142
- overlayId: payload.overlayId
143
- }));
144
- function overlayIdsBoundToPage() {
145
- return allOverlayMeta().filter((meta) => meta.closesOnNavigation === true).map((meta) => meta.id);
146
- }
147
- var closeOverlaysBoundToPage = creator(
148
- O + "closeOverlaysBoundToPage",
149
- (payload) => ({
150
- overlayIds: [...payload?.overlayIds ?? overlayIdsBoundToPage()]
151
- })
152
- );
153
- var closeAllOverlays = creator(O + "closeAllOverlays", () => void 0);
154
- var pruneStaleInstances = creator(O + "pruneStaleInstances", (payload) => payload);
155
- var W = "windowManager/";
156
- var pass = () => (payload) => payload;
157
- var focusWindow = creator(W + "focusWindow", pass());
158
- var restoreWindow = creator(W + "restoreWindow", pass());
159
- var toggleWindowsHidden = creator(W + "toggleWindowsHidden", () => void 0);
160
- var restoreAll = creator(W + "restoreAll", () => void 0);
161
- var minimizeAll = creator(W + "minimizeAll", pass());
162
- var arrangeActiveWindows = creator(W + "arrangeActiveWindows", pass());
163
- var revealWindow = creator(W + "revealWindow", pass());
164
- var updateWindowRect = creator(
165
- W + "updateWindowRect",
166
- pass()
167
- );
168
- var setOverlayStateValue = creator("overlayState/setOverlayStateValue", pass());
169
- var registerSyncEntry = creator("urlSync/registerSyncEntry", pass());
170
- var unregisterSyncEntry = creator("urlSync/unregisterSyncEntry", pass());
171
- var SUMMON_SLICE_KEYS = ["overlays", "windowManager", "urlSync", "overlayState"];
172
- function isSummonAction(action) {
173
- if (typeof action !== "object" || action === null) return false;
174
- const type = action.type;
175
- if (typeof type !== "string") return false;
176
- const slash = type.indexOf("/");
177
- return slash > 0 && SUMMON_SLICE_KEYS.includes(type.slice(0, slash));
178
- }
1
+ import {
2
+ DEFAULT_INSTANCE_ID,
3
+ DEFAULT_PORTS,
4
+ SUMMON_INSTALLED_ACTION,
5
+ SUMMON_SLICE_KEYS,
6
+ allOverlayMeta,
7
+ anonymousIdentity,
8
+ arrangeActiveWindows,
9
+ closeAllInstancesOfOverlay,
10
+ closeAllOverlays,
11
+ closeOverlay,
12
+ closeOverlaysBoundToPage,
13
+ consoleErrorSink,
14
+ consoleNotify,
15
+ createSummonGate,
16
+ debugOff,
17
+ defaultWindowIdFor,
18
+ dropPendingChannelsOf,
19
+ ensureSummonRuntime,
20
+ focusWindow,
21
+ getOverlayMeta,
22
+ getOverlayMetaByLinkKey,
23
+ installSummonCore,
24
+ instanceKey,
25
+ isRegisteredOverlay,
26
+ isSummonAction,
27
+ isSummonInstalled,
28
+ listOpenInstanceKeys,
29
+ locationRouter,
30
+ materializePendingChannels,
31
+ minimizeAll,
32
+ openOverlay,
33
+ openPendingEventChannel,
34
+ overlayIdsBoundToPage,
35
+ parseInstanceKey,
36
+ prefetchSummonRuntime,
37
+ pruneStaleInstances,
38
+ registerOverlayMeta,
39
+ registerSyncEntry,
40
+ resetOverlayRegistry,
41
+ resolvePorts,
42
+ restoreAll,
43
+ restoreWindow,
44
+ revealWindow,
45
+ selectAllMinimized,
46
+ selectAllWindows,
47
+ selectAnyOverlayTouched,
48
+ selectIsOverlayOpen,
49
+ selectOpenInstances,
50
+ selectOverlay,
51
+ selectOverlayData,
52
+ selectWindowsHidden,
53
+ setOverlayStateValue,
54
+ subscribeSummonInstalled,
55
+ subscribeToOverlayRegistry,
56
+ toggleOverlay,
57
+ toggleWindowsHidden,
58
+ unregisterSyncEntry,
59
+ updateWindowRect
60
+ } from "./chunk-server-C4KQZFIN.js";
61
+ import {
62
+ HANDLES_SLOT,
63
+ newHandleId,
64
+ registerHandleEntry,
65
+ removeHandleGroup,
66
+ unregisterHandleEntry
67
+ } from "./chunk-server-H7NUWPEM.js";
179
68
 
180
69
  // src/open/renderAcks.ts
181
- import { globalSlot as globalSlot2 } from "@ai-matrx/kit/global-slot";
182
- var slot = () => globalSlot2("ai-matrx.summon.renderWatchdog", () => ({ renderAcks: /* @__PURE__ */ new Map(), ackWaiters: /* @__PURE__ */ new Map(), watches: /* @__PURE__ */ new Map() }));
70
+ import { globalSlot } from "@ai-matrx/kit/global-slot";
71
+ var slot = () => globalSlot("ai-matrx.summon.renderWatchdog", () => ({ renderAcks: /* @__PURE__ */ new Map(), ackWaiters: /* @__PURE__ */ new Map(), watches: /* @__PURE__ */ new Map() }));
183
72
  function ackOverlaySurfaceRender(overlayId) {
184
73
  const s = slot();
185
74
  s.renderAcks.set(overlayId, { kind: "surface" });
@@ -194,162 +83,10 @@ function clearOverlaySurfaceRender(overlayId) {
194
83
  if (s.renderAcks.get(overlayId)?.kind === "surface") s.renderAcks.delete(overlayId);
195
84
  }
196
85
 
197
- // src/open/selectors.ts
198
- import { globalSlot as globalSlot3 } from "@ai-matrx/kit/global-slot";
199
- var overlaysOf = (state2) => state2.overlays;
200
- var CLOSED = Object.freeze({ isOpen: false, data: null });
201
- var EMPTY = Object.freeze([]);
202
- var selectOverlay = (state2, overlayId, instanceId = DEFAULT_INSTANCE_ID) => overlaysOf(state2)?.overlays[overlayId]?.[instanceId] ?? CLOSED;
203
- var selectIsOverlayOpen = (state2, overlayId, instanceId = DEFAULT_INSTANCE_ID) => selectOverlay(state2, overlayId, instanceId).isOpen;
204
- var selectOverlayData = (state2, overlayId, instanceId = DEFAULT_INSTANCE_ID) => selectOverlay(state2, overlayId, instanceId).data;
205
- var openCache = () => globalSlot3("ai-matrx.summon.openInstances", () => /* @__PURE__ */ new Map());
206
- var selectOpenInstances = (state2, overlayId) => {
207
- const bucket = overlaysOf(state2)?.overlays[overlayId];
208
- const cache = openCache();
209
- const hit = cache.get(overlayId);
210
- if (hit && hit.bucket === bucket) return hit.result;
211
- let result = EMPTY;
212
- if (bucket) {
213
- const open = [];
214
- for (const [instanceId, inst] of Object.entries(bucket)) if (inst.isOpen) open.push({ instanceId, data: inst.data });
215
- if (open.length > 0) result = open;
216
- }
217
- cache.set(overlayId, { bucket, result });
218
- return result;
219
- };
220
- function listOpenInstanceKeys(state2) {
221
- const keys = [];
222
- for (const [overlayId, bucket] of Object.entries(overlaysOf(state2)?.overlays ?? {})) {
223
- for (const [instanceId, inst] of Object.entries(bucket)) if (inst.isOpen) keys.push(`${overlayId}:${instanceId}`);
224
- }
225
- return keys;
226
- }
227
- function selectAnyOverlayTouched(state2) {
228
- for (const _ in overlaysOf(state2)?.overlays ?? {}) return true;
229
- return false;
230
- }
231
- var selectWindowsHidden = (state2) => state2.windowManager?.windowsHidden ?? false;
232
- var EMPTY_WINDOWS = Object.freeze([]);
233
- var lastWindowsMap = null;
234
- var lastWindows = EMPTY_WINDOWS;
235
- function selectAllWindows(state2) {
236
- const map = state2.windowManager?.windows;
237
- if (!map) return EMPTY_WINDOWS;
238
- if (map !== lastWindowsMap) {
239
- lastWindowsMap = map;
240
- lastWindows = Object.values(map).sort((a, b) => b.zIndex - a.zIndex);
241
- }
242
- return lastWindows;
243
- }
244
- function selectAllMinimized(state2) {
245
- const map = state2.windowManager?.windows;
246
- if (!map) return false;
247
- const wins = Object.values(map);
248
- return wins.length > 0 && wins.every((w) => w.state === "minimized");
249
- }
250
-
251
- // src/open/gate.ts
252
- import { globalSlot as globalSlot4 } from "@ai-matrx/kit/global-slot";
253
- var SUMMON_INSTALLED_ACTION = "@@summon/installed";
254
- var slot2 = () => globalSlot4("ai-matrx.summon.gate", () => ({ core: null, loading: null, gates: /* @__PURE__ */ new Set(), listeners: /* @__PURE__ */ new Set() }));
255
- function installSummonCore(core) {
256
- const s = slot2();
257
- if (s.core) return;
258
- s.core = core;
259
- const gates = [...s.gates];
260
- s.gates.clear();
261
- for (const gate of gates) gate.install(core);
262
- for (const listener of [...s.listeners]) listener();
263
- }
264
- function isSummonInstalled() {
265
- return slot2().core !== null;
266
- }
267
- function subscribeSummonInstalled(listener) {
268
- const s = slot2();
269
- s.listeners.add(listener);
270
- return () => s.listeners.delete(listener);
271
- }
272
- function ensureSummonRuntime() {
273
- const s = slot2();
274
- if (s.core) return Promise.resolve();
275
- s.loading ??= import("@ai-matrx/summon").then(
276
- (core) => installSummonCore(core.summonCore),
277
- (error) => {
278
- s.loading = null;
279
- throw error;
280
- }
281
- );
282
- return s.loading;
283
- }
284
- function prefetchSummonRuntime() {
285
- ensureSummonRuntime().catch(() => void 0);
286
- }
287
- function createSummonGate(options = {}) {
288
- let inject = null;
289
- let injected = false;
290
- let api = null;
291
- let next = null;
292
- let chain = null;
293
- const queue = [];
294
- const settle = (core2, live) => {
295
- if (inject && !injected) {
296
- inject(core2.reducers);
297
- injected = true;
298
- }
299
- if (!api || !next || chain) return;
300
- const store = api;
301
- let composed = next;
302
- for (const middleware2 of [...core2.createMiddleware(options.ports)].reverse()) {
303
- composed = middleware2(store)(composed);
304
- }
305
- chain = composed;
306
- const flush = () => {
307
- if (live) store.dispatch({ type: SUMMON_INSTALLED_ACTION });
308
- for (const action of queue.splice(0)) store.dispatch(action);
309
- };
310
- if (live) flush();
311
- else if (queue.length > 0) queueMicrotask(flush);
312
- };
313
- const internals = { install: (core2) => settle(core2, true) };
314
- const core = () => slot2().core;
315
- const middleware = (storeApi) => {
316
- api = storeApi;
317
- return (nextDispatch) => {
318
- next = nextDispatch;
319
- const loaded = core();
320
- if (loaded) settle(loaded, false);
321
- else slot2().gates.add(internals);
322
- return (action) => {
323
- if (chain) return chain(action);
324
- if (!isSummonAction(action)) return nextDispatch(action);
325
- queue.push(action);
326
- void ensureSummonRuntime().catch((error) => {
327
- console.error("[summon] the overlay runtime failed to load; queued requests are kept for the next try", error);
328
- });
329
- return action;
330
- };
331
- };
332
- };
333
- return {
334
- middleware,
335
- attachReducer(fn) {
336
- inject = fn;
337
- const loaded = core();
338
- if (loaded) {
339
- inject(loaded.reducers);
340
- injected = true;
341
- }
342
- }
343
- };
344
- }
345
-
346
- // src/handles/slot.ts
347
- var HANDLES_SLOT = "ai-matrx.summon.handles";
348
-
349
86
  // src/open/peek.ts
350
87
  function peekHandle(id) {
351
- const slot3 = globalThis[Symbol.for(HANDLES_SLOT)];
352
- return slot3?.callbacks.get(id)?.callback;
88
+ const slot2 = globalThis[Symbol.for(HANDLES_SLOT)];
89
+ return slot2?.callbacks.get(id)?.callback;
353
90
  }
354
91
 
355
92
  // src/open/lazyOpener.ts
@@ -391,7 +128,7 @@ function lazyOpener(overlayId, load, options = {}) {
391
128
  if (real) return real(...args);
392
129
  let target = null;
393
130
  let closed = false;
394
- const pending2 = [];
131
+ const pending = [];
395
132
  const standIn = {
396
133
  instanceId: instanceId ?? "",
397
134
  get callbackGroupId() {
@@ -399,7 +136,7 @@ function lazyOpener(overlayId, load, options = {}) {
399
136
  },
400
137
  update(patch) {
401
138
  if (target) target.update?.(patch);
402
- else if (!closed) pending2.push(patch);
139
+ else if (!closed) pending.push(patch);
403
140
  },
404
141
  close() {
405
142
  if (target) target.close?.();
@@ -411,7 +148,7 @@ function lazyOpener(overlayId, load, options = {}) {
411
148
  if (closed) return;
412
149
  const handle = opener(...args);
413
150
  target = handle ?? {};
414
- for (const patch of pending2.splice(0)) target.update?.(patch);
151
+ for (const patch of pending.splice(0)) target.update?.(patch);
415
152
  },
416
153
  (error) => {
417
154
  console.error(`[summon] the "${overlayId}" opener failed to load; nothing opened`, error);
@@ -422,28 +159,6 @@ function lazyOpener(overlayId, load, options = {}) {
422
159
  return lazy;
423
160
  }
424
161
 
425
- // src/open/channels.ts
426
- import { globalSlot as globalSlot5 } from "@ai-matrx/kit/global-slot";
427
- var pending = () => globalSlot5("ai-matrx.summon.pendingChannels", () => /* @__PURE__ */ new Map());
428
- function materializePendingChannels(createEventChannel) {
429
- const map = pending();
430
- for (const [id, entry] of [...map]) {
431
- map.delete(id);
432
- const channel = createEventChannel({ owner: entry.owner, id });
433
- channel.subscribe((message) => entry.getHandlers()?.[message.type]?.(message.payload));
434
- }
435
- }
436
- function openPendingEventChannel(owner, getHandlers) {
437
- const id = `ch-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
438
- pending().set(id, { owner, getHandlers });
439
- void import("@ai-matrx/summon/handles").then(({ createEventChannel }) => materializePendingChannels(createEventChannel));
440
- return id;
441
- }
442
- function dropPendingChannelsOf(owner) {
443
- const map = pending();
444
- for (const [id, entry] of [...map]) if (entry.owner === owner) map.delete(id);
445
- }
446
-
447
162
  // src/open/grammar.ts
448
163
  var hex = (ch) => `%${ch.charCodeAt(0).toString(16).toUpperCase().padStart(2, "0")}`;
449
164
  function encodeLinkId(id) {
@@ -501,6 +216,7 @@ export {
501
216
  materializePendingChannels,
502
217
  minimizeAll,
503
218
  mintInstanceId,
219
+ newHandleId,
504
220
  openOverlay,
505
221
  openPendingEventChannel,
506
222
  overlayIdsBoundToPage,
@@ -508,8 +224,10 @@ export {
508
224
  peekHandle,
509
225
  prefetchSummonRuntime,
510
226
  pruneStaleInstances,
227
+ registerHandleEntry,
511
228
  registerOverlayMeta,
512
229
  registerSyncEntry,
230
+ removeHandleGroup,
513
231
  resetOverlayRegistry,
514
232
  resolvePorts,
515
233
  restoreAll,
@@ -528,6 +246,7 @@ export {
528
246
  subscribeToOverlayRegistry,
529
247
  toggleOverlay,
530
248
  toggleWindowsHidden,
249
+ unregisterHandleEntry,
531
250
  unregisterSyncEntry,
532
251
  updateWindowRect
533
252
  };