import * as react_jsx_runtime from 'react/jsx-runtime'; import React, { ReactNode } from 'react'; type PushHandler = (data: unknown) => void; /** * RPC Engine — communicates with the parent window (web platform) via postMessage. * * Security model: * 1. On init, the SDK sends { type: '__charx_rpc__', method: 'sdk.init' } to the parent. * 2. The platform responds with { type: '__charx_ready__', token, origin } — a per-session * secret token that proves the parent is the legitimate platform. * 3. All subsequent outgoing RPC messages include the token. * 4. The platform validates the token on every call, rejecting unauthorised frames. * 5. Incoming messages are accepted only from window.parent (e.source check). * * Protocol (matches html-message.tsx): * iframe → parent: { type: '__charx_rpc__', iframeId, token?, id?, method, args[] } * parent → iframe: { type: '__charx_ready__', iframeId, token, origin } * parent → iframe: { type: '__charx_rpc_response__', iframeId, id, result?, error? } * parent → iframe: { type: '__charx_push__', event, data } */ declare class RpcEngine { private pending; private pushHandlers; private readonly iframeId; private readonly target; /** Session token issued by the platform after the init handshake */ private _token; /** Platform's origin — used as targetOrigin for all outgoing messages after handshake */ private _platformOrigin; /** Resolvers waiting for the __charx_ready__ handshake */ private _readyResolvers; private _handshakeDone; constructor(target?: Window); private static _genId; private handleMessage; /** * Returns a Promise that resolves when the platform handshake completes. * Used by CharxSdk.init() to wait for the session token. */ waitReady(): Promise; get iframeIdValue(): string; /** * Two-way call — returns a Promise that resolves with the platform's response. * Rejects if the platform returns an error or if `timeoutMs` elapses with no response. */ call(method: string, args?: unknown[], timeoutMs?: number): Promise; /** Fire-and-forget — no response expected. */ post(method: string, args?: unknown[]): Promise; /** Subscribe to push events sent by the platform */ push(event: string, handler: PushHandler): () => void; /** Destroy the engine — rejects all pending calls and removes the message listener */ destroy(): void; } interface Message { id: string; role: 'user' | 'assistant' | 'system'; content: string; createdAt: number; tokenCount?: number; swipes?: string[]; activeSwipe?: number; variables?: Record; } interface SendOptions { onData?: (chunk: string) => void; onComplete?: (message: Message) => void; onError?: (error: Error) => void; onStart?: (payload: ChatStreamStartPayload) => void; model?: string; temperature?: number; injectedSystemPrompts?: string[]; timeoutMs?: number; requestId?: string; } /** Options for sdk.chat.generateRaw() — silent background LLM call */ interface GenerateRawOptions { /** Override the model for this call */ model?: string; temperature?: number; maxTokens?: number; /** * When true, prepend the character context (system prompt, worldbook, etc.) * from the current conversation. Defaults to true when conversationId is available. */ includeCharacterContext?: boolean; timeoutMs?: number; } /** A message passed to generateRaw() as part of the messages array */ interface GenerateRawMessage { role: 'system' | 'user' | 'assistant'; content: string; } interface ChatHistoryOptions { limit?: number; offset?: number; page?: number; pageSize?: number; } interface MessagesModule { list(params?: ChatHistoryOptions): Promise; getAll(): Promise; delete(id: string): Promise; edit(id: string, content: string): Promise; /** * @deprecated Compatibility placeholder only. * Current creator preview and web chat hosts may reject this call. * Prefer regenerate(), continue(), edit(), or explicit message state in variables. */ swipe(id: string, direction: 'left' | 'right'): Promise; } interface ChatStreamStartPayload { requestId?: string; userMessageId?: string | number; assistantMessageId?: string | number; } interface ChatSendTask { requestId: string; done: Promise; stop(): Promise; } interface CharacterInfo { id: string | number; name: string; avatar?: string; displayIntro?: string; firstMes?: string; alternateGreetings?: string[]; tags?: string[]; creator?: string; version?: string | number; } interface PersonaInfo { id?: string | number; name?: string; avatar?: string; callName?: string; gender?: string; description?: string; } interface CharacterSettings { model?: string | null; } type VariableMap = Record; type Unsubscribe = () => void; interface ToastOptions { text: string; type?: 'success' | 'error' | 'warning' | 'info'; duration?: number; icon?: string; } /** ToastOptions 或可直接展示的简短文本值。 */ type ToastInput = ToastOptions | string | number | boolean; interface PanelOptions { url: string; title?: string; mode?: 'fullscreen' | 'sidebar' | 'modal'; width?: number | string; } /** PanelOptions 或扩展面板 URL 简写。 */ type PanelInput = PanelOptions | string; interface AlertOptions { message: string; title?: string; confirmText?: string; } interface ConfirmOptions { message: string; title?: string; confirmText?: string; cancelText?: string; } interface PromptOptions { message: string; title?: string; placeholder?: string; defaultValue?: string; } interface SpeakOptions { voice?: 'character' | 'system' | string; speed?: number; pitch?: number; } interface BgmOptions { loop?: boolean; volume?: number; fadeIn?: number; } interface BgmStopOptions { fadeOut?: number; } interface SfxOptions { volume?: number; } interface SaveSlot { slot: number; description?: string; savedAt: number; snapshot?: Record; } interface Achievement { id: string; name: string; description: string; unlockedAt?: number; } interface RankEntry { userId: string; username: string; score: number; rank: number; } interface WorldbookEntryState { entryKey: string; comment: string; /** The full text content of the entry — now included in getAll() response */ content: string; /** Trigger keywords for this entry */ keys: string[]; enabled: boolean; baseEnabled: boolean; isOverridden: boolean; constant: boolean; insertionOrder: number; } interface ConversationWorldbookResponse { conversationId: number; characterId: number; entries: WorldbookEntryState[]; totalCount: number; enabledCount: number; } type ChatStatus = 'idle' | 'sending' | 'streaming' | 'error'; interface UseChatReturn { messages: Message[]; status: ChatStatus; error: Error | null; currentRequestId: string | null; currentAssistantMessageId: string | null; send: (message: string, options?: SendOptions) => void; sendStream: (message: string, options?: SendOptions) => ChatSendTask; stop: () => Promise; regenerate: () => Promise; continue: () => Promise; deleteMessage: (id: string) => Promise; editMessage: (id: string, content: string) => Promise; /** * @deprecated Compatibility placeholder only. * Current creator preview and web chat hosts may reject this call. */ swipeMessage: (id: string, direction: 'left' | 'right') => Promise; generateRaw: (messages: GenerateRawMessage[], options?: GenerateRawOptions) => Promise; injectPrompt: (content: string) => Promise; insertSystemMessage: (content: string) => Promise; getConversationId: () => Promise; loadMore: () => Promise; hasMore: boolean; } declare class ChatModule { private rpc; readonly messages: MessagesModule; constructor(rpc: RpcEngine); private static genRequestId; /** * Send a message to the character. * * The platform processes the request through its normal chat flow. * `onData` fires for each streaming chunk; `onComplete` fires when the * stream finishes; `onError` fires if the generation fails. */ send(message: string, options?: SendOptions): void; stop(): Promise; regenerate(): Promise; continue(): Promise; getInput(): Promise; setInput(text: string): Promise; /** Set the active greeting index before the first user message is sent */ setGreetingIndex(index: number): Promise; /** Get the current active greeting index */ getGreetingIndex(): Promise; /** @deprecated Use setGreetingIndex(index) */ setFirstMesIndex(index: number): Promise; sendStream(message: string, options?: SendOptions): ChatSendTask; /** * Inject a system prompt into the next user-facing generation call. * Equivalent to SillyTavern injectPrompts(). * The injected prompt is cleared automatically after the next chat.send(). */ injectPrompt(content: string): Promise; /** * Insert a system message into the conversation without triggering AI generation. * Equivalent to SillyTavern createChatMessages() with role=system. */ insertSystemMessage(content: string): Promise; /** Get the current conversation ID */ getConversationId(): Promise; /** * Subscribe to conversation switch events. * Fires when the user navigates to a different conversation. * Equivalent to SillyTavern CHAT_CHANGED event. */ onChatChanged(callback: (payload: { conversationId: number; }) => void): Unsubscribe; /** * Subscribe to message-updated events. * Fires when an assistant message is fully saved (stream complete) or updated. * Equivalent to SillyTavern MESSAGE_UPDATED event. */ onMessageUpdated(callback: (message: Message) => void): Unsubscribe; /** * Subscribe to message-edited events. * Fires when a message is edited via sdk.chat.messages.edit(). * Equivalent to SillyTavern MESSAGE_EDITED event. */ onMessageEdited(callback: (message: Message) => void): Unsubscribe; /** * Silent background LLM generation — equivalent to SillyTavern generateRaw(). * Calls the AI model without adding any messages to the chat history. * When includeCharacterContext is true (default), the character's system prompt * and worldbook are included in the request context. */ generateRaw(messages: GenerateRawMessage[], options?: GenerateRawOptions): Promise; /** * Subscribe to message-deleted events. * Fires when a message is deleted via sdk.chat.messages.delete(). * Equivalent to SillyTavern MESSAGE_DELETED event. */ onMessageDeleted(callback: (message: Message) => void): Unsubscribe; } declare class CharacterModule { private rpc; constructor(rpc: RpcEngine); getInfo(): Promise; getPersona(): Promise; getSettings(): Promise; } declare class VariableModule { private rpc; private observedValues; constructor(rpc: RpcEngine); getAll(): Promise; get(key: string): Promise; set(key: string, value: T): Promise; setMany(vars: VariableMap): Promise; increment(key: string, delta?: number): Promise; decrement(key: string, delta?: number): Promise; delete(key: string): Promise; clear(): Promise; /** * Watch a single variable for changes pushed from the platform. * Requires the platform to send `{ type: '__charx_push__', event: 'variable.changed', data: { key, value } }`. */ watch(key: string, callback: (value: T, oldValue: T | undefined) => void): Unsubscribe; /** * Watch all variables — callback receives the full variable map on any change. * Re-fetches the complete map after each push event so the callback always * receives a consistent snapshot (the push payload is a single { key, value }, * not the full map). */ watchAll(callback: (vars: VariableMap) => void): Unsubscribe; } declare class StorageModule { private rpc; constructor(rpc: RpcEngine); set(key: string, value: T): Promise; get(key: string): Promise; getOrDefault(key: string, defaultValue: T): Promise; has(key: string): Promise; remove(key: string): Promise; clear(): Promise; keys(): Promise; } declare class UIModule { private rpc; constructor(rpc: RpcEngine); toast(options: ToastInput): Promise; alert(options: AlertOptions): Promise; alert(message: string): Promise; confirm(options: ConfirmOptions): Promise; confirm(message: string): Promise; prompt(options: PromptOptions): Promise; prompt(message: string, defaultValue?: string): Promise; openPanel(options: PanelInput): Promise; closePanel(): Promise; hideChatInput(): Promise; showChatInput(): Promise; setTheme(theme: 'dark' | 'light' | 'system'): Promise; scrollToBottom(): Promise; } declare class BgmController { private rpc; constructor(rpc: RpcEngine); play(url: string, options?: BgmOptions): Promise; stop(options?: BgmStopOptions): Promise; pause(): Promise; resume(): Promise; setVolume(volume: number): Promise; } declare class SfxController { private rpc; constructor(rpc: RpcEngine); play(url: string, options?: SfxOptions): Promise; preload(urls: string[]): Promise; } declare class MediaModule { private rpc; readonly bgm: BgmController; readonly sfx: SfxController; constructor(rpc: RpcEngine); speak(text: string, options?: SpeakOptions): Promise; stopSpeak(): Promise; } declare class GameAchievementsController { private rpc; constructor(rpc: RpcEngine); unlock(achievementId: string): Promise; list(): Promise; } declare class GameRankingController { private rpc; constructor(rpc: RpcEngine); submit(score: number, options?: { category?: string; }): Promise; getTop(options?: { limit?: number; category?: string; }): Promise; getSelf(options?: { category?: string; }): Promise; } declare class GameModule { private rpc; readonly achievements: GameAchievementsController; readonly ranking: GameRankingController; constructor(rpc: RpcEngine); save(options: { slot: number; description?: string; }): Promise; load(options: { slot: number; }): Promise>; listSaves(): Promise; deleteSave(slot: number): Promise; unlockAchievement(achievementId: string): Promise; listAchievements(): Promise; submitScore(score: number, options?: { category?: string; }): Promise; getTop(options?: { limit?: number; category?: string; }): Promise; getSelfRank(options?: { category?: string; }): Promise; } /** * Shared lightweight Markdown → HTML renderer. * Handles: bold+italic, bold, italic, inline code, line breaks. * All input is HTML-escaped first to prevent XSS. * Exported so MdRenderer and other consumers share one implementation. */ declare function renderMarkdown(text: string): string; declare class UtilsModule { private _rpc; constructor(_rpc: RpcEngine); clipboard: { writeText: (text: string) => Promise; readText: () => Promise; }; format: { /** Convert basic Markdown to safe HTML (bold, italic, inline code, line breaks). */ markdown: typeof renderMarkdown; /** Escape arbitrary text so it is safe to inject into innerHTML. */ sanitize: (html: string) => string; }; } declare class WorldbookModule { private rpc; constructor(rpc: RpcEngine); /** 获取当前会话所有世界书条目状态 */ getAll(): Promise; /** 启用某个条目 */ enable(entryKey: string): Promise; /** 禁用某个条目 */ disable(entryKey: string): Promise; /** 批量设置多个条目启用状态 */ batchToggle(entries: Array<{ entryKey: string; enabled: boolean; }>): Promise; /** 覆盖某个条目的内容(仅对当前会话有效) */ setContent(entryKey: string, content: string): Promise; /** 清除某个条目的内容覆盖(恢复模板内容) */ clearContent(entryKey: string): Promise; /** 重置所有覆盖(恢复全部条目到模板默认状态) */ reset(): Promise; } declare class CharxSdk { private static instance; private rpc; private _ready; private _chat?; private _character?; private _variable?; private _storage?; private _ui?; private _media?; private _game?; private _utils?; private _worldbook?; private constructor(); static getInstance(): CharxSdk; get isReady(): boolean; /** * Initialize the SDK. * Sends sdk.init to the platform and waits for a __charx_ready__ handshake * response containing a session token. All subsequent RPC calls carry this * token — the platform rejects calls from frames that skipped the handshake. * * Throws if the platform does not respond within 8 seconds (not embedded in * the platform, or running in a non-iframe context). */ init(): Promise; getRpc(): RpcEngine; get chat(): ChatModule; get character(): CharacterModule; get variable(): VariableModule; get storage(): StorageModule; get ui(): UIModule; get media(): MediaModule; get game(): GameModule; get utils(): UtilsModule; get worldbook(): WorldbookModule; } interface CharxProviderProps { children: ReactNode; /** Rendered while the SDK handshake is in progress */ fallback?: ReactNode; /** Rendered if SDK init fails (e.g. not inside the platform iframe) */ errorFallback?: (error: Error) => ReactNode; } declare function CharxProvider({ children, fallback, errorFallback }: CharxProviderProps): react_jsx_runtime.JSX.Element; declare function useCharx(): CharxSdk; declare function useChat(): UseChatReturn; declare function useVariable(key: string, defaultValue: T): [T, (v: T) => Promise]; declare function useVariables(): Record; declare function useCharacter(): CharacterInfo | null; declare function usePersona(): PersonaInfo | null; declare function useStorage(key: string, defaultValue: T): [T, (v: T) => Promise, () => Promise]; interface MessageListProps { messages: Message[]; onLoadMore?: () => void; renderMessage?: (message: Message, isStreaming: boolean) => React.ReactNode; isStreaming?: boolean; } declare function MessageItem({ message, isStreaming }: { message: Message; isStreaming?: boolean; }): react_jsx_runtime.JSX.Element; declare function MessageList({ messages, onLoadMore, renderMessage, isStreaming }: MessageListProps): react_jsx_runtime.JSX.Element; declare const Thread: { MessageList: typeof MessageList; MessageItem: typeof MessageItem; }; interface MdRendererProps { content: string; className?: string; style?: React.CSSProperties; } declare function MdRenderer({ content, className, style }: MdRendererProps): react_jsx_runtime.JSX.Element; export { CharxProvider, MdRenderer, Thread, useCharacter, useCharx, useChat, usePersona, useStorage, useVariable, useVariables };