@ai-matrx/summon 0.1.7 → 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/CHANGELOG.md +15 -2
- package/dist/gate-DUvE-Cc1.d.cts +399 -0
- package/dist/gate-DUvE-Cc1.d.ts +399 -0
- package/dist/handles.cjs +1 -0
- package/dist/handles.cjs.map +1 -1
- package/dist/handles.d.cts +3 -61
- package/dist/handles.d.ts +3 -61
- package/dist/handles.js +1 -0
- package/dist/handles.js.map +1 -1
- package/dist/helpers-2NY1ha0V.d.cts +63 -0
- package/dist/helpers-2NY1ha0V.d.ts +63 -0
- package/dist/index.cjs +194 -159
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -355
- package/dist/index.d.ts +9 -355
- package/dist/index.js +200 -165
- package/dist/index.js.map +1 -1
- package/dist/instanceBody-CgZAFnic.d.cts +23 -0
- package/dist/instanceBody-CgZAFnic.d.ts +23 -0
- package/dist/open.cjs +408 -0
- package/dist/open.cjs.map +1 -0
- package/dist/open.d.cts +22 -0
- package/dist/open.d.ts +22 -0
- package/dist/open.js +375 -0
- package/dist/open.js.map +1 -0
- package/dist/react.cjs +249 -352
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +11 -151
- package/dist/react.d.ts +11 -151
- package/dist/react.js +210 -306
- package/dist/react.js.map +1 -1
- package/dist/root.cjs +277 -0
- package/dist/root.cjs.map +1 -0
- package/dist/root.d.cts +175 -0
- package/dist/root.d.ts +175 -0
- package/dist/root.js +254 -0
- package/dist/root.js.map +1 -0
- package/dist/window-host.cjs +11 -2
- package/dist/window-host.cjs.map +1 -1
- package/dist/window-host.d.cts +1 -0
- package/dist/window-host.d.ts +1 -0
- package/dist/window-host.js +11 -2
- package/dist/window-host.js.map +1 -1
- package/dist/window.cjs +2 -1
- package/dist/window.cjs.map +1 -1
- package/dist/window.d.cts +3 -2
- package/dist/window.d.ts +3 -2
- package/dist/window.js +2 -1
- package/dist/window.js.map +1 -1
- package/package.json +28 -5
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
import { Reducer, Middleware } from '@reduxjs/toolkit';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The shared vocabulary of @ai-matrx/summon. Framework-free: no React, no Redux imports.
|
|
5
|
+
*
|
|
6
|
+
* An OVERLAY is any component rendered on top of the app by dispatch — a window, dialog, sheet,
|
|
7
|
+
* light floating window, toast-like card, anything. It is identified by an `OverlayId` and opened
|
|
8
|
+
* as one or more INSTANCES (`instanceId`, "default" for single-instance overlays).
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* The host's overlay registry: overlay id → the data its opener accepts. Hosts extend it by
|
|
12
|
+
* module augmentation so every open call is type-checked:
|
|
13
|
+
*
|
|
14
|
+
* declare module "@ai-matrx/summon" {
|
|
15
|
+
* interface OverlayRegistry { notesWindow: { noteId?: string } }
|
|
16
|
+
* }
|
|
17
|
+
*
|
|
18
|
+
* `defineOverlay` emits nothing at runtime for this; the augmentation is the host's one-line
|
|
19
|
+
* declaration per overlay (the converter writes it next to each definition).
|
|
20
|
+
*/
|
|
21
|
+
interface OverlayRegistry {
|
|
22
|
+
}
|
|
23
|
+
/** Every registered overlay id; plain `string` until the host augments the registry. */
|
|
24
|
+
type OverlayId = [keyof OverlayRegistry] extends [never] ? string : Extract<keyof OverlayRegistry, string>;
|
|
25
|
+
/** The open-data type declared for an overlay id. */
|
|
26
|
+
type OverlayDataOf<Id extends string> = Id extends keyof OverlayRegistry ? OverlayRegistry[Id] : Record<string, unknown>;
|
|
27
|
+
/**
|
|
28
|
+
* Data as it arrives at render time. It crossed Redux, a URL or storage, so it is NOT trusted to
|
|
29
|
+
* match the opener's type: render code narrows it (or the definition supplies `parse`).
|
|
30
|
+
*/
|
|
31
|
+
type OverlayRawData = Readonly<Record<string, unknown>> | null;
|
|
32
|
+
declare const DEFAULT_INSTANCE_ID = "default";
|
|
33
|
+
/** `single`: one instance ("default"). `multi`: any number, each with its own instanceId. */
|
|
34
|
+
type InstanceMode = "single" | "multi";
|
|
35
|
+
/**
|
|
36
|
+
* What closing does to a mounted overlay (Arman, 2026-10-16, C38 R3):
|
|
37
|
+
* none — unmount (default).
|
|
38
|
+
* hidden — stay mounted but hidden; reopening shows the same live component (LRU-capped).
|
|
39
|
+
* restore — unmount, but values saved with `useOverlayState` come back on reopen.
|
|
40
|
+
* Minimizing a window always keeps its component mounted, whatever this says.
|
|
41
|
+
*/
|
|
42
|
+
type KeepAlive = "none" | "hidden" | "restore";
|
|
43
|
+
/** `overlayId:instanceId` — the one key every subsystem uses for an open instance. */
|
|
44
|
+
type InstanceKey = `${string}:${string}`;
|
|
45
|
+
declare function instanceKey(overlayId: string, instanceId?: string): InstanceKey;
|
|
46
|
+
declare function parseInstanceKey(key: string): {
|
|
47
|
+
overlayId: string;
|
|
48
|
+
instanceId: string;
|
|
49
|
+
} | null;
|
|
50
|
+
type MobilePresentation = "fullscreen" | "drawer" | "card" | "hidden";
|
|
51
|
+
/**
|
|
52
|
+
* Default-deny allowlist of the open data a window may save and restore. A window with no
|
|
53
|
+
* preservation entry restores geometry only.
|
|
54
|
+
*/
|
|
55
|
+
interface WindowPreservation {
|
|
56
|
+
readonly dataKeys: readonly string[];
|
|
57
|
+
readonly requiredDataKeys?: readonly string[];
|
|
58
|
+
readonly allowedDataValues?: Readonly<Record<string, readonly (string | number | boolean | null)[]>>;
|
|
59
|
+
/** Default 32 KiB. */
|
|
60
|
+
readonly maxDataBytes?: number;
|
|
61
|
+
}
|
|
62
|
+
/** One declared home for an unbidden (system-raised) window: a route prefix, or one exact page. */
|
|
63
|
+
type UnbiddenHomeRoute = string | {
|
|
64
|
+
readonly route: string;
|
|
65
|
+
readonly exact: true;
|
|
66
|
+
};
|
|
67
|
+
interface OverlayWindowOptions {
|
|
68
|
+
readonly mobile?: MobilePresentation;
|
|
69
|
+
readonly mobileSidebarAs?: "drawer" | "inline";
|
|
70
|
+
/** Never saved or restored (debug panels, one-shot tools, callback-bound editors). */
|
|
71
|
+
readonly ephemeral?: boolean;
|
|
72
|
+
readonly preservation?: WindowPreservation;
|
|
73
|
+
/**
|
|
74
|
+
* Values merged under saved data when a window is RESTORED (reload, another device). Unlike the
|
|
75
|
+
* definition's `defaults`, never applied to a normal open.
|
|
76
|
+
*/
|
|
77
|
+
readonly restoreDefaults?: Readonly<Record<string, unknown>>;
|
|
78
|
+
/**
|
|
79
|
+
* The window-manager id the WindowPanel registers under for the default instance. Default: the
|
|
80
|
+
* overlay id. The render watchdog reveals and inspects this id until the panel acks its own.
|
|
81
|
+
*/
|
|
82
|
+
readonly windowId?: string;
|
|
83
|
+
readonly deprecated?: {
|
|
84
|
+
readonly replacement?: string;
|
|
85
|
+
readonly reason?: string;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Where a window nobody opened (system-raised) may raise itself. Default deny: no home → it may
|
|
89
|
+
* not raise itself anywhere (`mayRaiseUnbidden` in the window section).
|
|
90
|
+
*/
|
|
91
|
+
readonly unbiddenHome?: readonly UnbiddenHomeRoute[];
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Host-specific types the package passes through untouched. A Redux host augments `dispatch`
|
|
95
|
+
* with its thunk-aware dispatch so link hydrators can dispatch its thunks without casts:
|
|
96
|
+
*
|
|
97
|
+
* declare module "@ai-matrx/summon" { interface OverlayHostTypes { dispatch: AppDispatch } }
|
|
98
|
+
*/
|
|
99
|
+
interface OverlayHostTypes {
|
|
100
|
+
}
|
|
101
|
+
type OverlayHostDispatch = OverlayHostTypes extends {
|
|
102
|
+
dispatch: infer D;
|
|
103
|
+
} ? D : (action: unknown) => unknown;
|
|
104
|
+
interface LinkHydrateContext<Data> {
|
|
105
|
+
/** The id segment of the link token (`notes:<id>`). */
|
|
106
|
+
readonly id: string;
|
|
107
|
+
/** Decoded `k-v` arguments of the token. */
|
|
108
|
+
readonly args: Readonly<Record<string, string>>;
|
|
109
|
+
/** Open this overlay. */
|
|
110
|
+
open(options?: {
|
|
111
|
+
readonly instanceId?: string;
|
|
112
|
+
readonly data?: Data;
|
|
113
|
+
}): void;
|
|
114
|
+
/** The host store's dispatch, for thunks a hydrator needs (loading a record first). Typed by
|
|
115
|
+
* augmenting `OverlayHostTypes` with the host's dispatch type. */
|
|
116
|
+
readonly dispatch: OverlayHostDispatch;
|
|
117
|
+
}
|
|
118
|
+
interface OverlayLinkSpec<Data> {
|
|
119
|
+
/** The token type key in `?panels=key:id`. Unique across the host. */
|
|
120
|
+
readonly key: string;
|
|
121
|
+
/** Older keys that still resolve to this overlay. */
|
|
122
|
+
readonly aliases?: readonly string[];
|
|
123
|
+
/** Turn a link token into an open overlay (and its data). `"refused"` keeps the token and says why. */
|
|
124
|
+
hydrate(context: LinkHydrateContext<Data>): void | "refused" | Promise<void | "refused">;
|
|
125
|
+
}
|
|
126
|
+
interface OverlayDefinitionMeta<Id extends string = string, Data = Record<string, unknown>> {
|
|
127
|
+
readonly id: Id;
|
|
128
|
+
/** Human label: tray, menus, diagnostics. */
|
|
129
|
+
readonly label: string;
|
|
130
|
+
readonly instance?: InstanceMode;
|
|
131
|
+
readonly keepAlive?: KeepAlive;
|
|
132
|
+
/** Close when the route changes — the overlay shows a piece of the page that opened it. */
|
|
133
|
+
readonly closesOnNavigation?: boolean;
|
|
134
|
+
/** Present only for overlays that render a WindowPanel. */
|
|
135
|
+
readonly window?: OverlayWindowOptions;
|
|
136
|
+
readonly link?: OverlayLinkSpec<Data>;
|
|
137
|
+
/** Defaults merged under open data (replaces the old per-overlay schema registry). */
|
|
138
|
+
readonly defaults?: Partial<Data>;
|
|
139
|
+
}
|
|
140
|
+
/** The window-manager id a singleton window overlay registers under (`window.windowId ?? id`). */
|
|
141
|
+
declare function defaultWindowIdFor(meta: Pick<OverlayDefinitionMeta, "id" | "window">): string;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Everything the overlays system needs from its host, as ports. Every port ships a working
|
|
145
|
+
* default, so a bare host gets a working system with zero wiring (package standard rule 8); a
|
|
146
|
+
* host overrides only what it has: identity, navigation, notifications, error sink, debug flag,
|
|
147
|
+
* persistence. Framework-free.
|
|
148
|
+
*/
|
|
149
|
+
type Unsubscribe = () => void;
|
|
150
|
+
/** Who the person is, for isolating saved state. `key` changes → everything saved is swapped. */
|
|
151
|
+
interface IdentityPort {
|
|
152
|
+
current(): {
|
|
153
|
+
readonly key: string;
|
|
154
|
+
readonly ready: boolean;
|
|
155
|
+
};
|
|
156
|
+
subscribe(listener: () => void): Unsubscribe;
|
|
157
|
+
}
|
|
158
|
+
/** The address bar: route changes (close-on-navigation) and the `?panels=` link channel. */
|
|
159
|
+
interface RouterPort {
|
|
160
|
+
pathname(): string;
|
|
161
|
+
search(): string;
|
|
162
|
+
/** Replace the query string without navigating or remounting the page. */
|
|
163
|
+
replaceSearch(nextSearch: string): void;
|
|
164
|
+
subscribe(listener: () => void): Unsubscribe;
|
|
165
|
+
}
|
|
166
|
+
interface NotifyOptions {
|
|
167
|
+
readonly id?: string;
|
|
168
|
+
readonly description?: string;
|
|
169
|
+
/** How long the notice stays up (ms). Hosts without timed notices ignore it. */
|
|
170
|
+
readonly duration?: number;
|
|
171
|
+
/** One action button (e.g. the render watchdog's "Show it"). Hosts without actions ignore it. */
|
|
172
|
+
readonly action?: {
|
|
173
|
+
readonly label: string;
|
|
174
|
+
readonly onClick: () => void;
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
interface NotifyPort {
|
|
178
|
+
info(message: string, options?: NotifyOptions): void;
|
|
179
|
+
warn(message: string, options?: NotifyOptions): void;
|
|
180
|
+
error(message: string, options?: NotifyOptions): void;
|
|
181
|
+
/** Withdraw a notice by id (optional). */
|
|
182
|
+
dismiss?(id: string): void;
|
|
183
|
+
}
|
|
184
|
+
interface ErrorSinkPort {
|
|
185
|
+
capture(error: unknown, context: Readonly<Record<string, unknown>>): void;
|
|
186
|
+
}
|
|
187
|
+
interface DebugPort {
|
|
188
|
+
enabled(): boolean;
|
|
189
|
+
subscribe?(listener: () => void): Unsubscribe;
|
|
190
|
+
}
|
|
191
|
+
/** A stored value with its optimistic-concurrency version (0 when the store has none). */
|
|
192
|
+
interface StoredValue<T = unknown> {
|
|
193
|
+
readonly value: T;
|
|
194
|
+
readonly version: number;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Where saved overlay state lives when persistence is on. Keys are already scoped to the
|
|
198
|
+
* identity by the caller (`<identityKey>/<key>`) for stores that are not per-person themselves.
|
|
199
|
+
* Implementations: the browser-local store (`./persistence`), `@ai-matrx/data` over
|
|
200
|
+
* `users.user_surface_state` (`./persistence/data`), or any host database.
|
|
201
|
+
*/
|
|
202
|
+
interface OverlayPersistencePort {
|
|
203
|
+
/**
|
|
204
|
+
* True when the store is per-person itself (rows scoped to the signed-in person, e.g. the
|
|
205
|
+
* `@ai-matrx/data` adapter): the persistence section then passes plain keys (`workspace`,
|
|
206
|
+
* `state:<instanceKey>`) instead of `<identityKey>/<key>`, and defaults to `scope: "person"`.
|
|
207
|
+
*/
|
|
208
|
+
readonly perPerson?: boolean;
|
|
209
|
+
load<T = unknown>(key: string): Promise<StoredValue<T> | null>;
|
|
210
|
+
save<T = unknown>(key: string, value: T, options?: {
|
|
211
|
+
readonly expectedVersion?: number;
|
|
212
|
+
}): Promise<{
|
|
213
|
+
readonly version: number;
|
|
214
|
+
}>;
|
|
215
|
+
remove(key: string): Promise<void>;
|
|
216
|
+
list?(prefix: string): Promise<readonly string[]>;
|
|
217
|
+
/**
|
|
218
|
+
* Every saved value at once (key → value), for stores where one read is cheaper than several.
|
|
219
|
+
* When present, restoring an identity costs exactly this one call: the workspace and every
|
|
220
|
+
* saved component state come out of it, and `load`/`list` are not called on boot.
|
|
221
|
+
*/
|
|
222
|
+
loadAll?(): Promise<ReadonlyMap<string, StoredValue>>;
|
|
223
|
+
}
|
|
224
|
+
interface SummonPorts {
|
|
225
|
+
readonly identity: IdentityPort;
|
|
226
|
+
readonly router: RouterPort;
|
|
227
|
+
readonly notify: NotifyPort;
|
|
228
|
+
readonly errors: ErrorSinkPort;
|
|
229
|
+
readonly debug: DebugPort;
|
|
230
|
+
/** `null` = persistence off (R6). */
|
|
231
|
+
readonly persistence: OverlayPersistencePort | null;
|
|
232
|
+
}
|
|
233
|
+
declare const anonymousIdentity: IdentityPort;
|
|
234
|
+
/** `window.location` + `history.replaceState`; inert on the server. */
|
|
235
|
+
declare const locationRouter: RouterPort;
|
|
236
|
+
declare const consoleNotify: NotifyPort;
|
|
237
|
+
declare const consoleErrorSink: ErrorSinkPort;
|
|
238
|
+
declare const debugOff: DebugPort;
|
|
239
|
+
declare const DEFAULT_PORTS: SummonPorts;
|
|
240
|
+
declare function resolvePorts(overrides: Partial<SummonPorts> | undefined): SummonPorts;
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* A definition's meta with its data type erased, so definitions of every data shape share one
|
|
244
|
+
* registry without casts. (`never` erasure made `defaults` unassignable.)
|
|
245
|
+
*/
|
|
246
|
+
interface AnyOverlayMeta extends Omit<OverlayDefinitionMeta<string, unknown>, "defaults"> {
|
|
247
|
+
readonly defaults?: object | undefined;
|
|
248
|
+
}
|
|
249
|
+
type AnyMeta = AnyOverlayMeta;
|
|
250
|
+
/**
|
|
251
|
+
* Register (or re-register) definitions. Re-registering an id replaces it (hot reload). A link
|
|
252
|
+
* key claimed by two different ids is a host bug and throws, naming both.
|
|
253
|
+
*/
|
|
254
|
+
declare function registerOverlayMeta(definitions: readonly AnyOverlayMeta[]): void;
|
|
255
|
+
declare function getOverlayMeta(overlayId: string): AnyMeta | undefined;
|
|
256
|
+
declare function getOverlayMetaByLinkKey(linkKey: string): AnyMeta | undefined;
|
|
257
|
+
declare function allOverlayMeta(): readonly AnyMeta[];
|
|
258
|
+
declare function isRegisteredOverlay(overlayId: string): boolean;
|
|
259
|
+
declare function subscribeToOverlayRegistry(listener: () => void): () => void;
|
|
260
|
+
/** Test-only. */
|
|
261
|
+
declare function resetOverlayRegistry(): void;
|
|
262
|
+
|
|
263
|
+
interface OpenOverlayPayload<Id extends OverlayId = OverlayId> {
|
|
264
|
+
overlayId: Id;
|
|
265
|
+
instanceId?: string;
|
|
266
|
+
data?: OverlayDataOf<Id> | null;
|
|
267
|
+
}
|
|
268
|
+
interface CloseOverlayPayload<Id extends OverlayId = OverlayId> {
|
|
269
|
+
overlayId: Id;
|
|
270
|
+
instanceId?: string;
|
|
271
|
+
}
|
|
272
|
+
type ToggleOverlayPayload<Id extends OverlayId = OverlayId> = OpenOverlayPayload<Id>;
|
|
273
|
+
interface CloseAllInstancesPayload<Id extends OverlayId = OverlayId> {
|
|
274
|
+
overlayId: Id;
|
|
275
|
+
}
|
|
276
|
+
interface CloseOverlaysBoundToPagePayload {
|
|
277
|
+
/** Overlay ids whose definitions say `closesOnNavigation`. */
|
|
278
|
+
overlayIds: readonly string[];
|
|
279
|
+
}
|
|
280
|
+
interface PruneStaleInstancesPayload {
|
|
281
|
+
olderThanMs: number;
|
|
282
|
+
}
|
|
283
|
+
/** Raw reducer payload: untyped ids + the registry defaults the creator resolved. */
|
|
284
|
+
interface RawOpenPayload {
|
|
285
|
+
overlayId: string;
|
|
286
|
+
instanceId?: string;
|
|
287
|
+
data?: unknown;
|
|
288
|
+
defaults?: Readonly<Record<string, unknown>>;
|
|
289
|
+
}
|
|
290
|
+
interface SummonAction<P> {
|
|
291
|
+
type: string;
|
|
292
|
+
payload: P;
|
|
293
|
+
/** Structurally a Redux `UnknownAction`. */
|
|
294
|
+
[extra: string]: unknown;
|
|
295
|
+
}
|
|
296
|
+
type Creator<Args extends unknown[], P> = ((...args: Args) => SummonAction<P>) & {
|
|
297
|
+
readonly type: string;
|
|
298
|
+
match(action: unknown): action is SummonAction<P>;
|
|
299
|
+
};
|
|
300
|
+
declare const openOverlay: Creator<[payload: OpenOverlayPayload<string>], RawOpenPayload>;
|
|
301
|
+
declare const closeOverlay: Creator<[payload: CloseOverlayPayload<string>], {
|
|
302
|
+
overlayId: string;
|
|
303
|
+
instanceId?: never;
|
|
304
|
+
} | {
|
|
305
|
+
overlayId: string;
|
|
306
|
+
instanceId: string;
|
|
307
|
+
}>;
|
|
308
|
+
declare const toggleOverlay: Creator<[payload: ToggleOverlayPayload<string>], RawOpenPayload>;
|
|
309
|
+
declare const closeAllInstancesOfOverlay: Creator<[payload: CloseAllInstancesPayload<string>], {
|
|
310
|
+
overlayId: string;
|
|
311
|
+
}>;
|
|
312
|
+
/** Ids of every registered overlay whose definition says `closesOnNavigation`. */
|
|
313
|
+
declare function overlayIdsBoundToPage(): string[];
|
|
314
|
+
/** Close page-bound overlays. Omit the ids to use the registry's `closesOnNavigation` list. */
|
|
315
|
+
declare const closeOverlaysBoundToPage: Creator<[payload?: Partial<CloseOverlaysBoundToPagePayload> | undefined], CloseOverlaysBoundToPagePayload>;
|
|
316
|
+
declare const closeAllOverlays: Creator<[], undefined>;
|
|
317
|
+
declare const pruneStaleInstances: Creator<[payload: PruneStaleInstancesPayload], PruneStaleInstancesPayload>;
|
|
318
|
+
declare const focusWindow: Creator<[payload: string], string>;
|
|
319
|
+
declare const restoreWindow: Creator<[payload: string], string>;
|
|
320
|
+
declare const toggleWindowsHidden: Creator<[], undefined>;
|
|
321
|
+
declare const restoreAll: Creator<[], undefined>;
|
|
322
|
+
declare const minimizeAll: Creator<[payload: {
|
|
323
|
+
viewportWidth: number;
|
|
324
|
+
viewportHeight: number;
|
|
325
|
+
}], {
|
|
326
|
+
viewportWidth: number;
|
|
327
|
+
viewportHeight: number;
|
|
328
|
+
}>;
|
|
329
|
+
/** Every slice key the summon reducers own; an action under one of them needs the runtime. */
|
|
330
|
+
declare const SUMMON_SLICE_KEYS: readonly ["overlays", "windowManager", "urlSync", "overlayState"];
|
|
331
|
+
declare function isSummonAction(action: unknown): action is {
|
|
332
|
+
type: string;
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
interface OverlayInstance {
|
|
336
|
+
isOpen: boolean;
|
|
337
|
+
data: unknown;
|
|
338
|
+
/** Unix ms of the last open (pruneStaleInstances reads it). */
|
|
339
|
+
lastUsedAt?: number;
|
|
340
|
+
}
|
|
341
|
+
interface OverlayState {
|
|
342
|
+
overlays: Record<string, Record<string, OverlayInstance>>;
|
|
343
|
+
}
|
|
344
|
+
/** The slice of any store these selectors need (absent until the summon runtime is installed). */
|
|
345
|
+
type StateWithOverlays = {
|
|
346
|
+
overlays?: OverlayState;
|
|
347
|
+
};
|
|
348
|
+
interface OpenInstanceView {
|
|
349
|
+
instanceId: string;
|
|
350
|
+
data: unknown;
|
|
351
|
+
}
|
|
352
|
+
declare const selectOverlay: (state: StateWithOverlays, overlayId: string, instanceId?: string) => OverlayInstance;
|
|
353
|
+
declare const selectIsOverlayOpen: (state: StateWithOverlays, overlayId: string, instanceId?: string) => boolean;
|
|
354
|
+
declare const selectOverlayData: (state: StateWithOverlays, overlayId: string, instanceId?: string) => unknown;
|
|
355
|
+
/** All open instances of an overlay id; the array reference is stable while the open set is unchanged. */
|
|
356
|
+
declare const selectOpenInstances: (state: StateWithOverlays, overlayId: string) => readonly OpenInstanceView[];
|
|
357
|
+
/** Every open instance key (`overlayId:instanceId`). */
|
|
358
|
+
declare function listOpenInstanceKeys(state: StateWithOverlays): string[];
|
|
359
|
+
/** True once anything has ever been opened in this store (a key exists in the slice). */
|
|
360
|
+
declare function selectAnyOverlayTouched(state: StateWithOverlays): boolean;
|
|
361
|
+
/** The global hide-all flag (false before the runtime is installed). */
|
|
362
|
+
declare const selectWindowsHidden: (state: {
|
|
363
|
+
windowManager?: {
|
|
364
|
+
windowsHidden: boolean;
|
|
365
|
+
};
|
|
366
|
+
}) => boolean;
|
|
367
|
+
|
|
368
|
+
/** What the core hands the gate when it loads. */
|
|
369
|
+
interface SummonCore {
|
|
370
|
+
readonly reducers: Readonly<Record<string, Reducer>>;
|
|
371
|
+
createMiddleware(ports?: Partial<SummonPorts>): Middleware[];
|
|
372
|
+
}
|
|
373
|
+
/** Dispatched once after the slices are injected into a live store, so they hold their initial state. */
|
|
374
|
+
declare const SUMMON_INSTALLED_ACTION = "@@summon/installed";
|
|
375
|
+
/** Called by the core module when it evaluates (idempotent). */
|
|
376
|
+
declare function installSummonCore(core: SummonCore): void;
|
|
377
|
+
declare function isSummonInstalled(): boolean;
|
|
378
|
+
declare function subscribeSummonInstalled(listener: () => void): () => void;
|
|
379
|
+
/** Load the summon core (one import(), shared by every caller). Resolves once it is installed. */
|
|
380
|
+
declare function ensureSummonRuntime(): Promise<void>;
|
|
381
|
+
/** Start loading the core without waiting (idle, pointer intent). Errors surface on the next real request. */
|
|
382
|
+
declare function prefetchSummonRuntime(): void;
|
|
383
|
+
interface SummonGate {
|
|
384
|
+
/** Put this in the host store's middleware chain. */
|
|
385
|
+
readonly middleware: Middleware;
|
|
386
|
+
/**
|
|
387
|
+
* Give the gate the host root reducer's inject function — before `configureStore`, so a core
|
|
388
|
+
* that is already loaded (a page that imported the window section) is injected before the
|
|
389
|
+
* store's first state exists.
|
|
390
|
+
*/
|
|
391
|
+
attachReducer(inject: (reducers: Readonly<Record<string, Reducer>>) => void): void;
|
|
392
|
+
}
|
|
393
|
+
interface CreateSummonGateOptions {
|
|
394
|
+
/** Ports for the summon middleware (render watchdog: notify, errors, debug). */
|
|
395
|
+
readonly ports?: Partial<SummonPorts>;
|
|
396
|
+
}
|
|
397
|
+
declare function createSummonGate(options?: CreateSummonGateOptions): SummonGate;
|
|
398
|
+
|
|
399
|
+
export { isRegisteredOverlay as $, type AnyOverlayMeta as A, anonymousIdentity as B, type CloseOverlaysBoundToPagePayload as C, DEFAULT_INSTANCE_ID as D, type ErrorSinkPort as E, closeAllInstancesOfOverlay as F, closeOverlay as G, closeOverlaysBoundToPage as H, type InstanceKey as I, consoleErrorSink as J, type KeepAlive as K, type LinkHydrateContext as L, type MobilePresentation as M, type NotifyOptions as N, type OverlayState as O, type PruneStaleInstancesPayload as P, consoleNotify as Q, type RawOpenPayload as R, type SummonPorts as S, type ToggleOverlayPayload as T, type UnbiddenHomeRoute as U, debugOff as V, type WindowPreservation as W, defaultWindowIdFor as X, getOverlayMeta as Y, getOverlayMetaByLinkKey as Z, instanceKey as _, type StateWithOverlays as a, listOpenInstanceKeys as a0, locationRouter as a1, openOverlay as a2, overlayIdsBoundToPage as a3, parseInstanceKey as a4, registerOverlayMeta as a5, resetOverlayRegistry as a6, resolvePorts as a7, selectIsOverlayOpen as a8, selectOpenInstances as a9, selectOverlay as aa, selectOverlayData as ab, subscribeToOverlayRegistry as ac, toggleOverlay as ad, type CreateSummonGateOptions as ae, SUMMON_INSTALLED_ACTION as af, SUMMON_SLICE_KEYS as ag, type SummonAction as ah, type SummonGate as ai, closeAllOverlays as aj, createSummonGate as ak, ensureSummonRuntime as al, focusWindow as am, installSummonCore as an, isSummonAction as ao, isSummonInstalled as ap, minimizeAll as aq, prefetchSummonRuntime as ar, pruneStaleInstances as as, restoreAll as at, restoreWindow as au, selectAnyOverlayTouched as av, selectWindowsHidden as aw, subscribeSummonInstalled as ax, toggleWindowsHidden as ay, type OverlayDefinitionMeta as b, type SummonCore as c, type CloseAllInstancesPayload as d, type CloseOverlayPayload as e, DEFAULT_PORTS as f, type DebugPort as g, type IdentityPort as h, type InstanceMode as i, type NotifyPort as j, type OpenInstanceView as k, type OpenOverlayPayload as l, type OverlayDataOf as m, type OverlayHostDispatch as n, type OverlayHostTypes as o, type OverlayId as p, type OverlayInstance as q, type OverlayLinkSpec as r, type OverlayPersistencePort as s, type OverlayRawData as t, type OverlayRegistry as u, type OverlayWindowOptions as v, type RouterPort as w, type StoredValue as x, type Unsubscribe as y, allOverlayMeta as z };
|
package/dist/handles.cjs
CHANGED
package/dist/handles.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/handles.ts","../src/handles/callbackManager.ts","../src/handles/ids.ts","../src/handles/helpers.ts"],"sourcesContent":["// @ai-matrx/summon/handles — the handles registry: callbacks, event channels, one-shot requests\n// and imperative object handles, owner-scoped to open overlay instances. Framework-free: importing\n// this section never loads React or Redux.\nexport {\n CallbackManager,\n callbackManager,\n disposeOwner,\n HANDLES_SLOT,\n type Callback,\n type CallbackContext,\n type HandleSlot,\n type ProgressInfo,\n type RegisterOptions,\n type TriggerOptions,\n} from \"./handles/callbackManager\";\nexport {\n createEventChannel,\n createRequest,\n getEventChannel,\n getHandle,\n getRequest,\n HandleDisposedError,\n registerHandle,\n removeHandle,\n type EventChannel,\n type OwnerOption,\n type PendingRequest,\n type RequestHandle,\n} from \"./handles/helpers\";\nexport { newHandleId } from \"./handles/ids\";\n","/**\n * The handles registry — everything that cannot travel through Redux (callbacks, event channels,\n * one-shot requests, imperative object handles) lives here under a string id; only the id goes\n * into overlay open data.\n *\n * Successor of `@ai-matrx/chat` `utils/callbackManager.ts` with the SAME public verbs and types, so\n * moving a caller is an import-path swap. Changes (CHANGELOG 0.1.0):\n * 1. State lives in the global slot \"ai-matrx.summon.handles\", never in module scope: a\n * duplicated module graph (ESM + CJS, unsplit bundles, two packages) sees one registry.\n * 2. Removal bug fixed: `trigger` / `triggerWithContext` / `remove` deleted the entry BEFORE\n * `removeFromGroups` read it, so group membership never shrank and emptied groups were never\n * dropped. Removal now reads the entry first, in one place (`deleteEntry`).\n * 3. Owner scoping: `registerWithContext(cb, { owner })` (an InstanceKey `overlayId:instanceId`)\n * ties the entry to an open overlay instance; `disposeOwner(owner)` removes everything it\n * owns. The overlays close middleware calls it, so no opener disposes by hand.\n * 4. The object slot is handle-agnostic: `registerWidgetHandle<H extends object>(handle)` stores\n * any object (no chat `WidgetHandle` import).\n * 5. Ids come from `crypto.randomUUID` (no `uuid` dependency), with a fallback for insecure\n * contexts where `randomUUID` is absent.\n *\n * Framework-free: no React, no Redux.\n */\nimport { globalSlot } from \"@ai-matrx/kit/global-slot\";\nimport { newHandleId } from \"./ids\";\n\nexport type CallbackContext = Record<string, unknown>;\n\nexport interface ProgressInfo {\n progress?: number;\n status?: \"pending\" | \"running\" | \"completed\" | \"error\";\n error?: Error;\n}\n\nexport type Callback<T = unknown, C extends CallbackContext = CallbackContext> = (\n data: T,\n context?: C,\n) => void | Promise<void>;\n\n/** What an entry's slot holds: a callback, or an object handle retrieved with `get`. */\nexport type HandleSlot = Callback<never, never> | object;\n\nexport interface RegisterOptions<C extends CallbackContext = CallbackContext> {\n context?: C;\n groupId?: string;\n /** The InstanceKey (`overlayId:instanceId`) that owns this entry; disposed when it closes. */\n owner?: string;\n}\n\nexport interface TriggerOptions<C extends CallbackContext = CallbackContext> {\n context?: C;\n progress?: ProgressInfo;\n removeAfterTrigger?: boolean;\n}\n\n/** A registry entry. `callback` is the heterogeneous slot (function or object handle). */\ninterface CallbackEntry {\n callback: HandleSlot;\n context?: CallbackContext;\n groupId?: string;\n owner?: string;\n listeners?: Array<Callback<never, never>>;\n /** Runs once when the entry leaves the registry for any reason (requests reject here). */\n onRemove?: () => void;\n}\n\ninterface HandlesState {\n readonly callbacks: Map<string, CallbackEntry>;\n readonly groups: Map<string, Set<string>>;\n readonly owners: Map<string, Set<string>>;\n readonly registryListeners: Set<() => void>;\n}\n\nexport const HANDLES_SLOT = \"ai-matrx.summon.handles\";\n\nconst handlesState = (): HandlesState =>\n globalSlot<HandlesState>(HANDLES_SLOT, () => ({\n callbacks: new Map(),\n groups: new Map(),\n owners: new Map(),\n registryListeners: new Set(),\n }));\n\n/** Invoke a slot as a callback (a function slot only; object handles are never invoked). */\nfunction invoke(slot: HandleSlot, data: unknown, context?: CallbackContext): void | Promise<void> {\n if (typeof slot !== \"function\") return undefined;\n return (slot as Callback<unknown, CallbackContext>)(data, context);\n}\n\nfunction invokeListener(listener: Callback<never, never>, data: unknown, context?: CallbackContext): void | Promise<void> {\n return (listener as Callback<unknown, CallbackContext>)(data, context);\n}\n\n/** Internal registration options beyond the public ones (used by the typed helpers). */\nexport interface InternalRegisterOptions extends RegisterOptions {\n id?: string;\n onRemove?: () => void;\n}\n\nexport class CallbackManager {\n private get s(): HandlesState {\n return handlesState();\n }\n\n /**\n * Observe the registry itself: `listener` runs after any entry is added or removed. This lets a\n * view that resolves ids with `get` re-render when an id goes away (`useSyncExternalStore`).\n */\n subscribeToRegistry(listener: () => void): () => void {\n const listeners = this.s.registryListeners;\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n }\n\n private notifyRegistry(): void {\n for (const listener of [...this.s.registryListeners]) listener();\n }\n\n /** Register a callback; returns its id. */\n register<T>(callback: Callback<T>): string {\n return this.registerEntry(callback as HandleSlot, {});\n }\n\n /** Register with optional context, group and owner. */\n registerWithContext<T, C extends CallbackContext = CallbackContext>(\n callback: Callback<T, C>,\n options: RegisterOptions<C> = {},\n ): string {\n return this.registerEntry(callback as HandleSlot, options);\n }\n\n /** @internal The one insertion path (typed helpers pass a fixed id and a removal hook). */\n registerEntry(slot: HandleSlot, options: InternalRegisterOptions): string {\n const s = this.s;\n const callbackId = options.id ?? newHandleId();\n if (s.callbacks.has(callbackId)) this.deleteEntry(callbackId, false);\n const entry: CallbackEntry = { callback: slot };\n if (options.context !== undefined) entry.context = options.context;\n if (options.groupId !== undefined) entry.groupId = options.groupId;\n if (options.owner !== undefined) entry.owner = options.owner;\n if (options.onRemove !== undefined) entry.onRemove = options.onRemove;\n s.callbacks.set(callbackId, entry);\n\n if (options.groupId !== undefined) {\n const group = s.groups.get(options.groupId) ?? new Set<string>();\n group.add(callbackId);\n s.groups.set(options.groupId, group);\n }\n if (options.owner !== undefined) {\n const owned = s.owners.get(options.owner) ?? new Set<string>();\n owned.add(callbackId);\n s.owners.set(options.owner, owned);\n }\n this.notifyRegistry();\n return callbackId;\n }\n\n /** Subscribe to results for a callback id. */\n subscribe<T, C extends CallbackContext = CallbackContext>(callbackId: string, listener: Callback<T, C>): boolean {\n const entry = this.s.callbacks.get(callbackId);\n if (!entry) return false;\n (entry.listeners ??= []).push(listener as Callback<never, never>);\n return true;\n }\n\n /** Unsubscribe a listener from a callback id. */\n unsubscribe<T, C extends CallbackContext = CallbackContext>(callbackId: string, listener: Callback<T, C>): boolean {\n const entry = this.s.callbacks.get(callbackId);\n if (!entry || !entry.listeners) return false;\n const index = entry.listeners.indexOf(listener as Callback<never, never>);\n if (index === -1) return false;\n entry.listeners.splice(index, 1);\n return true;\n }\n\n /** Run a callback once, notify its listeners, then remove it. */\n trigger<T>(callbackId: string, data: T): void {\n const entry = this.s.callbacks.get(callbackId);\n if (!entry) return;\n void invoke(entry.callback, data);\n if (entry.listeners && entry.listeners.length > 0) {\n for (const listener of [...entry.listeners]) void invokeListener(listener, data);\n }\n this.deleteEntry(callbackId, true);\n }\n\n /** Trigger with merged context and progress; removes unless `removeAfterTrigger: false`. */\n triggerWithContext<T, C extends CallbackContext = CallbackContext>(\n callbackId: string,\n data: T,\n options?: TriggerOptions<C>,\n ): void {\n const entry = this.s.callbacks.get(callbackId);\n if (!entry) return;\n const mergedContext: CallbackContext = {\n ...entry.context,\n ...options?.context,\n ...(options?.progress && { progress: options.progress }),\n };\n void invoke(entry.callback, data, mergedContext);\n if (entry.listeners && entry.listeners.length > 0) {\n for (const listener of [...entry.listeners]) void invokeListener(listener, data, mergedContext);\n }\n if (options?.removeAfterTrigger !== false) this.deleteEntry(callbackId, true);\n }\n\n /** Trigger every callback in a group. */\n triggerGroup<T, C extends CallbackContext = CallbackContext>(groupId: string, data: T, options?: TriggerOptions<C>): void {\n const group = this.s.groups.get(groupId);\n if (!group) return;\n for (const callbackId of [...group]) this.triggerWithContext(callbackId, data, options);\n if (options?.removeAfterTrigger !== false) this.s.groups.delete(groupId);\n }\n\n /**\n * Run the one durable command registered for a group. A command is retained on rejection so its\n * caller can retry, and is removed only after its promise settles successfully.\n */\n async triggerGroupCommand<T, C extends CallbackContext = CallbackContext>(\n groupId: string,\n data: T,\n options?: { context?: C; removeAfterSuccess?: boolean },\n ): Promise<void> {\n const group = this.s.groups.get(groupId);\n const callbackIds = group ? [...group] : [];\n const callbackId = callbackIds[0];\n if (callbackIds.length !== 1 || callbackId === undefined) {\n throw new Error(`Expected exactly one command callback for group \"${groupId}\", found ${callbackIds.length}`);\n }\n const entry = this.s.callbacks.get(callbackId);\n if (!entry) throw new Error(`Command callback \"${callbackId}\" is no longer available`);\n\n const mergedContext: CallbackContext = { ...entry.context, ...options?.context };\n await invoke(entry.callback, data, mergedContext);\n\n // Observers never control command settlement: the command already acknowledged.\n for (const listener of entry.listeners ?? []) {\n try {\n await invokeListener(listener, data, mergedContext);\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error(\"[overlays/handles] command observer failed\", error);\n }\n }\n\n if (options?.removeAfterSuccess !== false) {\n this.deleteEntry(callbackId, true);\n this.s.groups.delete(groupId);\n }\n }\n\n /** Report progress to a callback (or every callback of a group) without removing it. */\n updateProgress(\n id: string,\n progress: number,\n options?: { status?: ProgressInfo[\"status\"]; error?: Error; groupId?: boolean },\n ): void {\n const progressInfo: ProgressInfo = { progress, status: options?.status || \"running\" };\n if (options?.error !== undefined) progressInfo.error = options.error;\n if (options?.groupId) {\n this.triggerGroup(id, null, { progress: progressInfo, removeAfterTrigger: false });\n } else {\n this.triggerWithContext(id, null, { progress: progressInfo, removeAfterTrigger: false });\n }\n }\n\n /** Create a new, empty group and return its id. */\n createGroup(): string {\n const groupId = newHandleId();\n this.s.groups.set(groupId, new Set());\n return groupId;\n }\n\n /** Remove one entry (and its group/owner membership). */\n remove(callbackId: string): void {\n this.deleteEntry(callbackId, true);\n }\n\n /** Alias of `remove` — the preferred name when unregistering a handle on unmount. */\n unregister(callbackId: string): void {\n this.remove(callbackId);\n }\n\n /** The stored callback or object handle for an id, without invoking it. */\n get<T = unknown>(callbackId: string): T | undefined {\n return this.s.callbacks.get(callbackId)?.callback as T | undefined;\n }\n\n /** True when the id is registered. */\n has(callbackId: string): boolean {\n return this.s.callbacks.has(callbackId);\n }\n\n /**\n * Register an object handle (a widget handle, an editor API, …). The object occupies the slot;\n * it is never invoked by `trigger`, only retrieved with `get`.\n */\n registerWidgetHandle<H extends object>(handle: H, options: { owner?: string } = {}): string {\n return this.registerEntry(handle, options.owner === undefined ? {} : { owner: options.owner });\n }\n\n /** Remove a group and all its callbacks. */\n removeGroup(groupId: string): void {\n const s = this.s;\n const group = s.groups.get(groupId);\n if (!group) return;\n s.groups.delete(groupId);\n for (const callbackId of [...group]) this.deleteEntry(callbackId, false);\n this.notifyRegistry();\n }\n\n /** Remove everything registered with `owner` (an InstanceKey). Returns how many were removed. */\n disposeOwner(owner: string): number {\n const s = this.s;\n const owned = s.owners.get(owner);\n if (!owned) return 0;\n s.owners.delete(owner);\n const ids = [...owned];\n for (const callbackId of ids) this.deleteEntry(callbackId, false);\n if (ids.length > 0) this.notifyRegistry();\n return ids.length;\n }\n\n /** Ids currently owned by `owner`. */\n ownedBy(owner: string): readonly string[] {\n return [...(this.s.owners.get(owner) ?? [])];\n }\n\n /** The member ids of a group (empty when unknown). */\n groupMembers(groupId: string): readonly string[] {\n return [...(this.s.groups.get(groupId) ?? [])];\n }\n\n /** Total registered entries (diagnostics, leak tests). */\n size(): number {\n return this.s.callbacks.size;\n }\n\n /**\n * The one removal path. Reads the entry BEFORE deleting it so group and owner membership shrink\n * (the old `removeFromGroups`-after-delete bug), then runs the entry's removal hook.\n */\n private deleteEntry(callbackId: string, notify: boolean): void {\n const s = this.s;\n const entry = s.callbacks.get(callbackId);\n if (!entry) return;\n s.callbacks.delete(callbackId);\n if (entry.groupId !== undefined) {\n const group = s.groups.get(entry.groupId);\n group?.delete(callbackId);\n if (group?.size === 0) s.groups.delete(entry.groupId);\n }\n if (entry.owner !== undefined) {\n const owned = s.owners.get(entry.owner);\n owned?.delete(callbackId);\n if (owned?.size === 0) s.owners.delete(entry.owner);\n }\n if (notify) this.notifyRegistry();\n entry.onRemove?.();\n }\n}\n\n/** The process-wide handles registry (state in the global slot; every instance shares it). */\nexport const callbackManager = new CallbackManager();\n\n/** Remove everything owned by an open instance (`overlayId:instanceId`). */\nexport function disposeOwner(owner: string): number {\n return callbackManager.disposeOwner(owner);\n}\n","/** A fresh handle id: `crypto.randomUUID` when present, else a v4 UUID from `getRandomValues`. */\nexport function newHandleId(): string {\n const c: Crypto | undefined = typeof globalThis.crypto === \"undefined\" ? undefined : globalThis.crypto;\n if (c && typeof c.randomUUID === \"function\") return c.randomUUID();\n const bytes = new Uint8Array(16);\n if (c && typeof c.getRandomValues === \"function\") {\n c.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 16; i += 1) bytes[i] = Math.floor(Math.random() * 256);\n }\n bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x40;\n bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80;\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n","/**\n * Typed helpers over the handles registry: imperative object handles, event channels and one-shot\n * requests. Each is stored in the same registry (so its id can ride overlay open data and `get`\n * still resolves it) and accepts an `owner` InstanceKey so closing the owning overlay disposes it.\n */\nimport { callbackManager } from \"./callbackManager\";\n\nexport interface OwnerOption {\n /** The InstanceKey (`overlayId:instanceId`) that owns this handle; disposed when it closes. */\n owner?: string;\n}\n\n/** Thrown into a request's promise when it is disposed before being answered. */\nexport class HandleDisposedError extends Error {\n readonly handleId: string;\n constructor(handleId: string, message = `[overlays/handles] \"${handleId}\" was disposed before it settled`) {\n super(message);\n this.name = \"HandleDisposedError\";\n this.handleId = handleId;\n }\n}\n\nfunction ownerOptions(options: OwnerOption | undefined): { owner?: string } {\n return options?.owner === undefined ? {} : { owner: options.owner };\n}\n\n// ── Imperative object handles ────────────────────────────────────────────────────────────────\n\n/**\n * Register an imperative object handle under a caller-chosen id (an editor API, a widget handle,\n * a ref's methods). Re-registering an id replaces the previous handle. Returns a disposer that\n * removes the handle only if it is still the one registered (safe for React effect cleanup).\n */\nexport function registerHandle<T extends object>(id: string, handle: T, options?: OwnerOption): () => void {\n callbackManager.registerEntry(handle, { id, ...ownerOptions(options) });\n return () => {\n if (callbackManager.get<T>(id) === handle) callbackManager.remove(id);\n };\n}\n\n/** The object handle registered under `id`, or undefined. */\nexport function getHandle<T extends object>(id: string): T | undefined {\n const value = callbackManager.get<unknown>(id);\n return typeof value === \"object\" && value !== null ? (value as T) : undefined;\n}\n\n/** Remove the handle registered under `id`. */\nexport function removeHandle(id: string): void {\n callbackManager.remove(id);\n}\n\n// ── Event channels ───────────────────────────────────────────────────────────────────────────\n\nexport interface EventChannel<Events> {\n readonly id: string;\n /** Deliver an event to every subscriber (no-op after dispose). */\n emit(event: Events): void;\n /** Listen; returns the unsubscribe. */\n subscribe(listener: (event: Events) => void): () => void;\n /** Remove the channel and drop every subscriber. */\n dispose(): void;\n readonly disposed: boolean;\n}\n\n/**\n * A many-shot event stream between an opener and an overlay. Pass `channel.id` in open data; the\n * overlay resolves it with `getEventChannel(id)`.\n */\nexport function createEventChannel<Events>(options?: OwnerOption): EventChannel<Events> {\n const listeners = new Set<(event: Events) => void>();\n let disposed = false;\n let id = \"\";\n const channel: EventChannel<Events> = {\n get id() {\n return id;\n },\n get disposed() {\n return disposed;\n },\n emit(event) {\n if (disposed) return;\n for (const listener of [...listeners]) listener(event);\n },\n subscribe(listener) {\n if (disposed) return () => {};\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n dispose() {\n if (disposed) return;\n callbackManager.remove(id);\n },\n };\n id = callbackManager.registerEntry(channel, {\n ...ownerOptions(options),\n onRemove: () => {\n disposed = true;\n listeners.clear();\n },\n });\n return channel;\n}\n\n/** The channel registered under `id`, or undefined once disposed. */\nexport function getEventChannel<Events>(id: string): EventChannel<Events> | undefined {\n return getHandle<EventChannel<Events>>(id);\n}\n\n// ── One-shot requests ────────────────────────────────────────────────────────────────────────\n\nexport interface PendingRequest<Req, Res> {\n readonly id: string;\n /** What the asker sent. */\n readonly request: Req;\n /** Answer the request (first answer wins; later calls are ignored). */\n resolve(response: Res): void;\n /** Fail the request. */\n reject(reason: unknown): void;\n readonly settled: boolean;\n}\n\nexport interface RequestHandle<Req, Res> extends PendingRequest<Req, Res> {\n /** Settles with the answer; rejects with `HandleDisposedError` when disposed unanswered. */\n readonly promise: Promise<Res>;\n /** Remove the request; an unanswered one rejects. */\n dispose(): void;\n}\n\n/**\n * A one-shot promise bridge: the asker awaits `promise`, the overlay answers through\n * `getRequest(id).resolve(…)`. Disposing it unanswered (or closing its owner) rejects.\n */\nexport function createRequest<Req, Res>(request: Req, options?: OwnerOption): RequestHandle<Req, Res> {\n let settle!: (response: Res) => void;\n let fail!: (reason: unknown) => void;\n const promise = new Promise<Res>((resolve, reject) => {\n settle = resolve;\n fail = reject;\n });\n // A disposed request nobody awaited must not surface as an unhandled rejection.\n promise.catch(() => {});\n let settled = false;\n let id = \"\";\n const handle: RequestHandle<Req, Res> = {\n get id() {\n return id;\n },\n request,\n promise,\n get settled() {\n return settled;\n },\n resolve(response) {\n if (settled) return;\n settled = true;\n settle(response);\n callbackManager.remove(id);\n },\n reject(reason) {\n if (settled) return;\n settled = true;\n fail(reason);\n callbackManager.remove(id);\n },\n dispose() {\n callbackManager.remove(id);\n },\n };\n id = callbackManager.registerEntry(handle, {\n ...ownerOptions(options),\n onRemove: () => {\n if (settled) return;\n settled = true;\n fail(new HandleDisposedError(id));\n },\n });\n return handle;\n}\n\n/** The pending request registered under `id`, or undefined once answered or disposed. */\nexport function getRequest<Req, Res>(id: string): PendingRequest<Req, Res> | undefined {\n return getHandle<RequestHandle<Req, Res>>(id);\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/handles.ts","../src/handles/callbackManager.ts","../src/handles/ids.ts","../src/handles/helpers.ts"],"sourcesContent":["// @ai-matrx/summon/handles — the handles registry: callbacks, event channels, one-shot requests\n// and imperative object handles, owner-scoped to open overlay instances. Framework-free: importing\n// this section never loads React or Redux.\nexport {\n CallbackManager,\n callbackManager,\n disposeOwner,\n HANDLES_SLOT,\n type Callback,\n type CallbackContext,\n type HandleSlot,\n type ProgressInfo,\n type RegisterOptions,\n type TriggerOptions,\n} from \"./handles/callbackManager\";\nexport {\n createEventChannel,\n createRequest,\n getEventChannel,\n getHandle,\n getRequest,\n HandleDisposedError,\n registerHandle,\n removeHandle,\n type EventChannel,\n type OwnerOption,\n type PendingRequest,\n type RequestHandle,\n} from \"./handles/helpers\";\nexport { newHandleId } from \"./handles/ids\";\n","/**\n * The handles registry — everything that cannot travel through Redux (callbacks, event channels,\n * one-shot requests, imperative object handles) lives here under a string id; only the id goes\n * into overlay open data.\n *\n * Successor of `@ai-matrx/chat` `utils/callbackManager.ts` with the SAME public verbs and types, so\n * moving a caller is an import-path swap. Changes (CHANGELOG 0.1.0):\n * 1. State lives in the global slot \"ai-matrx.summon.handles\", never in module scope: a\n * duplicated module graph (ESM + CJS, unsplit bundles, two packages) sees one registry.\n * 2. Removal bug fixed: `trigger` / `triggerWithContext` / `remove` deleted the entry BEFORE\n * `removeFromGroups` read it, so group membership never shrank and emptied groups were never\n * dropped. Removal now reads the entry first, in one place (`deleteEntry`).\n * 3. Owner scoping: `registerWithContext(cb, { owner })` (an InstanceKey `overlayId:instanceId`)\n * ties the entry to an open overlay instance; `disposeOwner(owner)` removes everything it\n * owns. The overlays close middleware calls it, so no opener disposes by hand.\n * 4. The object slot is handle-agnostic: `registerWidgetHandle<H extends object>(handle)` stores\n * any object (no chat `WidgetHandle` import).\n * 5. Ids come from `crypto.randomUUID` (no `uuid` dependency), with a fallback for insecure\n * contexts where `randomUUID` is absent.\n *\n * Framework-free: no React, no Redux.\n */\nimport { globalSlot } from \"@ai-matrx/kit/global-slot\";\nimport { newHandleId } from \"./ids\";\n\nexport type CallbackContext = Record<string, unknown>;\n\nexport interface ProgressInfo {\n progress?: number;\n status?: \"pending\" | \"running\" | \"completed\" | \"error\";\n error?: Error;\n}\n\nexport type Callback<T = unknown, C extends CallbackContext = CallbackContext> = (\n data: T,\n context?: C,\n) => void | Promise<void>;\n\n/** What an entry's slot holds: a callback, or an object handle retrieved with `get`. */\nexport type HandleSlot = Callback<never, never> | object;\n\nexport interface RegisterOptions<C extends CallbackContext = CallbackContext> {\n context?: C;\n groupId?: string;\n /** The InstanceKey (`overlayId:instanceId`) that owns this entry; disposed when it closes. */\n owner?: string;\n}\n\nexport interface TriggerOptions<C extends CallbackContext = CallbackContext> {\n context?: C;\n progress?: ProgressInfo;\n removeAfterTrigger?: boolean;\n}\n\n/** A registry entry. `callback` is the heterogeneous slot (function or object handle). */\ninterface CallbackEntry {\n callback: HandleSlot;\n context?: CallbackContext;\n groupId?: string;\n owner?: string;\n listeners?: Array<Callback<never, never>>;\n /** Runs once when the entry leaves the registry for any reason (requests reject here). */\n onRemove?: () => void;\n}\n\ninterface HandlesState {\n readonly callbacks: Map<string, CallbackEntry>;\n readonly groups: Map<string, Set<string>>;\n readonly owners: Map<string, Set<string>>;\n readonly registryListeners: Set<() => void>;\n}\n\nexport const HANDLES_SLOT = \"ai-matrx.summon.handles\";\n\nconst handlesState = (): HandlesState =>\n globalSlot<HandlesState>(HANDLES_SLOT, () => ({\n callbacks: new Map(),\n groups: new Map(),\n owners: new Map(),\n registryListeners: new Set(),\n }));\n\n/** Invoke a slot as a callback (a function slot only; object handles are never invoked). */\nfunction invoke(slot: HandleSlot, data: unknown, context?: CallbackContext): void | Promise<void> {\n if (typeof slot !== \"function\") return undefined;\n return (slot as Callback<unknown, CallbackContext>)(data, context);\n}\n\nfunction invokeListener(listener: Callback<never, never>, data: unknown, context?: CallbackContext): void | Promise<void> {\n return (listener as Callback<unknown, CallbackContext>)(data, context);\n}\n\n/** Internal registration options beyond the public ones (used by the typed helpers). */\nexport interface InternalRegisterOptions extends RegisterOptions {\n id?: string;\n onRemove?: () => void;\n}\n\nexport class CallbackManager {\n private get s(): HandlesState {\n return handlesState();\n }\n\n /**\n * Observe the registry itself: `listener` runs after any entry is added or removed. This lets a\n * view that resolves ids with `get` re-render when an id goes away (`useSyncExternalStore`).\n */\n subscribeToRegistry(listener: () => void): () => void {\n const listeners = this.s.registryListeners;\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n }\n\n private notifyRegistry(): void {\n for (const listener of [...this.s.registryListeners]) listener();\n }\n\n /** Register a callback; returns its id. */\n register<T>(callback: Callback<T>): string {\n return this.registerEntry(callback as HandleSlot, {});\n }\n\n /** Register with optional context, group and owner. */\n registerWithContext<T, C extends CallbackContext = CallbackContext>(\n callback: Callback<T, C>,\n options: RegisterOptions<C> = {},\n ): string {\n return this.registerEntry(callback as HandleSlot, options);\n }\n\n /** @internal The one insertion path (typed helpers pass a fixed id and a removal hook). */\n registerEntry(slot: HandleSlot, options: InternalRegisterOptions): string {\n const s = this.s;\n const callbackId = options.id ?? newHandleId();\n if (s.callbacks.has(callbackId)) this.deleteEntry(callbackId, false);\n const entry: CallbackEntry = { callback: slot };\n if (options.context !== undefined) entry.context = options.context;\n if (options.groupId !== undefined) entry.groupId = options.groupId;\n if (options.owner !== undefined) entry.owner = options.owner;\n if (options.onRemove !== undefined) entry.onRemove = options.onRemove;\n s.callbacks.set(callbackId, entry);\n\n if (options.groupId !== undefined) {\n const group = s.groups.get(options.groupId) ?? new Set<string>();\n group.add(callbackId);\n s.groups.set(options.groupId, group);\n }\n if (options.owner !== undefined) {\n const owned = s.owners.get(options.owner) ?? new Set<string>();\n owned.add(callbackId);\n s.owners.set(options.owner, owned);\n }\n this.notifyRegistry();\n return callbackId;\n }\n\n /** Subscribe to results for a callback id. */\n subscribe<T, C extends CallbackContext = CallbackContext>(callbackId: string, listener: Callback<T, C>): boolean {\n const entry = this.s.callbacks.get(callbackId);\n if (!entry) return false;\n (entry.listeners ??= []).push(listener as Callback<never, never>);\n return true;\n }\n\n /** Unsubscribe a listener from a callback id. */\n unsubscribe<T, C extends CallbackContext = CallbackContext>(callbackId: string, listener: Callback<T, C>): boolean {\n const entry = this.s.callbacks.get(callbackId);\n if (!entry || !entry.listeners) return false;\n const index = entry.listeners.indexOf(listener as Callback<never, never>);\n if (index === -1) return false;\n entry.listeners.splice(index, 1);\n return true;\n }\n\n /** Run a callback once, notify its listeners, then remove it. */\n trigger<T>(callbackId: string, data: T): void {\n const entry = this.s.callbacks.get(callbackId);\n if (!entry) return;\n void invoke(entry.callback, data);\n if (entry.listeners && entry.listeners.length > 0) {\n for (const listener of [...entry.listeners]) void invokeListener(listener, data);\n }\n this.deleteEntry(callbackId, true);\n }\n\n /** Trigger with merged context and progress; removes unless `removeAfterTrigger: false`. */\n triggerWithContext<T, C extends CallbackContext = CallbackContext>(\n callbackId: string,\n data: T,\n options?: TriggerOptions<C>,\n ): void {\n const entry = this.s.callbacks.get(callbackId);\n if (!entry) return;\n const mergedContext: CallbackContext = {\n ...entry.context,\n ...options?.context,\n ...(options?.progress && { progress: options.progress }),\n };\n void invoke(entry.callback, data, mergedContext);\n if (entry.listeners && entry.listeners.length > 0) {\n for (const listener of [...entry.listeners]) void invokeListener(listener, data, mergedContext);\n }\n if (options?.removeAfterTrigger !== false) this.deleteEntry(callbackId, true);\n }\n\n /** Trigger every callback in a group. */\n triggerGroup<T, C extends CallbackContext = CallbackContext>(groupId: string, data: T, options?: TriggerOptions<C>): void {\n const group = this.s.groups.get(groupId);\n if (!group) return;\n for (const callbackId of [...group]) this.triggerWithContext(callbackId, data, options);\n if (options?.removeAfterTrigger !== false) this.s.groups.delete(groupId);\n }\n\n /**\n * Run the one durable command registered for a group. A command is retained on rejection so its\n * caller can retry, and is removed only after its promise settles successfully.\n */\n async triggerGroupCommand<T, C extends CallbackContext = CallbackContext>(\n groupId: string,\n data: T,\n options?: { context?: C; removeAfterSuccess?: boolean },\n ): Promise<void> {\n const group = this.s.groups.get(groupId);\n const callbackIds = group ? [...group] : [];\n const callbackId = callbackIds[0];\n if (callbackIds.length !== 1 || callbackId === undefined) {\n throw new Error(`Expected exactly one command callback for group \"${groupId}\", found ${callbackIds.length}`);\n }\n const entry = this.s.callbacks.get(callbackId);\n if (!entry) throw new Error(`Command callback \"${callbackId}\" is no longer available`);\n\n const mergedContext: CallbackContext = { ...entry.context, ...options?.context };\n await invoke(entry.callback, data, mergedContext);\n\n // Observers never control command settlement: the command already acknowledged.\n for (const listener of entry.listeners ?? []) {\n try {\n await invokeListener(listener, data, mergedContext);\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error(\"[overlays/handles] command observer failed\", error);\n }\n }\n\n if (options?.removeAfterSuccess !== false) {\n this.deleteEntry(callbackId, true);\n this.s.groups.delete(groupId);\n }\n }\n\n /** Report progress to a callback (or every callback of a group) without removing it. */\n updateProgress(\n id: string,\n progress: number,\n options?: { status?: ProgressInfo[\"status\"]; error?: Error; groupId?: boolean },\n ): void {\n const progressInfo: ProgressInfo = { progress, status: options?.status || \"running\" };\n if (options?.error !== undefined) progressInfo.error = options.error;\n if (options?.groupId) {\n this.triggerGroup(id, null, { progress: progressInfo, removeAfterTrigger: false });\n } else {\n this.triggerWithContext(id, null, { progress: progressInfo, removeAfterTrigger: false });\n }\n }\n\n /** Create a new, empty group and return its id. */\n createGroup(): string {\n const groupId = newHandleId();\n this.s.groups.set(groupId, new Set());\n return groupId;\n }\n\n /** Remove one entry (and its group/owner membership). */\n remove(callbackId: string): void {\n this.deleteEntry(callbackId, true);\n }\n\n /** Alias of `remove` — the preferred name when unregistering a handle on unmount. */\n unregister(callbackId: string): void {\n this.remove(callbackId);\n }\n\n /** The stored callback or object handle for an id, without invoking it. */\n get<T = unknown>(callbackId: string): T | undefined {\n return this.s.callbacks.get(callbackId)?.callback as T | undefined;\n }\n\n /** True when the id is registered. */\n has(callbackId: string): boolean {\n return this.s.callbacks.has(callbackId);\n }\n\n /**\n * Register an object handle (a widget handle, an editor API, …). The object occupies the slot;\n * it is never invoked by `trigger`, only retrieved with `get`.\n */\n registerWidgetHandle<H extends object>(handle: H, options: { owner?: string } = {}): string {\n return this.registerEntry(handle, options.owner === undefined ? {} : { owner: options.owner });\n }\n\n /** Remove a group and all its callbacks. */\n removeGroup(groupId: string): void {\n const s = this.s;\n const group = s.groups.get(groupId);\n if (!group) return;\n s.groups.delete(groupId);\n for (const callbackId of [...group]) this.deleteEntry(callbackId, false);\n this.notifyRegistry();\n }\n\n /** Remove everything registered with `owner` (an InstanceKey). Returns how many were removed. */\n disposeOwner(owner: string): number {\n const s = this.s;\n const owned = s.owners.get(owner);\n if (!owned) return 0;\n s.owners.delete(owner);\n const ids = [...owned];\n for (const callbackId of ids) this.deleteEntry(callbackId, false);\n if (ids.length > 0) this.notifyRegistry();\n return ids.length;\n }\n\n /** Ids currently owned by `owner`. */\n ownedBy(owner: string): readonly string[] {\n return [...(this.s.owners.get(owner) ?? [])];\n }\n\n /** The member ids of a group (empty when unknown). */\n groupMembers(groupId: string): readonly string[] {\n return [...(this.s.groups.get(groupId) ?? [])];\n }\n\n /** Total registered entries (diagnostics, leak tests). */\n size(): number {\n return this.s.callbacks.size;\n }\n\n /**\n * The one removal path. Reads the entry BEFORE deleting it so group and owner membership shrink\n * (the old `removeFromGroups`-after-delete bug), then runs the entry's removal hook.\n */\n private deleteEntry(callbackId: string, notify: boolean): void {\n const s = this.s;\n const entry = s.callbacks.get(callbackId);\n if (!entry) return;\n s.callbacks.delete(callbackId);\n if (entry.groupId !== undefined) {\n const group = s.groups.get(entry.groupId);\n group?.delete(callbackId);\n if (group?.size === 0) s.groups.delete(entry.groupId);\n }\n if (entry.owner !== undefined) {\n const owned = s.owners.get(entry.owner);\n owned?.delete(callbackId);\n if (owned?.size === 0) s.owners.delete(entry.owner);\n }\n if (notify) this.notifyRegistry();\n entry.onRemove?.();\n }\n}\n\n/** The process-wide handles registry (state in the global slot; every instance shares it). */\nexport const callbackManager = new CallbackManager();\n\n/** Remove everything owned by an open instance (`overlayId:instanceId`). */\nexport function disposeOwner(owner: string): number {\n return callbackManager.disposeOwner(owner);\n}\n","/** A fresh handle id: `crypto.randomUUID` when present, else a v4 UUID from `getRandomValues`. */\nexport function newHandleId(): string {\n const c: Crypto | undefined = typeof globalThis.crypto === \"undefined\" ? undefined : globalThis.crypto;\n if (c && typeof c.randomUUID === \"function\") return c.randomUUID();\n const bytes = new Uint8Array(16);\n if (c && typeof c.getRandomValues === \"function\") {\n c.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 16; i += 1) bytes[i] = Math.floor(Math.random() * 256);\n }\n bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x40;\n bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80;\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n","/**\n * Typed helpers over the handles registry: imperative object handles, event channels and one-shot\n * requests. Each is stored in the same registry (so its id can ride overlay open data and `get`\n * still resolves it) and accepts an `owner` InstanceKey so closing the owning overlay disposes it.\n */\nimport { callbackManager } from \"./callbackManager\";\n\nexport interface OwnerOption {\n /** The InstanceKey (`overlayId:instanceId`) that owns this handle; disposed when it closes. */\n owner?: string;\n}\n\n/** Thrown into a request's promise when it is disposed before being answered. */\nexport class HandleDisposedError extends Error {\n readonly handleId: string;\n constructor(handleId: string, message = `[overlays/handles] \"${handleId}\" was disposed before it settled`) {\n super(message);\n this.name = \"HandleDisposedError\";\n this.handleId = handleId;\n }\n}\n\nfunction ownerOptions(options: OwnerOption | undefined): { owner?: string } {\n return options?.owner === undefined ? {} : { owner: options.owner };\n}\n\n// ── Imperative object handles ────────────────────────────────────────────────────────────────\n\n/**\n * Register an imperative object handle under a caller-chosen id (an editor API, a widget handle,\n * a ref's methods). Re-registering an id replaces the previous handle. Returns a disposer that\n * removes the handle only if it is still the one registered (safe for React effect cleanup).\n */\nexport function registerHandle<T extends object>(id: string, handle: T, options?: OwnerOption): () => void {\n callbackManager.registerEntry(handle, { id, ...ownerOptions(options) });\n return () => {\n if (callbackManager.get<T>(id) === handle) callbackManager.remove(id);\n };\n}\n\n/** The object handle registered under `id`, or undefined. */\nexport function getHandle<T extends object>(id: string): T | undefined {\n const value = callbackManager.get<unknown>(id);\n return typeof value === \"object\" && value !== null ? (value as T) : undefined;\n}\n\n/** Remove the handle registered under `id`. */\nexport function removeHandle(id: string): void {\n callbackManager.remove(id);\n}\n\n// ── Event channels ───────────────────────────────────────────────────────────────────────────\n\nexport interface EventChannel<Events> {\n readonly id: string;\n /** Deliver an event to every subscriber (no-op after dispose). */\n emit(event: Events): void;\n /** Listen; returns the unsubscribe. */\n subscribe(listener: (event: Events) => void): () => void;\n /** Remove the channel and drop every subscriber. */\n dispose(): void;\n readonly disposed: boolean;\n}\n\n/**\n * A many-shot event stream between an opener and an overlay. Pass `channel.id` in open data; the\n * overlay resolves it with `getEventChannel(id)`.\n */\nexport function createEventChannel<Events>(options?: OwnerOption & { readonly id?: string }): EventChannel<Events> {\n const listeners = new Set<(event: Events) => void>();\n let disposed = false;\n let id = \"\";\n const channel: EventChannel<Events> = {\n get id() {\n return id;\n },\n get disposed() {\n return disposed;\n },\n emit(event) {\n if (disposed) return;\n for (const listener of [...listeners]) listener(event);\n },\n subscribe(listener) {\n if (disposed) return () => {};\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n dispose() {\n if (disposed) return;\n callbackManager.remove(id);\n },\n };\n id = callbackManager.registerEntry(channel, {\n ...(options?.id === undefined ? {} : { id: options.id }),\n ...ownerOptions(options),\n onRemove: () => {\n disposed = true;\n listeners.clear();\n },\n });\n return channel;\n}\n\n/** The channel registered under `id`, or undefined once disposed. */\nexport function getEventChannel<Events>(id: string): EventChannel<Events> | undefined {\n return getHandle<EventChannel<Events>>(id);\n}\n\n// ── One-shot requests ────────────────────────────────────────────────────────────────────────\n\nexport interface PendingRequest<Req, Res> {\n readonly id: string;\n /** What the asker sent. */\n readonly request: Req;\n /** Answer the request (first answer wins; later calls are ignored). */\n resolve(response: Res): void;\n /** Fail the request. */\n reject(reason: unknown): void;\n readonly settled: boolean;\n}\n\nexport interface RequestHandle<Req, Res> extends PendingRequest<Req, Res> {\n /** Settles with the answer; rejects with `HandleDisposedError` when disposed unanswered. */\n readonly promise: Promise<Res>;\n /** Remove the request; an unanswered one rejects. */\n dispose(): void;\n}\n\n/**\n * A one-shot promise bridge: the asker awaits `promise`, the overlay answers through\n * `getRequest(id).resolve(…)`. Disposing it unanswered (or closing its owner) rejects.\n */\nexport function createRequest<Req, Res>(request: Req, options?: OwnerOption): RequestHandle<Req, Res> {\n let settle!: (response: Res) => void;\n let fail!: (reason: unknown) => void;\n const promise = new Promise<Res>((resolve, reject) => {\n settle = resolve;\n fail = reject;\n });\n // A disposed request nobody awaited must not surface as an unhandled rejection.\n promise.catch(() => {});\n let settled = false;\n let id = \"\";\n const handle: RequestHandle<Req, Res> = {\n get id() {\n return id;\n },\n request,\n promise,\n get settled() {\n return settled;\n },\n resolve(response) {\n if (settled) return;\n settled = true;\n settle(response);\n callbackManager.remove(id);\n },\n reject(reason) {\n if (settled) return;\n settled = true;\n fail(reason);\n callbackManager.remove(id);\n },\n dispose() {\n callbackManager.remove(id);\n },\n };\n id = callbackManager.registerEntry(handle, {\n ...ownerOptions(options),\n onRemove: () => {\n if (settled) return;\n settled = true;\n fail(new HandleDisposedError(id));\n },\n });\n return handle;\n}\n\n/** The pending request registered under `id`, or undefined once answered or disposed. */\nexport function getRequest<Req, Res>(id: string): PendingRequest<Req, Res> | undefined {\n return getHandle<RequestHandle<Req, Res>>(id);\n}\n"],"mappings":"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","names":[]}
|
package/dist/handles.d.cts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { E as EventChannel, H as HandleDisposedError, O as OwnerOption, P as PendingRequest, R as RequestHandle, c as createEventChannel, a as createRequest, g as getEventChannel, b as getHandle, d as getRequest, r as registerHandle, e as removeHandle } from './helpers-2NY1ha0V.cjs';
|
|
2
|
+
|
|
1
3
|
type CallbackContext = Record<string, unknown>;
|
|
2
4
|
interface ProgressInfo {
|
|
3
5
|
progress?: number;
|
|
@@ -100,67 +102,7 @@ declare const callbackManager: CallbackManager;
|
|
|
100
102
|
/** Remove everything owned by an open instance (`overlayId:instanceId`). */
|
|
101
103
|
declare function disposeOwner(owner: string): number;
|
|
102
104
|
|
|
103
|
-
interface OwnerOption {
|
|
104
|
-
/** The InstanceKey (`overlayId:instanceId`) that owns this handle; disposed when it closes. */
|
|
105
|
-
owner?: string;
|
|
106
|
-
}
|
|
107
|
-
/** Thrown into a request's promise when it is disposed before being answered. */
|
|
108
|
-
declare class HandleDisposedError extends Error {
|
|
109
|
-
readonly handleId: string;
|
|
110
|
-
constructor(handleId: string, message?: string);
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Register an imperative object handle under a caller-chosen id (an editor API, a widget handle,
|
|
114
|
-
* a ref's methods). Re-registering an id replaces the previous handle. Returns a disposer that
|
|
115
|
-
* removes the handle only if it is still the one registered (safe for React effect cleanup).
|
|
116
|
-
*/
|
|
117
|
-
declare function registerHandle<T extends object>(id: string, handle: T, options?: OwnerOption): () => void;
|
|
118
|
-
/** The object handle registered under `id`, or undefined. */
|
|
119
|
-
declare function getHandle<T extends object>(id: string): T | undefined;
|
|
120
|
-
/** Remove the handle registered under `id`. */
|
|
121
|
-
declare function removeHandle(id: string): void;
|
|
122
|
-
interface EventChannel<Events> {
|
|
123
|
-
readonly id: string;
|
|
124
|
-
/** Deliver an event to every subscriber (no-op after dispose). */
|
|
125
|
-
emit(event: Events): void;
|
|
126
|
-
/** Listen; returns the unsubscribe. */
|
|
127
|
-
subscribe(listener: (event: Events) => void): () => void;
|
|
128
|
-
/** Remove the channel and drop every subscriber. */
|
|
129
|
-
dispose(): void;
|
|
130
|
-
readonly disposed: boolean;
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* A many-shot event stream between an opener and an overlay. Pass `channel.id` in open data; the
|
|
134
|
-
* overlay resolves it with `getEventChannel(id)`.
|
|
135
|
-
*/
|
|
136
|
-
declare function createEventChannel<Events>(options?: OwnerOption): EventChannel<Events>;
|
|
137
|
-
/** The channel registered under `id`, or undefined once disposed. */
|
|
138
|
-
declare function getEventChannel<Events>(id: string): EventChannel<Events> | undefined;
|
|
139
|
-
interface PendingRequest<Req, Res> {
|
|
140
|
-
readonly id: string;
|
|
141
|
-
/** What the asker sent. */
|
|
142
|
-
readonly request: Req;
|
|
143
|
-
/** Answer the request (first answer wins; later calls are ignored). */
|
|
144
|
-
resolve(response: Res): void;
|
|
145
|
-
/** Fail the request. */
|
|
146
|
-
reject(reason: unknown): void;
|
|
147
|
-
readonly settled: boolean;
|
|
148
|
-
}
|
|
149
|
-
interface RequestHandle<Req, Res> extends PendingRequest<Req, Res> {
|
|
150
|
-
/** Settles with the answer; rejects with `HandleDisposedError` when disposed unanswered. */
|
|
151
|
-
readonly promise: Promise<Res>;
|
|
152
|
-
/** Remove the request; an unanswered one rejects. */
|
|
153
|
-
dispose(): void;
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* A one-shot promise bridge: the asker awaits `promise`, the overlay answers through
|
|
157
|
-
* `getRequest(id).resolve(…)`. Disposing it unanswered (or closing its owner) rejects.
|
|
158
|
-
*/
|
|
159
|
-
declare function createRequest<Req, Res>(request: Req, options?: OwnerOption): RequestHandle<Req, Res>;
|
|
160
|
-
/** The pending request registered under `id`, or undefined once answered or disposed. */
|
|
161
|
-
declare function getRequest<Req, Res>(id: string): PendingRequest<Req, Res> | undefined;
|
|
162
|
-
|
|
163
105
|
/** A fresh handle id: `crypto.randomUUID` when present, else a v4 UUID from `getRandomValues`. */
|
|
164
106
|
declare function newHandleId(): string;
|
|
165
107
|
|
|
166
|
-
export { type Callback, type CallbackContext, CallbackManager,
|
|
108
|
+
export { type Callback, type CallbackContext, CallbackManager, HANDLES_SLOT, type HandleSlot, type ProgressInfo, type RegisterOptions, type TriggerOptions, callbackManager, disposeOwner, newHandleId };
|