/** * The widget's single source of session state. * * This replaces three independent implementations that each called * `widgetSessions.list` and kept their own `sessions` / `loading` / `error` / * `unavailable` signals: `createChatHistory` (consumed by `Bot`), one inside * `WithSidebar`, and one inside `WithoutSidebar`. They stayed roughly in step by * broadcasting `toruk-sessions-updated` on `window` after every write, which * meant three requests per change, three chances to diverge, and no way for the * sidebar to know which session was actually open. * * Two behaviours had already drifted apart before consolidation, so one had to * win: `WithSidebar` searched server-side (finds sessions beyond the loaded * page) while `WithoutSidebar` filtered the loaded array client-side. Server-side * search wins because it is the only one that can find an old chat. It is * debounced here — the sidebar previously issued one request per keystroke, and * routing the history overlay through the same path without a debounce would * have multiplied that. * * Session *reads* live here. Registering the current chat as a session — the * create call, its retry policy and its error surface — stays in `Bot`, because * only `Bot` knows when a conversation has begun and nothing else consumes it. * * `Bot` owns the chat itself, so selecting a session cannot be implemented here. * It registers a bridge (`attachChat`) instead, and every surface then calls one * `selectSession` / `newChat` rather than dispatching an event and hoping. */ import { type SessionFailure } from '@/widget/services/sessions'; import type { TorukSession } from '@/sessions/sessions.types'; import type { WidgetFeatureFlags } from '@/types/features'; /** A history row. Shape follows Core's session output. */ export type ChatSession = TorukSession; export type SessionStoreParams = { apiHost?: string; deploymentId: string; /** * Preview mounts (deployment wizard review step) make no session reads or * writes at all — a trial chat must not appear in the real history. */ previewMode?: boolean; onRequest?: (request: RequestInit) => Promise; }; /** * The chat behaviour `Bot` owns and the session surfaces need to trigger. * Registered once on mount; absent until then, which is why every caller * tolerates a missing bridge rather than assuming one. */ export type ChatBridge = { /** Load an existing session's transcript into the live chat. */ loadSession: (session: ChatSession) => void | Promise; /** Clear the chat and start a new one. */ newChat: () => void; }; export type SessionStore = ReturnType; export declare function createSessionStore(params: SessionStoreParams): { sessions: () => ChatSession[]; scopedSession: import("solid-js").Accessor; setScopedSession: import("solid-js").Setter; loading: import("solid-js").Accessor; loadingMore: import("solid-js").Accessor; hasMore: () => boolean; loadMore: () => Promise; error: import("solid-js").Accessor; unavailable: import("solid-js").Accessor; unreachable: import("solid-js").Accessor; deploymentMissing: import("solid-js").Accessor; setDeploymentMissing: import("solid-js").Setter; retry: (query?: string) => Promise; search: import("solid-js").Accessor; setSearch: (query: string) => void; activeSessionId: import("solid-js").Accessor; setActiveSessionId: import("solid-js").Setter; activeTitle: import("solid-js").Accessor; setActiveTitle: import("solid-js").Setter; historyOpen: import("solid-js").Accessor; openHistory: () => void; closeHistory: () => false; artifactsOpen: import("solid-js").Accessor; openArtifacts: () => void; closeArtifacts: () => false; artifactsEnabled: import("solid-js").Accessor; setArtifactsEnabled: import("solid-js").Setter; features: import("solid-js").Accessor; setFeatures: import("solid-js").Setter; locked: import("solid-js").Accessor; setLocked: import("solid-js").Setter; openScopedSession: (session: ChatSession) => Promise; refresh: (query?: string) => Promise; rename: (session: ChatSession, title: string) => Promise; remove: (session: ChatSession) => Promise; selectSession: (session: ChatSession) => Promise; newChat: () => void; attachChat: (next: ChatBridge) => () => void; dispose: () => void; }; declare const SessionStoreContext: import("solid-js").Context<{ sessions: () => ChatSession[]; scopedSession: import("solid-js").Accessor; setScopedSession: import("solid-js").Setter; loading: import("solid-js").Accessor; loadingMore: import("solid-js").Accessor; hasMore: () => boolean; loadMore: () => Promise; error: import("solid-js").Accessor; unavailable: import("solid-js").Accessor; unreachable: import("solid-js").Accessor; deploymentMissing: import("solid-js").Accessor; setDeploymentMissing: import("solid-js").Setter; retry: (query?: string) => Promise; search: import("solid-js").Accessor; setSearch: (query: string) => void; activeSessionId: import("solid-js").Accessor; setActiveSessionId: import("solid-js").Setter; activeTitle: import("solid-js").Accessor; setActiveTitle: import("solid-js").Setter; historyOpen: import("solid-js").Accessor; openHistory: () => void; closeHistory: () => false; artifactsOpen: import("solid-js").Accessor; openArtifacts: () => void; closeArtifacts: () => false; artifactsEnabled: import("solid-js").Accessor; setArtifactsEnabled: import("solid-js").Setter; features: import("solid-js").Accessor; setFeatures: import("solid-js").Setter; locked: import("solid-js").Accessor; setLocked: import("solid-js").Setter; openScopedSession: (session: ChatSession) => Promise; refresh: (query?: string) => Promise; rename: (session: ChatSession, title: string) => Promise; remove: (session: ChatSession) => Promise; selectSession: (session: ChatSession) => Promise; newChat: () => void; attachChat: (next: ChatBridge) => () => void; dispose: () => void; } | undefined>; export { SessionStoreContext }; /** * Read the shared store. Throws when no provider is above the caller, because * the alternative — silently creating a second store — is the exact failure this * module exists to remove. */ export declare function useSessionStore(): SessionStore;