@ai-matrx/summon 0.1.13 → 0.1.14

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.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/types.ts","../src/core/ports.ts","../src/core/registry.ts","../src/open/actions.ts","../src/open/renderAcks.ts","../src/open/selectors.ts","../src/open/gate.ts","../src/open/channels.ts"],"sourcesContent":["/**\n * The shared vocabulary of @ai-matrx/summon. Framework-free: no React, no Redux imports.\n *\n * An OVERLAY is any component rendered on top of the app by dispatch — a window, dialog, sheet,\n * light floating window, toast-like card, anything. It is identified by an `OverlayId` and opened\n * as one or more INSTANCES (`instanceId`, \"default\" for single-instance overlays).\n */\n\n/**\n * The host's overlay registry: overlay id → the data its opener accepts. Hosts extend it by\n * module augmentation so every open call is type-checked:\n *\n * declare module \"@ai-matrx/summon\" {\n * interface OverlayRegistry { notesWindow: { noteId?: string } }\n * }\n *\n * `defineOverlay` emits nothing at runtime for this; the augmentation is the host's one-line\n * declaration per overlay (the converter writes it next to each definition).\n */\n// Declared in ./augment (bundled only into the core's declarations, so `declare module\n// \"@ai-matrx/summon\"` merges into it); every section reads it through the package name.\nimport type { OverlayRegistry, OverlayHostTypes } from \"@ai-matrx/summon\";\nexport type { OverlayRegistry, OverlayHostTypes };\n\n/** Every registered overlay id; plain `string` until the host augments the registry. */\nexport type OverlayId = [keyof OverlayRegistry] extends [never]\n ? string\n : Extract<keyof OverlayRegistry, string>;\n\n/** The open-data type declared for an overlay id. */\nexport type OverlayDataOf<Id extends string> = Id extends keyof OverlayRegistry\n ? OverlayRegistry[Id]\n : Record<string, unknown>;\n\n/**\n * Data as it arrives at render time. It crossed Redux, a URL or storage, so it is NOT trusted to\n * match the opener's type: render code narrows it (or the definition supplies `parse`).\n */\nexport type OverlayRawData = Readonly<Record<string, unknown>> | null;\n\nexport const DEFAULT_INSTANCE_ID = \"default\";\n\n/** `single`: one instance (\"default\"). `multi`: any number, each with its own instanceId. */\nexport type InstanceMode = \"single\" | \"multi\";\n\n/**\n * What closing does to a mounted overlay (Arman, 2026-10-16, C38 R3):\n * none — unmount (default).\n * hidden — stay mounted but hidden; reopening shows the same live component (LRU-capped).\n * restore — unmount, but values saved with `useOverlayState` come back on reopen.\n * Minimizing a window always keeps its component mounted, whatever this says.\n */\nexport type KeepAlive = \"none\" | \"hidden\" | \"restore\";\n\n/** `overlayId:instanceId` — the one key every subsystem uses for an open instance. */\nexport type InstanceKey = `${string}:${string}`;\n\nexport function instanceKey(overlayId: string, instanceId: string = DEFAULT_INSTANCE_ID): InstanceKey {\n return `${overlayId}:${instanceId}`;\n}\n\nexport function parseInstanceKey(key: string): { overlayId: string; instanceId: string } | null {\n const at = key.indexOf(\":\");\n if (at <= 0 || at === key.length - 1) return null;\n return { overlayId: key.slice(0, at), instanceId: key.slice(at + 1) };\n}\n\n// ── Window options (consumed by the window surface; inert for other surfaces) ──────────────────\n\nexport type MobilePresentation = \"fullscreen\" | \"drawer\" | \"card\" | \"hidden\";\n\n/**\n * Default-deny allowlist of the open data a window may save and restore. A window with no\n * preservation entry restores geometry only.\n */\nexport interface WindowPreservation {\n readonly dataKeys: readonly string[];\n readonly requiredDataKeys?: readonly string[];\n readonly allowedDataValues?: Readonly<Record<string, readonly (string | number | boolean | null)[]>>;\n /** Default 32 KiB. */\n readonly maxDataBytes?: number;\n}\n\n/** One declared home for an unbidden (system-raised) window: a route prefix, or one exact page. */\nexport type UnbiddenHomeRoute = string | { readonly route: string; readonly exact: true };\n\nexport interface OverlayWindowOptions {\n readonly mobile?: MobilePresentation;\n readonly mobileSidebarAs?: \"drawer\" | \"inline\";\n /** Never saved or restored (debug panels, one-shot tools, callback-bound editors). */\n readonly ephemeral?: boolean;\n readonly preservation?: WindowPreservation;\n /**\n * Values merged under saved data when a window is RESTORED (reload, another device). Unlike the\n * definition's `defaults`, never applied to a normal open.\n */\n readonly restoreDefaults?: Readonly<Record<string, unknown>>;\n /**\n * The window-manager id the WindowPanel registers under for the default instance. Default: the\n * overlay id. The render watchdog reveals and inspects this id until the panel acks its own.\n */\n readonly windowId?: string;\n readonly deprecated?: { readonly replacement?: string; readonly reason?: string };\n /**\n * Where a window nobody opened (system-raised) may raise itself. Default deny: no home → it may\n * not raise itself anywhere (`mayRaiseUnbidden` in the window section).\n */\n readonly unbiddenHome?: readonly UnbiddenHomeRoute[];\n}\n\n// ── Host types (augmentable) ────────────────────────────────────────────────────────────────\n\n/**\n * Host-specific types the package passes through untouched. A Redux host augments `dispatch`\n * with its thunk-aware dispatch so link hydrators can dispatch its thunks without casts:\n *\n * declare module \"@ai-matrx/summon\" { interface OverlayHostTypes { dispatch: AppDispatch } }\n */\nexport type OverlayHostDispatch = OverlayHostTypes extends { dispatch: infer D } ? D : (action: unknown) => unknown;\n\n// ── Links (address-bar references) ──────────────────────────────────────────────────────────\n\nexport interface LinkHydrateContext<Data> {\n /** The id segment of the link token (`notes:<id>`). */\n readonly id: string;\n /** Decoded `k-v` arguments of the token. */\n readonly args: Readonly<Record<string, string>>;\n /** Open this overlay. */\n open(options?: { readonly instanceId?: string; readonly data?: Data }): void;\n /** The host store's dispatch, for thunks a hydrator needs (loading a record first). Typed by\n * augmenting `OverlayHostTypes` with the host's dispatch type. */\n readonly dispatch: OverlayHostDispatch;\n}\n\nexport interface OverlayLinkSpec<Data> {\n /** The token type key in `?panels=key:id`. Unique across the host. */\n readonly key: string;\n /** Older keys that still resolve to this overlay. */\n readonly aliases?: readonly string[];\n /** Turn a link token into an open overlay (and its data). `\"refused\"` keeps the token and says why. */\n hydrate(context: LinkHydrateContext<Data>): void | \"refused\" | Promise<void | \"refused\">;\n}\n\n// ── Definitions (framework-free half; the React half adds `render`) ─────────────────────────\n\nexport interface OverlayDefinitionMeta<Id extends string = string, Data = Record<string, unknown>> {\n readonly id: Id;\n /** Human label: tray, menus, diagnostics. */\n readonly label: string;\n readonly instance?: InstanceMode;\n readonly keepAlive?: KeepAlive;\n /** Close when the route changes — the overlay shows a piece of the page that opened it. */\n readonly closesOnNavigation?: boolean;\n /** Present only for overlays that render a WindowPanel. */\n readonly window?: OverlayWindowOptions;\n readonly link?: OverlayLinkSpec<Data>;\n /** Defaults merged under open data (replaces the old per-overlay schema registry). */\n readonly defaults?: Partial<Data>;\n}\n\n/** The window-manager id a singleton window overlay registers under (`window.windowId ?? id`). */\nexport function defaultWindowIdFor(meta: Pick<OverlayDefinitionMeta, \"id\" | \"window\">): string {\n return meta.window?.windowId ?? meta.id;\n}\n","/**\n * Everything the overlays system needs from its host, as ports. Every port ships a working\n * default, so a bare host gets a working system with zero wiring (package standard rule 8); a\n * host overrides only what it has: identity, navigation, notifications, error sink, debug flag,\n * persistence. Framework-free.\n */\n\nexport type Unsubscribe = () => void;\n\n/** Who the person is, for isolating saved state. `key` changes → everything saved is swapped. */\nexport interface IdentityPort {\n current(): { readonly key: string; readonly ready: boolean };\n subscribe(listener: () => void): Unsubscribe;\n}\n\n/** The address bar: route changes (close-on-navigation) and the `?panels=` link channel. */\nexport interface RouterPort {\n pathname(): string;\n search(): string;\n /** Replace the query string without navigating or remounting the page. */\n replaceSearch(nextSearch: string): void;\n subscribe(listener: () => void): Unsubscribe;\n}\n\nexport interface NotifyOptions {\n readonly id?: string;\n readonly description?: string;\n /** How long the notice stays up (ms). Hosts without timed notices ignore it. */\n readonly duration?: number;\n /** One action button (e.g. the render watchdog's \"Show it\"). Hosts without actions ignore it. */\n readonly action?: { readonly label: string; readonly onClick: () => void };\n}\n\nexport interface NotifyPort {\n info(message: string, options?: NotifyOptions): void;\n warn(message: string, options?: NotifyOptions): void;\n error(message: string, options?: NotifyOptions): void;\n /** Withdraw a notice by id (optional). */\n dismiss?(id: string): void;\n}\n\nexport interface ErrorSinkPort {\n capture(error: unknown, context: Readonly<Record<string, unknown>>): void;\n}\n\nexport interface DebugPort {\n enabled(): boolean;\n subscribe?(listener: () => void): Unsubscribe;\n}\n\n/** A stored value with its optimistic-concurrency version (0 when the store has none). */\nexport interface StoredValue<T = unknown> {\n readonly value: T;\n readonly version: number;\n}\n\n/**\n * Where saved overlay state lives when persistence is on. Keys are already scoped to the\n * identity by the caller (`<identityKey>/<key>`) for stores that are not per-person themselves.\n * Implementations: the browser-local store (`./persistence`), `@ai-matrx/data` over\n * `users.user_surface_state` (`./persistence/data`), or any host database.\n */\nexport interface OverlayPersistencePort {\n /**\n * True when the store is per-person itself (rows scoped to the signed-in person, e.g. the\n * `@ai-matrx/data` adapter): the persistence section then passes plain keys (`workspace`,\n * `state:<instanceKey>`) instead of `<identityKey>/<key>`, and defaults to `scope: \"person\"`.\n */\n readonly perPerson?: boolean;\n load<T = unknown>(key: string): Promise<StoredValue<T> | null>;\n save<T = unknown>(key: string, value: T, options?: { readonly expectedVersion?: number }): Promise<{ readonly version: number }>;\n remove(key: string): Promise<void>;\n list?(prefix: string): Promise<readonly string[]>;\n /**\n * Every saved value at once (key → value), for stores where one read is cheaper than several.\n * When present, restoring an identity costs exactly this one call: the workspace and every\n * saved component state come out of it, and `load`/`list` are not called on boot.\n */\n loadAll?(): Promise<ReadonlyMap<string, StoredValue>>;\n}\n\nexport interface SummonPorts {\n readonly identity: IdentityPort;\n readonly router: RouterPort;\n readonly notify: NotifyPort;\n readonly errors: ErrorSinkPort;\n readonly debug: DebugPort;\n /** `null` = persistence off (R6). */\n readonly persistence: OverlayPersistencePort | null;\n}\n\nconst noop = (): void => {};\n\nexport const anonymousIdentity: IdentityPort = {\n current: () => ({ key: \"anonymous\", ready: true }),\n subscribe: () => noop,\n};\n\n/** `window.location` + `history.replaceState`; inert on the server. */\nexport const locationRouter: RouterPort = {\n pathname: () => (typeof window === \"undefined\" ? \"/\" : window.location.pathname),\n search: () => (typeof window === \"undefined\" ? \"\" : window.location.search),\n replaceSearch: (nextSearch) => {\n if (typeof window === \"undefined\") return;\n const query = nextSearch && !nextSearch.startsWith(\"?\") ? `?${nextSearch}` : nextSearch;\n const url = `${window.location.pathname}${query}${window.location.hash}`;\n window.history.replaceState(window.history.state, \"\", url);\n },\n subscribe: (listener) => {\n if (typeof window === \"undefined\") return noop;\n window.addEventListener(\"popstate\", listener);\n return () => window.removeEventListener(\"popstate\", listener);\n },\n};\n\n/* eslint-disable no-console */\nexport const consoleNotify: NotifyPort = {\n info: (message) => console.info(`[summon] ${message}`),\n warn: (message) => console.warn(`[summon] ${message}`),\n error: (message) => console.error(`[summon] ${message}`),\n};\n\nexport const consoleErrorSink: ErrorSinkPort = {\n capture: (error, context) => console.error(\"[summon]\", error, context),\n};\n/* eslint-enable no-console */\n\nexport const debugOff: DebugPort = { enabled: () => false };\n\nexport const DEFAULT_PORTS: SummonPorts = {\n identity: anonymousIdentity,\n router: locationRouter,\n notify: consoleNotify,\n errors: consoleErrorSink,\n debug: debugOff,\n persistence: null,\n};\n\nexport function resolvePorts(overrides: Partial<SummonPorts> | undefined): SummonPorts {\n return { ...DEFAULT_PORTS, ...overrides };\n}\n","/**\n * The process-wide registry of overlay definition metadata (the framework-free half of each\n * definition). The host registers its definitions once (`<SummonHost definitions>` does it);\n * reducers stay pure — middleware and hooks read this registry and put what reducers need in the\n * action payload (e.g. the ids bound to the page).\n *\n * State lives in a global slot so a duplicated module graph (ESM + CJS, unsplit bundles) sees one\n * registry (kit `globalSlot`, architecture D9).\n */\nimport { globalSlot } from \"@ai-matrx/kit/global-slot\";\nimport type { OverlayDefinitionMeta } from \"./types\";\n\n/**\n * A definition's meta with its data type erased, so definitions of every data shape share one\n * registry without casts. (`never` erasure made `defaults` unassignable.)\n */\nexport interface AnyOverlayMeta extends Omit<OverlayDefinitionMeta<string, unknown>, \"defaults\"> {\n readonly defaults?: object | undefined;\n}\n\ntype AnyMeta = AnyOverlayMeta;\n\ninterface RegistryState {\n readonly byId: Map<string, AnyMeta>;\n readonly byLinkKey: Map<string, AnyMeta>;\n readonly listeners: Set<() => void>;\n}\n\nconst state = (): RegistryState =>\n globalSlot<RegistryState>(\"ai-matrx.summon.registry\", () => ({\n byId: new Map(),\n byLinkKey: new Map(),\n listeners: new Set(),\n }));\n\n/**\n * Register (or re-register) definitions. Re-registering an id replaces it (hot reload). A link\n * key claimed by two different ids is a host bug and throws, naming both.\n */\nexport function registerOverlayMeta(definitions: readonly AnyOverlayMeta[]): void {\n const s = state();\n for (const def of definitions) {\n s.byId.set(def.id, def);\n const keys = def.link ? [def.link.key, ...(def.link.aliases ?? [])] : [];\n for (const key of keys) {\n const holder = s.byLinkKey.get(key);\n if (holder && holder.id !== def.id) {\n throw new Error(`[summon] link key \"${key}\" is claimed by both \"${holder.id}\" and \"${def.id}\"`);\n }\n s.byLinkKey.set(key, def);\n }\n }\n for (const listener of s.listeners) listener();\n}\n\nexport function getOverlayMeta(overlayId: string): AnyMeta | undefined {\n return state().byId.get(overlayId);\n}\n\nexport function getOverlayMetaByLinkKey(linkKey: string): AnyMeta | undefined {\n return state().byLinkKey.get(linkKey);\n}\n\nexport function allOverlayMeta(): readonly AnyMeta[] {\n return [...state().byId.values()];\n}\n\nexport function isRegisteredOverlay(overlayId: string): boolean {\n return state().byId.has(overlayId);\n}\n\nexport function subscribeToOverlayRegistry(listener: () => void): () => void {\n const s = state();\n s.listeners.add(listener);\n return () => s.listeners.delete(listener);\n}\n\n/** Test-only. */\nexport function resetOverlayRegistry(): void {\n const s = state();\n s.byId.clear();\n s.byLinkKey.clear();\n}\n","// The public action creators, light: plain objects with the slices' own type strings, so a file\n// that only opens or closes something never loads a slice. The slices (core) handle these exact\n// types; `actions.parity.test.ts` proves every creator here equals its slice twin.\n//\n// `openOverlay`/`toggleOverlay` keep the two guarantees the slice creators had: functions are\n// stripped from open data (they can never travel through Redux — the D33 dead-button class) and\n// the definition's registered `defaults` ride the payload, so the reducer stays pure.\nimport { getOverlayMeta, allOverlayMeta } from \"../core/registry\";\nimport { DEFAULT_INSTANCE_ID, type InstanceKey, type OverlayDataOf, type OverlayId } from \"../core/types\";\n\nexport interface OpenOverlayPayload<Id extends OverlayId = OverlayId> {\n overlayId: Id;\n instanceId?: string;\n data?: OverlayDataOf<Id> | null;\n}\n\nexport interface CloseOverlayPayload<Id extends OverlayId = OverlayId> {\n overlayId: Id;\n instanceId?: string;\n}\n\nexport type ToggleOverlayPayload<Id extends OverlayId = OverlayId> = OpenOverlayPayload<Id>;\n\nexport interface CloseAllInstancesPayload<Id extends OverlayId = OverlayId> {\n overlayId: Id;\n}\n\nexport interface CloseOverlaysBoundToPagePayload {\n /** Overlay ids whose definitions say `closesOnNavigation`. */\n overlayIds: readonly string[];\n}\n\nexport interface PruneStaleInstancesPayload {\n olderThanMs: number;\n}\n\n/** Raw reducer payload: untyped ids + the registry defaults the creator resolved. */\nexport interface RawOpenPayload {\n overlayId: string;\n instanceId?: string;\n data?: unknown;\n defaults?: Readonly<Record<string, unknown>>;\n}\n\nexport interface SummonAction<P> {\n type: string;\n payload: P;\n /** Structurally a Redux `UnknownAction`. */\n [extra: string]: unknown;\n}\n\ntype Creator<Args extends unknown[], P> = ((...args: Args) => SummonAction<P>) & {\n readonly type: string;\n match(action: unknown): action is SummonAction<P>;\n};\n\nfunction creator<Args extends unknown[], P>(type: string, build: (...args: Args) => P): Creator<Args, P> {\n const create = (...args: Args): SummonAction<P> => ({ type, payload: build(...args) });\n return Object.assign(create, {\n type,\n toString: () => type,\n match: (action: unknown): action is SummonAction<P> =>\n typeof action === \"object\" && action !== null && (action as { type?: unknown }).type === type,\n });\n}\n\n/** A creator whose call signature stays generic (the inferred `creator` form erases `Id`). */\ntype Generic<F> = F & { readonly type: string; match(action: unknown): action is SummonAction<unknown> };\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction stripFunctions(overlayId: string, data: unknown): unknown {\n if (!isPlainRecord(data)) return data;\n const offenders = Object.keys(data).filter((key) => typeof data[key] === \"function\");\n if (offenders.length === 0) return data;\n // eslint-disable-next-line no-console\n console.error(\n `[summon] BUG: function value(s) in openOverlay data for \"${overlayId}\" (keys: ${offenders.join(\", \")}). ` +\n `Functions cannot travel through Redux — the handler would NEVER fire. Register a handle ` +\n `(@ai-matrx/summon/handles) and pass its id string instead. The offending key(s) were stripped from state.`,\n );\n const cleaned = { ...data };\n for (const key of offenders) delete cleaned[key];\n return cleaned;\n}\n\nfunction rawOpen(payload: { overlayId: string; instanceId?: string; data?: unknown }): RawOpenPayload {\n const raw: RawOpenPayload = { overlayId: payload.overlayId };\n if (payload.instanceId !== undefined) raw.instanceId = payload.instanceId;\n if (payload.data !== undefined) raw.data = stripFunctions(payload.overlayId, payload.data);\n const defaults: unknown = getOverlayMeta(payload.overlayId)?.defaults;\n if (isPlainRecord(defaults)) raw.defaults = stripFunctions(payload.overlayId, defaults) as Record<string, unknown>;\n return raw;\n}\n\nconst O = \"overlays/\";\n\nexport const openOverlay = creator(O + \"openOverlay\", (payload: OpenOverlayPayload) => rawOpen(payload)) as Generic<\n <Id extends OverlayId>(payload: OpenOverlayPayload<Id>) => SummonAction<RawOpenPayload>\n>;\n\nexport const closeOverlay = creator(O + \"closeOverlay\", (payload: CloseOverlayPayload): { overlayId: string; instanceId?: string } =>\n payload.instanceId === undefined ? { overlayId: payload.overlayId } : { overlayId: payload.overlayId, instanceId: payload.instanceId },\n) as Generic<<Id extends OverlayId>(payload: CloseOverlayPayload<Id>) => SummonAction<{ overlayId: string; instanceId?: string }>>;\n\nexport const toggleOverlay = creator(O + \"toggleOverlay\", (payload: ToggleOverlayPayload) => rawOpen(payload)) as Generic<\n <Id extends OverlayId>(payload: ToggleOverlayPayload<Id>) => SummonAction<RawOpenPayload>\n>;\n\nexport const closeAllInstancesOfOverlay = creator(O + \"closeAllInstancesOfOverlay\", (payload: CloseAllInstancesPayload) => ({\n overlayId: payload.overlayId as string,\n})) as Generic<<Id extends OverlayId>(payload: CloseAllInstancesPayload<Id>) => SummonAction<{ overlayId: string }>>;\n\n/** Ids of every registered overlay whose definition says `closesOnNavigation`. */\nexport function overlayIdsBoundToPage(): string[] {\n return allOverlayMeta()\n .filter((meta) => meta.closesOnNavigation === true)\n .map((meta) => meta.id);\n}\n\n/** Close page-bound overlays. Omit the ids to use the registry's `closesOnNavigation` list. */\nexport const closeOverlaysBoundToPage = creator(\n O + \"closeOverlaysBoundToPage\",\n (payload?: Partial<CloseOverlaysBoundToPagePayload>): CloseOverlaysBoundToPagePayload => ({\n overlayIds: [...(payload?.overlayIds ?? overlayIdsBoundToPage())],\n }),\n);\n\nexport const closeAllOverlays = creator(O + \"closeAllOverlays\", () => undefined);\nexport const pruneStaleInstances = creator(O + \"pruneStaleInstances\", (payload: PruneStaleInstancesPayload) => payload);\n\n// ── Window manager: the ones callers outside a window dispatch (menus, shortcuts, settings) ──\n\nconst W = \"windowManager/\";\nconst pass = <P>() => (payload: P) => payload;\n\nexport const focusWindow = creator(W + \"focusWindow\", pass<string>());\nexport const restoreWindow = creator(W + \"restoreWindow\", pass<string>());\nexport const toggleWindowsHidden = creator(W + \"toggleWindowsHidden\", () => undefined);\nexport const restoreAll = creator(W + \"restoreAll\", () => undefined);\nexport const minimizeAll = creator(W + \"minimizeAll\", pass<{ viewportWidth: number; viewportHeight: number }>());\n\nexport interface ArrangeActiveWindowsPayload {\n layout: import(\"../core/geometry/windowArrangements\").GlobalLayoutType;\n viewportWidth: number;\n viewportHeight: number;\n dirX?: \"ltr\" | \"rtl\";\n dirY?: \"ttb\" | \"btt\";\n primary?: \"horizontal\" | \"vertical\";\n}\nexport const arrangeActiveWindows = creator(W + \"arrangeActiveWindows\", pass<ArrangeActiveWindowsPayload>());\n\nexport const revealWindow = creator(W + \"revealWindow\", pass<{ id: string; viewportWidth: number; viewportHeight: number }>());\nexport const updateWindowRect = creator(\n W + \"updateWindowRect\",\n pass<{ id: string; rect: Partial<import(\"../core/geometry/types\").WindowRect> }>(),\n);\n\n// ── Saved component state ──\n\nexport const setOverlayStateValue = creator(\"overlayState/setOverlayStateValue\", pass<{ key: InstanceKey; name: string; value: unknown }>());\n\n// ── Links ────────────────────────────────────────────────────────────────────────────────────\n\nexport interface UrlSyncEntryPayload {\n typeKey: string;\n instanceId: string;\n args?: Readonly<Record<string, string>>;\n}\nexport const registerSyncEntry = creator(\"urlSync/registerSyncEntry\", pass<UrlSyncEntryPayload>());\nexport const unregisterSyncEntry = creator(\"urlSync/unregisterSyncEntry\", pass<{ typeKey: string; instanceId: string }>());\n\n/** Every slice key the summon reducers own; an action under one of them needs the runtime. */\nexport const SUMMON_SLICE_KEYS = [\"overlays\", \"windowManager\", \"urlSync\", \"overlayState\"] as const;\n\nexport function isSummonAction(action: unknown): action is { type: string } {\n if (typeof action !== \"object\" || action === null) return false;\n const type = (action as { type?: unknown }).type;\n if (typeof type !== \"string\") return false;\n const slash = type.indexOf(\"/\");\n return slash > 0 && (SUMMON_SLICE_KEYS as readonly string[]).includes(type.slice(0, slash));\n}\n\nexport { DEFAULT_INSTANCE_ID };\n","// Render acknowledgements a mobile surface reports (it renders instead of a WindowPanel). Light:\n// the same slot the render watchdog (core) reads, so a boot-graph hook can report without the core.\nimport { globalSlot } from \"@ai-matrx/kit/global-slot\";\n\ninterface AckSlot {\n readonly renderAcks: Map<string, { kind: \"window\"; windowId: string } | { kind: \"surface\" }>;\n readonly ackWaiters: Map<string, () => void>;\n readonly watches: Map<string, unknown>;\n}\n\n// Same key and shape as core/middleware/renderWatchdog.ts (RENDER_WATCHDOG_SLOT).\nconst slot = (): AckSlot =>\n globalSlot<AckSlot>(\"ai-matrx.summon.renderWatchdog\", () => ({ renderAcks: new Map(), ackWaiters: new Map(), watches: new Map() }));\n\nexport function ackOverlaySurfaceRender(overlayId: string): void {\n const s = slot();\n s.renderAcks.set(overlayId, { kind: \"surface\" });\n const notify = s.ackWaiters.get(overlayId);\n if (notify) {\n s.ackWaiters.delete(overlayId);\n notify();\n }\n}\n\nexport function clearOverlaySurfaceRender(overlayId: string): void {\n const s = slot();\n if (s.renderAcks.get(overlayId)?.kind === \"surface\") s.renderAcks.delete(overlayId);\n}\n","// The public overlay selectors, light and safe before the runtime: a host that loads the summon\n// slices on first use (the gate) has no `overlays` key until then, and every overlay reads closed.\nimport { DEFAULT_INSTANCE_ID } from \"../core/types\";\nimport { globalSlot } from \"@ai-matrx/kit/global-slot\";\n\nexport interface OverlayInstance {\n isOpen: boolean;\n data: unknown;\n /** Unix ms of the last open (pruneStaleInstances reads it). */\n lastUsedAt?: number;\n}\n\nexport interface OverlayState {\n overlays: Record<string, Record<string, OverlayInstance>>;\n}\n\n/** The slice of any store these selectors need (absent until the summon runtime is installed). */\n// `| object`: an all-optional type is \"weak\", and a host state sharing no key with it (before the\n// slices are injected, or typed without them) would be refused by TypeScript.\nexport type StateWithOverlays = { overlays?: OverlayState } | object;\nconst overlaysOf = (state: StateWithOverlays): OverlayState | undefined => (state as { overlays?: OverlayState }).overlays;\n\nexport interface OpenInstanceView {\n instanceId: string;\n data: unknown;\n}\n\nconst CLOSED: OverlayInstance = Object.freeze({ isOpen: false, data: null });\nconst EMPTY: readonly OpenInstanceView[] = Object.freeze([]);\n\nexport const selectOverlay = (state: StateWithOverlays, overlayId: string, instanceId: string = DEFAULT_INSTANCE_ID): OverlayInstance =>\n overlaysOf(state)?.overlays[overlayId]?.[instanceId] ?? CLOSED;\n\nexport const selectIsOverlayOpen = (state: StateWithOverlays, overlayId: string, instanceId: string = DEFAULT_INSTANCE_ID): boolean =>\n selectOverlay(state, overlayId, instanceId).isOpen;\n\nexport const selectOverlayData = (state: StateWithOverlays, overlayId: string, instanceId: string = DEFAULT_INSTANCE_ID): unknown =>\n selectOverlay(state, overlayId, instanceId).data;\n\ninterface CachedOpen {\n bucket: Record<string, OverlayInstance> | undefined;\n result: readonly OpenInstanceView[];\n}\nconst openCache = (): Map<string, CachedOpen> => globalSlot(\"ai-matrx.summon.openInstances\", () => new Map<string, CachedOpen>());\n\n/** All open instances of an overlay id; the array reference is stable while the open set is unchanged. */\nexport const selectOpenInstances = (state: StateWithOverlays, overlayId: string): readonly OpenInstanceView[] => {\n const bucket = overlaysOf(state)?.overlays[overlayId];\n const cache = openCache();\n const hit = cache.get(overlayId);\n if (hit && hit.bucket === bucket) return hit.result;\n let result: readonly OpenInstanceView[] = EMPTY;\n if (bucket) {\n const open: OpenInstanceView[] = [];\n for (const [instanceId, inst] of Object.entries(bucket)) if (inst.isOpen) open.push({ instanceId, data: inst.data });\n if (open.length > 0) result = open;\n }\n cache.set(overlayId, { bucket, result });\n return result;\n};\n\n/** Every open instance key (`overlayId:instanceId`). */\nexport function listOpenInstanceKeys(state: StateWithOverlays): string[] {\n const keys: string[] = [];\n for (const [overlayId, bucket] of Object.entries(overlaysOf(state)?.overlays ?? {})) {\n for (const [instanceId, inst] of Object.entries(bucket)) if (inst.isOpen) keys.push(`${overlayId}:${instanceId}`);\n }\n return keys;\n}\n\n/** True once anything has ever been opened in this store (a key exists in the slice). */\nexport function selectAnyOverlayTouched(state: StateWithOverlays): boolean {\n for (const _ in overlaysOf(state)?.overlays ?? {}) return true;\n return false;\n}\n\n/** The global hide-all flag (false before the runtime is installed). */\nexport const selectWindowsHidden = (state: object): boolean =>\n (state as { windowManager?: { windowsHidden: boolean } }).windowManager?.windowsHidden ?? false;\n\ntype WindowLike = import(\"../core/windowManagerSlice\").WindowEntry;\nconst EMPTY_WINDOWS: readonly never[] = Object.freeze([]);\nlet lastWindowsMap: unknown = null;\nlet lastWindows: readonly WindowLike[] = EMPTY_WINDOWS;\n\n/** Every registered window, topmost first (empty before the runtime is installed). Memoized on the map. */\nexport function selectAllWindows<W extends WindowLike = WindowLike>(state: object): readonly W[] {\n const map = (state as { windowManager?: { windows: Record<string, W> } }).windowManager?.windows;\n if (!map) return EMPTY_WINDOWS;\n if (map !== lastWindowsMap) {\n lastWindowsMap = map;\n lastWindows = Object.values(map).sort((a, b) => b.zIndex - a.zIndex);\n }\n return lastWindows as readonly W[];\n}\n\n/** True when windows exist and every one is minimized (false before the runtime is installed). */\nexport function selectAllMinimized(state: object): boolean {\n const map = (state as { windowManager?: { windows: Record<string, { state: string }> } }).windowManager?.windows;\n if (!map) return false;\n const wins = Object.values(map);\n return wins.length > 0 && wins.every((w) => w.state === \"minimized\");\n}\n","// The summon gate: a host store carries NONE of the summon slices or middleware until something\n// needs them. The gate is one middleware in the host chain. Before the core is loaded, every\n// summon action (open, close, a window action…) is queued and the first one starts ONE import()\n// of the core; when the core module evaluates it installs itself into every gate — the slices are\n// injected into the host's root reducer, the real middleware (close lifecycle, render watchdog)\n// joins the chain, and the queue replays in order. A host may also start the import early\n// (`prefetchSummonRuntime` on idle or pointer intent) so the first click opens at once.\n//\n// A module that needs the slices synchronously (the window section, links, persistence) imports\n// the core statically; the core installs at evaluation, so its state exists before it renders.\nimport type { Dispatch, Middleware, MiddlewareAPI, Reducer, UnknownAction } from \"@reduxjs/toolkit\";\nimport { globalSlot } from \"@ai-matrx/kit/global-slot\";\nimport type { SummonPorts } from \"../core/ports\";\nimport { isSummonAction } from \"./actions\";\n\n/** What the core hands the gate when it loads. */\nexport interface SummonCore {\n readonly reducers: Readonly<Record<string, Reducer>>;\n createMiddleware(ports?: Partial<SummonPorts>): Middleware[];\n}\n\n/** Dispatched once after the slices are injected into a live store, so they hold their initial state. */\nexport const SUMMON_INSTALLED_ACTION = \"@@summon/installed\";\n\ninterface GateInternals {\n install(core: SummonCore): void;\n}\n\ninterface GateSlot {\n core: SummonCore | null;\n loading: Promise<void> | null;\n readonly gates: Set<GateInternals>;\n readonly listeners: Set<() => void>;\n}\n\nconst slot = (): GateSlot =>\n globalSlot<GateSlot>(\"ai-matrx.summon.gate\", () => ({ core: null, loading: null, gates: new Set(), listeners: new Set() }));\n\n/** Called by the core module when it evaluates (idempotent). */\nexport function installSummonCore(core: SummonCore): void {\n const s = slot();\n if (s.core) return;\n s.core = core;\n const gates = [...s.gates];\n s.gates.clear();\n for (const gate of gates) gate.install(core);\n for (const listener of [...s.listeners]) listener();\n}\n\nexport function isSummonInstalled(): boolean {\n return slot().core !== null;\n}\n\nexport function subscribeSummonInstalled(listener: () => void): () => void {\n const s = slot();\n s.listeners.add(listener);\n return () => s.listeners.delete(listener);\n}\n\n/** Load the summon core (one import(), shared by every caller). Resolves once it is installed. */\nexport function ensureSummonRuntime(): Promise<void> {\n const s = slot();\n if (s.core) return Promise.resolve();\n s.loading ??= import(\"@ai-matrx/summon\").then(\n (core) => installSummonCore(core.summonCore),\n (error: unknown) => {\n s.loading = null; // a failed chunk may be retried by the next request\n throw error;\n },\n );\n return s.loading;\n}\n\n/** Start loading the core without waiting (idle, pointer intent). Errors surface on the next real request. */\nexport function prefetchSummonRuntime(): void {\n ensureSummonRuntime().catch(() => undefined);\n}\n\nexport interface SummonGate {\n /** Put this in the host store's middleware chain. */\n readonly middleware: Middleware;\n /**\n * Give the gate the host root reducer's inject function — before `configureStore`, so a core\n * that is already loaded (a page that imported the window section) is injected before the\n * store's first state exists.\n */\n attachReducer(inject: (reducers: Readonly<Record<string, Reducer>>) => void): void;\n}\n\nexport interface CreateSummonGateOptions {\n /** Ports for the summon middleware (render watchdog: notify, errors, debug). */\n readonly ports?: Partial<SummonPorts>;\n}\n\nexport function createSummonGate(options: CreateSummonGateOptions = {}): SummonGate {\n let inject: ((reducers: Readonly<Record<string, Reducer>>) => void) | null = null;\n let injected = false;\n let api: MiddlewareAPI<Dispatch<UnknownAction>, unknown> | null = null;\n let next: ((action: unknown) => unknown) | null = null;\n let chain: ((action: unknown) => unknown) | null = null;\n const queue: unknown[] = [];\n\n const settle = (core: SummonCore, live: boolean) => {\n if (inject && !injected) {\n inject(core.reducers);\n injected = true;\n }\n if (!api || !next || chain) return;\n const store = api;\n let composed: (action: unknown) => unknown = next;\n for (const middleware of [...core.createMiddleware(options.ports)].reverse()) {\n composed = middleware(store)(composed) as (action: unknown) => unknown;\n }\n chain = composed;\n const flush = () => {\n if (live) store.dispatch({ type: SUMMON_INSTALLED_ACTION });\n for (const action of queue.splice(0)) store.dispatch(action as UnknownAction);\n };\n // Redux forbids dispatching while the middleware chain is being built.\n if (live) flush();\n else if (queue.length > 0) queueMicrotask(flush);\n };\n\n const internals: GateInternals = { install: (core) => settle(core, true) };\n const core = () => slot().core;\n\n const middleware: Middleware = (storeApi) => {\n api = storeApi as MiddlewareAPI<Dispatch<UnknownAction>, unknown>;\n return (nextDispatch) => {\n next = nextDispatch as (action: unknown) => unknown;\n const loaded = core();\n if (loaded) settle(loaded, false);\n else slot().gates.add(internals);\n return (action) => {\n if (chain) return chain(action);\n if (!isSummonAction(action)) return nextDispatch(action);\n queue.push(action);\n void ensureSummonRuntime().catch((error: unknown) => {\n // eslint-disable-next-line no-console\n console.error(\"[summon] the overlay runtime failed to load; queued requests are kept for the next try\", error);\n });\n return action;\n };\n };\n };\n\n return {\n middleware,\n attachReducer(fn) {\n inject = fn;\n const loaded = core();\n if (loaded) {\n inject(loaded.reducers);\n injected = true;\n }\n },\n };\n}\n","// Callback-aware opening without loading the handles registry up front. The opener needs a\n// channel id synchronously (it rides open data); the channel itself is created when the handles\n// section arrives — one import() started by the first such open — or at once by whoever emits\n// first (the render tree has handles statically). Closing the owner before then drops it.\nimport { globalSlot } from \"@ai-matrx/kit/global-slot\";\nimport type { EventChannel } from \"../handles/helpers\";\n\ntype Handlers = Readonly<Record<string, ((payload: unknown) => void) | undefined>> | undefined;\n\ninterface PendingChannel {\n readonly owner: string;\n readonly getHandlers: () => Handlers;\n}\n\n/** The one message shape on an overlay's channel. */\nexport interface OverlayEventMessage {\n readonly type: string;\n readonly payload: unknown;\n}\n\ntype CreateChannel = (options: { owner?: string; id?: string }) => EventChannel<OverlayEventMessage>;\n\nconst pending = (): Map<string, PendingChannel> => globalSlot(\"ai-matrx.summon.pendingChannels\", () => new Map<string, PendingChannel>());\n\n/** Create every pending channel now (idempotent per id). */\nexport function materializePendingChannels(createEventChannel: CreateChannel): void {\n const map = pending();\n for (const [id, entry] of [...map]) {\n map.delete(id);\n const channel = createEventChannel({ owner: entry.owner, id });\n channel.subscribe((message) => entry.getHandlers()?.[message.type]?.(message.payload));\n }\n}\n\n/** Reserve a channel owned by `owner` whose events go to the handlers `getHandlers` returns at emit time. */\nexport function openPendingEventChannel(owner: string, getHandlers: () => Handlers): string {\n const id = `ch-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n pending().set(id, { owner, getHandlers });\n void import(\"@ai-matrx/summon/handles\").then(({ createEventChannel }) => materializePendingChannels(createEventChannel));\n return id;\n}\n\n/** The owner closed before its channel was created: forget it. */\nexport function dropPendingChannelsOf(owner: string): void {\n const map = pending();\n for (const [id, entry] of [...map]) if (entry.owner === owner) map.delete(id);\n}\n"],"mappings":"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","names":["globalSlot","globalSlot","state","globalSlot","slot","globalSlot","core","middleware","globalSlot"]}
1
+ {"version":3,"sources":["../src/core/types.ts","../src/core/ports.ts","../src/core/registry.ts","../src/open/actions.ts","../src/open/renderAcks.ts","../src/open/selectors.ts","../src/open/gate.ts","../src/open/channels.ts","../src/open/grammar.ts"],"sourcesContent":["/**\n * The shared vocabulary of @ai-matrx/summon. Framework-free: no React, no Redux imports.\n *\n * An OVERLAY is any component rendered on top of the app by dispatch — a window, dialog, sheet,\n * light floating window, toast-like card, anything. It is identified by an `OverlayId` and opened\n * as one or more INSTANCES (`instanceId`, \"default\" for single-instance overlays).\n */\n\n/**\n * The host's overlay registry: overlay id → the data its opener accepts. Hosts extend it by\n * module augmentation so every open call is type-checked:\n *\n * declare module \"@ai-matrx/summon\" {\n * interface OverlayRegistry { notesWindow: { noteId?: string } }\n * }\n *\n * `defineOverlay` emits nothing at runtime for this; the augmentation is the host's one-line\n * declaration per overlay (the converter writes it next to each definition).\n */\n// Declared in ./augment (bundled only into the core's declarations, so `declare module\n// \"@ai-matrx/summon\"` merges into it); every section reads it through the package name.\nimport type { OverlayRegistry, OverlayHostTypes } from \"@ai-matrx/summon\";\nexport type { OverlayRegistry, OverlayHostTypes };\n\n/** Every registered overlay id; plain `string` until the host augments the registry. */\nexport type OverlayId = [keyof OverlayRegistry] extends [never]\n ? string\n : Extract<keyof OverlayRegistry, string>;\n\n/** The open-data type declared for an overlay id. */\nexport type OverlayDataOf<Id extends string> = Id extends keyof OverlayRegistry\n ? OverlayRegistry[Id]\n : Record<string, unknown>;\n\n/**\n * Data as it arrives at render time. It crossed Redux, a URL or storage, so it is NOT trusted to\n * match the opener's type: render code narrows it (or the definition supplies `parse`).\n */\nexport type OverlayRawData = Readonly<Record<string, unknown>> | null;\n\nexport const DEFAULT_INSTANCE_ID = \"default\";\n\n/** `single`: one instance (\"default\"). `multi`: any number, each with its own instanceId. */\nexport type InstanceMode = \"single\" | \"multi\";\n\n/**\n * What closing does to a mounted overlay (Arman, 2026-10-16, C38 R3):\n * none — unmount (default).\n * hidden — stay mounted but hidden; reopening shows the same live component (LRU-capped).\n * restore — unmount, but values saved with `useOverlayState` come back on reopen.\n * Minimizing a window always keeps its component mounted, whatever this says.\n */\nexport type KeepAlive = \"none\" | \"hidden\" | \"restore\";\n\n/** `overlayId:instanceId` — the one key every subsystem uses for an open instance. */\nexport type InstanceKey = `${string}:${string}`;\n\nexport function instanceKey(overlayId: string, instanceId: string = DEFAULT_INSTANCE_ID): InstanceKey {\n return `${overlayId}:${instanceId}`;\n}\n\nexport function parseInstanceKey(key: string): { overlayId: string; instanceId: string } | null {\n const at = key.indexOf(\":\");\n if (at <= 0 || at === key.length - 1) return null;\n return { overlayId: key.slice(0, at), instanceId: key.slice(at + 1) };\n}\n\n// ── Window options (consumed by the window surface; inert for other surfaces) ──────────────────\n\nexport type MobilePresentation = \"fullscreen\" | \"drawer\" | \"card\" | \"hidden\";\n\n/**\n * Default-deny allowlist of the open data a window may save and restore. A window with no\n * preservation entry restores geometry only.\n */\nexport interface WindowPreservation {\n readonly dataKeys: readonly string[];\n readonly requiredDataKeys?: readonly string[];\n readonly allowedDataValues?: Readonly<Record<string, readonly (string | number | boolean | null)[]>>;\n /** Default 32 KiB. */\n readonly maxDataBytes?: number;\n}\n\n/** One declared home for an unbidden (system-raised) window: a route prefix, or one exact page. */\nexport type UnbiddenHomeRoute = string | { readonly route: string; readonly exact: true };\n\nexport interface OverlayWindowOptions {\n readonly mobile?: MobilePresentation;\n readonly mobileSidebarAs?: \"drawer\" | \"inline\";\n /** Never saved or restored (debug panels, one-shot tools, callback-bound editors). */\n readonly ephemeral?: boolean;\n readonly preservation?: WindowPreservation;\n /**\n * Values merged under saved data when a window is RESTORED (reload, another device). Unlike the\n * definition's `defaults`, never applied to a normal open.\n */\n readonly restoreDefaults?: Readonly<Record<string, unknown>>;\n /**\n * The window-manager id the WindowPanel registers under for the default instance. Default: the\n * overlay id. The render watchdog reveals and inspects this id until the panel acks its own.\n */\n readonly windowId?: string;\n readonly deprecated?: { readonly replacement?: string; readonly reason?: string };\n /**\n * Where a window nobody opened (system-raised) may raise itself. Default deny: no home → it may\n * not raise itself anywhere (`mayRaiseUnbidden` in the window section).\n */\n readonly unbiddenHome?: readonly UnbiddenHomeRoute[];\n}\n\n// ── Host types (augmentable) ────────────────────────────────────────────────────────────────\n\n/**\n * Host-specific types the package passes through untouched. A Redux host augments `dispatch`\n * with its thunk-aware dispatch so link hydrators can dispatch its thunks without casts:\n *\n * declare module \"@ai-matrx/summon\" { interface OverlayHostTypes { dispatch: AppDispatch } }\n */\nexport type OverlayHostDispatch = OverlayHostTypes extends { dispatch: infer D } ? D : (action: unknown) => unknown;\n\n// ── Links (address-bar references) ──────────────────────────────────────────────────────────\n\nexport interface LinkHydrateContext<Data> {\n /** The id segment of the link token (`notes:<id>`). */\n readonly id: string;\n /** Decoded `k-v` arguments of the token. */\n readonly args: Readonly<Record<string, string>>;\n /** Open this overlay. */\n open(options?: { readonly instanceId?: string; readonly data?: Data }): void;\n /** The host store's dispatch, for thunks a hydrator needs (loading a record first). Typed by\n * augmenting `OverlayHostTypes` with the host's dispatch type. */\n readonly dispatch: OverlayHostDispatch;\n}\n\nexport interface OverlayLinkSpec<Data> {\n /** The token type key in `?panels=key:id`. Unique across the host. */\n readonly key: string;\n /** Older keys that still resolve to this overlay. */\n readonly aliases?: readonly string[];\n /** Turn a link token into an open overlay (and its data). `\"refused\"` keeps the token and says why. */\n hydrate(context: LinkHydrateContext<Data>): void | \"refused\" | Promise<void | \"refused\">;\n}\n\n// ── Definitions (framework-free half; the React half adds `render`) ─────────────────────────\n\nexport interface OverlayDefinitionMeta<Id extends string = string, Data = Record<string, unknown>> {\n readonly id: Id;\n /** Human label: tray, menus, diagnostics. */\n readonly label: string;\n readonly instance?: InstanceMode;\n readonly keepAlive?: KeepAlive;\n /** Close when the route changes — the overlay shows a piece of the page that opened it. */\n readonly closesOnNavigation?: boolean;\n /** Present only for overlays that render a WindowPanel. */\n readonly window?: OverlayWindowOptions;\n readonly link?: OverlayLinkSpec<Data>;\n /** Defaults merged under open data (replaces the old per-overlay schema registry). */\n readonly defaults?: Partial<Data>;\n}\n\n/** The window-manager id a singleton window overlay registers under (`window.windowId ?? id`). */\nexport function defaultWindowIdFor(meta: Pick<OverlayDefinitionMeta, \"id\" | \"window\">): string {\n return meta.window?.windowId ?? meta.id;\n}\n","/**\n * Everything the overlays system needs from its host, as ports. Every port ships a working\n * default, so a bare host gets a working system with zero wiring (package standard rule 8); a\n * host overrides only what it has: identity, navigation, notifications, error sink, debug flag,\n * persistence. Framework-free.\n */\n\nexport type Unsubscribe = () => void;\n\n/** Who the person is, for isolating saved state. `key` changes → everything saved is swapped. */\nexport interface IdentityPort {\n current(): { readonly key: string; readonly ready: boolean };\n subscribe(listener: () => void): Unsubscribe;\n}\n\n/** The address bar: route changes (close-on-navigation) and the `?panels=` link channel. */\nexport interface RouterPort {\n pathname(): string;\n search(): string;\n /** Replace the query string without navigating or remounting the page. */\n replaceSearch(nextSearch: string): void;\n subscribe(listener: () => void): Unsubscribe;\n}\n\nexport interface NotifyOptions {\n readonly id?: string;\n readonly description?: string;\n /** How long the notice stays up (ms). Hosts without timed notices ignore it. */\n readonly duration?: number;\n /** One action button (e.g. the render watchdog's \"Show it\"). Hosts without actions ignore it. */\n readonly action?: { readonly label: string; readonly onClick: () => void };\n}\n\nexport interface NotifyPort {\n info(message: string, options?: NotifyOptions): void;\n warn(message: string, options?: NotifyOptions): void;\n error(message: string, options?: NotifyOptions): void;\n /** Withdraw a notice by id (optional). */\n dismiss?(id: string): void;\n}\n\nexport interface ErrorSinkPort {\n capture(error: unknown, context: Readonly<Record<string, unknown>>): void;\n}\n\nexport interface DebugPort {\n enabled(): boolean;\n subscribe?(listener: () => void): Unsubscribe;\n}\n\n/** A stored value with its optimistic-concurrency version (0 when the store has none). */\nexport interface StoredValue<T = unknown> {\n readonly value: T;\n readonly version: number;\n}\n\n/**\n * Where saved overlay state lives when persistence is on. Keys are already scoped to the\n * identity by the caller (`<identityKey>/<key>`) for stores that are not per-person themselves.\n * Implementations: the browser-local store (`./persistence`), `@ai-matrx/data` over\n * `users.user_surface_state` (`./persistence/data`), or any host database.\n */\nexport interface OverlayPersistencePort {\n /**\n * True when the store is per-person itself (rows scoped to the signed-in person, e.g. the\n * `@ai-matrx/data` adapter): the persistence section then passes plain keys (`workspace`,\n * `state:<instanceKey>`) instead of `<identityKey>/<key>`, and defaults to `scope: \"person\"`.\n */\n readonly perPerson?: boolean;\n load<T = unknown>(key: string): Promise<StoredValue<T> | null>;\n save<T = unknown>(key: string, value: T, options?: { readonly expectedVersion?: number }): Promise<{ readonly version: number }>;\n remove(key: string): Promise<void>;\n list?(prefix: string): Promise<readonly string[]>;\n /**\n * Every saved value at once (key → value), for stores where one read is cheaper than several.\n * When present, restoring an identity costs exactly this one call: the workspace and every\n * saved component state come out of it, and `load`/`list` are not called on boot.\n */\n loadAll?(): Promise<ReadonlyMap<string, StoredValue>>;\n}\n\nexport interface SummonPorts {\n readonly identity: IdentityPort;\n readonly router: RouterPort;\n readonly notify: NotifyPort;\n readonly errors: ErrorSinkPort;\n readonly debug: DebugPort;\n /** `null` = persistence off (R6). */\n readonly persistence: OverlayPersistencePort | null;\n}\n\nconst noop = (): void => {};\n\nexport const anonymousIdentity: IdentityPort = {\n current: () => ({ key: \"anonymous\", ready: true }),\n subscribe: () => noop,\n};\n\n/** `window.location` + `history.replaceState`; inert on the server. */\nexport const locationRouter: RouterPort = {\n pathname: () => (typeof window === \"undefined\" ? \"/\" : window.location.pathname),\n search: () => (typeof window === \"undefined\" ? \"\" : window.location.search),\n replaceSearch: (nextSearch) => {\n if (typeof window === \"undefined\") return;\n const query = nextSearch && !nextSearch.startsWith(\"?\") ? `?${nextSearch}` : nextSearch;\n const url = `${window.location.pathname}${query}${window.location.hash}`;\n window.history.replaceState(window.history.state, \"\", url);\n },\n subscribe: (listener) => {\n if (typeof window === \"undefined\") return noop;\n window.addEventListener(\"popstate\", listener);\n return () => window.removeEventListener(\"popstate\", listener);\n },\n};\n\n/* eslint-disable no-console */\nexport const consoleNotify: NotifyPort = {\n info: (message) => console.info(`[summon] ${message}`),\n warn: (message) => console.warn(`[summon] ${message}`),\n error: (message) => console.error(`[summon] ${message}`),\n};\n\nexport const consoleErrorSink: ErrorSinkPort = {\n capture: (error, context) => console.error(\"[summon]\", error, context),\n};\n/* eslint-enable no-console */\n\nexport const debugOff: DebugPort = { enabled: () => false };\n\nexport const DEFAULT_PORTS: SummonPorts = {\n identity: anonymousIdentity,\n router: locationRouter,\n notify: consoleNotify,\n errors: consoleErrorSink,\n debug: debugOff,\n persistence: null,\n};\n\nexport function resolvePorts(overrides: Partial<SummonPorts> | undefined): SummonPorts {\n return { ...DEFAULT_PORTS, ...overrides };\n}\n","/**\n * The process-wide registry of overlay definition metadata (the framework-free half of each\n * definition). The host registers its definitions once (`<SummonHost definitions>` does it);\n * reducers stay pure — middleware and hooks read this registry and put what reducers need in the\n * action payload (e.g. the ids bound to the page).\n *\n * State lives in a global slot so a duplicated module graph (ESM + CJS, unsplit bundles) sees one\n * registry (kit `globalSlot`, architecture D9).\n */\nimport { globalSlot } from \"@ai-matrx/kit/global-slot\";\nimport type { OverlayDefinitionMeta } from \"./types\";\n\n/**\n * A definition's meta with its data type erased, so definitions of every data shape share one\n * registry without casts. (`never` erasure made `defaults` unassignable.)\n */\nexport interface AnyOverlayMeta extends Omit<OverlayDefinitionMeta<string, unknown>, \"defaults\"> {\n readonly defaults?: object | undefined;\n}\n\ntype AnyMeta = AnyOverlayMeta;\n\ninterface RegistryState {\n readonly byId: Map<string, AnyMeta>;\n readonly byLinkKey: Map<string, AnyMeta>;\n readonly listeners: Set<() => void>;\n}\n\nconst state = (): RegistryState =>\n globalSlot<RegistryState>(\"ai-matrx.summon.registry\", () => ({\n byId: new Map(),\n byLinkKey: new Map(),\n listeners: new Set(),\n }));\n\n/**\n * Register (or re-register) definitions. Re-registering an id replaces it (hot reload). A link\n * key claimed by two different ids is a host bug and throws, naming both.\n */\nexport function registerOverlayMeta(definitions: readonly AnyOverlayMeta[]): void {\n const s = state();\n for (const def of definitions) {\n s.byId.set(def.id, def);\n const keys = def.link ? [def.link.key, ...(def.link.aliases ?? [])] : [];\n for (const key of keys) {\n const holder = s.byLinkKey.get(key);\n if (holder && holder.id !== def.id) {\n throw new Error(`[summon] link key \"${key}\" is claimed by both \"${holder.id}\" and \"${def.id}\"`);\n }\n s.byLinkKey.set(key, def);\n }\n }\n for (const listener of s.listeners) listener();\n}\n\nexport function getOverlayMeta(overlayId: string): AnyMeta | undefined {\n return state().byId.get(overlayId);\n}\n\nexport function getOverlayMetaByLinkKey(linkKey: string): AnyMeta | undefined {\n return state().byLinkKey.get(linkKey);\n}\n\nexport function allOverlayMeta(): readonly AnyMeta[] {\n return [...state().byId.values()];\n}\n\nexport function isRegisteredOverlay(overlayId: string): boolean {\n return state().byId.has(overlayId);\n}\n\nexport function subscribeToOverlayRegistry(listener: () => void): () => void {\n const s = state();\n s.listeners.add(listener);\n return () => s.listeners.delete(listener);\n}\n\n/** Test-only. */\nexport function resetOverlayRegistry(): void {\n const s = state();\n s.byId.clear();\n s.byLinkKey.clear();\n}\n","// The public action creators, light: plain objects with the slices' own type strings, so a file\n// that only opens or closes something never loads a slice. The slices (core) handle these exact\n// types; `actions.parity.test.ts` proves every creator here equals its slice twin.\n//\n// `openOverlay`/`toggleOverlay` keep the two guarantees the slice creators had: functions are\n// stripped from open data (they can never travel through Redux — the D33 dead-button class) and\n// the definition's registered `defaults` ride the payload, so the reducer stays pure.\nimport { getOverlayMeta, allOverlayMeta } from \"../core/registry\";\nimport { DEFAULT_INSTANCE_ID, type InstanceKey, type OverlayDataOf, type OverlayId } from \"../core/types\";\n\nexport interface OpenOverlayPayload<Id extends OverlayId = OverlayId> {\n overlayId: Id;\n instanceId?: string;\n data?: OverlayDataOf<Id> | null;\n}\n\nexport interface CloseOverlayPayload<Id extends OverlayId = OverlayId> {\n overlayId: Id;\n instanceId?: string;\n}\n\nexport type ToggleOverlayPayload<Id extends OverlayId = OverlayId> = OpenOverlayPayload<Id>;\n\nexport interface CloseAllInstancesPayload<Id extends OverlayId = OverlayId> {\n overlayId: Id;\n}\n\nexport interface CloseOverlaysBoundToPagePayload {\n /** Overlay ids whose definitions say `closesOnNavigation`. */\n overlayIds: readonly string[];\n}\n\nexport interface PruneStaleInstancesPayload {\n olderThanMs: number;\n}\n\n/** Raw reducer payload: untyped ids + the registry defaults the creator resolved. */\nexport interface RawOpenPayload {\n overlayId: string;\n instanceId?: string;\n data?: unknown;\n defaults?: Readonly<Record<string, unknown>>;\n}\n\nexport interface SummonAction<P> {\n type: string;\n payload: P;\n /** Structurally a Redux `UnknownAction`. */\n [extra: string]: unknown;\n}\n\ntype Creator<Args extends unknown[], P> = ((...args: Args) => SummonAction<P>) & {\n readonly type: string;\n match(action: unknown): action is SummonAction<P>;\n};\n\nfunction creator<Args extends unknown[], P>(type: string, build: (...args: Args) => P): Creator<Args, P> {\n const create = (...args: Args): SummonAction<P> => ({ type, payload: build(...args) });\n return Object.assign(create, {\n type,\n toString: () => type,\n match: (action: unknown): action is SummonAction<P> =>\n typeof action === \"object\" && action !== null && (action as { type?: unknown }).type === type,\n });\n}\n\n/** A creator whose call signature stays generic (the inferred `creator` form erases `Id`). */\ntype Generic<F> = F & { readonly type: string; match(action: unknown): action is SummonAction<unknown> };\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction stripFunctions(overlayId: string, data: unknown): unknown {\n if (!isPlainRecord(data)) return data;\n const offenders = Object.keys(data).filter((key) => typeof data[key] === \"function\");\n if (offenders.length === 0) return data;\n // eslint-disable-next-line no-console\n console.error(\n `[summon] BUG: function value(s) in openOverlay data for \"${overlayId}\" (keys: ${offenders.join(\", \")}). ` +\n `Functions cannot travel through Redux — the handler would NEVER fire. Register a handle ` +\n `(@ai-matrx/summon/handles) and pass its id string instead. The offending key(s) were stripped from state.`,\n );\n const cleaned = { ...data };\n for (const key of offenders) delete cleaned[key];\n return cleaned;\n}\n\nfunction rawOpen(payload: { overlayId: string; instanceId?: string; data?: unknown }): RawOpenPayload {\n const raw: RawOpenPayload = { overlayId: payload.overlayId };\n if (payload.instanceId !== undefined) raw.instanceId = payload.instanceId;\n if (payload.data !== undefined) raw.data = stripFunctions(payload.overlayId, payload.data);\n const defaults: unknown = getOverlayMeta(payload.overlayId)?.defaults;\n if (isPlainRecord(defaults)) raw.defaults = stripFunctions(payload.overlayId, defaults) as Record<string, unknown>;\n return raw;\n}\n\nconst O = \"overlays/\";\n\nexport const openOverlay = creator(O + \"openOverlay\", (payload: OpenOverlayPayload) => rawOpen(payload)) as Generic<\n <Id extends OverlayId>(payload: OpenOverlayPayload<Id>) => SummonAction<RawOpenPayload>\n>;\n\nexport const closeOverlay = creator(O + \"closeOverlay\", (payload: CloseOverlayPayload): { overlayId: string; instanceId?: string } =>\n payload.instanceId === undefined ? { overlayId: payload.overlayId } : { overlayId: payload.overlayId, instanceId: payload.instanceId },\n) as Generic<<Id extends OverlayId>(payload: CloseOverlayPayload<Id>) => SummonAction<{ overlayId: string; instanceId?: string }>>;\n\nexport const toggleOverlay = creator(O + \"toggleOverlay\", (payload: ToggleOverlayPayload) => rawOpen(payload)) as Generic<\n <Id extends OverlayId>(payload: ToggleOverlayPayload<Id>) => SummonAction<RawOpenPayload>\n>;\n\nexport const closeAllInstancesOfOverlay = creator(O + \"closeAllInstancesOfOverlay\", (payload: CloseAllInstancesPayload) => ({\n overlayId: payload.overlayId as string,\n})) as Generic<<Id extends OverlayId>(payload: CloseAllInstancesPayload<Id>) => SummonAction<{ overlayId: string }>>;\n\n/** Ids of every registered overlay whose definition says `closesOnNavigation`. */\nexport function overlayIdsBoundToPage(): string[] {\n return allOverlayMeta()\n .filter((meta) => meta.closesOnNavigation === true)\n .map((meta) => meta.id);\n}\n\n/** Close page-bound overlays. Omit the ids to use the registry's `closesOnNavigation` list. */\nexport const closeOverlaysBoundToPage = creator(\n O + \"closeOverlaysBoundToPage\",\n (payload?: Partial<CloseOverlaysBoundToPagePayload>): CloseOverlaysBoundToPagePayload => ({\n overlayIds: [...(payload?.overlayIds ?? overlayIdsBoundToPage())],\n }),\n);\n\nexport const closeAllOverlays = creator(O + \"closeAllOverlays\", () => undefined);\nexport const pruneStaleInstances = creator(O + \"pruneStaleInstances\", (payload: PruneStaleInstancesPayload) => payload);\n\n// ── Window manager: the ones callers outside a window dispatch (menus, shortcuts, settings) ──\n\nconst W = \"windowManager/\";\nconst pass = <P>() => (payload: P) => payload;\n\nexport const focusWindow = creator(W + \"focusWindow\", pass<string>());\nexport const restoreWindow = creator(W + \"restoreWindow\", pass<string>());\nexport const toggleWindowsHidden = creator(W + \"toggleWindowsHidden\", () => undefined);\nexport const restoreAll = creator(W + \"restoreAll\", () => undefined);\nexport const minimizeAll = creator(W + \"minimizeAll\", pass<{ viewportWidth: number; viewportHeight: number }>());\n\nexport interface ArrangeActiveWindowsPayload {\n layout: import(\"../core/geometry/windowArrangements\").GlobalLayoutType;\n viewportWidth: number;\n viewportHeight: number;\n dirX?: \"ltr\" | \"rtl\";\n dirY?: \"ttb\" | \"btt\";\n primary?: \"horizontal\" | \"vertical\";\n}\nexport const arrangeActiveWindows = creator(W + \"arrangeActiveWindows\", pass<ArrangeActiveWindowsPayload>());\n\nexport const revealWindow = creator(W + \"revealWindow\", pass<{ id: string; viewportWidth: number; viewportHeight: number }>());\nexport const updateWindowRect = creator(\n W + \"updateWindowRect\",\n pass<{ id: string; rect: Partial<import(\"../core/geometry/types\").WindowRect> }>(),\n);\n\n// ── Saved component state ──\n\nexport const setOverlayStateValue = creator(\"overlayState/setOverlayStateValue\", pass<{ key: InstanceKey; name: string; value: unknown }>());\n\n// ── Links ────────────────────────────────────────────────────────────────────────────────────\n\nexport interface UrlSyncEntryPayload {\n typeKey: string;\n instanceId: string;\n args?: Readonly<Record<string, string>>;\n}\nexport const registerSyncEntry = creator(\"urlSync/registerSyncEntry\", pass<UrlSyncEntryPayload>());\nexport const unregisterSyncEntry = creator(\"urlSync/unregisterSyncEntry\", pass<{ typeKey: string; instanceId: string }>());\n\n/** Every slice key the summon reducers own; an action under one of them needs the runtime. */\nexport const SUMMON_SLICE_KEYS = [\"overlays\", \"windowManager\", \"urlSync\", \"overlayState\"] as const;\n\nexport function isSummonAction(action: unknown): action is { type: string } {\n if (typeof action !== \"object\" || action === null) return false;\n const type = (action as { type?: unknown }).type;\n if (typeof type !== \"string\") return false;\n const slash = type.indexOf(\"/\");\n return slash > 0 && (SUMMON_SLICE_KEYS as readonly string[]).includes(type.slice(0, slash));\n}\n\nexport { DEFAULT_INSTANCE_ID };\n","// Render acknowledgements a mobile surface reports (it renders instead of a WindowPanel). Light:\n// the same slot the render watchdog (core) reads, so a boot-graph hook can report without the core.\nimport { globalSlot } from \"@ai-matrx/kit/global-slot\";\n\ninterface AckSlot {\n readonly renderAcks: Map<string, { kind: \"window\"; windowId: string } | { kind: \"surface\" }>;\n readonly ackWaiters: Map<string, () => void>;\n readonly watches: Map<string, unknown>;\n}\n\n// Same key and shape as core/middleware/renderWatchdog.ts (RENDER_WATCHDOG_SLOT).\nconst slot = (): AckSlot =>\n globalSlot<AckSlot>(\"ai-matrx.summon.renderWatchdog\", () => ({ renderAcks: new Map(), ackWaiters: new Map(), watches: new Map() }));\n\nexport function ackOverlaySurfaceRender(overlayId: string): void {\n const s = slot();\n s.renderAcks.set(overlayId, { kind: \"surface\" });\n const notify = s.ackWaiters.get(overlayId);\n if (notify) {\n s.ackWaiters.delete(overlayId);\n notify();\n }\n}\n\nexport function clearOverlaySurfaceRender(overlayId: string): void {\n const s = slot();\n if (s.renderAcks.get(overlayId)?.kind === \"surface\") s.renderAcks.delete(overlayId);\n}\n","// The public overlay selectors, light and safe before the runtime: a host that loads the summon\n// slices on first use (the gate) has no `overlays` key until then, and every overlay reads closed.\nimport { DEFAULT_INSTANCE_ID } from \"../core/types\";\nimport { globalSlot } from \"@ai-matrx/kit/global-slot\";\n\nexport interface OverlayInstance {\n isOpen: boolean;\n data: unknown;\n /** Unix ms of the last open (pruneStaleInstances reads it). */\n lastUsedAt?: number;\n}\n\nexport interface OverlayState {\n overlays: Record<string, Record<string, OverlayInstance>>;\n}\n\n/** The slice of any store these selectors need (absent until the summon runtime is installed). */\n// `| object`: an all-optional type is \"weak\", and a host state sharing no key with it (before the\n// slices are injected, or typed without them) would be refused by TypeScript.\nexport type StateWithOverlays = { overlays?: OverlayState } | object;\nconst overlaysOf = (state: StateWithOverlays): OverlayState | undefined => (state as { overlays?: OverlayState }).overlays;\n\nexport interface OpenInstanceView {\n instanceId: string;\n data: unknown;\n}\n\nconst CLOSED: OverlayInstance = Object.freeze({ isOpen: false, data: null });\nconst EMPTY: readonly OpenInstanceView[] = Object.freeze([]);\n\nexport const selectOverlay = (state: StateWithOverlays, overlayId: string, instanceId: string = DEFAULT_INSTANCE_ID): OverlayInstance =>\n overlaysOf(state)?.overlays[overlayId]?.[instanceId] ?? CLOSED;\n\nexport const selectIsOverlayOpen = (state: StateWithOverlays, overlayId: string, instanceId: string = DEFAULT_INSTANCE_ID): boolean =>\n selectOverlay(state, overlayId, instanceId).isOpen;\n\nexport const selectOverlayData = (state: StateWithOverlays, overlayId: string, instanceId: string = DEFAULT_INSTANCE_ID): unknown =>\n selectOverlay(state, overlayId, instanceId).data;\n\ninterface CachedOpen {\n bucket: Record<string, OverlayInstance> | undefined;\n result: readonly OpenInstanceView[];\n}\nconst openCache = (): Map<string, CachedOpen> => globalSlot(\"ai-matrx.summon.openInstances\", () => new Map<string, CachedOpen>());\n\n/** All open instances of an overlay id; the array reference is stable while the open set is unchanged. */\nexport const selectOpenInstances = (state: StateWithOverlays, overlayId: string): readonly OpenInstanceView[] => {\n const bucket = overlaysOf(state)?.overlays[overlayId];\n const cache = openCache();\n const hit = cache.get(overlayId);\n if (hit && hit.bucket === bucket) return hit.result;\n let result: readonly OpenInstanceView[] = EMPTY;\n if (bucket) {\n const open: OpenInstanceView[] = [];\n for (const [instanceId, inst] of Object.entries(bucket)) if (inst.isOpen) open.push({ instanceId, data: inst.data });\n if (open.length > 0) result = open;\n }\n cache.set(overlayId, { bucket, result });\n return result;\n};\n\n/** Every open instance key (`overlayId:instanceId`). */\nexport function listOpenInstanceKeys(state: StateWithOverlays): string[] {\n const keys: string[] = [];\n for (const [overlayId, bucket] of Object.entries(overlaysOf(state)?.overlays ?? {})) {\n for (const [instanceId, inst] of Object.entries(bucket)) if (inst.isOpen) keys.push(`${overlayId}:${instanceId}`);\n }\n return keys;\n}\n\n/** True once anything has ever been opened in this store (a key exists in the slice). */\nexport function selectAnyOverlayTouched(state: StateWithOverlays): boolean {\n for (const _ in overlaysOf(state)?.overlays ?? {}) return true;\n return false;\n}\n\n/** The global hide-all flag (false before the runtime is installed). */\nexport const selectWindowsHidden = (state: object): boolean =>\n (state as { windowManager?: { windowsHidden: boolean } }).windowManager?.windowsHidden ?? false;\n\ntype WindowLike = import(\"../core/windowManagerSlice\").WindowEntry;\nconst EMPTY_WINDOWS: readonly never[] = Object.freeze([]);\nlet lastWindowsMap: unknown = null;\nlet lastWindows: readonly WindowLike[] = EMPTY_WINDOWS;\n\n/** Every registered window, topmost first (empty before the runtime is installed). Memoized on the map. */\nexport function selectAllWindows<W extends WindowLike = WindowLike>(state: object): readonly W[] {\n const map = (state as { windowManager?: { windows: Record<string, W> } }).windowManager?.windows;\n if (!map) return EMPTY_WINDOWS;\n if (map !== lastWindowsMap) {\n lastWindowsMap = map;\n lastWindows = Object.values(map).sort((a, b) => b.zIndex - a.zIndex);\n }\n return lastWindows as readonly W[];\n}\n\n/** True when windows exist and every one is minimized (false before the runtime is installed). */\nexport function selectAllMinimized(state: object): boolean {\n const map = (state as { windowManager?: { windows: Record<string, { state: string }> } }).windowManager?.windows;\n if (!map) return false;\n const wins = Object.values(map);\n return wins.length > 0 && wins.every((w) => w.state === \"minimized\");\n}\n","// The summon gate: a host store carries NONE of the summon slices or middleware until something\n// needs them. The gate is one middleware in the host chain. Before the core is loaded, every\n// summon action (open, close, a window action…) is queued and the first one starts ONE import()\n// of the core; when the core module evaluates it installs itself into every gate — the slices are\n// injected into the host's root reducer, the real middleware (close lifecycle, render watchdog)\n// joins the chain, and the queue replays in order. A host may also start the import early\n// (`prefetchSummonRuntime` on idle or pointer intent) so the first click opens at once.\n//\n// A module that needs the slices synchronously (the window section, links, persistence) imports\n// the core statically; the core installs at evaluation, so its state exists before it renders.\nimport type { Dispatch, Middleware, MiddlewareAPI, Reducer, UnknownAction } from \"@reduxjs/toolkit\";\nimport { globalSlot } from \"@ai-matrx/kit/global-slot\";\nimport type { SummonPorts } from \"../core/ports\";\nimport { isSummonAction } from \"./actions\";\n\n/** What the core hands the gate when it loads. */\nexport interface SummonCore {\n readonly reducers: Readonly<Record<string, Reducer>>;\n createMiddleware(ports?: Partial<SummonPorts>): Middleware[];\n}\n\n/** Dispatched once after the slices are injected into a live store, so they hold their initial state. */\nexport const SUMMON_INSTALLED_ACTION = \"@@summon/installed\";\n\ninterface GateInternals {\n install(core: SummonCore): void;\n}\n\ninterface GateSlot {\n core: SummonCore | null;\n loading: Promise<void> | null;\n readonly gates: Set<GateInternals>;\n readonly listeners: Set<() => void>;\n}\n\nconst slot = (): GateSlot =>\n globalSlot<GateSlot>(\"ai-matrx.summon.gate\", () => ({ core: null, loading: null, gates: new Set(), listeners: new Set() }));\n\n/** Called by the core module when it evaluates (idempotent). */\nexport function installSummonCore(core: SummonCore): void {\n const s = slot();\n if (s.core) return;\n s.core = core;\n const gates = [...s.gates];\n s.gates.clear();\n for (const gate of gates) gate.install(core);\n for (const listener of [...s.listeners]) listener();\n}\n\nexport function isSummonInstalled(): boolean {\n return slot().core !== null;\n}\n\nexport function subscribeSummonInstalled(listener: () => void): () => void {\n const s = slot();\n s.listeners.add(listener);\n return () => s.listeners.delete(listener);\n}\n\n/** Load the summon core (one import(), shared by every caller). Resolves once it is installed. */\nexport function ensureSummonRuntime(): Promise<void> {\n const s = slot();\n if (s.core) return Promise.resolve();\n s.loading ??= import(\"@ai-matrx/summon\").then(\n (core) => installSummonCore(core.summonCore),\n (error: unknown) => {\n s.loading = null; // a failed chunk may be retried by the next request\n throw error;\n },\n );\n return s.loading;\n}\n\n/** Start loading the core without waiting (idle, pointer intent). Errors surface on the next real request. */\nexport function prefetchSummonRuntime(): void {\n ensureSummonRuntime().catch(() => undefined);\n}\n\nexport interface SummonGate {\n /** Put this in the host store's middleware chain. */\n readonly middleware: Middleware;\n /**\n * Give the gate the host root reducer's inject function — before `configureStore`, so a core\n * that is already loaded (a page that imported the window section) is injected before the\n * store's first state exists.\n */\n attachReducer(inject: (reducers: Readonly<Record<string, Reducer>>) => void): void;\n}\n\nexport interface CreateSummonGateOptions {\n /** Ports for the summon middleware (render watchdog: notify, errors, debug). */\n readonly ports?: Partial<SummonPorts>;\n}\n\nexport function createSummonGate(options: CreateSummonGateOptions = {}): SummonGate {\n let inject: ((reducers: Readonly<Record<string, Reducer>>) => void) | null = null;\n let injected = false;\n let api: MiddlewareAPI<Dispatch<UnknownAction>, unknown> | null = null;\n let next: ((action: unknown) => unknown) | null = null;\n let chain: ((action: unknown) => unknown) | null = null;\n const queue: unknown[] = [];\n\n const settle = (core: SummonCore, live: boolean) => {\n if (inject && !injected) {\n inject(core.reducers);\n injected = true;\n }\n if (!api || !next || chain) return;\n const store = api;\n let composed: (action: unknown) => unknown = next;\n for (const middleware of [...core.createMiddleware(options.ports)].reverse()) {\n composed = middleware(store)(composed) as (action: unknown) => unknown;\n }\n chain = composed;\n const flush = () => {\n if (live) store.dispatch({ type: SUMMON_INSTALLED_ACTION });\n for (const action of queue.splice(0)) store.dispatch(action as UnknownAction);\n };\n // Redux forbids dispatching while the middleware chain is being built.\n if (live) flush();\n else if (queue.length > 0) queueMicrotask(flush);\n };\n\n const internals: GateInternals = { install: (core) => settle(core, true) };\n const core = () => slot().core;\n\n const middleware: Middleware = (storeApi) => {\n api = storeApi as MiddlewareAPI<Dispatch<UnknownAction>, unknown>;\n return (nextDispatch) => {\n next = nextDispatch as (action: unknown) => unknown;\n const loaded = core();\n if (loaded) settle(loaded, false);\n else slot().gates.add(internals);\n return (action) => {\n if (chain) return chain(action);\n if (!isSummonAction(action)) return nextDispatch(action);\n queue.push(action);\n void ensureSummonRuntime().catch((error: unknown) => {\n // eslint-disable-next-line no-console\n console.error(\"[summon] the overlay runtime failed to load; queued requests are kept for the next try\", error);\n });\n return action;\n };\n };\n };\n\n return {\n middleware,\n attachReducer(fn) {\n inject = fn;\n const loaded = core();\n if (loaded) {\n inject(loaded.reducers);\n injected = true;\n }\n },\n };\n}\n","// Callback-aware opening without loading the handles registry up front. The opener needs a\n// channel id synchronously (it rides open data); the channel itself is created when the handles\n// section arrives — one import() started by the first such open — or at once by whoever emits\n// first (the render tree has handles statically). Closing the owner before then drops it.\nimport { globalSlot } from \"@ai-matrx/kit/global-slot\";\nimport type { EventChannel } from \"../handles/helpers\";\n\ntype Handlers = Readonly<Record<string, ((payload: unknown) => void) | undefined>> | undefined;\n\ninterface PendingChannel {\n readonly owner: string;\n readonly getHandlers: () => Handlers;\n}\n\n/** The one message shape on an overlay's channel. */\nexport interface OverlayEventMessage {\n readonly type: string;\n readonly payload: unknown;\n}\n\ntype CreateChannel = (options: { owner?: string; id?: string }) => EventChannel<OverlayEventMessage>;\n\nconst pending = (): Map<string, PendingChannel> => globalSlot(\"ai-matrx.summon.pendingChannels\", () => new Map<string, PendingChannel>());\n\n/** Create every pending channel now (idempotent per id). */\nexport function materializePendingChannels(createEventChannel: CreateChannel): void {\n const map = pending();\n for (const [id, entry] of [...map]) {\n map.delete(id);\n const channel = createEventChannel({ owner: entry.owner, id });\n channel.subscribe((message) => entry.getHandlers()?.[message.type]?.(message.payload));\n }\n}\n\n/** Reserve a channel owned by `owner` whose events go to the handlers `getHandlers` returns at emit time. */\nexport function openPendingEventChannel(owner: string, getHandlers: () => Handlers): string {\n const id = `ch-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n pending().set(id, { owner, getHandlers });\n void import(\"@ai-matrx/summon/handles\").then(({ createEventChannel }) => materializePendingChannels(createEventChannel));\n return id;\n}\n\n/** The owner closed before its channel was created: forget it. */\nexport function dropPendingChannelsOf(owner: string): void {\n const map = pending();\n for (const [id, entry] of [...map]) if (entry.owner === owner) map.delete(id);\n}\n","/**\n * The `?panels=` link grammar.\n *\n * panels = token (\",\" token)*\n * token = key [\":\" id [\":\" args]]\n * args = k \"-\" v (\"_\" k \"-\" v)*\n *\n * GRAMMAR v2 (this file): on WRITE, ids are percent-encoded for `% , :` and arg keys and values\n * for `% , : _ -`, so any value — a uuid, a date, a path, a list — survives the round trip.\n * Keys and ids keep `-` and `_` unencoded: they are not separators inside an id, and leaving them means a\n * uuid id writes byte-identically to v1. On READ, v1 tokens (unencoded) parse unchanged: an arg\n * pair splits on its FIRST hyphen, and decoding only touches well-formed `%XX` escapes.\n *\n * Framework-free; this is the one grammar every door (address bar, notifications, extension)\n * shares.\n */\n\nexport interface LinkToken {\n /** The token exactly as it appeared (the verbatim form written back while unresolved). */\n readonly raw: string;\n readonly key: string;\n /** `undefined` for a bare-key token (`keyword_research`). */\n readonly id: string | undefined;\n /** `undefined` when the token carries no args segment. */\n readonly args: Readonly<Record<string, string>> | undefined;\n}\n\nexport interface LinkEntry {\n readonly key: string;\n readonly id: string;\n readonly args?: Readonly<Record<string, string>> | undefined;\n}\n\nconst hex = (ch: string): string => `%${ch.charCodeAt(0).toString(16).toUpperCase().padStart(2, \"0\")}`;\n\n/** Encode a token id (`% , :`). */\nexport function encodeLinkId(id: string): string {\n return id.replace(/[%,:]/g, hex);\n}\n\n/** Encode an arg key or value (`% , : _ -`). */\nexport function encodeLinkArg(value: string): string {\n return value.replace(/[%,:_-]/g, hex);\n}\n\n/** Decode well-formed `%XX` escapes; anything else (a v1 literal `%`) is kept as written. */\nexport function decodeLinkPart(value: string): string {\n if (!value.includes(\"%\")) return value;\n return value.replace(/(?:%[0-9A-Fa-f]{2})+/g, (run) => {\n try {\n return decodeURIComponent(run);\n } catch {\n return run;\n }\n });\n}\n\n/** Parse one token (v1 or v2). Returns `null` for an empty token. */\nexport function parseLinkToken(raw: string): LinkToken | null {\n if (!raw) return null;\n const first = raw.indexOf(\":\");\n const key = first === -1 ? raw : raw.slice(0, first);\n if (!key) return null;\n if (first === -1) return { raw, key, id: undefined, args: undefined };\n const rest = raw.slice(first + 1);\n const second = rest.indexOf(\":\");\n const idPart = second === -1 ? rest : rest.slice(0, second);\n const argsPart = second === -1 ? undefined : rest.slice(second + 1);\n let args: Record<string, string> | undefined;\n if (argsPart) {\n args = {};\n for (const pair of argsPart.split(\"_\")) {\n // Split on the FIRST hyphen only: a v1 value may hold hyphens (uuid, date).\n const at = pair.indexOf(\"-\");\n if (at <= 0 || at === pair.length - 1) continue;\n args[decodeLinkPart(pair.slice(0, at))] = decodeLinkPart(pair.slice(at + 1));\n }\n }\n return { raw, key: decodeLinkPart(key), id: decodeLinkPart(idPart), args };\n}\n\n/** Parse a whole `panels` value. Empty segments are skipped. */\nexport function parseLinkParam(param: string | null | undefined): LinkToken[] {\n if (!param) return [];\n const out: LinkToken[] = [];\n for (const raw of param.split(\",\")) {\n const token = parseLinkToken(raw);\n if (token) out.push(token);\n }\n return out;\n}\n\n/** Write one entry as a v2 token. Args are written in key order so equal entries write equal tokens. */\nexport function formatLinkToken(entry: LinkEntry): string {\n let token = `${encodeLinkId(entry.key)}:${encodeLinkId(entry.id)}`;\n const args = entry.args;\n if (args) {\n const keys = Object.keys(args).sort();\n if (keys.length > 0) {\n token += `:${keys.map((k) => `${encodeLinkArg(k)}-${encodeLinkArg(args[k] ?? \"\")}`).join(\"_\")}`;\n }\n }\n return token;\n}\n\n/** The `panels` value from a search string or a full URL (`null` when absent). */\nexport function readPanelsParam(searchOrUrl: string): string | null {\n const q = searchOrUrl.indexOf(\"?\");\n const hash = searchOrUrl.indexOf(\"#\");\n let search: string;\n if (q === -1) {\n // A bare query string without \"?\" (`panels=…`) or a URL with no query.\n search = searchOrUrl.includes(\"=\") && !searchOrUrl.includes(\"/\") ? searchOrUrl : \"\";\n } else {\n search = searchOrUrl.slice(q + 1, hash > q ? hash : undefined);\n }\n return new URLSearchParams(search).get(\"panels\");\n}\n\n/** `search` with `panels` set to `param` (removed when empty). Returns \"\" or \"?…\". */\nexport function withPanelsParam(search: string, param: string): string {\n const params = new URLSearchParams(search.startsWith(\"?\") ? search.slice(1) : search);\n if (param) params.set(\"panels\", param);\n else params.delete(\"panels\");\n const qs = params.toString();\n return qs ? `?${qs}` : \"\";\n}\n"],"mappings":"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","names":["globalSlot","globalSlot","state","globalSlot","slot","globalSlot","core","middleware","globalSlot"]}
package/dist/url.cjs CHANGED
@@ -24,104 +24,27 @@ __export(url_exports, {
24
24
  OverlayLinkManager: () => OverlayLinkManager,
25
25
  canonicalLinkKey: () => canonicalLinkKey,
26
26
  canonicalizeToken: () => canonicalizeToken,
27
- decodeLinkPart: () => decodeLinkPart,
28
- encodeLinkArg: () => encodeLinkArg,
29
- encodeLinkId: () => encodeLinkId,
30
- formatLinkToken: () => formatLinkToken,
27
+ decodeLinkPart: () => import_open3.decodeLinkPart,
28
+ encodeLinkArg: () => import_open3.encodeLinkArg,
29
+ encodeLinkId: () => import_open3.encodeLinkId,
30
+ formatLinkToken: () => import_open3.formatLinkToken,
31
31
  hydrateLinkToken: () => hydrateLinkToken,
32
32
  mergeManagedLinkParam: () => mergeManagedLinkParam,
33
33
  openFromLink: () => openFromLink,
34
34
  openPanelRequest: () => openPanelRequest,
35
35
  openRegisteredOverlay: () => openRegisteredOverlay,
36
- parseLinkParam: () => parseLinkParam,
37
- parseLinkToken: () => parseLinkToken,
38
- readPanelsParam: () => readPanelsParam,
36
+ parseLinkParam: () => import_open3.parseLinkParam,
37
+ parseLinkToken: () => import_open3.parseLinkToken,
38
+ readPanelsParam: () => import_open3.readPanelsParam,
39
39
  serializeLinkEntries: () => serializeLinkEntries,
40
40
  unopenedWindowNotice: () => unopenedWindowNotice,
41
41
  useOverlayLink: () => import_react3.useOverlayLink,
42
- withPanelsParam: () => withPanelsParam,
42
+ withPanelsParam: () => import_open3.withPanelsParam,
43
43
  withUnresolvedTokens: () => withUnresolvedTokens
44
44
  });
45
45
  module.exports = __toCommonJS(url_exports);
46
46
  var import_react3 = require("@ai-matrx/summon/react");
47
-
48
- // src/url/grammar.ts
49
- var hex = (ch) => `%${ch.charCodeAt(0).toString(16).toUpperCase().padStart(2, "0")}`;
50
- function encodeLinkId(id) {
51
- return id.replace(/[%,:]/g, hex);
52
- }
53
- function encodeLinkArg(value) {
54
- return value.replace(/[%,:_-]/g, hex);
55
- }
56
- function decodeLinkPart(value) {
57
- if (!value.includes("%")) return value;
58
- return value.replace(/(?:%[0-9A-Fa-f]{2})+/g, (run) => {
59
- try {
60
- return decodeURIComponent(run);
61
- } catch {
62
- return run;
63
- }
64
- });
65
- }
66
- function parseLinkToken(raw) {
67
- if (!raw) return null;
68
- const first = raw.indexOf(":");
69
- const key = first === -1 ? raw : raw.slice(0, first);
70
- if (!key) return null;
71
- if (first === -1) return { raw, key, id: void 0, args: void 0 };
72
- const rest = raw.slice(first + 1);
73
- const second = rest.indexOf(":");
74
- const idPart = second === -1 ? rest : rest.slice(0, second);
75
- const argsPart = second === -1 ? void 0 : rest.slice(second + 1);
76
- let args;
77
- if (argsPart) {
78
- args = {};
79
- for (const pair of argsPart.split("_")) {
80
- const at = pair.indexOf("-");
81
- if (at <= 0 || at === pair.length - 1) continue;
82
- args[decodeLinkPart(pair.slice(0, at))] = decodeLinkPart(pair.slice(at + 1));
83
- }
84
- }
85
- return { raw, key: decodeLinkPart(key), id: decodeLinkPart(idPart), args };
86
- }
87
- function parseLinkParam(param) {
88
- if (!param) return [];
89
- const out = [];
90
- for (const raw of param.split(",")) {
91
- const token = parseLinkToken(raw);
92
- if (token) out.push(token);
93
- }
94
- return out;
95
- }
96
- function formatLinkToken(entry) {
97
- let token = `${encodeLinkId(entry.key)}:${encodeLinkId(entry.id)}`;
98
- const args = entry.args;
99
- if (args) {
100
- const keys = Object.keys(args).sort();
101
- if (keys.length > 0) {
102
- token += `:${keys.map((k) => `${encodeLinkArg(k)}-${encodeLinkArg(args[k] ?? "")}`).join("_")}`;
103
- }
104
- }
105
- return token;
106
- }
107
- function readPanelsParam(searchOrUrl) {
108
- const q = searchOrUrl.indexOf("?");
109
- const hash = searchOrUrl.indexOf("#");
110
- let search;
111
- if (q === -1) {
112
- search = searchOrUrl.includes("=") && !searchOrUrl.includes("/") ? searchOrUrl : "";
113
- } else {
114
- search = searchOrUrl.slice(q + 1, hash > q ? hash : void 0);
115
- }
116
- return new URLSearchParams(search).get("panels");
117
- }
118
- function withPanelsParam(search, param) {
119
- const params = new URLSearchParams(search.startsWith("?") ? search.slice(1) : search);
120
- if (param) params.set("panels", param);
121
- else params.delete("panels");
122
- const qs = params.toString();
123
- return qs ? `?${qs}` : "";
124
- }
47
+ var import_open3 = require("@ai-matrx/summon/open");
125
48
 
126
49
  // src/url/OverlayLinkManager.tsx
127
50
  var import_react = require("react");
@@ -130,6 +53,7 @@ var import_react2 = require("@ai-matrx/summon/react");
130
53
 
131
54
  // src/url/door.ts
132
55
  var import_summon = require("@ai-matrx/summon");
56
+ var import_open = require("@ai-matrx/summon/open");
133
57
  function openRegisteredOverlay(dispatch, overlayId, instanceId = import_summon.DEFAULT_INSTANCE_ID, data) {
134
58
  const defaults = (0, import_summon.getOverlayMeta)(overlayId)?.defaults;
135
59
  dispatch(
@@ -182,7 +106,7 @@ function hydrateLinkToken(token, dispatch, onError) {
182
106
  }
183
107
  }
184
108
  async function openFromLink(searchOrUrl, options) {
185
- const tokens = parseLinkParam(readPanelsParam(searchOrUrl));
109
+ const tokens = (0, import_open.parseLinkParam)((0, import_open.readPanelsParam)(searchOrUrl));
186
110
  const result = { opened: [], refused: [], unknown: [], failed: [] };
187
111
  const unknown = tokens.filter((token) => !(0, import_summon.getOverlayMetaByLinkKey)(token.key)?.link);
188
112
  if (options.requireAll && unknown.length > 0) {
@@ -226,9 +150,10 @@ function openPanelRequest(rawPayload, options) {
226
150
  }
227
151
 
228
152
  // src/url/OverlayLinkManager.tsx
153
+ var import_open2 = require("@ai-matrx/summon/open");
229
154
  function serializeLinkEntries(entries, managedKeys) {
230
155
  const managed = managedKeys ? new Set(managedKeys) : null;
231
- return Object.values(entries).filter((entry) => !managed || managed.has(entry.typeKey)).map((entry) => formatLinkToken({ key: entry.typeKey, id: entry.instanceId, args: entry.args })).join(",");
156
+ return Object.values(entries).filter((entry) => !managed || managed.has(entry.typeKey)).map((entry) => (0, import_open2.formatLinkToken)({ key: entry.typeKey, id: entry.instanceId, args: entry.args })).join(",");
232
157
  }
233
158
  function mergeManagedLinkParam(currentParam, nextManaged, managedKeys) {
234
159
  if (!managedKeys) return nextManaged;
@@ -284,7 +209,7 @@ function OverlayLinkManager({ managedKeys, noticeDeadlineMs }) {
284
209
  if (initialLoadDone.current) return;
285
210
  initialLoadDone.current = true;
286
211
  const managed = managedKeys ? new Set(managedKeys) : null;
287
- const tokens = parseLinkParam(readPanelsParam(router.search()));
212
+ const tokens = (0, import_open2.parseLinkParam)((0, import_open2.readPanelsParam)(router.search()));
288
213
  const noHydrator = [];
289
214
  for (const token of tokens) {
290
215
  if (managed && !managed.has(token.key)) continue;
@@ -331,13 +256,13 @@ function OverlayLinkManager({ managedKeys, noticeDeadlineMs }) {
331
256
  );
332
257
  }
333
258
  const liveSearch = router.search();
334
- const currentParam = readPanelsParam(liveSearch) ?? "";
259
+ const currentParam = (0, import_open2.readPanelsParam)(liveSearch) ?? "";
335
260
  const nextManaged = withUnresolvedTokens(
336
261
  serializeLinkEntries(entries, managedKeys),
337
262
  stillPending.map((pending) => pending.token)
338
263
  );
339
264
  const nextParam = mergeManagedLinkParam(currentParam, nextManaged, managedKeys);
340
- if (currentParam !== nextParam) router.replaceSearch(withPanelsParam(liveSearch, nextParam));
265
+ if (currentParam !== nextParam) router.replaceSearch((0, import_open2.withPanelsParam)(liveSearch, nextParam));
341
266
  }, [entries, isHydrated, managedKeys, router, search, noticeDue, asyncTick]);
342
267
  return null;
343
268
  }
package/dist/url.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/url.ts","../src/url/grammar.ts","../src/url/OverlayLinkManager.tsx","../src/url/door.ts"],"sourcesContent":["// @ai-matrx/summon/url — address-bar links: the `?panels=` grammar, the link manager, the\n// `useOverlayLink` publisher and the one door (`openFromLink`) every link source goes through.\nexport { useOverlayLink } from \"@ai-matrx/summon/react\";\nexport {\n parseLinkToken,\n parseLinkParam,\n formatLinkToken,\n encodeLinkId,\n encodeLinkArg,\n decodeLinkPart,\n readPanelsParam,\n withPanelsParam,\n type LinkToken,\n type LinkEntry,\n} from \"./url/grammar\";\nexport {\n OverlayLinkManager,\n serializeLinkEntries,\n mergeManagedLinkParam,\n withUnresolvedTokens,\n unopenedWindowNotice,\n type OverlayLinkManagerProps,\n} from \"./url/OverlayLinkManager\";\nexport {\n openFromLink,\n openPanelRequest,\n hydrateLinkToken,\n canonicalLinkKey,\n canonicalizeToken,\n openRegisteredOverlay,\n type OpenFromLinkResult,\n type OpenFromLinkOptions,\n type OpenPanelRequest,\n type OpenPanelResult,\n type TokenOutcome,\n type LinkDispatch,\n} from \"./url/door\";\n","/**\n * The `?panels=` link grammar.\n *\n * panels = token (\",\" token)*\n * token = key [\":\" id [\":\" args]]\n * args = k \"-\" v (\"_\" k \"-\" v)*\n *\n * GRAMMAR v2 (this file): on WRITE, ids are percent-encoded for `% , :` and arg keys and values\n * for `% , : _ -`, so any value — a uuid, a date, a path, a list — survives the round trip.\n * Keys and ids keep `-` and `_` unencoded: they are not separators inside an id, and leaving them means a\n * uuid id writes byte-identically to v1. On READ, v1 tokens (unencoded) parse unchanged: an arg\n * pair splits on its FIRST hyphen, and decoding only touches well-formed `%XX` escapes.\n *\n * Framework-free; this is the one grammar every door (address bar, notifications, extension)\n * shares.\n */\n\nexport interface LinkToken {\n /** The token exactly as it appeared (the verbatim form written back while unresolved). */\n readonly raw: string;\n readonly key: string;\n /** `undefined` for a bare-key token (`keyword_research`). */\n readonly id: string | undefined;\n /** `undefined` when the token carries no args segment. */\n readonly args: Readonly<Record<string, string>> | undefined;\n}\n\nexport interface LinkEntry {\n readonly key: string;\n readonly id: string;\n readonly args?: Readonly<Record<string, string>> | undefined;\n}\n\nconst hex = (ch: string): string => `%${ch.charCodeAt(0).toString(16).toUpperCase().padStart(2, \"0\")}`;\n\n/** Encode a token id (`% , :`). */\nexport function encodeLinkId(id: string): string {\n return id.replace(/[%,:]/g, hex);\n}\n\n/** Encode an arg key or value (`% , : _ -`). */\nexport function encodeLinkArg(value: string): string {\n return value.replace(/[%,:_-]/g, hex);\n}\n\n/** Decode well-formed `%XX` escapes; anything else (a v1 literal `%`) is kept as written. */\nexport function decodeLinkPart(value: string): string {\n if (!value.includes(\"%\")) return value;\n return value.replace(/(?:%[0-9A-Fa-f]{2})+/g, (run) => {\n try {\n return decodeURIComponent(run);\n } catch {\n return run;\n }\n });\n}\n\n/** Parse one token (v1 or v2). Returns `null` for an empty token. */\nexport function parseLinkToken(raw: string): LinkToken | null {\n if (!raw) return null;\n const first = raw.indexOf(\":\");\n const key = first === -1 ? raw : raw.slice(0, first);\n if (!key) return null;\n if (first === -1) return { raw, key, id: undefined, args: undefined };\n const rest = raw.slice(first + 1);\n const second = rest.indexOf(\":\");\n const idPart = second === -1 ? rest : rest.slice(0, second);\n const argsPart = second === -1 ? undefined : rest.slice(second + 1);\n let args: Record<string, string> | undefined;\n if (argsPart) {\n args = {};\n for (const pair of argsPart.split(\"_\")) {\n // Split on the FIRST hyphen only: a v1 value may hold hyphens (uuid, date).\n const at = pair.indexOf(\"-\");\n if (at <= 0 || at === pair.length - 1) continue;\n args[decodeLinkPart(pair.slice(0, at))] = decodeLinkPart(pair.slice(at + 1));\n }\n }\n return { raw, key: decodeLinkPart(key), id: decodeLinkPart(idPart), args };\n}\n\n/** Parse a whole `panels` value. Empty segments are skipped. */\nexport function parseLinkParam(param: string | null | undefined): LinkToken[] {\n if (!param) return [];\n const out: LinkToken[] = [];\n for (const raw of param.split(\",\")) {\n const token = parseLinkToken(raw);\n if (token) out.push(token);\n }\n return out;\n}\n\n/** Write one entry as a v2 token. Args are written in key order so equal entries write equal tokens. */\nexport function formatLinkToken(entry: LinkEntry): string {\n let token = `${encodeLinkId(entry.key)}:${encodeLinkId(entry.id)}`;\n const args = entry.args;\n if (args) {\n const keys = Object.keys(args).sort();\n if (keys.length > 0) {\n token += `:${keys.map((k) => `${encodeLinkArg(k)}-${encodeLinkArg(args[k] ?? \"\")}`).join(\"_\")}`;\n }\n }\n return token;\n}\n\n/** The `panels` value from a search string or a full URL (`null` when absent). */\nexport function readPanelsParam(searchOrUrl: string): string | null {\n const q = searchOrUrl.indexOf(\"?\");\n const hash = searchOrUrl.indexOf(\"#\");\n let search: string;\n if (q === -1) {\n // A bare query string without \"?\" (`panels=…`) or a URL with no query.\n search = searchOrUrl.includes(\"=\") && !searchOrUrl.includes(\"/\") ? searchOrUrl : \"\";\n } else {\n search = searchOrUrl.slice(q + 1, hash > q ? hash : undefined);\n }\n return new URLSearchParams(search).get(\"panels\");\n}\n\n/** `search` with `panels` set to `param` (removed when empty). Returns \"\" or \"?…\". */\nexport function withPanelsParam(search: string, param: string): string {\n const params = new URLSearchParams(search.startsWith(\"?\") ? search.slice(1) : search);\n if (param) params.set(\"panels\", param);\n else params.delete(\"panels\");\n const qs = params.toString();\n return qs ? `?${qs}` : \"\";\n}\n","/**\n * OverlayLinkManager — the address bar's `?panels=` channel (successor of matrx-frontend's\n * UrlPanelManager). Mount ONCE inside <SummonProvider>. Driven entirely by `ports.router`.\n *\n * 1. On mount: read `?panels=`, hydrate each token through the one door (`hydrateLinkToken`).\n * 2. After that: write back the union of registered link entries (`useOverlayLink`) plus every\n * pasted token that has not been settled yet, via `router.replaceSearch` — never navigation.\n *\n * THE ADDRESS IS NEVER DESTROYED BY A CLOCK (matrx-frontend V-28 NEW-5). A token whose window has\n * not registered yet is kept verbatim in the address however long its lazy chunk takes. The\n * deadline (12 s prod / 45 s dev) decides one thing only: when to stop waiting silently and tell\n * the person, through `ports.notify` and `ports.errors`.\n *\n * A token is SETTLED when ANY registered entry carries its canonical key — the window a hydrator\n * opens may publish a different id (a vault link names an item, the vault window publishes its\n * singleton id) and may even be a different overlay than the one owning the key (key `agent`\n * opens display-mode shells). An alias resolves to its definition's own `link.key`.\n */\nimport { useEffect, useRef, useState, useSyncExternalStore } from \"react\";\nimport {\n LAZY_WINDOW_MOUNT_DEADLINE_MS,\n getOverlayMetaByLinkKey,\n selectIsUrlHydrated,\n selectUrlSyncEntries,\n setHydrated,\n type UrlSyncEntry,\n} from \"@ai-matrx/summon\";\nimport { useSummonDispatch, useSummonPorts, useSummonSelector } from \"@ai-matrx/summon/react\";\nimport { canonicalLinkKey, canonicalizeToken, hydrateLinkToken } from \"./door\";\nimport { formatLinkToken, parseLinkParam, readPanelsParam, withPanelsParam } from \"./grammar\";\n\nexport interface OverlayLinkManagerProps {\n /**\n * Restrict hydration and write-back to these link keys (a route-scoped manager). Tokens of\n * other keys are preserved verbatim and never hydrated. Omit for the app-wide manager.\n */\n readonly managedKeys?: readonly string[];\n /** Override the notice deadline (ms). Default: 12 s in production, 45 s in development. */\n readonly noticeDeadlineMs?: number;\n}\n\n/** Serialize registered entries as v2 tokens (only managed keys when given). */\nexport function serializeLinkEntries(entries: Readonly<Record<string, UrlSyncEntry>>, managedKeys?: readonly string[]): string {\n const managed = managedKeys ? new Set(managedKeys) : null;\n return Object.values(entries)\n .filter((entry) => !managed || managed.has(entry.typeKey))\n .map((entry) => formatLinkToken({ key: entry.typeKey, id: entry.instanceId, args: entry.args }))\n .join(\",\");\n}\n\n/** Keep the current param's unmanaged tokens; replace the managed ones with `nextManaged`. */\nexport function mergeManagedLinkParam(currentParam: string, nextManaged: string, managedKeys?: readonly string[]): string {\n if (!managedKeys) return nextManaged;\n const managed = new Set(managedKeys);\n const unmanaged = currentParam\n .split(\",\")\n .filter(Boolean)\n .filter((token) => !managed.has(token.split(\":\")[0] ?? \"\"));\n return [...unmanaged, ...nextManaged.split(\",\").filter(Boolean)].join(\",\");\n}\n\n/**\n * Re-attach pasted tokens no window has settled. A token is skipped when its CANONICAL key is\n * already represented by a live entry, so a late registration replaces the placeholder.\n */\nexport function withUnresolvedTokens(managedParam: string, unresolvedTokens: readonly string[]): string {\n if (unresolvedTokens.length === 0) return managedParam;\n const managed = managedParam.split(\",\").filter(Boolean);\n const represented = new Set(managed.map((token) => canonicalLinkKey(token.split(\":\")[0] ?? \"\")));\n const kept = unresolvedTokens.filter((token) => Boolean(token) && !represented.has(canonicalLinkKey(token.split(\":\")[0] ?? \"\")));\n return [...managed, ...kept].join(\",\");\n}\n\n/** The honest sentence for a link naming a window that did not open. */\nexport function unopenedWindowNotice(keys: readonly string[]): string {\n return (\n `This link names a window this build could not open: ${keys.join(\", \")}. ` +\n `The link is unchanged in your address bar — reload to try again, or report it if it keeps failing.`\n );\n}\n\ninterface PendingToken {\n /** What is written back while unsettled (canonical key, pasted id and args). */\n readonly token: string;\n /** The key the person pasted (named in the notice). */\n readonly tokenKey: string;\n readonly canonicalKey: string;\n}\n\nconst noopSubscribe = () => () => {};\n\nexport function OverlayLinkManager({ managedKeys, noticeDeadlineMs }: OverlayLinkManagerProps): null {\n const ports = useSummonPorts();\n const dispatch = useSummonDispatch();\n const entries = useSummonSelector(selectUrlSyncEntries);\n const isHydrated = useSummonSelector(selectIsUrlHydrated);\n const router = ports.router;\n // Re-run the write-back after ANY address change the router reports.\n const search = useSyncExternalStore(router.subscribe ?? noopSubscribe, router.search, () => \"\");\n\n const initialLoadDone = useRef(false);\n // Keyed by canonical key + id so two tokens that canonicalise together never overwrite each\n // other (V-30 NEW-5); the settle sweep still runs on canonical key.\n const unresolved = useRef(new Map<string, PendingToken>());\n const announced = useRef(new Set<string>());\n const [noticeDue, setNoticeDue] = useState(false);\n const [asyncTick, setAsyncTick] = useState(0);\n const deadline = noticeDeadlineMs ?? LAZY_WINDOW_MOUNT_DEADLINE_MS;\n\n const announce = (keys: readonly string[], reason: \"no-hydrator\" | \"never-registered\" | \"hydrator-threw\"): void => {\n const fresh = keys.filter((key) => !announced.current.has(key));\n if (fresh.length === 0) return;\n for (const key of fresh) announced.current.add(key);\n const joined = fresh.join(\", \");\n const why =\n reason === \"no-hydrator\"\n ? `no registered definition owns ${fresh.length > 1 ? \"these keys\" : \"this key\"}`\n : reason === \"hydrator-threw\"\n ? \"its hydrator threw\"\n : `hydrated, but no window registered its link within ${deadline}ms`;\n const message =\n `[overlays/url] ?panels= token(s) [${joined}]: ${why}. The token is KEPT in the address. ` +\n `Give the overlay definition a matching \\`link\\` (key or alias), or stop publishing the link.`;\n ports.errors.capture(new Error(message), {\n source: \"url-panel-unopened\",\n relation: `?panels=${joined}`,\n code: reason,\n typeKeys: fresh,\n deadlineMs: deadline,\n userMessage: unopenedWindowNotice(fresh),\n });\n ports.notify.error(unopenedWindowNotice(fresh), { duration: 12_000 });\n };\n const announceRef = useRef(announce);\n announceRef.current = announce;\n\n // 1. HYDRATION (address → store), once.\n useEffect(() => {\n if (initialLoadDone.current) return;\n initialLoadDone.current = true;\n const managed = managedKeys ? new Set(managedKeys) : null;\n const tokens = parseLinkParam(readPanelsParam(router.search()));\n const noHydrator: string[] = [];\n for (const token of tokens) {\n if (managed && !managed.has(token.key)) continue; // preserved verbatim by the write-back\n const canonicalKey = canonicalLinkKey(token.key);\n const pendingKey = `${canonicalKey}\\u0000${token.id ?? \"\"}`;\n const pending: PendingToken = { token: canonicalizeToken(token.raw), tokenKey: token.key, canonicalKey };\n if (!getOverlayMetaByLinkKey(token.key)?.link) {\n unresolved.current.set(pendingKey, { ...pending, token: token.raw });\n noHydrator.push(token.key);\n continue;\n }\n unresolved.current.set(pendingKey, pending);\n const outcome = hydrateLinkToken(token, dispatch, (error) => {\n ports.errors.capture(error, { source: \"url-panel-hydrator\", token: token.raw });\n });\n const apply = (result: string): void => {\n // A refused link is dropped from the address; it is not \"still to come\".\n if (result === \"refused\" && unresolved.current.get(pendingKey) === pending) {\n unresolved.current.delete(pendingKey);\n setAsyncTick((n) => n + 1);\n }\n };\n if (typeof outcome === \"string\") apply(outcome);\n else void outcome.then(apply);\n }\n if (noHydrator.length > 0) announceRef.current(noHydrator, \"no-hydrator\");\n dispatch(setHydrated());\n }, [dispatch, managedKeys, router, ports]);\n\n // The notice deadline: never gates a write; only turns a silent wait into a visible notice.\n useEffect(() => {\n if (!isHydrated || unresolved.current.size === 0) return undefined;\n const timer = setTimeout(() => setNoticeDue(true), deadline);\n return () => clearTimeout(timer);\n }, [isHydrated, deadline]);\n\n // 2. WRITE-BACK (store → address).\n useEffect(() => {\n if (!isHydrated) return;\n const observed = new Set(Object.values(entries).map((entry) => canonicalLinkKey(entry.typeKey)));\n for (const [key, pending] of [...unresolved.current.entries()]) {\n if (observed.has(pending.canonicalKey)) unresolved.current.delete(key);\n }\n const stillPending = [...unresolved.current.values()];\n if (noticeDue && stillPending.length > 0) {\n announceRef.current(\n stillPending.map((pending) => pending.tokenKey),\n \"never-registered\",\n );\n }\n // The LIVE address, never a snapshot: the page may have written `?view=` a moment ago.\n const liveSearch = router.search();\n const currentParam = readPanelsParam(liveSearch) ?? \"\";\n const nextManaged = withUnresolvedTokens(\n serializeLinkEntries(entries, managedKeys),\n stillPending.map((pending) => pending.token),\n );\n const nextParam = mergeManagedLinkParam(currentParam, nextManaged, managedKeys);\n if (currentParam !== nextParam) router.replaceSearch(withPanelsParam(liveSearch, nextParam));\n }, [entries, isHydrated, managedKeys, router, search, noticeDue, asyncTick]);\n\n return null;\n}\n","/**\n * The ONE door every link source goes through: the address-bar manager on load, a notification\n * that opens its link in place, the extension bridge. A token is resolved through the registry —\n * `getOverlayMetaByLinkKey(key).link.hydrate({ id, args, open, dispatch })` — never a side table.\n */\nimport type { Dispatch, UnknownAction } from \"@reduxjs/toolkit\";\nimport {\n DEFAULT_INSTANCE_ID,\n getOverlayMeta,\n getOverlayMetaByLinkKey,\n isRegisteredOverlay,\n overlaysRawActions,\n type AnyOverlayMeta,\n type OverlayHostDispatch,\n} from \"@ai-matrx/summon\";\nimport { parseLinkParam, readPanelsParam, type LinkToken } from \"./grammar\";\n\n/** Any Redux dispatch that takes plain actions (a host's thunk-aware dispatch qualifies). */\nexport type LinkDispatch = Dispatch<UnknownAction>;\n\n/**\n * Open an overlay by its registry id from inside the package. Uses the raw action so internal\n * code passes plain strings (a host's augmented `OverlayId` union never needs a cast here); the\n * definition's `defaults` are merged underneath exactly as the typed creator does.\n */\nexport function openRegisteredOverlay(\n dispatch: LinkDispatch,\n overlayId: string,\n instanceId: string = DEFAULT_INSTANCE_ID,\n data?: unknown,\n): void {\n const defaults = getOverlayMeta(overlayId)?.defaults;\n dispatch(\n overlaysRawActions.openOverlay({\n overlayId,\n instanceId,\n ...(data === undefined ? {} : { data }),\n ...(isRecord(defaults) ? { defaults } : {}),\n }),\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** The key a token is judged by: the owning definition's own `link.key` (aliases resolve to it). */\nexport function canonicalLinkKey(key: string): string {\n return getOverlayMetaByLinkKey(key)?.link?.key ?? key;\n}\n\n/** The token with its key replaced by the canonical key; id and args carry across untouched. */\nexport function canonicalizeToken(raw: string): string {\n const at = raw.indexOf(\":\");\n const key = at === -1 ? raw : raw.slice(0, at);\n const canonical = canonicalLinkKey(key);\n if (canonical === key) return raw;\n return at === -1 ? canonical : `${canonical}${raw.slice(at)}`;\n}\n\nexport type TokenOutcome = \"opened\" | \"refused\" | \"unknown\" | \"failed\";\n\n/**\n * Run one token's hydrator. Synchronous hydrators dispatch before this returns; an async one\n * yields a promise. A throw (sync or async) is `\"failed\"` and is reported to `onError`.\n */\nexport function hydrateLinkToken(\n token: LinkToken,\n dispatch: LinkDispatch,\n onError?: (error: unknown, token: LinkToken) => void,\n): TokenOutcome | Promise<TokenOutcome> {\n const meta: AnyOverlayMeta | undefined = getOverlayMetaByLinkKey(token.key);\n const link = meta?.link;\n if (!meta || !link) return \"unknown\";\n const ownerId = meta.id;\n const settle = (result: void | \"refused\"): TokenOutcome => (result === \"refused\" ? \"refused\" : \"opened\");\n const fail = (error: unknown): TokenOutcome => {\n onError?.(error, token);\n return \"failed\";\n };\n try {\n const result = link.hydrate({\n id: token.id ?? \"\",\n args: token.args ?? {},\n open: (options) => openRegisteredOverlay(dispatch, ownerId, options?.instanceId ?? DEFAULT_INSTANCE_ID, options?.data),\n // The host's store dispatch IS the host dispatch at runtime; its thunk-aware type is the\n // host's augmentation (`OverlayHostTypes`), which the package cannot see.\n dispatch: dispatch as unknown as OverlayHostDispatch,\n });\n if (result && typeof (result as PromiseLike<unknown>).then === \"function\") {\n return Promise.resolve(result).then(settle, fail);\n }\n return settle(result as void | \"refused\");\n } catch (error) {\n return fail(error);\n }\n}\n\nexport interface OpenFromLinkResult {\n /** Tokens (verbatim) whose hydrator ran and did not refuse. */\n readonly opened: string[];\n /** Tokens whose hydrator declined the link on purpose. */\n readonly refused: string[];\n /** Tokens whose key no registered definition owns. */\n readonly unknown: string[];\n /** Tokens whose hydrator threw. */\n readonly failed: string[];\n}\n\nexport interface OpenFromLinkOptions {\n readonly dispatch: LinkDispatch;\n /**\n * All or nothing: when any token's key is unknown, open NOTHING and report the unknown tokens\n * (a notification then opens the link in a new tab instead of half of it in place).\n */\n readonly requireAll?: boolean;\n readonly onError?: (error: unknown, token: LinkToken) => void;\n}\n\n/**\n * Open every `?panels=` token of a search string or URL through its definition's hydrator.\n * Synchronous hydrators have dispatched by the time this returns; the promise settles once\n * async hydrators finish.\n */\nexport async function openFromLink(searchOrUrl: string, options: OpenFromLinkOptions): Promise<OpenFromLinkResult> {\n const tokens = parseLinkParam(readPanelsParam(searchOrUrl));\n const result: OpenFromLinkResult = { opened: [], refused: [], unknown: [], failed: [] };\n const unknown = tokens.filter((token) => !getOverlayMetaByLinkKey(token.key)?.link);\n if (options.requireAll && unknown.length > 0) {\n result.unknown.push(...unknown.map((token) => token.raw));\n return result;\n }\n const outcomes = tokens.map((token) => hydrateLinkToken(token, options.dispatch, options.onError));\n const settled = await Promise.all(outcomes.map((outcome) => Promise.resolve(outcome)));\n settled.forEach((outcome, index) => {\n const raw = tokens[index]?.raw ?? \"\";\n result[outcome === \"opened\" ? \"opened\" : outcome].push(raw);\n });\n return result;\n}\n\n// ── The extension door ──────────────────────────────────────────────────────────────────────\n\nexport interface OpenPanelRequest {\n readonly panelId: string;\n readonly instanceId?: string;\n readonly data?: Readonly<Record<string, unknown>>;\n}\n\nexport type OpenPanelResult =\n | { readonly ok: true; readonly opened: true; readonly panelId: string; readonly instanceId: string | null }\n | { readonly ok: false; readonly error: \"invalid_payload\" | \"unknown_panel\"; readonly details?: unknown };\n\nfunction readOpenPanelRequest(raw: unknown): OpenPanelRequest | string {\n if (!isRecord(raw)) return \"payload must be an object\";\n const { panelId, instanceId, data } = raw;\n if (typeof panelId !== \"string\" || panelId.length === 0) return \"panelId must be a non-empty string\";\n if (instanceId !== undefined && instanceId !== null && (typeof instanceId !== \"string\" || instanceId.length === 0)) {\n return \"instanceId must be a non-empty string when given\";\n }\n if (data !== undefined && data !== null && !isRecord(data)) return \"data must be an object when given\";\n return {\n panelId,\n ...(typeof instanceId === \"string\" ? { instanceId } : {}),\n ...(isRecord(data) ? { data } : {}),\n };\n}\n\n/**\n * Open a registered overlay by id for an outside caller (the browser extension's `openPanel`\n * envelope). Validates the payload and the id; failures come back as values, never throws, so\n * the bridge can reply verbatim. `instanceId: null` in the reply = the caller used the singleton.\n */\nexport function openPanelRequest(rawPayload: unknown, options: { readonly dispatch: LinkDispatch }): OpenPanelResult {\n const request = readOpenPanelRequest(rawPayload);\n if (typeof request === \"string\") return { ok: false, error: \"invalid_payload\", details: request };\n if (!isRegisteredOverlay(request.panelId)) {\n return {\n ok: false,\n error: \"unknown_panel\",\n details: { panelId: request.panelId, hint: \"panelId must be the id of a registered overlay definition.\" },\n };\n }\n openRegisteredOverlay(options.dispatch, request.panelId, request.instanceId ?? DEFAULT_INSTANCE_ID, request.data);\n return { ok: true, opened: true, panelId: request.panelId, instanceId: request.instanceId ?? null };\n}\n"],"mappings":"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","names":["import_react","import_summon","import_react"]}
1
+ {"version":3,"sources":["../src/url.ts","../src/url/OverlayLinkManager.tsx","../src/url/door.ts"],"sourcesContent":["// @ai-matrx/summon/url — address-bar links: the `?panels=` grammar, the link manager, the\n// `useOverlayLink` publisher and the one door (`openFromLink`) every link source goes through.\nexport { useOverlayLink } from \"@ai-matrx/summon/react\";\nexport {\n parseLinkToken,\n parseLinkParam,\n formatLinkToken,\n encodeLinkId,\n encodeLinkArg,\n decodeLinkPart,\n readPanelsParam,\n withPanelsParam,\n type LinkToken,\n type LinkEntry,\n} from \"@ai-matrx/summon/open\";\nexport {\n OverlayLinkManager,\n serializeLinkEntries,\n mergeManagedLinkParam,\n withUnresolvedTokens,\n unopenedWindowNotice,\n type OverlayLinkManagerProps,\n} from \"./url/OverlayLinkManager\";\nexport {\n openFromLink,\n openPanelRequest,\n hydrateLinkToken,\n canonicalLinkKey,\n canonicalizeToken,\n openRegisteredOverlay,\n type OpenFromLinkResult,\n type OpenFromLinkOptions,\n type OpenPanelRequest,\n type OpenPanelResult,\n type TokenOutcome,\n type LinkDispatch,\n} from \"./url/door\";\n","/**\n * OverlayLinkManager — the address bar's `?panels=` channel (successor of matrx-frontend's\n * UrlPanelManager). Mount ONCE inside <SummonProvider>. Driven entirely by `ports.router`.\n *\n * 1. On mount: read `?panels=`, hydrate each token through the one door (`hydrateLinkToken`).\n * 2. After that: write back the union of registered link entries (`useOverlayLink`) plus every\n * pasted token that has not been settled yet, via `router.replaceSearch` — never navigation.\n *\n * THE ADDRESS IS NEVER DESTROYED BY A CLOCK (matrx-frontend V-28 NEW-5). A token whose window has\n * not registered yet is kept verbatim in the address however long its lazy chunk takes. The\n * deadline (12 s prod / 45 s dev) decides one thing only: when to stop waiting silently and tell\n * the person, through `ports.notify` and `ports.errors`.\n *\n * A token is SETTLED when ANY registered entry carries its canonical key — the window a hydrator\n * opens may publish a different id (a vault link names an item, the vault window publishes its\n * singleton id) and may even be a different overlay than the one owning the key (key `agent`\n * opens display-mode shells). An alias resolves to its definition's own `link.key`.\n */\nimport { useEffect, useRef, useState, useSyncExternalStore } from \"react\";\nimport {\n LAZY_WINDOW_MOUNT_DEADLINE_MS,\n getOverlayMetaByLinkKey,\n selectIsUrlHydrated,\n selectUrlSyncEntries,\n setHydrated,\n type UrlSyncEntry,\n} from \"@ai-matrx/summon\";\nimport { useSummonDispatch, useSummonPorts, useSummonSelector } from \"@ai-matrx/summon/react\";\nimport { canonicalLinkKey, canonicalizeToken, hydrateLinkToken } from \"./door\";\nimport { formatLinkToken, parseLinkParam, readPanelsParam, withPanelsParam } from \"@ai-matrx/summon/open\";\n\nexport interface OverlayLinkManagerProps {\n /**\n * Restrict hydration and write-back to these link keys (a route-scoped manager). Tokens of\n * other keys are preserved verbatim and never hydrated. Omit for the app-wide manager.\n */\n readonly managedKeys?: readonly string[];\n /** Override the notice deadline (ms). Default: 12 s in production, 45 s in development. */\n readonly noticeDeadlineMs?: number;\n}\n\n/** Serialize registered entries as v2 tokens (only managed keys when given). */\nexport function serializeLinkEntries(entries: Readonly<Record<string, UrlSyncEntry>>, managedKeys?: readonly string[]): string {\n const managed = managedKeys ? new Set(managedKeys) : null;\n return Object.values(entries)\n .filter((entry) => !managed || managed.has(entry.typeKey))\n .map((entry) => formatLinkToken({ key: entry.typeKey, id: entry.instanceId, args: entry.args }))\n .join(\",\");\n}\n\n/** Keep the current param's unmanaged tokens; replace the managed ones with `nextManaged`. */\nexport function mergeManagedLinkParam(currentParam: string, nextManaged: string, managedKeys?: readonly string[]): string {\n if (!managedKeys) return nextManaged;\n const managed = new Set(managedKeys);\n const unmanaged = currentParam\n .split(\",\")\n .filter(Boolean)\n .filter((token) => !managed.has(token.split(\":\")[0] ?? \"\"));\n return [...unmanaged, ...nextManaged.split(\",\").filter(Boolean)].join(\",\");\n}\n\n/**\n * Re-attach pasted tokens no window has settled. A token is skipped when its CANONICAL key is\n * already represented by a live entry, so a late registration replaces the placeholder.\n */\nexport function withUnresolvedTokens(managedParam: string, unresolvedTokens: readonly string[]): string {\n if (unresolvedTokens.length === 0) return managedParam;\n const managed = managedParam.split(\",\").filter(Boolean);\n const represented = new Set(managed.map((token) => canonicalLinkKey(token.split(\":\")[0] ?? \"\")));\n const kept = unresolvedTokens.filter((token) => Boolean(token) && !represented.has(canonicalLinkKey(token.split(\":\")[0] ?? \"\")));\n return [...managed, ...kept].join(\",\");\n}\n\n/** The honest sentence for a link naming a window that did not open. */\nexport function unopenedWindowNotice(keys: readonly string[]): string {\n return (\n `This link names a window this build could not open: ${keys.join(\", \")}. ` +\n `The link is unchanged in your address bar — reload to try again, or report it if it keeps failing.`\n );\n}\n\ninterface PendingToken {\n /** What is written back while unsettled (canonical key, pasted id and args). */\n readonly token: string;\n /** The key the person pasted (named in the notice). */\n readonly tokenKey: string;\n readonly canonicalKey: string;\n}\n\nconst noopSubscribe = () => () => {};\n\nexport function OverlayLinkManager({ managedKeys, noticeDeadlineMs }: OverlayLinkManagerProps): null {\n const ports = useSummonPorts();\n const dispatch = useSummonDispatch();\n const entries = useSummonSelector(selectUrlSyncEntries);\n const isHydrated = useSummonSelector(selectIsUrlHydrated);\n const router = ports.router;\n // Re-run the write-back after ANY address change the router reports.\n const search = useSyncExternalStore(router.subscribe ?? noopSubscribe, router.search, () => \"\");\n\n const initialLoadDone = useRef(false);\n // Keyed by canonical key + id so two tokens that canonicalise together never overwrite each\n // other (V-30 NEW-5); the settle sweep still runs on canonical key.\n const unresolved = useRef(new Map<string, PendingToken>());\n const announced = useRef(new Set<string>());\n const [noticeDue, setNoticeDue] = useState(false);\n const [asyncTick, setAsyncTick] = useState(0);\n const deadline = noticeDeadlineMs ?? LAZY_WINDOW_MOUNT_DEADLINE_MS;\n\n const announce = (keys: readonly string[], reason: \"no-hydrator\" | \"never-registered\" | \"hydrator-threw\"): void => {\n const fresh = keys.filter((key) => !announced.current.has(key));\n if (fresh.length === 0) return;\n for (const key of fresh) announced.current.add(key);\n const joined = fresh.join(\", \");\n const why =\n reason === \"no-hydrator\"\n ? `no registered definition owns ${fresh.length > 1 ? \"these keys\" : \"this key\"}`\n : reason === \"hydrator-threw\"\n ? \"its hydrator threw\"\n : `hydrated, but no window registered its link within ${deadline}ms`;\n const message =\n `[overlays/url] ?panels= token(s) [${joined}]: ${why}. The token is KEPT in the address. ` +\n `Give the overlay definition a matching \\`link\\` (key or alias), or stop publishing the link.`;\n ports.errors.capture(new Error(message), {\n source: \"url-panel-unopened\",\n relation: `?panels=${joined}`,\n code: reason,\n typeKeys: fresh,\n deadlineMs: deadline,\n userMessage: unopenedWindowNotice(fresh),\n });\n ports.notify.error(unopenedWindowNotice(fresh), { duration: 12_000 });\n };\n const announceRef = useRef(announce);\n announceRef.current = announce;\n\n // 1. HYDRATION (address → store), once.\n useEffect(() => {\n if (initialLoadDone.current) return;\n initialLoadDone.current = true;\n const managed = managedKeys ? new Set(managedKeys) : null;\n const tokens = parseLinkParam(readPanelsParam(router.search()));\n const noHydrator: string[] = [];\n for (const token of tokens) {\n if (managed && !managed.has(token.key)) continue; // preserved verbatim by the write-back\n const canonicalKey = canonicalLinkKey(token.key);\n const pendingKey = `${canonicalKey}\\u0000${token.id ?? \"\"}`;\n const pending: PendingToken = { token: canonicalizeToken(token.raw), tokenKey: token.key, canonicalKey };\n if (!getOverlayMetaByLinkKey(token.key)?.link) {\n unresolved.current.set(pendingKey, { ...pending, token: token.raw });\n noHydrator.push(token.key);\n continue;\n }\n unresolved.current.set(pendingKey, pending);\n const outcome = hydrateLinkToken(token, dispatch, (error) => {\n ports.errors.capture(error, { source: \"url-panel-hydrator\", token: token.raw });\n });\n const apply = (result: string): void => {\n // A refused link is dropped from the address; it is not \"still to come\".\n if (result === \"refused\" && unresolved.current.get(pendingKey) === pending) {\n unresolved.current.delete(pendingKey);\n setAsyncTick((n) => n + 1);\n }\n };\n if (typeof outcome === \"string\") apply(outcome);\n else void outcome.then(apply);\n }\n if (noHydrator.length > 0) announceRef.current(noHydrator, \"no-hydrator\");\n dispatch(setHydrated());\n }, [dispatch, managedKeys, router, ports]);\n\n // The notice deadline: never gates a write; only turns a silent wait into a visible notice.\n useEffect(() => {\n if (!isHydrated || unresolved.current.size === 0) return undefined;\n const timer = setTimeout(() => setNoticeDue(true), deadline);\n return () => clearTimeout(timer);\n }, [isHydrated, deadline]);\n\n // 2. WRITE-BACK (store → address).\n useEffect(() => {\n if (!isHydrated) return;\n const observed = new Set(Object.values(entries).map((entry) => canonicalLinkKey(entry.typeKey)));\n for (const [key, pending] of [...unresolved.current.entries()]) {\n if (observed.has(pending.canonicalKey)) unresolved.current.delete(key);\n }\n const stillPending = [...unresolved.current.values()];\n if (noticeDue && stillPending.length > 0) {\n announceRef.current(\n stillPending.map((pending) => pending.tokenKey),\n \"never-registered\",\n );\n }\n // The LIVE address, never a snapshot: the page may have written `?view=` a moment ago.\n const liveSearch = router.search();\n const currentParam = readPanelsParam(liveSearch) ?? \"\";\n const nextManaged = withUnresolvedTokens(\n serializeLinkEntries(entries, managedKeys),\n stillPending.map((pending) => pending.token),\n );\n const nextParam = mergeManagedLinkParam(currentParam, nextManaged, managedKeys);\n if (currentParam !== nextParam) router.replaceSearch(withPanelsParam(liveSearch, nextParam));\n }, [entries, isHydrated, managedKeys, router, search, noticeDue, asyncTick]);\n\n return null;\n}\n","/**\n * The ONE door every link source goes through: the address-bar manager on load, a notification\n * that opens its link in place, the extension bridge. A token is resolved through the registry —\n * `getOverlayMetaByLinkKey(key).link.hydrate({ id, args, open, dispatch })` — never a side table.\n */\nimport type { Dispatch, UnknownAction } from \"@reduxjs/toolkit\";\nimport {\n DEFAULT_INSTANCE_ID,\n getOverlayMeta,\n getOverlayMetaByLinkKey,\n isRegisteredOverlay,\n overlaysRawActions,\n type AnyOverlayMeta,\n type OverlayHostDispatch,\n} from \"@ai-matrx/summon\";\nimport { parseLinkParam, readPanelsParam, type LinkToken } from \"@ai-matrx/summon/open\";\n\n/** Any Redux dispatch that takes plain actions (a host's thunk-aware dispatch qualifies). */\nexport type LinkDispatch = Dispatch<UnknownAction>;\n\n/**\n * Open an overlay by its registry id from inside the package. Uses the raw action so internal\n * code passes plain strings (a host's augmented `OverlayId` union never needs a cast here); the\n * definition's `defaults` are merged underneath exactly as the typed creator does.\n */\nexport function openRegisteredOverlay(\n dispatch: LinkDispatch,\n overlayId: string,\n instanceId: string = DEFAULT_INSTANCE_ID,\n data?: unknown,\n): void {\n const defaults = getOverlayMeta(overlayId)?.defaults;\n dispatch(\n overlaysRawActions.openOverlay({\n overlayId,\n instanceId,\n ...(data === undefined ? {} : { data }),\n ...(isRecord(defaults) ? { defaults } : {}),\n }),\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** The key a token is judged by: the owning definition's own `link.key` (aliases resolve to it). */\nexport function canonicalLinkKey(key: string): string {\n return getOverlayMetaByLinkKey(key)?.link?.key ?? key;\n}\n\n/** The token with its key replaced by the canonical key; id and args carry across untouched. */\nexport function canonicalizeToken(raw: string): string {\n const at = raw.indexOf(\":\");\n const key = at === -1 ? raw : raw.slice(0, at);\n const canonical = canonicalLinkKey(key);\n if (canonical === key) return raw;\n return at === -1 ? canonical : `${canonical}${raw.slice(at)}`;\n}\n\nexport type TokenOutcome = \"opened\" | \"refused\" | \"unknown\" | \"failed\";\n\n/**\n * Run one token's hydrator. Synchronous hydrators dispatch before this returns; an async one\n * yields a promise. A throw (sync or async) is `\"failed\"` and is reported to `onError`.\n */\nexport function hydrateLinkToken(\n token: LinkToken,\n dispatch: LinkDispatch,\n onError?: (error: unknown, token: LinkToken) => void,\n): TokenOutcome | Promise<TokenOutcome> {\n const meta: AnyOverlayMeta | undefined = getOverlayMetaByLinkKey(token.key);\n const link = meta?.link;\n if (!meta || !link) return \"unknown\";\n const ownerId = meta.id;\n const settle = (result: void | \"refused\"): TokenOutcome => (result === \"refused\" ? \"refused\" : \"opened\");\n const fail = (error: unknown): TokenOutcome => {\n onError?.(error, token);\n return \"failed\";\n };\n try {\n const result = link.hydrate({\n id: token.id ?? \"\",\n args: token.args ?? {},\n open: (options) => openRegisteredOverlay(dispatch, ownerId, options?.instanceId ?? DEFAULT_INSTANCE_ID, options?.data),\n // The host's store dispatch IS the host dispatch at runtime; its thunk-aware type is the\n // host's augmentation (`OverlayHostTypes`), which the package cannot see.\n dispatch: dispatch as unknown as OverlayHostDispatch,\n });\n if (result && typeof (result as PromiseLike<unknown>).then === \"function\") {\n return Promise.resolve(result).then(settle, fail);\n }\n return settle(result as void | \"refused\");\n } catch (error) {\n return fail(error);\n }\n}\n\nexport interface OpenFromLinkResult {\n /** Tokens (verbatim) whose hydrator ran and did not refuse. */\n readonly opened: string[];\n /** Tokens whose hydrator declined the link on purpose. */\n readonly refused: string[];\n /** Tokens whose key no registered definition owns. */\n readonly unknown: string[];\n /** Tokens whose hydrator threw. */\n readonly failed: string[];\n}\n\nexport interface OpenFromLinkOptions {\n readonly dispatch: LinkDispatch;\n /**\n * All or nothing: when any token's key is unknown, open NOTHING and report the unknown tokens\n * (a notification then opens the link in a new tab instead of half of it in place).\n */\n readonly requireAll?: boolean;\n readonly onError?: (error: unknown, token: LinkToken) => void;\n}\n\n/**\n * Open every `?panels=` token of a search string or URL through its definition's hydrator.\n * Synchronous hydrators have dispatched by the time this returns; the promise settles once\n * async hydrators finish.\n */\nexport async function openFromLink(searchOrUrl: string, options: OpenFromLinkOptions): Promise<OpenFromLinkResult> {\n const tokens = parseLinkParam(readPanelsParam(searchOrUrl));\n const result: OpenFromLinkResult = { opened: [], refused: [], unknown: [], failed: [] };\n const unknown = tokens.filter((token) => !getOverlayMetaByLinkKey(token.key)?.link);\n if (options.requireAll && unknown.length > 0) {\n result.unknown.push(...unknown.map((token) => token.raw));\n return result;\n }\n const outcomes = tokens.map((token) => hydrateLinkToken(token, options.dispatch, options.onError));\n const settled = await Promise.all(outcomes.map((outcome) => Promise.resolve(outcome)));\n settled.forEach((outcome, index) => {\n const raw = tokens[index]?.raw ?? \"\";\n result[outcome === \"opened\" ? \"opened\" : outcome].push(raw);\n });\n return result;\n}\n\n// ── The extension door ──────────────────────────────────────────────────────────────────────\n\nexport interface OpenPanelRequest {\n readonly panelId: string;\n readonly instanceId?: string;\n readonly data?: Readonly<Record<string, unknown>>;\n}\n\nexport type OpenPanelResult =\n | { readonly ok: true; readonly opened: true; readonly panelId: string; readonly instanceId: string | null }\n | { readonly ok: false; readonly error: \"invalid_payload\" | \"unknown_panel\"; readonly details?: unknown };\n\nfunction readOpenPanelRequest(raw: unknown): OpenPanelRequest | string {\n if (!isRecord(raw)) return \"payload must be an object\";\n const { panelId, instanceId, data } = raw;\n if (typeof panelId !== \"string\" || panelId.length === 0) return \"panelId must be a non-empty string\";\n if (instanceId !== undefined && instanceId !== null && (typeof instanceId !== \"string\" || instanceId.length === 0)) {\n return \"instanceId must be a non-empty string when given\";\n }\n if (data !== undefined && data !== null && !isRecord(data)) return \"data must be an object when given\";\n return {\n panelId,\n ...(typeof instanceId === \"string\" ? { instanceId } : {}),\n ...(isRecord(data) ? { data } : {}),\n };\n}\n\n/**\n * Open a registered overlay by id for an outside caller (the browser extension's `openPanel`\n * envelope). Validates the payload and the id; failures come back as values, never throws, so\n * the bridge can reply verbatim. `instanceId: null` in the reply = the caller used the singleton.\n */\nexport function openPanelRequest(rawPayload: unknown, options: { readonly dispatch: LinkDispatch }): OpenPanelResult {\n const request = readOpenPanelRequest(rawPayload);\n if (typeof request === \"string\") return { ok: false, error: \"invalid_payload\", details: request };\n if (!isRegisteredOverlay(request.panelId)) {\n return {\n ok: false,\n error: \"unknown_panel\",\n details: { panelId: request.panelId, hint: \"panelId must be the id of a registered overlay definition.\" },\n };\n }\n openRegisteredOverlay(options.dispatch, request.panelId, request.instanceId ?? DEFAULT_INSTANCE_ID, request.data);\n return { ok: true, opened: true, panelId: request.panelId, instanceId: request.instanceId ?? null };\n}\n"],"mappings":"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","names":["import_react","import_open","import_summon","import_react","import_open"]}