@plucky-ai/chat-sdk 0.2.0 → 0.3.0

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 CHANGED
@@ -1,461 +1,59 @@
1
- //#region rolldown:runtime
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __copyProps = (to, from, except, desc) => {
9
- if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
- key = keys[i];
11
- if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
- get: ((k) => from[k]).bind(null, key),
13
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
- });
15
- }
16
- return to;
17
- };
18
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
- value: mod,
20
- enumerable: true
21
- }) : target, mod));
22
1
 
23
- //#endregion
24
- let dequal = require("dequal");
25
- dequal = __toESM(dequal);
26
- let zod = require("zod");
27
- zod = __toESM(zod);
28
-
29
- //#region src/bus.ts
30
- var Bus = class {
31
- handlers = /* @__PURE__ */ new Map();
32
- on(event, cb) {
33
- if (!this.handlers.has(event)) this.handlers.set(event, /* @__PURE__ */ new Set());
34
- this.handlers.get(event).add(cb);
35
- return () => this.handlers.get(event).delete(cb);
36
- }
37
- emit(event, payload) {
38
- this.handlers.get(event)?.forEach((h) => h(payload));
39
- }
40
- };
41
- function bindPostMessage(bus, win, origin) {
42
- const onMsg = (e) => {
43
- if (e.origin !== origin) return;
44
- if (!e.data || typeof e.data !== "object") return;
45
- if (!("type" in e.data)) return;
46
- bus.emit(e.data.type, e.data.payload);
47
- };
48
- win.addEventListener("message", onMsg);
49
- return () => win.removeEventListener("message", onMsg);
2
+ //#region src/Plucky.ts
3
+ function Plucky(options) {
4
+ const settingScript = document.createElement("script");
5
+ settingScript.id = "plucky-settings";
6
+ settingScript.textContent = `window.pluckySettings = ${JSON.stringify(options)}`;
7
+ document.head.appendChild(settingScript);
8
+ const initScript = document.createElement("script");
9
+ initScript.id = "plucky-init";
10
+ initScript.textContent = `(function(){var w=window;var ic=w.Plucky;if(typeof ic==="function"){ic('update',w.pluckySettings);}else{var d=document;var i=function(){i.c(arguments);};i.q=[];i.c=function(args){i.q.push(args);};w.Plucky=i;var l=function(){var s=d.createElement('script');s.type='text/javascript';s.async=true;s.src=(window.pluckySettings.baseUrl||'https://widget.plucky.ai')+'/loader/'+window.pluckySettings.appId;var x=d.getElementsByTagName('script')[0];x.parentNode.insertBefore(s, x);};if(document.readyState==='complete'){l();}else if(w.attachEvent){w.attachEvent('onload',l);}else{w.addEventListener('load',l,false);}}})();`;
11
+ document.head.appendChild(initScript);
50
12
  }
51
13
 
52
14
  //#endregion
53
- //#region src/sidebar.ts
54
- function createSidebar() {
55
- let host = null;
56
- let iframe = null;
57
- let mounted = false;
58
- let hidden = false;
59
- let mode = "push";
60
- let widthPx = 360;
61
- let zIndex = 2147483646;
62
- let idPrefix = "plucky";
63
- let cssId = "";
64
- let hostId = "";
65
- let shiftClass = "";
66
- let hiddenClass = "";
67
- let nonce;
68
- const ensureStyle = (css$1) => {
69
- let tag = document.getElementById(cssId);
70
- if (!tag) {
71
- tag = document.createElement("style");
72
- tag.id = cssId;
73
- if (nonce) tag.setAttribute("nonce", nonce);
74
- document.head.appendChild(tag);
75
- }
76
- tag.textContent = css$1;
77
- };
78
- const css = () => `
79
- :root { --${idPrefix}-w: ${widthPx}px; }
80
-
81
- body.${shiftClass} {
82
- padding-inline-end: var(--${idPrefix}-w) !important;
15
+ //#region src/index.ts
16
+ function sendMessage(args) {
17
+ runIfLoaded((Plucky$1) => {
18
+ Plucky$1("sendMessage", args);
19
+ });
83
20
  }
84
-
85
- /* Fixed sidebar; overlay vs push is just whether body has padding */
86
- #${hostId} {
87
- position: fixed;
88
- inset-block: 0;
89
- inset-inline-end: 0;
90
- width: var(--${idPrefix}-w);
91
- max-width: 100vw;
92
- z-index: ${zIndex};
93
- background: transparent;
21
+ function addTools(tools) {
22
+ runIfLoaded((Plucky$1) => {
23
+ Plucky$1("addTools", tools);
24
+ });
94
25
  }
95
- #${hostId} > iframe { width: 100%; height: 100%; border: 0; display: block; }
96
-
97
- /* Hidden state: keep in DOM, don’t render or accept focus/clicks */
98
- #${hostId}.${hiddenClass} {
99
- display: none !important;
26
+ function removeTools(tools) {
27
+ runIfLoaded((Plucky$1) => {
28
+ Plucky$1("removeTools", tools);
29
+ });
100
30
  }
101
- `;
102
- function mount(opts) {
103
- if (mounted) return;
104
- widthPx = opts.widthPx ?? widthPx;
105
- zIndex = opts.zIndex ?? zIndex;
106
- idPrefix = opts.idPrefix ?? idPrefix;
107
- nonce = opts.nonce;
108
- mode = opts.initialMode ?? mode;
109
- hostId = `${idPrefix}-sidebar`;
110
- cssId = `${idPrefix}-sidebar-css`;
111
- shiftClass = `${idPrefix}-shift`;
112
- hiddenClass = `${idPrefix}-hidden`;
113
- ensureStyle(css());
114
- host = document.getElementById(hostId);
115
- if (!host) {
116
- host = document.createElement("div");
117
- host.id = hostId;
118
- host.style.zIndex = String(zIndex);
119
- document.body.appendChild(host);
120
- }
121
- if (!iframe) {
122
- iframe = document.createElement("iframe");
123
- iframe.title = opts.iframeTitle ?? "Plucky";
124
- iframe.setAttribute("aria-label", iframe.title);
125
- iframe.src = `${opts.baseUrl.replace(/\/$/, "")}/widget/${encodeURIComponent(opts.appId)}`;
126
- host.appendChild(iframe);
127
- }
128
- if (hidden) host.classList.add(hiddenClass);
129
- else host.classList.remove(hiddenClass);
130
- if (!hidden && mode === "push") document.body.classList.add(shiftClass);
131
- else document.body.classList.remove(shiftClass);
132
- mounted = true;
133
- }
134
- function unmount() {
135
- if (!mounted) return;
136
- document.body.classList.remove(shiftClass);
137
- host?.remove();
138
- document.getElementById(cssId)?.remove();
139
- host = null;
140
- iframe = null;
141
- mounted = false;
142
- hidden = false;
143
- }
144
- function setMode(next) {
145
- mode = next;
146
- if (!mounted) return;
147
- if (!hidden && mode === "push") document.body.classList.add(shiftClass);
148
- else document.body.classList.remove(shiftClass);
149
- }
150
- function setWidth(width) {
151
- const widthCssValue = typeof width === "number" ? `${Math.max(0, Math.round(width))}px` : width;
152
- document.documentElement.style.setProperty(`--${idPrefix}-w`, widthCssValue);
153
- }
154
- function setZIndex(z$1) {
155
- zIndex = z$1;
156
- if (host) host.style.zIndex = String(zIndex);
157
- }
158
- function hide() {
159
- if (!mounted || hidden) return;
160
- hidden = true;
161
- document.body.classList.remove(shiftClass);
162
- host?.classList.add(hiddenClass);
163
- if (host) {
164
- host.setAttribute("aria-hidden", "true");
165
- host.inert = true;
166
- }
167
- iframe?.contentWindow?.postMessage({
168
- type: "PLUCKY_VISIBILITY",
169
- payload: "hidden"
170
- }, "*");
171
- }
172
- function show() {
173
- if (!mounted || !hidden) return;
174
- hidden = false;
175
- host?.classList.remove(hiddenClass);
176
- if (host) {
177
- host.removeAttribute("aria-hidden");
178
- try {
179
- host.inert = false;
180
- } catch {}
181
- }
182
- if (mode === "push") document.body.classList.add(shiftClass);
183
- iframe?.contentWindow?.postMessage({
184
- type: "PLUCKY_VISIBILITY",
185
- payload: "visible"
186
- }, "*");
187
- }
188
- return {
189
- mount,
190
- unmount,
191
- setMode,
192
- setWidth,
193
- setZIndex,
194
- hide,
195
- show,
196
- isHidden: () => hidden,
197
- getMode: () => mode,
198
- getContainer: () => host,
199
- getIframe: () => iframe,
200
- ready: () => !!iframe?.contentWindow
201
- };
31
+ function setWidth(px) {
32
+ runIfLoaded((Plucky$1) => {
33
+ Plucky$1("setWidth", px);
34
+ });
202
35
  }
203
-
204
- //#endregion
205
- //#region src/utils.ts
206
- function safeLocalStorageGet(key) {
207
- try {
208
- return window.localStorage.getItem(key);
209
- } catch {
210
- return null;
211
- }
36
+ function setFullscreen(fullscreen) {
37
+ runIfLoaded((Plucky$1) => {
38
+ Plucky$1("setFullscreen", { fullscreen });
39
+ });
212
40
  }
213
- function safeLocalStorageSet(key, value) {
214
- try {
215
- window.localStorage.setItem(key, value);
216
- } catch {}
217
- }
218
-
219
- //#endregion
220
- //#region src/api.ts
221
- function createAPI() {
222
- const bus = new Bus();
223
- let inited = false;
224
- const sidebar = createSidebar();
225
- let state = {
226
- appId: "",
227
- baseUrl: "https://widget.plucky.ai",
228
- mode: "push",
229
- containerId: void 0,
230
- user: {},
231
- tools: [],
232
- tags: [],
233
- width: 360,
234
- fullscreen: false
235
- };
236
- let currentMode = "push";
237
- let resizeListener = null;
238
- function getScrollbarWidth() {
239
- return window.innerWidth - document.documentElement.clientWidth;
240
- }
241
- function getFullscreenWidth() {
242
- const scrollbarWidth = getScrollbarWidth();
243
- return scrollbarWidth > 0 ? `calc(100vw - ${scrollbarWidth}px)` : "100vw";
244
- }
245
- function post(type, payload) {
246
- const iframe = sidebar.getIframe();
247
- const targetOrigin = new URL(state.baseUrl).origin;
248
- iframe?.contentWindow?.postMessage({
249
- type,
250
- payload
251
- }, targetOrigin);
252
- }
253
- function switchMode(next) {
254
- if (next === currentMode) return;
255
- sidebar.setMode(next);
256
- currentMode = next;
257
- }
258
- function init$1(opts) {
259
- if (inited) return api$1;
260
- const { tools,...rest } = opts;
261
- state = {
262
- ...state,
263
- ...rest
264
- };
265
- if (tools && tools.length > 0) registerManyTools(tools, false);
266
- currentMode = state.mode;
267
- bindPostMessage(bus, window, new URL(state.baseUrl).origin);
268
- bus.on("PLUCKY_CLOSE", () => sidebar.hide());
269
- bus.on("PLUCKY_WIDGET_MOUNTED", () => {
270
- const existingToken = safeLocalStorageGet(`pls::${state.appId}`);
271
- post("PLUCKY_LOAD_CONFIG", {
272
- appId: state.appId,
273
- user: state.user,
274
- mode: state.mode,
275
- sessionToken: existingToken || void 0,
276
- tools: getAllToolJSON(),
277
- tags: state.tags
278
- });
279
- if (!existingToken) post("PLUCKY_SESSION_REQUEST", { reason: "missing" });
280
- });
281
- sidebar.mount({
282
- appId: state.appId,
283
- baseUrl: state.baseUrl,
284
- iframeTitle: "Plucky",
285
- initialMode: currentMode,
286
- widthPx: state.width
287
- });
288
- bus.on("PLUCKY_SET_WIDTH", (px) => sidebar.setWidth(px));
289
- bus.on("PLUCKY_SWITCH_MODE", (m) => setMode(m));
290
- bus.on("PLUCKY_SESSION_UPDATED", (payload) => {
291
- const storageKey = `pls::${state.appId}`;
292
- if (typeof payload.token === "string" && payload.token) safeLocalStorageSet(storageKey, payload.token);
293
- });
294
- bus.on("PLUCKY_SET_FULLSCREEN", (payload) => setFullscreen(payload.fullscreen));
295
- bus.on("PLUCKY_RESPONSE_RECEIVED", async (response) => {
296
- const lastMessage = response.messages[response.messages.length - 1];
297
- if (typeof lastMessage.content === "string") return;
298
- const toolResultIds = lastMessage.content.filter((m) => m.type === "tool_result").map((m) => m.toolUseId);
299
- const unfulfilledToolCalls = lastMessage.content.filter((m) => m.type === "tool_use").filter((m) => !toolResultIds.includes(m.id));
300
- if (unfulfilledToolCalls.length === 0) return;
301
- const promises = unfulfilledToolCalls.map(async (toolCall) => {
302
- const tool = state.tools.find((t) => t.name === toolCall.name);
303
- if (!tool) return {
304
- toolUseId: toolCall.id,
305
- content: "Tool not found.",
306
- type: "tool_result"
307
- };
308
- if (!tool.cb) return {
309
- toolUseId: toolCall.id,
310
- content: "Received.",
311
- type: "tool_result"
312
- };
313
- try {
314
- let input = toolCall.input;
315
- if (typeof input === "string") input = JSON.parse(input);
316
- const result = await tool.cb(input);
317
- return {
318
- toolUseId: toolCall.id,
319
- content: result,
320
- type: "tool_result"
321
- };
322
- } catch (e) {
323
- return {
324
- toolUseId: toolCall.id,
325
- content: `Error: ${e instanceof Error ? e.message : String(e)}`,
326
- type: "tool_result"
327
- };
328
- }
329
- });
330
- sendMessage({
331
- content: await Promise.all(promises),
332
- lastMessageId: lastMessage.id,
333
- chatId: response.chatId
334
- });
335
- });
336
- inited = true;
337
- return api$1;
338
- }
339
- function sendMessage(args) {
340
- const { content, lastMessageId, createChat, chatId } = args;
341
- if (sidebar.isHidden()) sidebar.show();
342
- post("PLUCKY_SEND_MESSAGE", {
343
- content,
344
- createChat: createChat ?? false,
345
- lastMessageId,
346
- chatId
347
- });
348
- }
349
- function setInput(input) {
350
- sidebar.getIframe()?.contentWindow?.focus();
351
- post("PLUCKY_SET_INPUT", { input });
352
- }
353
- function setMode(mode) {
354
- state.mode = mode;
355
- currentMode = mode;
356
- sidebar.setMode(mode);
357
- post("PLUCKY_SWITCH_MODE", mode);
358
- }
359
- function on(event, cb) {
360
- return bus.on(event, cb);
361
- }
362
- function open() {
363
- sidebar.show();
364
- }
365
- function close() {
366
- sidebar.hide();
367
- }
368
- function toggle() {
369
- if (sidebar.isHidden()) sidebar.show();
370
- else sidebar.hide();
371
- }
372
- function registerTool(tool, notify = true) {
373
- const currentToolState = getAllToolJSON();
374
- if (state.tools.find((t) => t.name === tool.name)) state.tools = state.tools.filter((t) => t.name !== tool.name);
375
- state.tools.push(tool);
376
- state.tools.sort((a, b) => a.name.localeCompare(b.name));
377
- const newToolState = getAllToolJSON();
378
- if (notify && !(0, dequal.dequal)(currentToolState, newToolState)) notifyToolConfigUpdated();
379
- }
380
- function registerManyTools(tools, notify = true) {
381
- const currentToolState = getAllToolJSON();
382
- for (const tool of tools) registerTool(tool, false);
383
- const newToolState = getAllToolJSON();
384
- if (notify && !(0, dequal.dequal)(currentToolState, newToolState)) notifyToolConfigUpdated();
385
- }
386
- function removeTool(name, notify = true) {
387
- if (!state.tools.find((t) => t.name === name)) console.warn(`Tool ${name} not found, skipping.`);
388
- state.tools = state.tools.filter((t) => t.name !== name);
389
- if (notify) notifyToolConfigUpdated();
390
- }
391
- function notifyToolConfigUpdated() {
392
- post("PLUCKY_TOOL_CONFIG_UPDATED", { tools: getAllToolJSON() });
393
- }
394
- function getAllToolJSON() {
395
- return state.tools.map((t) => ({
396
- name: t.name,
397
- description: t.description,
398
- defaultLoadingText: t.defaultLoadingText,
399
- defaultSuccessText: t.defaultSuccessText,
400
- inputSchema: t.inputSchema instanceof zod.ZodObject ? zod.z.toJSONSchema(t.inputSchema) : t.inputSchema
401
- }));
402
- }
403
- function setWidth(px) {
404
- state.width = px;
405
- sidebar.setWidth(px);
406
- }
407
- function setFullscreen(fullscreen) {
408
- state.fullscreen = fullscreen;
409
- if (resizeListener) {
410
- window.removeEventListener("resize", resizeListener);
411
- resizeListener = null;
412
- }
413
- if (fullscreen) {
414
- sidebar.setWidth(getFullscreenWidth());
415
- sidebar.setMode("overlay");
416
- resizeListener = () => {
417
- if (state.fullscreen) sidebar.setWidth(getFullscreenWidth());
418
- };
419
- window.addEventListener("resize", resizeListener);
420
- } else {
421
- sidebar.setWidth(state.width);
422
- sidebar.setMode("push");
423
- }
424
- }
425
- const api$1 = {
426
- init: init$1,
427
- setMode,
428
- switchMode,
429
- open,
430
- close,
431
- toggle,
432
- on,
433
- isReady: () => sidebar.ready(),
434
- sendMessage,
435
- isOpen: () => !sidebar.isHidden(),
436
- registerTool,
437
- registerManyTools,
438
- removeTool,
439
- setInput,
440
- setWidth,
441
- setFullscreen
442
- };
443
- return api$1;
444
- }
445
-
446
- //#endregion
447
- //#region src/index.ts
448
- let api = null;
449
- function init(opts) {
450
- if (!api) api = createAPI();
451
- return api.init(opts);
41
+ function toggle() {
42
+ runIfLoaded((Plucky$1) => {
43
+ Plucky$1("toggle");
44
+ });
452
45
  }
453
- function getAPI() {
454
- if (!api) api = createAPI();
455
- return api;
46
+ function runIfLoaded(fn) {
47
+ if (typeof window !== "undefined" && window.Plucky) fn(window.Plucky);
48
+ else console.warn("Window is not defined");
456
49
  }
457
50
 
458
51
  //#endregion
459
- exports.getAPI = getAPI;
460
- exports.init = init;
52
+ exports.Plucky = Plucky;
53
+ exports.addTools = addTools;
54
+ exports.removeTools = removeTools;
55
+ exports.sendMessage = sendMessage;
56
+ exports.setFullscreen = setFullscreen;
57
+ exports.setWidth = setWidth;
58
+ exports.toggle = toggle;
461
59
  //# sourceMappingURL=index.cjs.map
@@ -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":[],"sources":["../src/Plucky.ts","../src/index.ts"],"sourcesContent":["import { type PluckySettingsParams } from '@plucky-ai/loader-types'\n\nexport function Plucky(options: PluckySettingsParams) {\n const settingScript = document.createElement('script')\n settingScript.id = 'plucky-settings'\n settingScript.textContent = `window.pluckySettings = ${JSON.stringify(options)}`\n document.head.appendChild(settingScript)\n\n const initScript = document.createElement('script')\n initScript.id = 'plucky-init'\n initScript.textContent = `(function(){var w=window;var ic=w.Plucky;if(typeof ic===\"function\"){ic('update',w.pluckySettings);}else{var d=document;var i=function(){i.c(arguments);};i.q=[];i.c=function(args){i.q.push(args);};w.Plucky=i;var l=function(){var s=d.createElement('script');s.type='text/javascript';s.async=true;s.src=(window.pluckySettings.baseUrl||'https://widget.plucky.ai')+'/loader/'+window.pluckySettings.appId;var x=d.getElementsByTagName('script')[0];x.parentNode.insertBefore(s, x);};if(document.readyState==='complete'){l();}else if(w.attachEvent){w.attachEvent('onload',l);}else{w.addEventListener('load',l,false);}}})();`\n document.head.appendChild(initScript)\n}\n","import { ToolConfig } from '@plucky-ai/loader-types'\nimport { PluckyFunction } from './types'\n\nexport type { ToolConfig } from '@plucky-ai/loader-types'\nexport { Plucky } from './Plucky'\nexport function sendMessage(args: { content: string; createChat?: boolean }) {\n runIfLoaded((Plucky) => {\n Plucky('sendMessage', args)\n })\n}\n\nexport function addTools(tools: ToolConfig[]) {\n runIfLoaded((Plucky) => {\n Plucky('addTools', tools)\n })\n}\n\nexport function removeTools(tools: string[]) {\n runIfLoaded((Plucky) => {\n Plucky('removeTools', tools)\n })\n}\n\nexport function setWidth(px: number) {\n runIfLoaded((Plucky) => {\n Plucky('setWidth', px)\n })\n}\n\nexport function setFullscreen(fullscreen: boolean) {\n runIfLoaded((Plucky) => {\n Plucky('setFullscreen', { fullscreen })\n })\n}\n\nexport function toggle() {\n runIfLoaded((Plucky) => {\n Plucky('toggle')\n })\n}\n\nfunction runIfLoaded(fn: (arg: PluckyFunction) => void) {\n if (typeof window !== 'undefined' && window.Plucky) {\n fn(window.Plucky)\n } else {\n console.warn('Window is not defined')\n }\n}\n"],"mappings":";;AAEA,SAAgB,OAAO,SAA+B;CACpD,MAAM,gBAAgB,SAAS,cAAc,SAAS;AACtD,eAAc,KAAK;AACnB,eAAc,cAAc,2BAA2B,KAAK,UAAU,QAAQ;AAC9E,UAAS,KAAK,YAAY,cAAc;CAExC,MAAM,aAAa,SAAS,cAAc,SAAS;AACnD,YAAW,KAAK;AAChB,YAAW,cAAc;AACzB,UAAS,KAAK,YAAY,WAAW;;;;;ACNvC,SAAgB,YAAY,MAAiD;AAC3E,cAAa,aAAW;AACtB,WAAO,eAAe,KAAK;GAC3B;;AAGJ,SAAgB,SAAS,OAAqB;AAC5C,cAAa,aAAW;AACtB,WAAO,YAAY,MAAM;GACzB;;AAGJ,SAAgB,YAAY,OAAiB;AAC3C,cAAa,aAAW;AACtB,WAAO,eAAe,MAAM;GAC5B;;AAGJ,SAAgB,SAAS,IAAY;AACnC,cAAa,aAAW;AACtB,WAAO,YAAY,GAAG;GACtB;;AAGJ,SAAgB,cAAc,YAAqB;AACjD,cAAa,aAAW;AACtB,WAAO,iBAAiB,EAAE,YAAY,CAAC;GACvC;;AAGJ,SAAgB,SAAS;AACvB,cAAa,aAAW;AACtB,WAAO,SAAS;GAChB;;AAGJ,SAAS,YAAY,IAAmC;AACtD,KAAI,OAAO,WAAW,eAAe,OAAO,OAC1C,IAAG,OAAO,OAAO;KAEjB,SAAQ,KAAK,wBAAwB"}
package/dist/index.d.cts CHANGED
@@ -1,80 +1,18 @@
1
- import { ToolResultContentBlock } from "@plucky-ai/llm";
2
- import { ZodObject, z } from "zod";
1
+ import { PluckySettingsParams, ToolConfig, ToolConfig as ToolConfig$1 } from "@plucky-ai/loader-types";
3
2
 
4
- //#region src/types.d.ts
5
- type Mode = 'push' | 'overlay';
6
- interface SimpleToolConfig {
7
- name: string;
8
- description: string;
9
- defaultLoadingText?: string | null;
10
- defaultSuccessText?: string | null;
11
- inputSchema?: ZodObject | Record<string, unknown>;
12
- }
13
- type InferToolInput<T$1 extends ZodObject<any> | Record<string, unknown> | undefined> = T$1 extends ZodObject<any> ? z.infer<T$1> : Record<string, unknown>;
14
- interface ToolConfig<TInputSchema extends ZodObject<any> | Record<string, unknown> | undefined = undefined> extends Omit<SimpleToolConfig, 'inputSchema'> {
15
- inputSchema?: TInputSchema;
16
- cb?: (input: InferToolInput<TInputSchema>) => Promise<string> | string;
17
- }
18
- interface InitOptions {
19
- appId: string;
20
- baseUrl?: string;
21
- mode?: Mode;
22
- containerId?: string;
23
- user?: {
24
- id?: string;
25
- email?: string;
26
- name?: string;
27
- externalId?: string;
28
- metadata?: Record<string, any>;
29
- };
30
- tags?: Array<string>;
31
- tools?: Array<ToolConfig<any>>;
32
- width?: number;
33
- fullscreen?: boolean;
34
- }
35
- interface PluckyAPIOptions extends InitOptions {
36
- tools: Array<ToolConfig<any>>;
37
- tags: Array<string>;
38
- fullscreen?: boolean;
39
- }
40
- interface MountOptions {
41
- appId: string;
42
- baseUrl: string;
43
- iframeTitle?: string;
44
- widthPx?: number;
45
- heightPx?: number;
46
- zIndex?: number;
47
- idPrefix?: string;
48
- nonce?: string;
49
- dir?: 'ltr' | 'rtl';
50
- }
51
- interface PluckyAPI {
52
- init: (opts: InitOptions) => PluckyAPI;
53
- setMode: (mode: Mode) => void;
54
- switchMode: (mode: 'push' | 'overlay') => void;
55
- open: () => void;
56
- close: () => void;
57
- toggle: () => void;
58
- on: <T = any>(event: MessageType, cb: (payload: T) => void) => () => void;
59
- isReady: () => boolean;
60
- setInput: (input: string) => void;
61
- sendMessage: (args: {
62
- content: string | Array<ToolResultContentBlock>;
63
- lastMessageId?: string;
64
- createChat?: boolean;
65
- }) => void;
66
- isOpen: () => boolean;
67
- registerTool: (tool: ToolConfig<any>) => void;
68
- registerManyTools: (tools: Array<ToolConfig<any>>) => void;
69
- removeTool: (name: string) => void;
70
- setWidth: (px: number) => void;
71
- setFullscreen: (fullscreen: boolean) => void;
72
- }
73
- type MessageType = 'PLUCKY_LOAD_CONFIG' | 'PLUCKY_TOOL_CONFIG_UPDATED' | 'PLUCKY_SESSION_LOADED' | 'PLUCKY_CLOSE' | 'PLUCKY_SET_WIDTH' | 'PLUCKY_SWITCH_MODE' | 'PLUCKY_TOOL_CALL' | 'PLUCKY_WIDGET_MOUNTED' | 'PLUCKY_RESPONSE_RECEIVED' | 'PLUCKY_SEND_MESSAGE' | 'PLUCKY_SESSION_REQUEST' | 'PLUCKY_SESSION_UPDATED' | 'PLUCKY_SET_INPUT' | 'PLUCKY_SET_FULLSCREEN';
3
+ //#region src/Plucky.d.ts
4
+ declare function Plucky(options: PluckySettingsParams): void;
74
5
  //#endregion
75
6
  //#region src/index.d.ts
76
- declare function init(opts: InitOptions): PluckyAPI;
77
- declare function getAPI(): PluckyAPI;
7
+ declare function sendMessage(args: {
8
+ content: string;
9
+ createChat?: boolean;
10
+ }): void;
11
+ declare function addTools(tools: ToolConfig$1[]): void;
12
+ declare function removeTools(tools: string[]): void;
13
+ declare function setWidth(px: number): void;
14
+ declare function setFullscreen(fullscreen: boolean): void;
15
+ declare function toggle(): void;
78
16
  //#endregion
79
- export { InitOptions, MessageType, Mode, MountOptions, PluckyAPI, PluckyAPIOptions, SimpleToolConfig, ToolConfig, getAPI, init };
17
+ export { Plucky, type ToolConfig, addTools, removeTools, sendMessage, setFullscreen, setWidth, toggle };
80
18
  //# sourceMappingURL=index.d.cts.map
package/dist/index.d.ts CHANGED
@@ -1,80 +1,18 @@
1
- import { ZodObject, z } from "zod";
2
- import { ToolResultContentBlock } from "@plucky-ai/llm";
1
+ import { PluckySettingsParams, ToolConfig, ToolConfig as ToolConfig$1 } from "@plucky-ai/loader-types";
3
2
 
4
- //#region src/types.d.ts
5
- type Mode = 'push' | 'overlay';
6
- interface SimpleToolConfig {
7
- name: string;
8
- description: string;
9
- defaultLoadingText?: string | null;
10
- defaultSuccessText?: string | null;
11
- inputSchema?: ZodObject | Record<string, unknown>;
12
- }
13
- type InferToolInput<T$1 extends ZodObject<any> | Record<string, unknown> | undefined> = T$1 extends ZodObject<any> ? z.infer<T$1> : Record<string, unknown>;
14
- interface ToolConfig<TInputSchema extends ZodObject<any> | Record<string, unknown> | undefined = undefined> extends Omit<SimpleToolConfig, 'inputSchema'> {
15
- inputSchema?: TInputSchema;
16
- cb?: (input: InferToolInput<TInputSchema>) => Promise<string> | string;
17
- }
18
- interface InitOptions {
19
- appId: string;
20
- baseUrl?: string;
21
- mode?: Mode;
22
- containerId?: string;
23
- user?: {
24
- id?: string;
25
- email?: string;
26
- name?: string;
27
- externalId?: string;
28
- metadata?: Record<string, any>;
29
- };
30
- tags?: Array<string>;
31
- tools?: Array<ToolConfig<any>>;
32
- width?: number;
33
- fullscreen?: boolean;
34
- }
35
- interface PluckyAPIOptions extends InitOptions {
36
- tools: Array<ToolConfig<any>>;
37
- tags: Array<string>;
38
- fullscreen?: boolean;
39
- }
40
- interface MountOptions {
41
- appId: string;
42
- baseUrl: string;
43
- iframeTitle?: string;
44
- widthPx?: number;
45
- heightPx?: number;
46
- zIndex?: number;
47
- idPrefix?: string;
48
- nonce?: string;
49
- dir?: 'ltr' | 'rtl';
50
- }
51
- interface PluckyAPI {
52
- init: (opts: InitOptions) => PluckyAPI;
53
- setMode: (mode: Mode) => void;
54
- switchMode: (mode: 'push' | 'overlay') => void;
55
- open: () => void;
56
- close: () => void;
57
- toggle: () => void;
58
- on: <T = any>(event: MessageType, cb: (payload: T) => void) => () => void;
59
- isReady: () => boolean;
60
- setInput: (input: string) => void;
61
- sendMessage: (args: {
62
- content: string | Array<ToolResultContentBlock>;
63
- lastMessageId?: string;
64
- createChat?: boolean;
65
- }) => void;
66
- isOpen: () => boolean;
67
- registerTool: (tool: ToolConfig<any>) => void;
68
- registerManyTools: (tools: Array<ToolConfig<any>>) => void;
69
- removeTool: (name: string) => void;
70
- setWidth: (px: number) => void;
71
- setFullscreen: (fullscreen: boolean) => void;
72
- }
73
- type MessageType = 'PLUCKY_LOAD_CONFIG' | 'PLUCKY_TOOL_CONFIG_UPDATED' | 'PLUCKY_SESSION_LOADED' | 'PLUCKY_CLOSE' | 'PLUCKY_SET_WIDTH' | 'PLUCKY_SWITCH_MODE' | 'PLUCKY_TOOL_CALL' | 'PLUCKY_WIDGET_MOUNTED' | 'PLUCKY_RESPONSE_RECEIVED' | 'PLUCKY_SEND_MESSAGE' | 'PLUCKY_SESSION_REQUEST' | 'PLUCKY_SESSION_UPDATED' | 'PLUCKY_SET_INPUT' | 'PLUCKY_SET_FULLSCREEN';
3
+ //#region src/Plucky.d.ts
4
+ declare function Plucky(options: PluckySettingsParams): void;
74
5
  //#endregion
75
6
  //#region src/index.d.ts
76
- declare function init(opts: InitOptions): PluckyAPI;
77
- declare function getAPI(): PluckyAPI;
7
+ declare function sendMessage(args: {
8
+ content: string;
9
+ createChat?: boolean;
10
+ }): void;
11
+ declare function addTools(tools: ToolConfig$1[]): void;
12
+ declare function removeTools(tools: string[]): void;
13
+ declare function setWidth(px: number): void;
14
+ declare function setFullscreen(fullscreen: boolean): void;
15
+ declare function toggle(): void;
78
16
  //#endregion
79
- export { InitOptions, MessageType, Mode, MountOptions, PluckyAPI, PluckyAPIOptions, SimpleToolConfig, ToolConfig, getAPI, init };
17
+ export { Plucky, type ToolConfig, addTools, removeTools, sendMessage, setFullscreen, setWidth, toggle };
80
18
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,435 +1,52 @@
1
- import { dequal } from "dequal";
2
- import { ZodObject, z } from "zod";
3
-
4
- //#region src/bus.ts
5
- var Bus = class {
6
- handlers = /* @__PURE__ */ new Map();
7
- on(event, cb) {
8
- if (!this.handlers.has(event)) this.handlers.set(event, /* @__PURE__ */ new Set());
9
- this.handlers.get(event).add(cb);
10
- return () => this.handlers.get(event).delete(cb);
11
- }
12
- emit(event, payload) {
13
- this.handlers.get(event)?.forEach((h) => h(payload));
14
- }
15
- };
16
- function bindPostMessage(bus, win, origin) {
17
- const onMsg = (e) => {
18
- if (e.origin !== origin) return;
19
- if (!e.data || typeof e.data !== "object") return;
20
- if (!("type" in e.data)) return;
21
- bus.emit(e.data.type, e.data.payload);
22
- };
23
- win.addEventListener("message", onMsg);
24
- return () => win.removeEventListener("message", onMsg);
1
+ //#region src/Plucky.ts
2
+ function Plucky(options) {
3
+ const settingScript = document.createElement("script");
4
+ settingScript.id = "plucky-settings";
5
+ settingScript.textContent = `window.pluckySettings = ${JSON.stringify(options)}`;
6
+ document.head.appendChild(settingScript);
7
+ const initScript = document.createElement("script");
8
+ initScript.id = "plucky-init";
9
+ initScript.textContent = `(function(){var w=window;var ic=w.Plucky;if(typeof ic==="function"){ic('update',w.pluckySettings);}else{var d=document;var i=function(){i.c(arguments);};i.q=[];i.c=function(args){i.q.push(args);};w.Plucky=i;var l=function(){var s=d.createElement('script');s.type='text/javascript';s.async=true;s.src=(window.pluckySettings.baseUrl||'https://widget.plucky.ai')+'/loader/'+window.pluckySettings.appId;var x=d.getElementsByTagName('script')[0];x.parentNode.insertBefore(s, x);};if(document.readyState==='complete'){l();}else if(w.attachEvent){w.attachEvent('onload',l);}else{w.addEventListener('load',l,false);}}})();`;
10
+ document.head.appendChild(initScript);
25
11
  }
26
12
 
27
13
  //#endregion
28
- //#region src/sidebar.ts
29
- function createSidebar() {
30
- let host = null;
31
- let iframe = null;
32
- let mounted = false;
33
- let hidden = false;
34
- let mode = "push";
35
- let widthPx = 360;
36
- let zIndex = 2147483646;
37
- let idPrefix = "plucky";
38
- let cssId = "";
39
- let hostId = "";
40
- let shiftClass = "";
41
- let hiddenClass = "";
42
- let nonce;
43
- const ensureStyle = (css$1) => {
44
- let tag = document.getElementById(cssId);
45
- if (!tag) {
46
- tag = document.createElement("style");
47
- tag.id = cssId;
48
- if (nonce) tag.setAttribute("nonce", nonce);
49
- document.head.appendChild(tag);
50
- }
51
- tag.textContent = css$1;
52
- };
53
- const css = () => `
54
- :root { --${idPrefix}-w: ${widthPx}px; }
55
-
56
- body.${shiftClass} {
57
- padding-inline-end: var(--${idPrefix}-w) !important;
58
- }
59
-
60
- /* Fixed sidebar; overlay vs push is just whether body has padding */
61
- #${hostId} {
62
- position: fixed;
63
- inset-block: 0;
64
- inset-inline-end: 0;
65
- width: var(--${idPrefix}-w);
66
- max-width: 100vw;
67
- z-index: ${zIndex};
68
- background: transparent;
69
- }
70
- #${hostId} > iframe { width: 100%; height: 100%; border: 0; display: block; }
71
-
72
- /* Hidden state: keep in DOM, don’t render or accept focus/clicks */
73
- #${hostId}.${hiddenClass} {
74
- display: none !important;
14
+ //#region src/index.ts
15
+ function sendMessage(args) {
16
+ runIfLoaded((Plucky$1) => {
17
+ Plucky$1("sendMessage", args);
18
+ });
75
19
  }
76
- `;
77
- function mount(opts) {
78
- if (mounted) return;
79
- widthPx = opts.widthPx ?? widthPx;
80
- zIndex = opts.zIndex ?? zIndex;
81
- idPrefix = opts.idPrefix ?? idPrefix;
82
- nonce = opts.nonce;
83
- mode = opts.initialMode ?? mode;
84
- hostId = `${idPrefix}-sidebar`;
85
- cssId = `${idPrefix}-sidebar-css`;
86
- shiftClass = `${idPrefix}-shift`;
87
- hiddenClass = `${idPrefix}-hidden`;
88
- ensureStyle(css());
89
- host = document.getElementById(hostId);
90
- if (!host) {
91
- host = document.createElement("div");
92
- host.id = hostId;
93
- host.style.zIndex = String(zIndex);
94
- document.body.appendChild(host);
95
- }
96
- if (!iframe) {
97
- iframe = document.createElement("iframe");
98
- iframe.title = opts.iframeTitle ?? "Plucky";
99
- iframe.setAttribute("aria-label", iframe.title);
100
- iframe.src = `${opts.baseUrl.replace(/\/$/, "")}/widget/${encodeURIComponent(opts.appId)}`;
101
- host.appendChild(iframe);
102
- }
103
- if (hidden) host.classList.add(hiddenClass);
104
- else host.classList.remove(hiddenClass);
105
- if (!hidden && mode === "push") document.body.classList.add(shiftClass);
106
- else document.body.classList.remove(shiftClass);
107
- mounted = true;
108
- }
109
- function unmount() {
110
- if (!mounted) return;
111
- document.body.classList.remove(shiftClass);
112
- host?.remove();
113
- document.getElementById(cssId)?.remove();
114
- host = null;
115
- iframe = null;
116
- mounted = false;
117
- hidden = false;
118
- }
119
- function setMode(next) {
120
- mode = next;
121
- if (!mounted) return;
122
- if (!hidden && mode === "push") document.body.classList.add(shiftClass);
123
- else document.body.classList.remove(shiftClass);
124
- }
125
- function setWidth(width) {
126
- const widthCssValue = typeof width === "number" ? `${Math.max(0, Math.round(width))}px` : width;
127
- document.documentElement.style.setProperty(`--${idPrefix}-w`, widthCssValue);
128
- }
129
- function setZIndex(z$1) {
130
- zIndex = z$1;
131
- if (host) host.style.zIndex = String(zIndex);
132
- }
133
- function hide() {
134
- if (!mounted || hidden) return;
135
- hidden = true;
136
- document.body.classList.remove(shiftClass);
137
- host?.classList.add(hiddenClass);
138
- if (host) {
139
- host.setAttribute("aria-hidden", "true");
140
- host.inert = true;
141
- }
142
- iframe?.contentWindow?.postMessage({
143
- type: "PLUCKY_VISIBILITY",
144
- payload: "hidden"
145
- }, "*");
146
- }
147
- function show() {
148
- if (!mounted || !hidden) return;
149
- hidden = false;
150
- host?.classList.remove(hiddenClass);
151
- if (host) {
152
- host.removeAttribute("aria-hidden");
153
- try {
154
- host.inert = false;
155
- } catch {}
156
- }
157
- if (mode === "push") document.body.classList.add(shiftClass);
158
- iframe?.contentWindow?.postMessage({
159
- type: "PLUCKY_VISIBILITY",
160
- payload: "visible"
161
- }, "*");
162
- }
163
- return {
164
- mount,
165
- unmount,
166
- setMode,
167
- setWidth,
168
- setZIndex,
169
- hide,
170
- show,
171
- isHidden: () => hidden,
172
- getMode: () => mode,
173
- getContainer: () => host,
174
- getIframe: () => iframe,
175
- ready: () => !!iframe?.contentWindow
176
- };
20
+ function addTools(tools) {
21
+ runIfLoaded((Plucky$1) => {
22
+ Plucky$1("addTools", tools);
23
+ });
177
24
  }
178
-
179
- //#endregion
180
- //#region src/utils.ts
181
- function safeLocalStorageGet(key) {
182
- try {
183
- return window.localStorage.getItem(key);
184
- } catch {
185
- return null;
186
- }
25
+ function removeTools(tools) {
26
+ runIfLoaded((Plucky$1) => {
27
+ Plucky$1("removeTools", tools);
28
+ });
187
29
  }
188
- function safeLocalStorageSet(key, value) {
189
- try {
190
- window.localStorage.setItem(key, value);
191
- } catch {}
30
+ function setWidth(px) {
31
+ runIfLoaded((Plucky$1) => {
32
+ Plucky$1("setWidth", px);
33
+ });
192
34
  }
193
-
194
- //#endregion
195
- //#region src/api.ts
196
- function createAPI() {
197
- const bus = new Bus();
198
- let inited = false;
199
- const sidebar = createSidebar();
200
- let state = {
201
- appId: "",
202
- baseUrl: "https://widget.plucky.ai",
203
- mode: "push",
204
- containerId: void 0,
205
- user: {},
206
- tools: [],
207
- tags: [],
208
- width: 360,
209
- fullscreen: false
210
- };
211
- let currentMode = "push";
212
- let resizeListener = null;
213
- function getScrollbarWidth() {
214
- return window.innerWidth - document.documentElement.clientWidth;
215
- }
216
- function getFullscreenWidth() {
217
- const scrollbarWidth = getScrollbarWidth();
218
- return scrollbarWidth > 0 ? `calc(100vw - ${scrollbarWidth}px)` : "100vw";
219
- }
220
- function post(type, payload) {
221
- const iframe = sidebar.getIframe();
222
- const targetOrigin = new URL(state.baseUrl).origin;
223
- iframe?.contentWindow?.postMessage({
224
- type,
225
- payload
226
- }, targetOrigin);
227
- }
228
- function switchMode(next) {
229
- if (next === currentMode) return;
230
- sidebar.setMode(next);
231
- currentMode = next;
232
- }
233
- function init$1(opts) {
234
- if (inited) return api$1;
235
- const { tools,...rest } = opts;
236
- state = {
237
- ...state,
238
- ...rest
239
- };
240
- if (tools && tools.length > 0) registerManyTools(tools, false);
241
- currentMode = state.mode;
242
- bindPostMessage(bus, window, new URL(state.baseUrl).origin);
243
- bus.on("PLUCKY_CLOSE", () => sidebar.hide());
244
- bus.on("PLUCKY_WIDGET_MOUNTED", () => {
245
- const existingToken = safeLocalStorageGet(`pls::${state.appId}`);
246
- post("PLUCKY_LOAD_CONFIG", {
247
- appId: state.appId,
248
- user: state.user,
249
- mode: state.mode,
250
- sessionToken: existingToken || void 0,
251
- tools: getAllToolJSON(),
252
- tags: state.tags
253
- });
254
- if (!existingToken) post("PLUCKY_SESSION_REQUEST", { reason: "missing" });
255
- });
256
- sidebar.mount({
257
- appId: state.appId,
258
- baseUrl: state.baseUrl,
259
- iframeTitle: "Plucky",
260
- initialMode: currentMode,
261
- widthPx: state.width
262
- });
263
- bus.on("PLUCKY_SET_WIDTH", (px) => sidebar.setWidth(px));
264
- bus.on("PLUCKY_SWITCH_MODE", (m) => setMode(m));
265
- bus.on("PLUCKY_SESSION_UPDATED", (payload) => {
266
- const storageKey = `pls::${state.appId}`;
267
- if (typeof payload.token === "string" && payload.token) safeLocalStorageSet(storageKey, payload.token);
268
- });
269
- bus.on("PLUCKY_SET_FULLSCREEN", (payload) => setFullscreen(payload.fullscreen));
270
- bus.on("PLUCKY_RESPONSE_RECEIVED", async (response) => {
271
- const lastMessage = response.messages[response.messages.length - 1];
272
- if (typeof lastMessage.content === "string") return;
273
- const toolResultIds = lastMessage.content.filter((m) => m.type === "tool_result").map((m) => m.toolUseId);
274
- const unfulfilledToolCalls = lastMessage.content.filter((m) => m.type === "tool_use").filter((m) => !toolResultIds.includes(m.id));
275
- if (unfulfilledToolCalls.length === 0) return;
276
- const promises = unfulfilledToolCalls.map(async (toolCall) => {
277
- const tool = state.tools.find((t) => t.name === toolCall.name);
278
- if (!tool) return {
279
- toolUseId: toolCall.id,
280
- content: "Tool not found.",
281
- type: "tool_result"
282
- };
283
- if (!tool.cb) return {
284
- toolUseId: toolCall.id,
285
- content: "Received.",
286
- type: "tool_result"
287
- };
288
- try {
289
- let input = toolCall.input;
290
- if (typeof input === "string") input = JSON.parse(input);
291
- const result = await tool.cb(input);
292
- return {
293
- toolUseId: toolCall.id,
294
- content: result,
295
- type: "tool_result"
296
- };
297
- } catch (e) {
298
- return {
299
- toolUseId: toolCall.id,
300
- content: `Error: ${e instanceof Error ? e.message : String(e)}`,
301
- type: "tool_result"
302
- };
303
- }
304
- });
305
- sendMessage({
306
- content: await Promise.all(promises),
307
- lastMessageId: lastMessage.id,
308
- chatId: response.chatId
309
- });
310
- });
311
- inited = true;
312
- return api$1;
313
- }
314
- function sendMessage(args) {
315
- const { content, lastMessageId, createChat, chatId } = args;
316
- if (sidebar.isHidden()) sidebar.show();
317
- post("PLUCKY_SEND_MESSAGE", {
318
- content,
319
- createChat: createChat ?? false,
320
- lastMessageId,
321
- chatId
322
- });
323
- }
324
- function setInput(input) {
325
- sidebar.getIframe()?.contentWindow?.focus();
326
- post("PLUCKY_SET_INPUT", { input });
327
- }
328
- function setMode(mode) {
329
- state.mode = mode;
330
- currentMode = mode;
331
- sidebar.setMode(mode);
332
- post("PLUCKY_SWITCH_MODE", mode);
333
- }
334
- function on(event, cb) {
335
- return bus.on(event, cb);
336
- }
337
- function open() {
338
- sidebar.show();
339
- }
340
- function close() {
341
- sidebar.hide();
342
- }
343
- function toggle() {
344
- if (sidebar.isHidden()) sidebar.show();
345
- else sidebar.hide();
346
- }
347
- function registerTool(tool, notify = true) {
348
- const currentToolState = getAllToolJSON();
349
- if (state.tools.find((t) => t.name === tool.name)) state.tools = state.tools.filter((t) => t.name !== tool.name);
350
- state.tools.push(tool);
351
- state.tools.sort((a, b) => a.name.localeCompare(b.name));
352
- const newToolState = getAllToolJSON();
353
- if (notify && !dequal(currentToolState, newToolState)) notifyToolConfigUpdated();
354
- }
355
- function registerManyTools(tools, notify = true) {
356
- const currentToolState = getAllToolJSON();
357
- for (const tool of tools) registerTool(tool, false);
358
- const newToolState = getAllToolJSON();
359
- if (notify && !dequal(currentToolState, newToolState)) notifyToolConfigUpdated();
360
- }
361
- function removeTool(name, notify = true) {
362
- if (!state.tools.find((t) => t.name === name)) console.warn(`Tool ${name} not found, skipping.`);
363
- state.tools = state.tools.filter((t) => t.name !== name);
364
- if (notify) notifyToolConfigUpdated();
365
- }
366
- function notifyToolConfigUpdated() {
367
- post("PLUCKY_TOOL_CONFIG_UPDATED", { tools: getAllToolJSON() });
368
- }
369
- function getAllToolJSON() {
370
- return state.tools.map((t) => ({
371
- name: t.name,
372
- description: t.description,
373
- defaultLoadingText: t.defaultLoadingText,
374
- defaultSuccessText: t.defaultSuccessText,
375
- inputSchema: t.inputSchema instanceof ZodObject ? z.toJSONSchema(t.inputSchema) : t.inputSchema
376
- }));
377
- }
378
- function setWidth(px) {
379
- state.width = px;
380
- sidebar.setWidth(px);
381
- }
382
- function setFullscreen(fullscreen) {
383
- state.fullscreen = fullscreen;
384
- if (resizeListener) {
385
- window.removeEventListener("resize", resizeListener);
386
- resizeListener = null;
387
- }
388
- if (fullscreen) {
389
- sidebar.setWidth(getFullscreenWidth());
390
- sidebar.setMode("overlay");
391
- resizeListener = () => {
392
- if (state.fullscreen) sidebar.setWidth(getFullscreenWidth());
393
- };
394
- window.addEventListener("resize", resizeListener);
395
- } else {
396
- sidebar.setWidth(state.width);
397
- sidebar.setMode("push");
398
- }
399
- }
400
- const api$1 = {
401
- init: init$1,
402
- setMode,
403
- switchMode,
404
- open,
405
- close,
406
- toggle,
407
- on,
408
- isReady: () => sidebar.ready(),
409
- sendMessage,
410
- isOpen: () => !sidebar.isHidden(),
411
- registerTool,
412
- registerManyTools,
413
- removeTool,
414
- setInput,
415
- setWidth,
416
- setFullscreen
417
- };
418
- return api$1;
35
+ function setFullscreen(fullscreen) {
36
+ runIfLoaded((Plucky$1) => {
37
+ Plucky$1("setFullscreen", { fullscreen });
38
+ });
419
39
  }
420
-
421
- //#endregion
422
- //#region src/index.ts
423
- let api = null;
424
- function init(opts) {
425
- if (!api) api = createAPI();
426
- return api.init(opts);
40
+ function toggle() {
41
+ runIfLoaded((Plucky$1) => {
42
+ Plucky$1("toggle");
43
+ });
427
44
  }
428
- function getAPI() {
429
- if (!api) api = createAPI();
430
- return api;
45
+ function runIfLoaded(fn) {
46
+ if (typeof window !== "undefined" && window.Plucky) fn(window.Plucky);
47
+ else console.warn("Window is not defined");
431
48
  }
432
49
 
433
50
  //#endregion
434
- export { getAPI, init };
51
+ export { Plucky, addTools, removeTools, sendMessage, setFullscreen, setWidth, toggle };
435
52
  //# sourceMappingURL=index.js.map
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":[],"sources":["../src/Plucky.ts","../src/index.ts"],"sourcesContent":["import { type PluckySettingsParams } from '@plucky-ai/loader-types'\n\nexport function Plucky(options: PluckySettingsParams) {\n const settingScript = document.createElement('script')\n settingScript.id = 'plucky-settings'\n settingScript.textContent = `window.pluckySettings = ${JSON.stringify(options)}`\n document.head.appendChild(settingScript)\n\n const initScript = document.createElement('script')\n initScript.id = 'plucky-init'\n initScript.textContent = `(function(){var w=window;var ic=w.Plucky;if(typeof ic===\"function\"){ic('update',w.pluckySettings);}else{var d=document;var i=function(){i.c(arguments);};i.q=[];i.c=function(args){i.q.push(args);};w.Plucky=i;var l=function(){var s=d.createElement('script');s.type='text/javascript';s.async=true;s.src=(window.pluckySettings.baseUrl||'https://widget.plucky.ai')+'/loader/'+window.pluckySettings.appId;var x=d.getElementsByTagName('script')[0];x.parentNode.insertBefore(s, x);};if(document.readyState==='complete'){l();}else if(w.attachEvent){w.attachEvent('onload',l);}else{w.addEventListener('load',l,false);}}})();`\n document.head.appendChild(initScript)\n}\n","import { ToolConfig } from '@plucky-ai/loader-types'\nimport { PluckyFunction } from './types'\n\nexport type { ToolConfig } from '@plucky-ai/loader-types'\nexport { Plucky } from './Plucky'\nexport function sendMessage(args: { content: string; createChat?: boolean }) {\n runIfLoaded((Plucky) => {\n Plucky('sendMessage', args)\n })\n}\n\nexport function addTools(tools: ToolConfig[]) {\n runIfLoaded((Plucky) => {\n Plucky('addTools', tools)\n })\n}\n\nexport function removeTools(tools: string[]) {\n runIfLoaded((Plucky) => {\n Plucky('removeTools', tools)\n })\n}\n\nexport function setWidth(px: number) {\n runIfLoaded((Plucky) => {\n Plucky('setWidth', px)\n })\n}\n\nexport function setFullscreen(fullscreen: boolean) {\n runIfLoaded((Plucky) => {\n Plucky('setFullscreen', { fullscreen })\n })\n}\n\nexport function toggle() {\n runIfLoaded((Plucky) => {\n Plucky('toggle')\n })\n}\n\nfunction runIfLoaded(fn: (arg: PluckyFunction) => void) {\n if (typeof window !== 'undefined' && window.Plucky) {\n fn(window.Plucky)\n } else {\n console.warn('Window is not defined')\n }\n}\n"],"mappings":";AAEA,SAAgB,OAAO,SAA+B;CACpD,MAAM,gBAAgB,SAAS,cAAc,SAAS;AACtD,eAAc,KAAK;AACnB,eAAc,cAAc,2BAA2B,KAAK,UAAU,QAAQ;AAC9E,UAAS,KAAK,YAAY,cAAc;CAExC,MAAM,aAAa,SAAS,cAAc,SAAS;AACnD,YAAW,KAAK;AAChB,YAAW,cAAc;AACzB,UAAS,KAAK,YAAY,WAAW;;;;;ACNvC,SAAgB,YAAY,MAAiD;AAC3E,cAAa,aAAW;AACtB,WAAO,eAAe,KAAK;GAC3B;;AAGJ,SAAgB,SAAS,OAAqB;AAC5C,cAAa,aAAW;AACtB,WAAO,YAAY,MAAM;GACzB;;AAGJ,SAAgB,YAAY,OAAiB;AAC3C,cAAa,aAAW;AACtB,WAAO,eAAe,MAAM;GAC5B;;AAGJ,SAAgB,SAAS,IAAY;AACnC,cAAa,aAAW;AACtB,WAAO,YAAY,GAAG;GACtB;;AAGJ,SAAgB,cAAc,YAAqB;AACjD,cAAa,aAAW;AACtB,WAAO,iBAAiB,EAAE,YAAY,CAAC;GACvC;;AAGJ,SAAgB,SAAS;AACvB,cAAa,aAAW;AACtB,WAAO,SAAS;GAChB;;AAGJ,SAAS,YAAY,IAAmC;AACtD,KAAI,OAAO,WAAW,eAAe,OAAO,OAC1C,IAAG,OAAO,OAAO;KAEjB,SAAQ,KAAK,wBAAwB"}
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plucky-ai/chat-sdk",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "main": "./index.cjs",
6
6
  "module": "./index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plucky-ai/chat-sdk",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -13,15 +13,13 @@
13
13
  }
14
14
  },
15
15
  "dependencies": {
16
- "dequal": "^2.0.3",
17
- "zod": "^4.1.11",
18
- "@plucky-ai/llm": "^0.1.0",
19
- "@plucky-ai/llm-schemas": "^0.1.0"
16
+ "@plucky-ai/loader-types": "^0.2.1"
20
17
  },
21
18
  "devDependencies": {
22
- "tsdown": "^0.15.9",
23
- "tsx": "^4.20.5",
24
- "typescript": "^5.9.2"
19
+ "tsdown": "^0.15.12",
20
+ "tsx": "^4.20.6",
21
+ "typescript": "^5.9.3",
22
+ "@plucky-ai/loader": "0.2.1"
25
23
  },
26
24
  "publishConfig": {
27
25
  "access": "public",