@plucky-ai/chat-sdk 0.2.0 → 0.2.1
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/index.cjs +5 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -291,7 +291,7 @@ function createAPI() {
|
|
|
291
291
|
const storageKey = `pls::${state.appId}`;
|
|
292
292
|
if (typeof payload.token === "string" && payload.token) safeLocalStorageSet(storageKey, payload.token);
|
|
293
293
|
});
|
|
294
|
-
bus.on("PLUCKY_SET_FULLSCREEN", (payload) =>
|
|
294
|
+
bus.on("PLUCKY_SET_FULLSCREEN", (payload) => handleSetFullscreen(payload.fullscreen));
|
|
295
295
|
bus.on("PLUCKY_RESPONSE_RECEIVED", async (response) => {
|
|
296
296
|
const lastMessage = response.messages[response.messages.length - 1];
|
|
297
297
|
if (typeof lastMessage.content === "string") return;
|
|
@@ -405,6 +405,10 @@ function createAPI() {
|
|
|
405
405
|
sidebar.setWidth(px);
|
|
406
406
|
}
|
|
407
407
|
function setFullscreen(fullscreen) {
|
|
408
|
+
post("PLUCKY_SET_FULLSCREEN", { fullscreen });
|
|
409
|
+
handleSetFullscreen(fullscreen);
|
|
410
|
+
}
|
|
411
|
+
function handleSetFullscreen(fullscreen) {
|
|
408
412
|
state.fullscreen = fullscreen;
|
|
409
413
|
if (resizeListener) {
|
|
410
414
|
window.removeEventListener("resize", resizeListener);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["host: HTMLDivElement | null","iframe: HTMLIFrameElement | null","mode: Mode","widthPx: number | string","nonce: string | undefined","css","z","state: Required<PluckyAPIOptions>","currentMode: 'push' | 'overlay'","resizeListener: (() => void) | null","init","api","ZodObject","z","api: PluckyAPI","api: PluckyAPI | null"],"sources":["../src/bus.ts","../src/sidebar.ts","../src/utils.ts","../src/api.ts","../src/index.ts"],"sourcesContent":["import type { MessageType } from './types'\n\ntype Handler = (p: any) => void\n\nexport class Bus {\n private handlers = new Map<MessageType, Set<Handler>>()\n\n on(event: MessageType, cb: Handler) {\n if (!this.handlers.has(event)) this.handlers.set(event, new Set())\n this.handlers.get(event)!.add(cb)\n return () => this.handlers.get(event)!.delete(cb)\n }\n\n emit(event: MessageType, payload?: any) {\n this.handlers.get(event)?.forEach((h) => h(payload))\n }\n}\n\nexport function bindPostMessage(bus: Bus, win: Window, origin: string) {\n const onMsg = (e: MessageEvent) => {\n if (e.origin !== origin) return\n if (!e.data || typeof e.data !== 'object') return\n if (!('type' in e.data)) return\n bus.emit(e.data.type, e.data.payload)\n }\n win.addEventListener('message', onMsg)\n return () => win.removeEventListener('message', onMsg)\n}\n","export type Mode = 'push' | 'overlay'\n\nexport interface SidebarOpts {\n appId: string\n baseUrl: string\n widthPx?: number\n zIndex?: number\n idPrefix?: string\n nonce?: string\n iframeTitle?: string\n initialMode?: Mode // 'push' (default) or 'overlay'\n}\n\nexport interface SidebarAPI {\n mount: (opts: SidebarOpts) => void\n unmount: () => void\n setMode: (mode: Mode) => void\n setWidth: (px: number | string) => void\n setZIndex: (z: number) => void\n hide: () => void // NEW: hide container + remove padding, keep iframe loaded\n show: () => void // NEW: restore visibility + padding if mode==='push'\n isHidden: () => boolean\n getMode: () => Mode\n getContainer: () => HTMLDivElement | null\n getIframe: () => HTMLIFrameElement | null\n ready: () => boolean\n}\n\nexport function createSidebar(): SidebarAPI {\n let host: HTMLDivElement | null = null\n let iframe: HTMLIFrameElement | null = null\n let mounted = false\n let hidden = false\n let mode: Mode = 'push'\n let widthPx: number | string = 360\n let zIndex = 2147483646\n let idPrefix = 'plucky'\n let cssId = ''\n let hostId = ''\n let shiftClass = ''\n let hiddenClass = ''\n let nonce: string | undefined\n\n const ensureStyle = (css: string) => {\n let tag = document.getElementById(cssId) as HTMLStyleElement | null\n if (!tag) {\n tag = document.createElement('style')\n tag.id = cssId\n if (nonce) tag.setAttribute('nonce', nonce)\n document.head.appendChild(tag)\n }\n tag.textContent = css\n }\n\n const css = () => `\n:root { --${idPrefix}-w: ${widthPx}px; }\n\nbody.${shiftClass} {\n padding-inline-end: var(--${idPrefix}-w) !important;\n}\n\n/* Fixed sidebar; overlay vs push is just whether body has padding */\n#${hostId} {\n position: fixed;\n inset-block: 0;\n inset-inline-end: 0;\n width: var(--${idPrefix}-w);\n max-width: 100vw;\n z-index: ${zIndex};\n background: transparent;\n}\n#${hostId} > iframe { width: 100%; height: 100%; border: 0; display: block; }\n\n/* Hidden state: keep in DOM, don’t render or accept focus/clicks */\n#${hostId}.${hiddenClass} {\n display: none !important;\n}\n`\n\n function mount(opts: SidebarOpts) {\n if (mounted) return\n\n widthPx = opts.widthPx ?? widthPx\n zIndex = opts.zIndex ?? zIndex\n idPrefix = opts.idPrefix ?? idPrefix\n nonce = opts.nonce\n mode = opts.initialMode ?? mode\n\n hostId = `${idPrefix}-sidebar`\n cssId = `${idPrefix}-sidebar-css`\n shiftClass = `${idPrefix}-shift`\n hiddenClass = `${idPrefix}-hidden`\n\n ensureStyle(css())\n\n host = document.getElementById(hostId) as HTMLDivElement | null\n if (!host) {\n host = document.createElement('div')\n host.id = hostId\n host.style.zIndex = String(zIndex)\n document.body.appendChild(host)\n }\n\n if (!iframe) {\n iframe = document.createElement('iframe')\n iframe.title = opts.iframeTitle ?? 'Plucky'\n iframe.setAttribute('aria-label', iframe.title)\n const base = opts.baseUrl.replace(/\\/$/, '')\n iframe.src = `${base}/widget/${encodeURIComponent(opts.appId)}`\n host.appendChild(iframe)\n }\n\n // Apply current visibility + mode\n if (hidden) host.classList.add(hiddenClass)\n else host.classList.remove(hiddenClass)\n\n if (!hidden && mode === 'push') document.body.classList.add(shiftClass)\n else document.body.classList.remove(shiftClass)\n\n mounted = true\n }\n\n function unmount() {\n if (!mounted) return\n document.body.classList.remove(shiftClass)\n host?.remove()\n document.getElementById(cssId)?.remove()\n host = null\n iframe = null\n mounted = false\n hidden = false\n }\n\n function setMode(next: Mode) {\n mode = next\n if (!mounted) return\n if (!hidden && mode === 'push') document.body.classList.add(shiftClass)\n else document.body.classList.remove(shiftClass)\n }\n\n function setWidth(width: number | string) {\n const widthCssValue =\n typeof width === 'number' ? `${Math.max(0, Math.round(width))}px` : width\n document.documentElement.style.setProperty(`--${idPrefix}-w`, widthCssValue)\n }\n\n function setZIndex(z: number) {\n zIndex = z\n if (host) host.style.zIndex = String(zIndex)\n }\n\n function hide() {\n if (!mounted || hidden) return\n hidden = true\n // Remove page padding if present\n document.body.classList.remove(shiftClass)\n // Hide the host container without unmounting the iframe\n host?.classList.add(hiddenClass)\n if (host) {\n host.setAttribute('aria-hidden', 'true')\n // Disable interactivity for assistive tech even if CSS changes\n ;(host as any).inert = true // harmless if not supported\n }\n // Optional: signal iframe to pause work\n iframe?.contentWindow?.postMessage(\n { type: 'PLUCKY_VISIBILITY', payload: 'hidden' },\n '*',\n )\n }\n\n function show() {\n if (!mounted || !hidden) return\n hidden = false\n host?.classList.remove(hiddenClass)\n if (host) {\n host.removeAttribute('aria-hidden')\n try {\n ;(host as any).inert = false\n } catch {}\n }\n if (mode === 'push') document.body.classList.add(shiftClass)\n iframe?.contentWindow?.postMessage(\n { type: 'PLUCKY_VISIBILITY', payload: 'visible' },\n '*',\n )\n }\n\n return {\n mount,\n unmount,\n setMode,\n setWidth,\n setZIndex,\n hide,\n show,\n isHidden: () => hidden,\n getMode: () => mode,\n getContainer: () => host,\n getIframe: () => iframe,\n ready: () => !!iframe?.contentWindow,\n }\n}\n","export function safeLocalStorageGet(key: string): string | null {\n try {\n return window.localStorage.getItem(key)\n } catch {\n return null\n }\n}\n\nexport function safeLocalStorageSet(key: string, value: string): void {\n try {\n window.localStorage.setItem(key, value)\n } catch {}\n}\n","import type {\n SavedMessage,\n ToolResultContentBlock,\n} from '@plucky-ai/llm-schemas'\nimport { dequal } from 'dequal'\nimport { ZodObject, z } from 'zod'\nimport { Bus, bindPostMessage } from './bus'\nimport { createSidebar } from './sidebar'\nimport type {\n InitOptions,\n MessageType,\n Mode,\n PluckyAPI,\n PluckyAPIOptions,\n SimpleToolConfig,\n ToolConfig,\n} from './types'\nimport { safeLocalStorageGet, safeLocalStorageSet } from './utils'\n\nexport function createAPI(): PluckyAPI {\n const bus = new Bus()\n let inited = false\n\n // Layout controllers\n const sidebar = createSidebar()\n\n // runtime state with sane defaults\n let state: Required<PluckyAPIOptions> = {\n appId: '',\n baseUrl: 'https://widget.plucky.ai',\n mode: 'push',\n containerId: undefined as unknown as string,\n user: {},\n tools: [],\n tags: [],\n width: 360,\n fullscreen: false,\n }\n\n // Track current mode and last mount options\n let currentMode: 'push' | 'overlay' = 'push'\n\n // Track resize listener for fullscreen mode\n let resizeListener: (() => void) | null = null\n\n // Helper to calculate scrollbar width\n function getScrollbarWidth(): number {\n return window.innerWidth - document.documentElement.clientWidth\n }\n\n // Helper to get fullscreen width CSS value accounting for scrollbar\n function getFullscreenWidth(): string {\n const scrollbarWidth = getScrollbarWidth()\n return scrollbarWidth > 0 ? `calc(100vw - ${scrollbarWidth}px)` : '100vw'\n }\n\n // Sidebar is the single DOM/layout owner; we post directly to its iframe\n function post(type: MessageType, payload?: any) {\n const iframe = sidebar.getIframe()\n const targetOrigin = new URL(state.baseUrl).origin\n iframe?.contentWindow?.postMessage({ type, payload }, targetOrigin)\n }\n\n function switchMode(next: 'push' | 'overlay') {\n if (next === currentMode) return\n\n // Just switch mode on the single layout\n sidebar.setMode(next)\n currentMode = next\n }\n\n function init(opts: InitOptions): PluckyAPI {\n if (inited) return api\n const { tools, ...rest } = opts\n state = { ...state, ...rest } as Required<PluckyAPIOptions>\n if (tools && tools.length > 0) {\n registerManyTools(tools, false)\n }\n currentMode = state.mode as 'push' | 'overlay'\n bindPostMessage(bus, window, new URL(state.baseUrl).origin)\n\n bus.on('PLUCKY_CLOSE', () => sidebar.hide())\n\n // Listen for iframe mount signal before sending boot\n bus.on('PLUCKY_WIDGET_MOUNTED', () => {\n const storageKey = `pls::${state.appId}`\n const existingToken = safeLocalStorageGet(storageKey)\n post('PLUCKY_LOAD_CONFIG', {\n appId: state.appId,\n user: state.user,\n mode: state.mode,\n sessionToken: existingToken || undefined,\n tools: getAllToolJSON(),\n tags: state.tags,\n })\n if (!existingToken) {\n post('PLUCKY_SESSION_REQUEST', { reason: 'missing' })\n }\n })\n\n // Mount the sidebar (creates iframe inside it)\n sidebar.mount({\n appId: state.appId,\n baseUrl: state.baseUrl,\n iframeTitle: 'Plucky',\n initialMode: currentMode,\n widthPx: state.width,\n })\n\n // Wire bus-driven layout changes to the sidebar\n bus.on('PLUCKY_SET_WIDTH', (px: number) => sidebar.setWidth(px))\n bus.on('PLUCKY_SWITCH_MODE', (m: Mode) => setMode(m))\n bus.on('PLUCKY_SESSION_UPDATED', (payload: { token?: string }) => {\n const storageKey = `pls::${state.appId}`\n if (typeof payload.token === 'string' && payload.token) {\n safeLocalStorageSet(storageKey, payload.token)\n }\n })\n bus.on('PLUCKY_SET_FULLSCREEN', (payload: { fullscreen: boolean }) =>\n setFullscreen(payload.fullscreen),\n )\n bus.on(\n 'PLUCKY_RESPONSE_RECEIVED',\n async (response: { messages: Array<SavedMessage>; chatId: string }) => {\n const lastMessage = response.messages[response.messages.length - 1]\n if (typeof lastMessage.content === 'string') return\n const toolResultIds = lastMessage.content\n .filter((m) => m.type === 'tool_result')\n .map((m) => m.toolUseId)\n const unfulfilledToolCalls = lastMessage.content\n .filter((m) => m.type === 'tool_use')\n .filter((m) => !toolResultIds.includes(m.id))\n if (unfulfilledToolCalls.length === 0) return\n const promises = unfulfilledToolCalls.map(\n async (toolCall): Promise<ToolResultContentBlock> => {\n const tool = state.tools.find((t) => t.name === toolCall.name)\n if (!tool) {\n return {\n toolUseId: toolCall.id,\n content: 'Tool not found.',\n type: 'tool_result',\n }\n }\n if (!tool.cb) {\n return {\n toolUseId: toolCall.id,\n content: 'Received.',\n type: 'tool_result',\n }\n }\n try {\n let input = toolCall.input as Record<string, unknown> | string\n if (typeof input === 'string') {\n input = JSON.parse(input) as Record<string, unknown>\n }\n const result = await tool.cb(input)\n return {\n toolUseId: toolCall.id,\n content: result,\n type: 'tool_result',\n }\n } catch (e) {\n return {\n toolUseId: toolCall.id,\n content: `Error: ${e instanceof Error ? e.message : String(e)}`,\n type: 'tool_result',\n }\n }\n },\n )\n\n const results = await Promise.all(promises)\n sendMessage({\n content: results,\n lastMessageId: lastMessage.id,\n chatId: response.chatId,\n })\n },\n )\n\n // Wait for iframe to signal it's ready before sending boot\n inited = true\n return api\n }\n\n function sendMessage(args: {\n content: string | Array<ToolResultContentBlock>\n lastMessageId?: string\n createChat?: boolean\n chatId?: string\n }) {\n const { content, lastMessageId, createChat, chatId } = args\n if (sidebar.isHidden()) {\n sidebar.show()\n }\n post('PLUCKY_SEND_MESSAGE', {\n content,\n createChat: createChat ?? false,\n lastMessageId,\n chatId,\n })\n }\n function setInput(input: string) {\n sidebar.getIframe()?.contentWindow?.focus()\n post('PLUCKY_SET_INPUT', { input })\n }\n\n function setMode(mode: Mode) {\n state.mode = mode\n currentMode = mode as 'push' | 'overlay'\n sidebar.setMode(mode)\n post('PLUCKY_SWITCH_MODE', mode)\n }\n\n function on(event: MessageType, cb: (p: any) => void) {\n return bus.on(event, cb)\n }\n\n function open() {\n sidebar.show()\n }\n\n function close() {\n sidebar.hide()\n }\n\n function toggle() {\n if (sidebar.isHidden()) {\n sidebar.show()\n } else {\n sidebar.hide()\n }\n }\n\n function registerTool(tool: ToolConfig, notify = true) {\n const currentToolState = getAllToolJSON()\n if (state.tools.find((t) => t.name === tool.name)) {\n state.tools = state.tools.filter((t) => t.name !== tool.name)\n }\n state.tools.push(tool)\n state.tools.sort((a, b) => a.name.localeCompare(b.name))\n const newToolState = getAllToolJSON()\n if (notify && !dequal(currentToolState, newToolState)) {\n notifyToolConfigUpdated()\n }\n }\n function registerManyTools(tools: Array<ToolConfig>, notify = true) {\n const currentToolState = getAllToolJSON()\n for (const tool of tools) {\n registerTool(tool, false)\n }\n const newToolState = getAllToolJSON()\n if (notify && !dequal(currentToolState, newToolState)) {\n notifyToolConfigUpdated()\n }\n }\n function removeTool(name: string, notify = true) {\n if (!state.tools.find((t) => t.name === name)) {\n console.warn(`Tool ${name} not found, skipping.`)\n }\n state.tools = state.tools.filter((t) => t.name !== name)\n if (notify) {\n notifyToolConfigUpdated()\n }\n }\n\n function notifyToolConfigUpdated() {\n post('PLUCKY_TOOL_CONFIG_UPDATED', { tools: getAllToolJSON() })\n }\n\n function getAllToolJSON(): Array<SimpleToolConfig> {\n return state.tools.map((t) => ({\n name: t.name,\n description: t.description,\n defaultLoadingText: t.defaultLoadingText,\n defaultSuccessText: t.defaultSuccessText,\n inputSchema:\n t.inputSchema instanceof ZodObject\n ? z.toJSONSchema(t.inputSchema)\n : t.inputSchema,\n }))\n }\n\n function setWidth(px: number) {\n state.width = px\n sidebar.setWidth(px)\n }\n\n function setFullscreen(fullscreen: boolean) {\n state.fullscreen = fullscreen\n\n // Clean up existing resize listener if any\n if (resizeListener) {\n window.removeEventListener('resize', resizeListener)\n resizeListener = null\n }\n\n if (fullscreen) {\n // Use CSS calc to account for scrollbar width, which stays responsive on resize\n sidebar.setWidth(getFullscreenWidth())\n sidebar.setMode('overlay')\n\n // Add resize listener to update width if scrollbar appears/disappears\n resizeListener = () => {\n if (state.fullscreen) {\n sidebar.setWidth(getFullscreenWidth())\n }\n }\n window.addEventListener('resize', resizeListener)\n } else {\n sidebar.setWidth(state.width)\n sidebar.setMode('push')\n }\n }\n\n const api: PluckyAPI = {\n init,\n setMode,\n switchMode,\n open,\n close,\n toggle,\n on,\n isReady: () => sidebar.ready(),\n sendMessage,\n isOpen: () => !sidebar.isHidden(),\n registerTool,\n registerManyTools,\n removeTool,\n setInput,\n setWidth,\n setFullscreen,\n }\n return api\n}\n","import { createAPI } from './api'\nimport type { InitOptions, PluckyAPI } from './types'\n\n// singleton exported API for convenience\nlet api: PluckyAPI | null = null\n\nexport function init(opts: InitOptions) {\n if (!api) api = createAPI()\n return api.init(opts)\n}\n\nexport function getAPI() {\n if (!api) api = createAPI()\n return api\n}\n\n// convenience re-exports\nexport type * from './types'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["host: HTMLDivElement | null","iframe: HTMLIFrameElement | null","mode: Mode","widthPx: number | string","nonce: string | undefined","css","z","state: Required<PluckyAPIOptions>","currentMode: 'push' | 'overlay'","resizeListener: (() => void) | null","init","api","ZodObject","z","api: PluckyAPI","api: PluckyAPI | null"],"sources":["../src/bus.ts","../src/sidebar.ts","../src/utils.ts","../src/api.ts","../src/index.ts"],"sourcesContent":["import type { MessageType } from './types'\n\ntype Handler = (p: any) => void\n\nexport class Bus {\n private handlers = new Map<MessageType, Set<Handler>>()\n\n on(event: MessageType, cb: Handler) {\n if (!this.handlers.has(event)) this.handlers.set(event, new Set())\n this.handlers.get(event)!.add(cb)\n return () => this.handlers.get(event)!.delete(cb)\n }\n\n emit(event: MessageType, payload?: any) {\n this.handlers.get(event)?.forEach((h) => h(payload))\n }\n}\n\nexport function bindPostMessage(bus: Bus, win: Window, origin: string) {\n const onMsg = (e: MessageEvent) => {\n if (e.origin !== origin) return\n if (!e.data || typeof e.data !== 'object') return\n if (!('type' in e.data)) return\n bus.emit(e.data.type, e.data.payload)\n }\n win.addEventListener('message', onMsg)\n return () => win.removeEventListener('message', onMsg)\n}\n","export type Mode = 'push' | 'overlay'\n\nexport interface SidebarOpts {\n appId: string\n baseUrl: string\n widthPx?: number\n zIndex?: number\n idPrefix?: string\n nonce?: string\n iframeTitle?: string\n initialMode?: Mode // 'push' (default) or 'overlay'\n}\n\nexport interface SidebarAPI {\n mount: (opts: SidebarOpts) => void\n unmount: () => void\n setMode: (mode: Mode) => void\n setWidth: (px: number | string) => void\n setZIndex: (z: number) => void\n hide: () => void // NEW: hide container + remove padding, keep iframe loaded\n show: () => void // NEW: restore visibility + padding if mode==='push'\n isHidden: () => boolean\n getMode: () => Mode\n getContainer: () => HTMLDivElement | null\n getIframe: () => HTMLIFrameElement | null\n ready: () => boolean\n}\n\nexport function createSidebar(): SidebarAPI {\n let host: HTMLDivElement | null = null\n let iframe: HTMLIFrameElement | null = null\n let mounted = false\n let hidden = false\n let mode: Mode = 'push'\n let widthPx: number | string = 360\n let zIndex = 2147483646\n let idPrefix = 'plucky'\n let cssId = ''\n let hostId = ''\n let shiftClass = ''\n let hiddenClass = ''\n let nonce: string | undefined\n\n const ensureStyle = (css: string) => {\n let tag = document.getElementById(cssId) as HTMLStyleElement | null\n if (!tag) {\n tag = document.createElement('style')\n tag.id = cssId\n if (nonce) tag.setAttribute('nonce', nonce)\n document.head.appendChild(tag)\n }\n tag.textContent = css\n }\n\n const css = () => `\n:root { --${idPrefix}-w: ${widthPx}px; }\n\nbody.${shiftClass} {\n padding-inline-end: var(--${idPrefix}-w) !important;\n}\n\n/* Fixed sidebar; overlay vs push is just whether body has padding */\n#${hostId} {\n position: fixed;\n inset-block: 0;\n inset-inline-end: 0;\n width: var(--${idPrefix}-w);\n max-width: 100vw;\n z-index: ${zIndex};\n background: transparent;\n}\n#${hostId} > iframe { width: 100%; height: 100%; border: 0; display: block; }\n\n/* Hidden state: keep in DOM, don’t render or accept focus/clicks */\n#${hostId}.${hiddenClass} {\n display: none !important;\n}\n`\n\n function mount(opts: SidebarOpts) {\n if (mounted) return\n\n widthPx = opts.widthPx ?? widthPx\n zIndex = opts.zIndex ?? zIndex\n idPrefix = opts.idPrefix ?? idPrefix\n nonce = opts.nonce\n mode = opts.initialMode ?? mode\n\n hostId = `${idPrefix}-sidebar`\n cssId = `${idPrefix}-sidebar-css`\n shiftClass = `${idPrefix}-shift`\n hiddenClass = `${idPrefix}-hidden`\n\n ensureStyle(css())\n\n host = document.getElementById(hostId) as HTMLDivElement | null\n if (!host) {\n host = document.createElement('div')\n host.id = hostId\n host.style.zIndex = String(zIndex)\n document.body.appendChild(host)\n }\n\n if (!iframe) {\n iframe = document.createElement('iframe')\n iframe.title = opts.iframeTitle ?? 'Plucky'\n iframe.setAttribute('aria-label', iframe.title)\n const base = opts.baseUrl.replace(/\\/$/, '')\n iframe.src = `${base}/widget/${encodeURIComponent(opts.appId)}`\n host.appendChild(iframe)\n }\n\n // Apply current visibility + mode\n if (hidden) host.classList.add(hiddenClass)\n else host.classList.remove(hiddenClass)\n\n if (!hidden && mode === 'push') document.body.classList.add(shiftClass)\n else document.body.classList.remove(shiftClass)\n\n mounted = true\n }\n\n function unmount() {\n if (!mounted) return\n document.body.classList.remove(shiftClass)\n host?.remove()\n document.getElementById(cssId)?.remove()\n host = null\n iframe = null\n mounted = false\n hidden = false\n }\n\n function setMode(next: Mode) {\n mode = next\n if (!mounted) return\n if (!hidden && mode === 'push') document.body.classList.add(shiftClass)\n else document.body.classList.remove(shiftClass)\n }\n\n function setWidth(width: number | string) {\n const widthCssValue =\n typeof width === 'number' ? `${Math.max(0, Math.round(width))}px` : width\n document.documentElement.style.setProperty(`--${idPrefix}-w`, widthCssValue)\n }\n\n function setZIndex(z: number) {\n zIndex = z\n if (host) host.style.zIndex = String(zIndex)\n }\n\n function hide() {\n if (!mounted || hidden) return\n hidden = true\n // Remove page padding if present\n document.body.classList.remove(shiftClass)\n // Hide the host container without unmounting the iframe\n host?.classList.add(hiddenClass)\n if (host) {\n host.setAttribute('aria-hidden', 'true')\n // Disable interactivity for assistive tech even if CSS changes\n ;(host as any).inert = true // harmless if not supported\n }\n // Optional: signal iframe to pause work\n iframe?.contentWindow?.postMessage(\n { type: 'PLUCKY_VISIBILITY', payload: 'hidden' },\n '*',\n )\n }\n\n function show() {\n if (!mounted || !hidden) return\n hidden = false\n host?.classList.remove(hiddenClass)\n if (host) {\n host.removeAttribute('aria-hidden')\n try {\n ;(host as any).inert = false\n } catch {}\n }\n if (mode === 'push') document.body.classList.add(shiftClass)\n iframe?.contentWindow?.postMessage(\n { type: 'PLUCKY_VISIBILITY', payload: 'visible' },\n '*',\n )\n }\n\n return {\n mount,\n unmount,\n setMode,\n setWidth,\n setZIndex,\n hide,\n show,\n isHidden: () => hidden,\n getMode: () => mode,\n getContainer: () => host,\n getIframe: () => iframe,\n ready: () => !!iframe?.contentWindow,\n }\n}\n","export function safeLocalStorageGet(key: string): string | null {\n try {\n return window.localStorage.getItem(key)\n } catch {\n return null\n }\n}\n\nexport function safeLocalStorageSet(key: string, value: string): void {\n try {\n window.localStorage.setItem(key, value)\n } catch {}\n}\n","import type {\n SavedMessage,\n ToolResultContentBlock,\n} from '@plucky-ai/llm-schemas'\nimport { dequal } from 'dequal'\nimport { ZodObject, z } from 'zod'\nimport { Bus, bindPostMessage } from './bus'\nimport { createSidebar } from './sidebar'\nimport type {\n InitOptions,\n MessageType,\n Mode,\n PluckyAPI,\n PluckyAPIOptions,\n SimpleToolConfig,\n ToolConfig,\n} from './types'\nimport { safeLocalStorageGet, safeLocalStorageSet } from './utils'\n\nexport function createAPI(): PluckyAPI {\n const bus = new Bus()\n let inited = false\n\n // Layout controllers\n const sidebar = createSidebar()\n\n // runtime state with sane defaults\n let state: Required<PluckyAPIOptions> = {\n appId: '',\n baseUrl: 'https://widget.plucky.ai',\n mode: 'push',\n containerId: undefined as unknown as string,\n user: {},\n tools: [],\n tags: [],\n width: 360,\n fullscreen: false,\n }\n\n // Track current mode and last mount options\n let currentMode: 'push' | 'overlay' = 'push'\n\n // Track resize listener for fullscreen mode\n let resizeListener: (() => void) | null = null\n\n // Helper to calculate scrollbar width\n function getScrollbarWidth(): number {\n return window.innerWidth - document.documentElement.clientWidth\n }\n\n // Helper to get fullscreen width CSS value accounting for scrollbar\n function getFullscreenWidth(): string {\n const scrollbarWidth = getScrollbarWidth()\n return scrollbarWidth > 0 ? `calc(100vw - ${scrollbarWidth}px)` : '100vw'\n }\n\n // Sidebar is the single DOM/layout owner; we post directly to its iframe\n function post(type: MessageType, payload?: any) {\n const iframe = sidebar.getIframe()\n const targetOrigin = new URL(state.baseUrl).origin\n iframe?.contentWindow?.postMessage({ type, payload }, targetOrigin)\n }\n\n function switchMode(next: 'push' | 'overlay') {\n if (next === currentMode) return\n\n // Just switch mode on the single layout\n sidebar.setMode(next)\n currentMode = next\n }\n\n function init(opts: InitOptions): PluckyAPI {\n if (inited) return api\n const { tools, ...rest } = opts\n state = { ...state, ...rest } as Required<PluckyAPIOptions>\n if (tools && tools.length > 0) {\n registerManyTools(tools, false)\n }\n currentMode = state.mode as 'push' | 'overlay'\n bindPostMessage(bus, window, new URL(state.baseUrl).origin)\n\n bus.on('PLUCKY_CLOSE', () => sidebar.hide())\n\n // Listen for iframe mount signal before sending boot\n bus.on('PLUCKY_WIDGET_MOUNTED', () => {\n const storageKey = `pls::${state.appId}`\n const existingToken = safeLocalStorageGet(storageKey)\n post('PLUCKY_LOAD_CONFIG', {\n appId: state.appId,\n user: state.user,\n mode: state.mode,\n sessionToken: existingToken || undefined,\n tools: getAllToolJSON(),\n tags: state.tags,\n })\n if (!existingToken) {\n post('PLUCKY_SESSION_REQUEST', { reason: 'missing' })\n }\n })\n\n // Mount the sidebar (creates iframe inside it)\n sidebar.mount({\n appId: state.appId,\n baseUrl: state.baseUrl,\n iframeTitle: 'Plucky',\n initialMode: currentMode,\n widthPx: state.width,\n })\n\n // Wire bus-driven layout changes to the sidebar\n bus.on('PLUCKY_SET_WIDTH', (px: number) => sidebar.setWidth(px))\n bus.on('PLUCKY_SWITCH_MODE', (m: Mode) => setMode(m))\n bus.on('PLUCKY_SESSION_UPDATED', (payload: { token?: string }) => {\n const storageKey = `pls::${state.appId}`\n if (typeof payload.token === 'string' && payload.token) {\n safeLocalStorageSet(storageKey, payload.token)\n }\n })\n bus.on('PLUCKY_SET_FULLSCREEN', (payload: { fullscreen: boolean }) =>\n handleSetFullscreen(payload.fullscreen),\n )\n bus.on(\n 'PLUCKY_RESPONSE_RECEIVED',\n async (response: { messages: Array<SavedMessage>; chatId: string }) => {\n const lastMessage = response.messages[response.messages.length - 1]\n if (typeof lastMessage.content === 'string') return\n const toolResultIds = lastMessage.content\n .filter((m) => m.type === 'tool_result')\n .map((m) => m.toolUseId)\n const unfulfilledToolCalls = lastMessage.content\n .filter((m) => m.type === 'tool_use')\n .filter((m) => !toolResultIds.includes(m.id))\n if (unfulfilledToolCalls.length === 0) return\n const promises = unfulfilledToolCalls.map(\n async (toolCall): Promise<ToolResultContentBlock> => {\n const tool = state.tools.find((t) => t.name === toolCall.name)\n if (!tool) {\n return {\n toolUseId: toolCall.id,\n content: 'Tool not found.',\n type: 'tool_result',\n }\n }\n if (!tool.cb) {\n return {\n toolUseId: toolCall.id,\n content: 'Received.',\n type: 'tool_result',\n }\n }\n try {\n let input = toolCall.input as Record<string, unknown> | string\n if (typeof input === 'string') {\n input = JSON.parse(input) as Record<string, unknown>\n }\n const result = await tool.cb(input)\n return {\n toolUseId: toolCall.id,\n content: result,\n type: 'tool_result',\n }\n } catch (e) {\n return {\n toolUseId: toolCall.id,\n content: `Error: ${e instanceof Error ? e.message : String(e)}`,\n type: 'tool_result',\n }\n }\n },\n )\n\n const results = await Promise.all(promises)\n sendMessage({\n content: results,\n lastMessageId: lastMessage.id,\n chatId: response.chatId,\n })\n },\n )\n\n // Wait for iframe to signal it's ready before sending boot\n inited = true\n return api\n }\n\n function sendMessage(args: {\n content: string | Array<ToolResultContentBlock>\n lastMessageId?: string\n createChat?: boolean\n chatId?: string\n }) {\n const { content, lastMessageId, createChat, chatId } = args\n if (sidebar.isHidden()) {\n sidebar.show()\n }\n post('PLUCKY_SEND_MESSAGE', {\n content,\n createChat: createChat ?? false,\n lastMessageId,\n chatId,\n })\n }\n function setInput(input: string) {\n sidebar.getIframe()?.contentWindow?.focus()\n post('PLUCKY_SET_INPUT', { input })\n }\n\n function setMode(mode: Mode) {\n state.mode = mode\n currentMode = mode as 'push' | 'overlay'\n sidebar.setMode(mode)\n post('PLUCKY_SWITCH_MODE', mode)\n }\n\n function on(event: MessageType, cb: (p: any) => void) {\n return bus.on(event, cb)\n }\n\n function open() {\n sidebar.show()\n }\n\n function close() {\n sidebar.hide()\n }\n\n function toggle() {\n if (sidebar.isHidden()) {\n sidebar.show()\n } else {\n sidebar.hide()\n }\n }\n\n function registerTool(tool: ToolConfig, notify = true) {\n const currentToolState = getAllToolJSON()\n if (state.tools.find((t) => t.name === tool.name)) {\n state.tools = state.tools.filter((t) => t.name !== tool.name)\n }\n state.tools.push(tool)\n state.tools.sort((a, b) => a.name.localeCompare(b.name))\n const newToolState = getAllToolJSON()\n if (notify && !dequal(currentToolState, newToolState)) {\n notifyToolConfigUpdated()\n }\n }\n function registerManyTools(tools: Array<ToolConfig>, notify = true) {\n const currentToolState = getAllToolJSON()\n for (const tool of tools) {\n registerTool(tool, false)\n }\n const newToolState = getAllToolJSON()\n if (notify && !dequal(currentToolState, newToolState)) {\n notifyToolConfigUpdated()\n }\n }\n function removeTool(name: string, notify = true) {\n if (!state.tools.find((t) => t.name === name)) {\n console.warn(`Tool ${name} not found, skipping.`)\n }\n state.tools = state.tools.filter((t) => t.name !== name)\n if (notify) {\n notifyToolConfigUpdated()\n }\n }\n\n function notifyToolConfigUpdated() {\n post('PLUCKY_TOOL_CONFIG_UPDATED', { tools: getAllToolJSON() })\n }\n\n function getAllToolJSON(): Array<SimpleToolConfig> {\n return state.tools.map((t) => ({\n name: t.name,\n description: t.description,\n defaultLoadingText: t.defaultLoadingText,\n defaultSuccessText: t.defaultSuccessText,\n inputSchema:\n t.inputSchema instanceof ZodObject\n ? z.toJSONSchema(t.inputSchema)\n : t.inputSchema,\n }))\n }\n\n function setWidth(px: number) {\n state.width = px\n sidebar.setWidth(px)\n }\n\n function setFullscreen(fullscreen: boolean) {\n post('PLUCKY_SET_FULLSCREEN', { fullscreen })\n handleSetFullscreen(fullscreen)\n }\n\n function handleSetFullscreen(fullscreen: boolean) {\n state.fullscreen = fullscreen\n\n // Clean up existing resize listener if any\n if (resizeListener) {\n window.removeEventListener('resize', resizeListener)\n resizeListener = null\n }\n\n if (fullscreen) {\n // Use CSS calc to account for scrollbar width, which stays responsive on resize\n sidebar.setWidth(getFullscreenWidth())\n sidebar.setMode('overlay')\n\n // Add resize listener to update width if scrollbar appears/disappears\n resizeListener = () => {\n if (state.fullscreen) {\n sidebar.setWidth(getFullscreenWidth())\n }\n }\n window.addEventListener('resize', resizeListener)\n } else {\n sidebar.setWidth(state.width)\n sidebar.setMode('push')\n }\n }\n\n const api: PluckyAPI = {\n init,\n setMode,\n switchMode,\n open,\n close,\n toggle,\n on,\n isReady: () => sidebar.ready(),\n sendMessage,\n isOpen: () => !sidebar.isHidden(),\n registerTool,\n registerManyTools,\n removeTool,\n setInput,\n setWidth,\n setFullscreen,\n }\n return api\n}\n","import { createAPI } from './api'\nimport type { InitOptions, PluckyAPI } from './types'\n\n// singleton exported API for convenience\nlet api: PluckyAPI | null = null\n\nexport function init(opts: InitOptions) {\n if (!api) api = createAPI()\n return api.init(opts)\n}\n\nexport function getAPI() {\n if (!api) api = createAPI()\n return api\n}\n\n// convenience re-exports\nexport type * from './types'\n"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -266,7 +266,7 @@ function createAPI() {
|
|
|
266
266
|
const storageKey = `pls::${state.appId}`;
|
|
267
267
|
if (typeof payload.token === "string" && payload.token) safeLocalStorageSet(storageKey, payload.token);
|
|
268
268
|
});
|
|
269
|
-
bus.on("PLUCKY_SET_FULLSCREEN", (payload) =>
|
|
269
|
+
bus.on("PLUCKY_SET_FULLSCREEN", (payload) => handleSetFullscreen(payload.fullscreen));
|
|
270
270
|
bus.on("PLUCKY_RESPONSE_RECEIVED", async (response) => {
|
|
271
271
|
const lastMessage = response.messages[response.messages.length - 1];
|
|
272
272
|
if (typeof lastMessage.content === "string") return;
|
|
@@ -380,6 +380,10 @@ function createAPI() {
|
|
|
380
380
|
sidebar.setWidth(px);
|
|
381
381
|
}
|
|
382
382
|
function setFullscreen(fullscreen) {
|
|
383
|
+
post("PLUCKY_SET_FULLSCREEN", { fullscreen });
|
|
384
|
+
handleSetFullscreen(fullscreen);
|
|
385
|
+
}
|
|
386
|
+
function handleSetFullscreen(fullscreen) {
|
|
383
387
|
state.fullscreen = fullscreen;
|
|
384
388
|
if (resizeListener) {
|
|
385
389
|
window.removeEventListener("resize", resizeListener);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["host: HTMLDivElement | null","iframe: HTMLIFrameElement | null","mode: Mode","widthPx: number | string","nonce: string | undefined","css","z","state: Required<PluckyAPIOptions>","currentMode: 'push' | 'overlay'","resizeListener: (() => void) | null","init","api","api: PluckyAPI","api: PluckyAPI | null"],"sources":["../src/bus.ts","../src/sidebar.ts","../src/utils.ts","../src/api.ts","../src/index.ts"],"sourcesContent":["import type { MessageType } from './types'\n\ntype Handler = (p: any) => void\n\nexport class Bus {\n private handlers = new Map<MessageType, Set<Handler>>()\n\n on(event: MessageType, cb: Handler) {\n if (!this.handlers.has(event)) this.handlers.set(event, new Set())\n this.handlers.get(event)!.add(cb)\n return () => this.handlers.get(event)!.delete(cb)\n }\n\n emit(event: MessageType, payload?: any) {\n this.handlers.get(event)?.forEach((h) => h(payload))\n }\n}\n\nexport function bindPostMessage(bus: Bus, win: Window, origin: string) {\n const onMsg = (e: MessageEvent) => {\n if (e.origin !== origin) return\n if (!e.data || typeof e.data !== 'object') return\n if (!('type' in e.data)) return\n bus.emit(e.data.type, e.data.payload)\n }\n win.addEventListener('message', onMsg)\n return () => win.removeEventListener('message', onMsg)\n}\n","export type Mode = 'push' | 'overlay'\n\nexport interface SidebarOpts {\n appId: string\n baseUrl: string\n widthPx?: number\n zIndex?: number\n idPrefix?: string\n nonce?: string\n iframeTitle?: string\n initialMode?: Mode // 'push' (default) or 'overlay'\n}\n\nexport interface SidebarAPI {\n mount: (opts: SidebarOpts) => void\n unmount: () => void\n setMode: (mode: Mode) => void\n setWidth: (px: number | string) => void\n setZIndex: (z: number) => void\n hide: () => void // NEW: hide container + remove padding, keep iframe loaded\n show: () => void // NEW: restore visibility + padding if mode==='push'\n isHidden: () => boolean\n getMode: () => Mode\n getContainer: () => HTMLDivElement | null\n getIframe: () => HTMLIFrameElement | null\n ready: () => boolean\n}\n\nexport function createSidebar(): SidebarAPI {\n let host: HTMLDivElement | null = null\n let iframe: HTMLIFrameElement | null = null\n let mounted = false\n let hidden = false\n let mode: Mode = 'push'\n let widthPx: number | string = 360\n let zIndex = 2147483646\n let idPrefix = 'plucky'\n let cssId = ''\n let hostId = ''\n let shiftClass = ''\n let hiddenClass = ''\n let nonce: string | undefined\n\n const ensureStyle = (css: string) => {\n let tag = document.getElementById(cssId) as HTMLStyleElement | null\n if (!tag) {\n tag = document.createElement('style')\n tag.id = cssId\n if (nonce) tag.setAttribute('nonce', nonce)\n document.head.appendChild(tag)\n }\n tag.textContent = css\n }\n\n const css = () => `\n:root { --${idPrefix}-w: ${widthPx}px; }\n\nbody.${shiftClass} {\n padding-inline-end: var(--${idPrefix}-w) !important;\n}\n\n/* Fixed sidebar; overlay vs push is just whether body has padding */\n#${hostId} {\n position: fixed;\n inset-block: 0;\n inset-inline-end: 0;\n width: var(--${idPrefix}-w);\n max-width: 100vw;\n z-index: ${zIndex};\n background: transparent;\n}\n#${hostId} > iframe { width: 100%; height: 100%; border: 0; display: block; }\n\n/* Hidden state: keep in DOM, don’t render or accept focus/clicks */\n#${hostId}.${hiddenClass} {\n display: none !important;\n}\n`\n\n function mount(opts: SidebarOpts) {\n if (mounted) return\n\n widthPx = opts.widthPx ?? widthPx\n zIndex = opts.zIndex ?? zIndex\n idPrefix = opts.idPrefix ?? idPrefix\n nonce = opts.nonce\n mode = opts.initialMode ?? mode\n\n hostId = `${idPrefix}-sidebar`\n cssId = `${idPrefix}-sidebar-css`\n shiftClass = `${idPrefix}-shift`\n hiddenClass = `${idPrefix}-hidden`\n\n ensureStyle(css())\n\n host = document.getElementById(hostId) as HTMLDivElement | null\n if (!host) {\n host = document.createElement('div')\n host.id = hostId\n host.style.zIndex = String(zIndex)\n document.body.appendChild(host)\n }\n\n if (!iframe) {\n iframe = document.createElement('iframe')\n iframe.title = opts.iframeTitle ?? 'Plucky'\n iframe.setAttribute('aria-label', iframe.title)\n const base = opts.baseUrl.replace(/\\/$/, '')\n iframe.src = `${base}/widget/${encodeURIComponent(opts.appId)}`\n host.appendChild(iframe)\n }\n\n // Apply current visibility + mode\n if (hidden) host.classList.add(hiddenClass)\n else host.classList.remove(hiddenClass)\n\n if (!hidden && mode === 'push') document.body.classList.add(shiftClass)\n else document.body.classList.remove(shiftClass)\n\n mounted = true\n }\n\n function unmount() {\n if (!mounted) return\n document.body.classList.remove(shiftClass)\n host?.remove()\n document.getElementById(cssId)?.remove()\n host = null\n iframe = null\n mounted = false\n hidden = false\n }\n\n function setMode(next: Mode) {\n mode = next\n if (!mounted) return\n if (!hidden && mode === 'push') document.body.classList.add(shiftClass)\n else document.body.classList.remove(shiftClass)\n }\n\n function setWidth(width: number | string) {\n const widthCssValue =\n typeof width === 'number' ? `${Math.max(0, Math.round(width))}px` : width\n document.documentElement.style.setProperty(`--${idPrefix}-w`, widthCssValue)\n }\n\n function setZIndex(z: number) {\n zIndex = z\n if (host) host.style.zIndex = String(zIndex)\n }\n\n function hide() {\n if (!mounted || hidden) return\n hidden = true\n // Remove page padding if present\n document.body.classList.remove(shiftClass)\n // Hide the host container without unmounting the iframe\n host?.classList.add(hiddenClass)\n if (host) {\n host.setAttribute('aria-hidden', 'true')\n // Disable interactivity for assistive tech even if CSS changes\n ;(host as any).inert = true // harmless if not supported\n }\n // Optional: signal iframe to pause work\n iframe?.contentWindow?.postMessage(\n { type: 'PLUCKY_VISIBILITY', payload: 'hidden' },\n '*',\n )\n }\n\n function show() {\n if (!mounted || !hidden) return\n hidden = false\n host?.classList.remove(hiddenClass)\n if (host) {\n host.removeAttribute('aria-hidden')\n try {\n ;(host as any).inert = false\n } catch {}\n }\n if (mode === 'push') document.body.classList.add(shiftClass)\n iframe?.contentWindow?.postMessage(\n { type: 'PLUCKY_VISIBILITY', payload: 'visible' },\n '*',\n )\n }\n\n return {\n mount,\n unmount,\n setMode,\n setWidth,\n setZIndex,\n hide,\n show,\n isHidden: () => hidden,\n getMode: () => mode,\n getContainer: () => host,\n getIframe: () => iframe,\n ready: () => !!iframe?.contentWindow,\n }\n}\n","export function safeLocalStorageGet(key: string): string | null {\n try {\n return window.localStorage.getItem(key)\n } catch {\n return null\n }\n}\n\nexport function safeLocalStorageSet(key: string, value: string): void {\n try {\n window.localStorage.setItem(key, value)\n } catch {}\n}\n","import type {\n SavedMessage,\n ToolResultContentBlock,\n} from '@plucky-ai/llm-schemas'\nimport { dequal } from 'dequal'\nimport { ZodObject, z } from 'zod'\nimport { Bus, bindPostMessage } from './bus'\nimport { createSidebar } from './sidebar'\nimport type {\n InitOptions,\n MessageType,\n Mode,\n PluckyAPI,\n PluckyAPIOptions,\n SimpleToolConfig,\n ToolConfig,\n} from './types'\nimport { safeLocalStorageGet, safeLocalStorageSet } from './utils'\n\nexport function createAPI(): PluckyAPI {\n const bus = new Bus()\n let inited = false\n\n // Layout controllers\n const sidebar = createSidebar()\n\n // runtime state with sane defaults\n let state: Required<PluckyAPIOptions> = {\n appId: '',\n baseUrl: 'https://widget.plucky.ai',\n mode: 'push',\n containerId: undefined as unknown as string,\n user: {},\n tools: [],\n tags: [],\n width: 360,\n fullscreen: false,\n }\n\n // Track current mode and last mount options\n let currentMode: 'push' | 'overlay' = 'push'\n\n // Track resize listener for fullscreen mode\n let resizeListener: (() => void) | null = null\n\n // Helper to calculate scrollbar width\n function getScrollbarWidth(): number {\n return window.innerWidth - document.documentElement.clientWidth\n }\n\n // Helper to get fullscreen width CSS value accounting for scrollbar\n function getFullscreenWidth(): string {\n const scrollbarWidth = getScrollbarWidth()\n return scrollbarWidth > 0 ? `calc(100vw - ${scrollbarWidth}px)` : '100vw'\n }\n\n // Sidebar is the single DOM/layout owner; we post directly to its iframe\n function post(type: MessageType, payload?: any) {\n const iframe = sidebar.getIframe()\n const targetOrigin = new URL(state.baseUrl).origin\n iframe?.contentWindow?.postMessage({ type, payload }, targetOrigin)\n }\n\n function switchMode(next: 'push' | 'overlay') {\n if (next === currentMode) return\n\n // Just switch mode on the single layout\n sidebar.setMode(next)\n currentMode = next\n }\n\n function init(opts: InitOptions): PluckyAPI {\n if (inited) return api\n const { tools, ...rest } = opts\n state = { ...state, ...rest } as Required<PluckyAPIOptions>\n if (tools && tools.length > 0) {\n registerManyTools(tools, false)\n }\n currentMode = state.mode as 'push' | 'overlay'\n bindPostMessage(bus, window, new URL(state.baseUrl).origin)\n\n bus.on('PLUCKY_CLOSE', () => sidebar.hide())\n\n // Listen for iframe mount signal before sending boot\n bus.on('PLUCKY_WIDGET_MOUNTED', () => {\n const storageKey = `pls::${state.appId}`\n const existingToken = safeLocalStorageGet(storageKey)\n post('PLUCKY_LOAD_CONFIG', {\n appId: state.appId,\n user: state.user,\n mode: state.mode,\n sessionToken: existingToken || undefined,\n tools: getAllToolJSON(),\n tags: state.tags,\n })\n if (!existingToken) {\n post('PLUCKY_SESSION_REQUEST', { reason: 'missing' })\n }\n })\n\n // Mount the sidebar (creates iframe inside it)\n sidebar.mount({\n appId: state.appId,\n baseUrl: state.baseUrl,\n iframeTitle: 'Plucky',\n initialMode: currentMode,\n widthPx: state.width,\n })\n\n // Wire bus-driven layout changes to the sidebar\n bus.on('PLUCKY_SET_WIDTH', (px: number) => sidebar.setWidth(px))\n bus.on('PLUCKY_SWITCH_MODE', (m: Mode) => setMode(m))\n bus.on('PLUCKY_SESSION_UPDATED', (payload: { token?: string }) => {\n const storageKey = `pls::${state.appId}`\n if (typeof payload.token === 'string' && payload.token) {\n safeLocalStorageSet(storageKey, payload.token)\n }\n })\n bus.on('PLUCKY_SET_FULLSCREEN', (payload: { fullscreen: boolean }) =>\n setFullscreen(payload.fullscreen),\n )\n bus.on(\n 'PLUCKY_RESPONSE_RECEIVED',\n async (response: { messages: Array<SavedMessage>; chatId: string }) => {\n const lastMessage = response.messages[response.messages.length - 1]\n if (typeof lastMessage.content === 'string') return\n const toolResultIds = lastMessage.content\n .filter((m) => m.type === 'tool_result')\n .map((m) => m.toolUseId)\n const unfulfilledToolCalls = lastMessage.content\n .filter((m) => m.type === 'tool_use')\n .filter((m) => !toolResultIds.includes(m.id))\n if (unfulfilledToolCalls.length === 0) return\n const promises = unfulfilledToolCalls.map(\n async (toolCall): Promise<ToolResultContentBlock> => {\n const tool = state.tools.find((t) => t.name === toolCall.name)\n if (!tool) {\n return {\n toolUseId: toolCall.id,\n content: 'Tool not found.',\n type: 'tool_result',\n }\n }\n if (!tool.cb) {\n return {\n toolUseId: toolCall.id,\n content: 'Received.',\n type: 'tool_result',\n }\n }\n try {\n let input = toolCall.input as Record<string, unknown> | string\n if (typeof input === 'string') {\n input = JSON.parse(input) as Record<string, unknown>\n }\n const result = await tool.cb(input)\n return {\n toolUseId: toolCall.id,\n content: result,\n type: 'tool_result',\n }\n } catch (e) {\n return {\n toolUseId: toolCall.id,\n content: `Error: ${e instanceof Error ? e.message : String(e)}`,\n type: 'tool_result',\n }\n }\n },\n )\n\n const results = await Promise.all(promises)\n sendMessage({\n content: results,\n lastMessageId: lastMessage.id,\n chatId: response.chatId,\n })\n },\n )\n\n // Wait for iframe to signal it's ready before sending boot\n inited = true\n return api\n }\n\n function sendMessage(args: {\n content: string | Array<ToolResultContentBlock>\n lastMessageId?: string\n createChat?: boolean\n chatId?: string\n }) {\n const { content, lastMessageId, createChat, chatId } = args\n if (sidebar.isHidden()) {\n sidebar.show()\n }\n post('PLUCKY_SEND_MESSAGE', {\n content,\n createChat: createChat ?? false,\n lastMessageId,\n chatId,\n })\n }\n function setInput(input: string) {\n sidebar.getIframe()?.contentWindow?.focus()\n post('PLUCKY_SET_INPUT', { input })\n }\n\n function setMode(mode: Mode) {\n state.mode = mode\n currentMode = mode as 'push' | 'overlay'\n sidebar.setMode(mode)\n post('PLUCKY_SWITCH_MODE', mode)\n }\n\n function on(event: MessageType, cb: (p: any) => void) {\n return bus.on(event, cb)\n }\n\n function open() {\n sidebar.show()\n }\n\n function close() {\n sidebar.hide()\n }\n\n function toggle() {\n if (sidebar.isHidden()) {\n sidebar.show()\n } else {\n sidebar.hide()\n }\n }\n\n function registerTool(tool: ToolConfig, notify = true) {\n const currentToolState = getAllToolJSON()\n if (state.tools.find((t) => t.name === tool.name)) {\n state.tools = state.tools.filter((t) => t.name !== tool.name)\n }\n state.tools.push(tool)\n state.tools.sort((a, b) => a.name.localeCompare(b.name))\n const newToolState = getAllToolJSON()\n if (notify && !dequal(currentToolState, newToolState)) {\n notifyToolConfigUpdated()\n }\n }\n function registerManyTools(tools: Array<ToolConfig>, notify = true) {\n const currentToolState = getAllToolJSON()\n for (const tool of tools) {\n registerTool(tool, false)\n }\n const newToolState = getAllToolJSON()\n if (notify && !dequal(currentToolState, newToolState)) {\n notifyToolConfigUpdated()\n }\n }\n function removeTool(name: string, notify = true) {\n if (!state.tools.find((t) => t.name === name)) {\n console.warn(`Tool ${name} not found, skipping.`)\n }\n state.tools = state.tools.filter((t) => t.name !== name)\n if (notify) {\n notifyToolConfigUpdated()\n }\n }\n\n function notifyToolConfigUpdated() {\n post('PLUCKY_TOOL_CONFIG_UPDATED', { tools: getAllToolJSON() })\n }\n\n function getAllToolJSON(): Array<SimpleToolConfig> {\n return state.tools.map((t) => ({\n name: t.name,\n description: t.description,\n defaultLoadingText: t.defaultLoadingText,\n defaultSuccessText: t.defaultSuccessText,\n inputSchema:\n t.inputSchema instanceof ZodObject\n ? z.toJSONSchema(t.inputSchema)\n : t.inputSchema,\n }))\n }\n\n function setWidth(px: number) {\n state.width = px\n sidebar.setWidth(px)\n }\n\n function setFullscreen(fullscreen: boolean) {\n state.fullscreen = fullscreen\n\n // Clean up existing resize listener if any\n if (resizeListener) {\n window.removeEventListener('resize', resizeListener)\n resizeListener = null\n }\n\n if (fullscreen) {\n // Use CSS calc to account for scrollbar width, which stays responsive on resize\n sidebar.setWidth(getFullscreenWidth())\n sidebar.setMode('overlay')\n\n // Add resize listener to update width if scrollbar appears/disappears\n resizeListener = () => {\n if (state.fullscreen) {\n sidebar.setWidth(getFullscreenWidth())\n }\n }\n window.addEventListener('resize', resizeListener)\n } else {\n sidebar.setWidth(state.width)\n sidebar.setMode('push')\n }\n }\n\n const api: PluckyAPI = {\n init,\n setMode,\n switchMode,\n open,\n close,\n toggle,\n on,\n isReady: () => sidebar.ready(),\n sendMessage,\n isOpen: () => !sidebar.isHidden(),\n registerTool,\n registerManyTools,\n removeTool,\n setInput,\n setWidth,\n setFullscreen,\n }\n return api\n}\n","import { createAPI } from './api'\nimport type { InitOptions, PluckyAPI } from './types'\n\n// singleton exported API for convenience\nlet api: PluckyAPI | null = null\n\nexport function init(opts: InitOptions) {\n if (!api) api = createAPI()\n return api.init(opts)\n}\n\nexport function getAPI() {\n if (!api) api = createAPI()\n return api\n}\n\n// convenience re-exports\nexport type * from './types'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["host: HTMLDivElement | null","iframe: HTMLIFrameElement | null","mode: Mode","widthPx: number | string","nonce: string | undefined","css","z","state: Required<PluckyAPIOptions>","currentMode: 'push' | 'overlay'","resizeListener: (() => void) | null","init","api","api: PluckyAPI","api: PluckyAPI | null"],"sources":["../src/bus.ts","../src/sidebar.ts","../src/utils.ts","../src/api.ts","../src/index.ts"],"sourcesContent":["import type { MessageType } from './types'\n\ntype Handler = (p: any) => void\n\nexport class Bus {\n private handlers = new Map<MessageType, Set<Handler>>()\n\n on(event: MessageType, cb: Handler) {\n if (!this.handlers.has(event)) this.handlers.set(event, new Set())\n this.handlers.get(event)!.add(cb)\n return () => this.handlers.get(event)!.delete(cb)\n }\n\n emit(event: MessageType, payload?: any) {\n this.handlers.get(event)?.forEach((h) => h(payload))\n }\n}\n\nexport function bindPostMessage(bus: Bus, win: Window, origin: string) {\n const onMsg = (e: MessageEvent) => {\n if (e.origin !== origin) return\n if (!e.data || typeof e.data !== 'object') return\n if (!('type' in e.data)) return\n bus.emit(e.data.type, e.data.payload)\n }\n win.addEventListener('message', onMsg)\n return () => win.removeEventListener('message', onMsg)\n}\n","export type Mode = 'push' | 'overlay'\n\nexport interface SidebarOpts {\n appId: string\n baseUrl: string\n widthPx?: number\n zIndex?: number\n idPrefix?: string\n nonce?: string\n iframeTitle?: string\n initialMode?: Mode // 'push' (default) or 'overlay'\n}\n\nexport interface SidebarAPI {\n mount: (opts: SidebarOpts) => void\n unmount: () => void\n setMode: (mode: Mode) => void\n setWidth: (px: number | string) => void\n setZIndex: (z: number) => void\n hide: () => void // NEW: hide container + remove padding, keep iframe loaded\n show: () => void // NEW: restore visibility + padding if mode==='push'\n isHidden: () => boolean\n getMode: () => Mode\n getContainer: () => HTMLDivElement | null\n getIframe: () => HTMLIFrameElement | null\n ready: () => boolean\n}\n\nexport function createSidebar(): SidebarAPI {\n let host: HTMLDivElement | null = null\n let iframe: HTMLIFrameElement | null = null\n let mounted = false\n let hidden = false\n let mode: Mode = 'push'\n let widthPx: number | string = 360\n let zIndex = 2147483646\n let idPrefix = 'plucky'\n let cssId = ''\n let hostId = ''\n let shiftClass = ''\n let hiddenClass = ''\n let nonce: string | undefined\n\n const ensureStyle = (css: string) => {\n let tag = document.getElementById(cssId) as HTMLStyleElement | null\n if (!tag) {\n tag = document.createElement('style')\n tag.id = cssId\n if (nonce) tag.setAttribute('nonce', nonce)\n document.head.appendChild(tag)\n }\n tag.textContent = css\n }\n\n const css = () => `\n:root { --${idPrefix}-w: ${widthPx}px; }\n\nbody.${shiftClass} {\n padding-inline-end: var(--${idPrefix}-w) !important;\n}\n\n/* Fixed sidebar; overlay vs push is just whether body has padding */\n#${hostId} {\n position: fixed;\n inset-block: 0;\n inset-inline-end: 0;\n width: var(--${idPrefix}-w);\n max-width: 100vw;\n z-index: ${zIndex};\n background: transparent;\n}\n#${hostId} > iframe { width: 100%; height: 100%; border: 0; display: block; }\n\n/* Hidden state: keep in DOM, don’t render or accept focus/clicks */\n#${hostId}.${hiddenClass} {\n display: none !important;\n}\n`\n\n function mount(opts: SidebarOpts) {\n if (mounted) return\n\n widthPx = opts.widthPx ?? widthPx\n zIndex = opts.zIndex ?? zIndex\n idPrefix = opts.idPrefix ?? idPrefix\n nonce = opts.nonce\n mode = opts.initialMode ?? mode\n\n hostId = `${idPrefix}-sidebar`\n cssId = `${idPrefix}-sidebar-css`\n shiftClass = `${idPrefix}-shift`\n hiddenClass = `${idPrefix}-hidden`\n\n ensureStyle(css())\n\n host = document.getElementById(hostId) as HTMLDivElement | null\n if (!host) {\n host = document.createElement('div')\n host.id = hostId\n host.style.zIndex = String(zIndex)\n document.body.appendChild(host)\n }\n\n if (!iframe) {\n iframe = document.createElement('iframe')\n iframe.title = opts.iframeTitle ?? 'Plucky'\n iframe.setAttribute('aria-label', iframe.title)\n const base = opts.baseUrl.replace(/\\/$/, '')\n iframe.src = `${base}/widget/${encodeURIComponent(opts.appId)}`\n host.appendChild(iframe)\n }\n\n // Apply current visibility + mode\n if (hidden) host.classList.add(hiddenClass)\n else host.classList.remove(hiddenClass)\n\n if (!hidden && mode === 'push') document.body.classList.add(shiftClass)\n else document.body.classList.remove(shiftClass)\n\n mounted = true\n }\n\n function unmount() {\n if (!mounted) return\n document.body.classList.remove(shiftClass)\n host?.remove()\n document.getElementById(cssId)?.remove()\n host = null\n iframe = null\n mounted = false\n hidden = false\n }\n\n function setMode(next: Mode) {\n mode = next\n if (!mounted) return\n if (!hidden && mode === 'push') document.body.classList.add(shiftClass)\n else document.body.classList.remove(shiftClass)\n }\n\n function setWidth(width: number | string) {\n const widthCssValue =\n typeof width === 'number' ? `${Math.max(0, Math.round(width))}px` : width\n document.documentElement.style.setProperty(`--${idPrefix}-w`, widthCssValue)\n }\n\n function setZIndex(z: number) {\n zIndex = z\n if (host) host.style.zIndex = String(zIndex)\n }\n\n function hide() {\n if (!mounted || hidden) return\n hidden = true\n // Remove page padding if present\n document.body.classList.remove(shiftClass)\n // Hide the host container without unmounting the iframe\n host?.classList.add(hiddenClass)\n if (host) {\n host.setAttribute('aria-hidden', 'true')\n // Disable interactivity for assistive tech even if CSS changes\n ;(host as any).inert = true // harmless if not supported\n }\n // Optional: signal iframe to pause work\n iframe?.contentWindow?.postMessage(\n { type: 'PLUCKY_VISIBILITY', payload: 'hidden' },\n '*',\n )\n }\n\n function show() {\n if (!mounted || !hidden) return\n hidden = false\n host?.classList.remove(hiddenClass)\n if (host) {\n host.removeAttribute('aria-hidden')\n try {\n ;(host as any).inert = false\n } catch {}\n }\n if (mode === 'push') document.body.classList.add(shiftClass)\n iframe?.contentWindow?.postMessage(\n { type: 'PLUCKY_VISIBILITY', payload: 'visible' },\n '*',\n )\n }\n\n return {\n mount,\n unmount,\n setMode,\n setWidth,\n setZIndex,\n hide,\n show,\n isHidden: () => hidden,\n getMode: () => mode,\n getContainer: () => host,\n getIframe: () => iframe,\n ready: () => !!iframe?.contentWindow,\n }\n}\n","export function safeLocalStorageGet(key: string): string | null {\n try {\n return window.localStorage.getItem(key)\n } catch {\n return null\n }\n}\n\nexport function safeLocalStorageSet(key: string, value: string): void {\n try {\n window.localStorage.setItem(key, value)\n } catch {}\n}\n","import type {\n SavedMessage,\n ToolResultContentBlock,\n} from '@plucky-ai/llm-schemas'\nimport { dequal } from 'dequal'\nimport { ZodObject, z } from 'zod'\nimport { Bus, bindPostMessage } from './bus'\nimport { createSidebar } from './sidebar'\nimport type {\n InitOptions,\n MessageType,\n Mode,\n PluckyAPI,\n PluckyAPIOptions,\n SimpleToolConfig,\n ToolConfig,\n} from './types'\nimport { safeLocalStorageGet, safeLocalStorageSet } from './utils'\n\nexport function createAPI(): PluckyAPI {\n const bus = new Bus()\n let inited = false\n\n // Layout controllers\n const sidebar = createSidebar()\n\n // runtime state with sane defaults\n let state: Required<PluckyAPIOptions> = {\n appId: '',\n baseUrl: 'https://widget.plucky.ai',\n mode: 'push',\n containerId: undefined as unknown as string,\n user: {},\n tools: [],\n tags: [],\n width: 360,\n fullscreen: false,\n }\n\n // Track current mode and last mount options\n let currentMode: 'push' | 'overlay' = 'push'\n\n // Track resize listener for fullscreen mode\n let resizeListener: (() => void) | null = null\n\n // Helper to calculate scrollbar width\n function getScrollbarWidth(): number {\n return window.innerWidth - document.documentElement.clientWidth\n }\n\n // Helper to get fullscreen width CSS value accounting for scrollbar\n function getFullscreenWidth(): string {\n const scrollbarWidth = getScrollbarWidth()\n return scrollbarWidth > 0 ? `calc(100vw - ${scrollbarWidth}px)` : '100vw'\n }\n\n // Sidebar is the single DOM/layout owner; we post directly to its iframe\n function post(type: MessageType, payload?: any) {\n const iframe = sidebar.getIframe()\n const targetOrigin = new URL(state.baseUrl).origin\n iframe?.contentWindow?.postMessage({ type, payload }, targetOrigin)\n }\n\n function switchMode(next: 'push' | 'overlay') {\n if (next === currentMode) return\n\n // Just switch mode on the single layout\n sidebar.setMode(next)\n currentMode = next\n }\n\n function init(opts: InitOptions): PluckyAPI {\n if (inited) return api\n const { tools, ...rest } = opts\n state = { ...state, ...rest } as Required<PluckyAPIOptions>\n if (tools && tools.length > 0) {\n registerManyTools(tools, false)\n }\n currentMode = state.mode as 'push' | 'overlay'\n bindPostMessage(bus, window, new URL(state.baseUrl).origin)\n\n bus.on('PLUCKY_CLOSE', () => sidebar.hide())\n\n // Listen for iframe mount signal before sending boot\n bus.on('PLUCKY_WIDGET_MOUNTED', () => {\n const storageKey = `pls::${state.appId}`\n const existingToken = safeLocalStorageGet(storageKey)\n post('PLUCKY_LOAD_CONFIG', {\n appId: state.appId,\n user: state.user,\n mode: state.mode,\n sessionToken: existingToken || undefined,\n tools: getAllToolJSON(),\n tags: state.tags,\n })\n if (!existingToken) {\n post('PLUCKY_SESSION_REQUEST', { reason: 'missing' })\n }\n })\n\n // Mount the sidebar (creates iframe inside it)\n sidebar.mount({\n appId: state.appId,\n baseUrl: state.baseUrl,\n iframeTitle: 'Plucky',\n initialMode: currentMode,\n widthPx: state.width,\n })\n\n // Wire bus-driven layout changes to the sidebar\n bus.on('PLUCKY_SET_WIDTH', (px: number) => sidebar.setWidth(px))\n bus.on('PLUCKY_SWITCH_MODE', (m: Mode) => setMode(m))\n bus.on('PLUCKY_SESSION_UPDATED', (payload: { token?: string }) => {\n const storageKey = `pls::${state.appId}`\n if (typeof payload.token === 'string' && payload.token) {\n safeLocalStorageSet(storageKey, payload.token)\n }\n })\n bus.on('PLUCKY_SET_FULLSCREEN', (payload: { fullscreen: boolean }) =>\n handleSetFullscreen(payload.fullscreen),\n )\n bus.on(\n 'PLUCKY_RESPONSE_RECEIVED',\n async (response: { messages: Array<SavedMessage>; chatId: string }) => {\n const lastMessage = response.messages[response.messages.length - 1]\n if (typeof lastMessage.content === 'string') return\n const toolResultIds = lastMessage.content\n .filter((m) => m.type === 'tool_result')\n .map((m) => m.toolUseId)\n const unfulfilledToolCalls = lastMessage.content\n .filter((m) => m.type === 'tool_use')\n .filter((m) => !toolResultIds.includes(m.id))\n if (unfulfilledToolCalls.length === 0) return\n const promises = unfulfilledToolCalls.map(\n async (toolCall): Promise<ToolResultContentBlock> => {\n const tool = state.tools.find((t) => t.name === toolCall.name)\n if (!tool) {\n return {\n toolUseId: toolCall.id,\n content: 'Tool not found.',\n type: 'tool_result',\n }\n }\n if (!tool.cb) {\n return {\n toolUseId: toolCall.id,\n content: 'Received.',\n type: 'tool_result',\n }\n }\n try {\n let input = toolCall.input as Record<string, unknown> | string\n if (typeof input === 'string') {\n input = JSON.parse(input) as Record<string, unknown>\n }\n const result = await tool.cb(input)\n return {\n toolUseId: toolCall.id,\n content: result,\n type: 'tool_result',\n }\n } catch (e) {\n return {\n toolUseId: toolCall.id,\n content: `Error: ${e instanceof Error ? e.message : String(e)}`,\n type: 'tool_result',\n }\n }\n },\n )\n\n const results = await Promise.all(promises)\n sendMessage({\n content: results,\n lastMessageId: lastMessage.id,\n chatId: response.chatId,\n })\n },\n )\n\n // Wait for iframe to signal it's ready before sending boot\n inited = true\n return api\n }\n\n function sendMessage(args: {\n content: string | Array<ToolResultContentBlock>\n lastMessageId?: string\n createChat?: boolean\n chatId?: string\n }) {\n const { content, lastMessageId, createChat, chatId } = args\n if (sidebar.isHidden()) {\n sidebar.show()\n }\n post('PLUCKY_SEND_MESSAGE', {\n content,\n createChat: createChat ?? false,\n lastMessageId,\n chatId,\n })\n }\n function setInput(input: string) {\n sidebar.getIframe()?.contentWindow?.focus()\n post('PLUCKY_SET_INPUT', { input })\n }\n\n function setMode(mode: Mode) {\n state.mode = mode\n currentMode = mode as 'push' | 'overlay'\n sidebar.setMode(mode)\n post('PLUCKY_SWITCH_MODE', mode)\n }\n\n function on(event: MessageType, cb: (p: any) => void) {\n return bus.on(event, cb)\n }\n\n function open() {\n sidebar.show()\n }\n\n function close() {\n sidebar.hide()\n }\n\n function toggle() {\n if (sidebar.isHidden()) {\n sidebar.show()\n } else {\n sidebar.hide()\n }\n }\n\n function registerTool(tool: ToolConfig, notify = true) {\n const currentToolState = getAllToolJSON()\n if (state.tools.find((t) => t.name === tool.name)) {\n state.tools = state.tools.filter((t) => t.name !== tool.name)\n }\n state.tools.push(tool)\n state.tools.sort((a, b) => a.name.localeCompare(b.name))\n const newToolState = getAllToolJSON()\n if (notify && !dequal(currentToolState, newToolState)) {\n notifyToolConfigUpdated()\n }\n }\n function registerManyTools(tools: Array<ToolConfig>, notify = true) {\n const currentToolState = getAllToolJSON()\n for (const tool of tools) {\n registerTool(tool, false)\n }\n const newToolState = getAllToolJSON()\n if (notify && !dequal(currentToolState, newToolState)) {\n notifyToolConfigUpdated()\n }\n }\n function removeTool(name: string, notify = true) {\n if (!state.tools.find((t) => t.name === name)) {\n console.warn(`Tool ${name} not found, skipping.`)\n }\n state.tools = state.tools.filter((t) => t.name !== name)\n if (notify) {\n notifyToolConfigUpdated()\n }\n }\n\n function notifyToolConfigUpdated() {\n post('PLUCKY_TOOL_CONFIG_UPDATED', { tools: getAllToolJSON() })\n }\n\n function getAllToolJSON(): Array<SimpleToolConfig> {\n return state.tools.map((t) => ({\n name: t.name,\n description: t.description,\n defaultLoadingText: t.defaultLoadingText,\n defaultSuccessText: t.defaultSuccessText,\n inputSchema:\n t.inputSchema instanceof ZodObject\n ? z.toJSONSchema(t.inputSchema)\n : t.inputSchema,\n }))\n }\n\n function setWidth(px: number) {\n state.width = px\n sidebar.setWidth(px)\n }\n\n function setFullscreen(fullscreen: boolean) {\n post('PLUCKY_SET_FULLSCREEN', { fullscreen })\n handleSetFullscreen(fullscreen)\n }\n\n function handleSetFullscreen(fullscreen: boolean) {\n state.fullscreen = fullscreen\n\n // Clean up existing resize listener if any\n if (resizeListener) {\n window.removeEventListener('resize', resizeListener)\n resizeListener = null\n }\n\n if (fullscreen) {\n // Use CSS calc to account for scrollbar width, which stays responsive on resize\n sidebar.setWidth(getFullscreenWidth())\n sidebar.setMode('overlay')\n\n // Add resize listener to update width if scrollbar appears/disappears\n resizeListener = () => {\n if (state.fullscreen) {\n sidebar.setWidth(getFullscreenWidth())\n }\n }\n window.addEventListener('resize', resizeListener)\n } else {\n sidebar.setWidth(state.width)\n sidebar.setMode('push')\n }\n }\n\n const api: PluckyAPI = {\n init,\n setMode,\n switchMode,\n open,\n close,\n toggle,\n on,\n isReady: () => sidebar.ready(),\n sendMessage,\n isOpen: () => !sidebar.isHidden(),\n registerTool,\n registerManyTools,\n removeTool,\n setInput,\n setWidth,\n setFullscreen,\n }\n return api\n}\n","import { createAPI } from './api'\nimport type { InitOptions, PluckyAPI } from './types'\n\n// singleton exported API for convenience\nlet api: PluckyAPI | null = null\n\nexport function init(opts: InitOptions) {\n if (!api) api = createAPI()\n return api.init(opts)\n}\n\nexport function getAPI() {\n if (!api) api = createAPI()\n return api\n}\n\n// convenience re-exports\nexport type * from './types'\n"],"mappings":"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"}
|
package/dist/package.json
CHANGED