@nexvio-ai/widget-js 0.1.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/react.cjs ADDED
@@ -0,0 +1,1550 @@
1
+ "use strict";
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 __typeError = (msg) => {
9
+ throw TypeError(msg);
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: true });
14
+ };
15
+ var __copyProps = (to, from, except, desc) => {
16
+ if (from && typeof from === "object" || typeof from === "function") {
17
+ for (let key of __getOwnPropNames(from))
18
+ if (!__hasOwnProp.call(to, key) && key !== except)
19
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
+ // If the importer is in node compatibility mode or this is not an ESM
25
+ // file that has been converted to a CommonJS file using a Babel-
26
+ // compatible transform (i.e. "__esModule" has not been set), then set
27
+ // "default" to the CommonJS "module.exports" for node compatibility.
28
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
+ mod
30
+ ));
31
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
33
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
34
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
35
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
36
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
37
+
38
+ // src/react/index.ts
39
+ var react_exports = {};
40
+ __export(react_exports, {
41
+ NexvioChatbot: () => NexvioChatbot,
42
+ NexvioWidget: () => NexvioWidget,
43
+ useNexvioChatbot: () => useNexvioChatbot,
44
+ useNexvioWidget: () => useNexvioWidget
45
+ });
46
+ module.exports = __toCommonJS(react_exports);
47
+
48
+ // src/react/NexvioChatbot.tsx
49
+ var React = __toESM(require("react"), 1);
50
+
51
+ // src/react/useNexvioChatbot.ts
52
+ var import_react2 = require("react");
53
+
54
+ // src/utils/debug.ts
55
+ function debugEnabled() {
56
+ try {
57
+ return typeof window !== "undefined" && window.__NEXVIO_WIDGET_DEBUG === true;
58
+ } catch {
59
+ return false;
60
+ }
61
+ }
62
+ function log(...args) {
63
+ if (debugEnabled()) console.log(...args);
64
+ }
65
+ function warn(...args) {
66
+ if (debugEnabled()) console.warn(...args);
67
+ }
68
+ function debug(...args) {
69
+ if (debugEnabled()) console.debug(...args);
70
+ }
71
+
72
+ // src/utils/EventEmitter.ts
73
+ var _listeners;
74
+ var EventEmitter = class {
75
+ constructor() {
76
+ __privateAdd(this, _listeners, /* @__PURE__ */ new Map());
77
+ }
78
+ on(event, listener) {
79
+ if (!__privateGet(this, _listeners).has(event)) {
80
+ __privateGet(this, _listeners).set(event, /* @__PURE__ */ new Set());
81
+ }
82
+ __privateGet(this, _listeners).get(event)?.add(listener);
83
+ }
84
+ once(event, listener) {
85
+ const onceListener = (payload) => {
86
+ this.off(event, onceListener);
87
+ listener(payload);
88
+ };
89
+ this.on(event, onceListener);
90
+ }
91
+ emit(event, payload) {
92
+ __privateGet(this, _listeners).get(event)?.forEach((listener) => listener(payload));
93
+ }
94
+ off(event, listener) {
95
+ if (!listener) {
96
+ __privateGet(this, _listeners).delete(event);
97
+ return;
98
+ }
99
+ __privateGet(this, _listeners).get(event)?.delete(listener);
100
+ }
101
+ clear() {
102
+ __privateGet(this, _listeners).clear();
103
+ }
104
+ };
105
+ _listeners = new WeakMap();
106
+
107
+ // src/utils/serializeError.ts
108
+ function serializeError(error) {
109
+ if (error instanceof Error) {
110
+ return {
111
+ name: error.name,
112
+ message: error.message,
113
+ stack: error.stack
114
+ };
115
+ }
116
+ if (typeof error === "object" && error !== null) {
117
+ const obj = error;
118
+ return {
119
+ name: typeof obj.name === "string" ? obj.name : "Error",
120
+ message: typeof obj.message === "string" ? obj.message : "Unknown error",
121
+ stack: typeof obj.stack === "string" ? obj.stack : void 0,
122
+ metadata: Object.fromEntries(Object.entries(obj).filter(([key]) => !["name", "message", "stack"].includes(key)))
123
+ };
124
+ }
125
+ return {
126
+ name: "Error",
127
+ message: String(error)
128
+ };
129
+ }
130
+ function deserializeError(serialized) {
131
+ const error = new Error(serialized.message);
132
+ error.name = serialized.name;
133
+ if (serialized.stack) {
134
+ error.stack = serialized.stack;
135
+ }
136
+ return error;
137
+ }
138
+
139
+ // src/messenger/BaseMessenger.ts
140
+ var MESSAGE_TOKEN = "__nexvioWidget";
141
+ var DEFAULT_COMMAND_CAPABILITY = () => true;
142
+ var _target, _targetOrigin, _handlers, _fetch, _events, _canReceiveCommand, _pending, _abortControllers, _BaseMessenger_instances, sendMessage_fn, sendCommand_fn, _handleMessage, isWidgetMessage_fn;
143
+ var BaseMessenger = class {
144
+ constructor(config) {
145
+ __privateAdd(this, _BaseMessenger_instances);
146
+ __privateAdd(this, _target);
147
+ __privateAdd(this, _targetOrigin);
148
+ __privateAdd(this, _handlers);
149
+ __privateAdd(this, _fetch);
150
+ __privateAdd(this, _events, new EventEmitter());
151
+ __privateAdd(this, _canReceiveCommand);
152
+ __privateAdd(this, _pending, /* @__PURE__ */ new Map());
153
+ __privateAdd(this, _abortControllers, /* @__PURE__ */ new Map());
154
+ this.commands = new Proxy(
155
+ {},
156
+ {
157
+ get: (_, command) => {
158
+ return (payload, transfer) => {
159
+ return __privateMethod(this, _BaseMessenger_instances, sendCommand_fn).call(this, command, payload, transfer);
160
+ };
161
+ }
162
+ }
163
+ );
164
+ __privateAdd(this, _handleMessage, async (event) => {
165
+ debug("[NexvioWidget][Messenger] window.message", {
166
+ origin: event.origin,
167
+ hasToken: !!(event.data && typeof event.data === "object" && event.data[MESSAGE_TOKEN] === true)
168
+ });
169
+ if (!__privateMethod(this, _BaseMessenger_instances, isWidgetMessage_fn).call(this, event)) {
170
+ return;
171
+ }
172
+ const data = event.data;
173
+ switch (data.type) {
174
+ case "event": {
175
+ log("[NexvioWidget][Messenger] <- event", { event: data.event, payload: data.payload });
176
+ __privateGet(this, _events).emit(data.event, data.payload);
177
+ break;
178
+ }
179
+ case "response": {
180
+ const handler = __privateGet(this, _pending).get(data.nonce);
181
+ if (!handler) {
182
+ warn("[NexvioWidget][Messenger] missing pending handler for response", data.nonce);
183
+ return;
184
+ }
185
+ __privateGet(this, _pending).delete(data.nonce);
186
+ if (data.error) {
187
+ handler.reject(deserializeError(data.error));
188
+ } else {
189
+ handler.resolve(data.payload);
190
+ }
191
+ break;
192
+ }
193
+ case "command": {
194
+ if (!__privateGet(this, _canReceiveCommand).call(this, data.command)) {
195
+ __privateMethod(this, _BaseMessenger_instances, sendMessage_fn).call(this, {
196
+ type: "response",
197
+ nonce: data.nonce,
198
+ error: serializeError(new Error(`Command "${data.command}" is not supported by the host`))
199
+ });
200
+ return;
201
+ }
202
+ const commandCapitalized = `on${data.command.charAt(0).toUpperCase()}${data.command.slice(1)}`;
203
+ const handler = __privateGet(this, _handlers)[commandCapitalized];
204
+ if (!handler) {
205
+ __privateMethod(this, _BaseMessenger_instances, sendMessage_fn).call(this, {
206
+ type: "response",
207
+ nonce: data.nonce,
208
+ error: serializeError(new Error(`Command handler "${data.command}" not implemented by host`))
209
+ });
210
+ return;
211
+ }
212
+ try {
213
+ log("[NexvioWidget][Messenger] <- command", { command: data.command, payload: data.payload });
214
+ const result = await handler(data.payload);
215
+ __privateMethod(this, _BaseMessenger_instances, sendMessage_fn).call(this, { type: "response", nonce: data.nonce, payload: result });
216
+ } catch (error) {
217
+ __privateMethod(this, _BaseMessenger_instances, sendMessage_fn).call(this, {
218
+ type: "response",
219
+ nonce: data.nonce,
220
+ error: serializeError(error)
221
+ });
222
+ }
223
+ break;
224
+ }
225
+ case "fetch": {
226
+ log("[NexvioWidget][Messenger] <- fetch", { url: data.url });
227
+ const controller = new AbortController();
228
+ __privateGet(this, _abortControllers).set(data.nonce, controller);
229
+ try {
230
+ const response = await __privateGet(this, _fetch).call(this, data.url, {
231
+ ...data.init,
232
+ signal: controller.signal
233
+ });
234
+ const contentType = response.headers.get("content-type") ?? "";
235
+ let payload;
236
+ if (contentType.includes("application/json")) {
237
+ payload = await response.json();
238
+ } else {
239
+ payload = await response.text();
240
+ }
241
+ __privateMethod(this, _BaseMessenger_instances, sendMessage_fn).call(this, {
242
+ type: "response",
243
+ nonce: data.nonce,
244
+ payload: {
245
+ ok: response.ok,
246
+ status: response.status,
247
+ statusText: response.statusText,
248
+ headers: Object.fromEntries(response.headers.entries()),
249
+ body: payload
250
+ }
251
+ });
252
+ } catch (error) {
253
+ __privateMethod(this, _BaseMessenger_instances, sendMessage_fn).call(this, {
254
+ type: "response",
255
+ nonce: data.nonce,
256
+ error: serializeError(error)
257
+ });
258
+ } finally {
259
+ __privateGet(this, _abortControllers).delete(data.nonce);
260
+ }
261
+ break;
262
+ }
263
+ case "abort": {
264
+ const controller = __privateGet(this, _abortControllers).get(data.nonce);
265
+ controller?.abort(data.reason);
266
+ __privateGet(this, _abortControllers).delete(data.nonce);
267
+ break;
268
+ }
269
+ default:
270
+ break;
271
+ }
272
+ });
273
+ __privateSet(this, _target, config.target);
274
+ __privateSet(this, _targetOrigin, config.targetOrigin);
275
+ __privateSet(this, _handlers, config.handlers);
276
+ __privateSet(this, _fetch, config.fetch ?? fetch.bind(globalThis));
277
+ __privateSet(this, _canReceiveCommand, config.canReceiveCommand ?? DEFAULT_COMMAND_CAPABILITY);
278
+ }
279
+ connect() {
280
+ log("[NexvioWidget][Messenger] connect", { targetOrigin: __privateGet(this, _targetOrigin) });
281
+ window.addEventListener("message", __privateGet(this, _handleMessage));
282
+ }
283
+ disconnect() {
284
+ log("[NexvioWidget][Messenger] disconnect");
285
+ window.removeEventListener("message", __privateGet(this, _handleMessage));
286
+ __privateGet(this, _events).clear();
287
+ __privateGet(this, _pending).clear();
288
+ __privateGet(this, _abortControllers).forEach((controller) => controller.abort());
289
+ __privateGet(this, _abortControllers).clear();
290
+ }
291
+ on(event, listener) {
292
+ __privateGet(this, _events).on(event, listener);
293
+ }
294
+ off(event, listener) {
295
+ __privateGet(this, _events).off(event, listener);
296
+ }
297
+ };
298
+ _target = new WeakMap();
299
+ _targetOrigin = new WeakMap();
300
+ _handlers = new WeakMap();
301
+ _fetch = new WeakMap();
302
+ _events = new WeakMap();
303
+ _canReceiveCommand = new WeakMap();
304
+ _pending = new WeakMap();
305
+ _abortControllers = new WeakMap();
306
+ _BaseMessenger_instances = new WeakSet();
307
+ sendMessage_fn = function(message, transfer) {
308
+ const target = __privateGet(this, _target).call(this);
309
+ if (!target) {
310
+ throw new Error("Widget frame not ready");
311
+ }
312
+ const payload = { ...message, [MESSAGE_TOKEN]: true };
313
+ try {
314
+ debug("[NexvioWidget][Messenger] postMessage", {
315
+ type: message.type,
316
+ command: message.command,
317
+ targetOrigin: __privateGet(this, _targetOrigin)
318
+ });
319
+ target.postMessage(payload, __privateGet(this, _targetOrigin), transfer);
320
+ } catch (error) {
321
+ const shouldRetryWithAnyOrigin = __privateGet(this, _targetOrigin) !== "*" && error instanceof DOMException && (error.name === "SecurityError" || /target origin provided/i.test(error.message));
322
+ if (shouldRetryWithAnyOrigin) {
323
+ warn('[NexvioWidget][Messenger] SecurityError posting to targetOrigin. Retrying with "*"');
324
+ target.postMessage(payload, "*", transfer);
325
+ return;
326
+ }
327
+ throw error;
328
+ }
329
+ };
330
+ sendCommand_fn = async function(command, payload, transfer) {
331
+ const nonce = crypto.randomUUID();
332
+ return new Promise((resolve, reject) => {
333
+ __privateGet(this, _pending).set(nonce, { resolve, reject, stack: new Error().stack ?? "" });
334
+ try {
335
+ __privateMethod(this, _BaseMessenger_instances, sendMessage_fn).call(this, { type: "command", command, payload, nonce }, transfer);
336
+ } catch (error) {
337
+ __privateGet(this, _pending).delete(nonce);
338
+ reject(error);
339
+ }
340
+ });
341
+ };
342
+ _handleMessage = new WeakMap();
343
+ isWidgetMessage_fn = function(event) {
344
+ if (!event.data || typeof event.data !== "object" || event.data[MESSAGE_TOKEN] !== true) {
345
+ return false;
346
+ }
347
+ const targetWin = __privateGet(this, _target).call(this);
348
+ if (targetWin && event.source && event.source !== targetWin) {
349
+ debug("[NexvioWidget][Messenger] drop message: source mismatch");
350
+ return false;
351
+ }
352
+ if (event.origin !== __privateGet(this, _targetOrigin)) {
353
+ if (targetWin && event.source === targetWin) {
354
+ warn("[NexvioWidget][Messenger] learning targetOrigin from first message", {
355
+ from: __privateGet(this, _targetOrigin),
356
+ to: event.origin
357
+ });
358
+ __privateSet(this, _targetOrigin, event.origin);
359
+ } else {
360
+ debug("[NexvioWidget][Messenger] drop message: origin mismatch", {
361
+ expected: __privateGet(this, _targetOrigin),
362
+ got: event.origin
363
+ });
364
+ return false;
365
+ }
366
+ }
367
+ return true;
368
+ };
369
+
370
+ // src/messenger/WidgetFrameMessenger.ts
371
+ var WidgetFrameMessenger = class extends BaseMessenger {
372
+ constructor(config) {
373
+ super({
374
+ target: config.target,
375
+ targetOrigin: config.targetOrigin,
376
+ handlers: config.handlers,
377
+ fetch: config.fetch,
378
+ canReceiveCommand: () => true
379
+ });
380
+ }
381
+ };
382
+
383
+ // src/utils/base64.ts
384
+ function toBase64(input) {
385
+ if (typeof globalThis.btoa === "function") {
386
+ return globalThis.btoa(input);
387
+ }
388
+ const buffer = globalThis.Buffer;
389
+ if (buffer) {
390
+ return buffer.from(input, "binary").toString("base64");
391
+ }
392
+ throw new Error("No base64 encoder available in this environment");
393
+ }
394
+ function encodeBase64(value) {
395
+ if (value === void 0) {
396
+ throw new TypeError("encodeBase64: `undefined` cannot be serialized. Pass null instead.");
397
+ }
398
+ const json = JSON.stringify(value);
399
+ const bytes = new TextEncoder().encode(json);
400
+ let binary = "";
401
+ for (const byte of bytes) {
402
+ binary += String.fromCharCode(byte);
403
+ }
404
+ return toBase64(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
405
+ }
406
+
407
+ // src/utils/stripFunctions.ts
408
+ function stripFunctions(input, cloneMap = /* @__PURE__ */ new WeakMap()) {
409
+ if (typeof input !== "object" || input === null) {
410
+ return input;
411
+ }
412
+ if (cloneMap.has(input)) {
413
+ return cloneMap.get(input);
414
+ }
415
+ if (Array.isArray(input)) {
416
+ const arrClone = [];
417
+ cloneMap.set(input, arrClone);
418
+ for (const item of input) {
419
+ arrClone.push(stripFunctions(item, cloneMap));
420
+ }
421
+ return arrClone;
422
+ }
423
+ const clone = {};
424
+ cloneMap.set(input, clone);
425
+ for (const [key, value] of Object.entries(input)) {
426
+ if (typeof value === "function") {
427
+ continue;
428
+ }
429
+ clone[key] = stripFunctions(value, cloneMap);
430
+ }
431
+ return clone;
432
+ }
433
+
434
+ // src/utils/zod-to-json-schema.ts
435
+ function zodToJsonSchema(schema) {
436
+ if (!schema || !schema._def) {
437
+ return { type: "object", properties: {}, additionalProperties: false };
438
+ }
439
+ const def = schema._def;
440
+ const typeName = def.typeName;
441
+ if (typeName === "ZodObject") {
442
+ const shape = def.shape();
443
+ const properties = {};
444
+ const required = [];
445
+ for (const key in shape) {
446
+ const fieldSchema = shape[key];
447
+ properties[key] = zodToJsonSchema(fieldSchema);
448
+ if (fieldSchema._def.typeName !== "ZodOptional") {
449
+ required.push(key);
450
+ }
451
+ }
452
+ return {
453
+ type: "object",
454
+ properties,
455
+ required: required.length > 0 ? required : void 0,
456
+ additionalProperties: false
457
+ };
458
+ }
459
+ if (typeName === "ZodString") {
460
+ const result = { type: "string" };
461
+ if (def.description) {
462
+ result.description = def.description;
463
+ }
464
+ return result;
465
+ }
466
+ if (typeName === "ZodNumber") {
467
+ const result = { type: "number" };
468
+ if (def.description) {
469
+ result.description = def.description;
470
+ }
471
+ return result;
472
+ }
473
+ if (typeName === "ZodBoolean") {
474
+ const result = { type: "boolean" };
475
+ if (def.description) {
476
+ result.description = def.description;
477
+ }
478
+ return result;
479
+ }
480
+ if (typeName === "ZodArray") {
481
+ const result = {
482
+ type: "array",
483
+ items: zodToJsonSchema(def.type)
484
+ };
485
+ if (def.description) {
486
+ result.description = def.description;
487
+ }
488
+ return result;
489
+ }
490
+ if (typeName === "ZodEnum") {
491
+ const result = {
492
+ type: "string",
493
+ enum: def.values
494
+ };
495
+ if (def.description) {
496
+ result.description = def.description;
497
+ }
498
+ return result;
499
+ }
500
+ if (typeName === "ZodOptional") {
501
+ return zodToJsonSchema(def.innerType);
502
+ }
503
+ if (typeName === "ZodNullable") {
504
+ const innerSchema = zodToJsonSchema(def.innerType);
505
+ return {
506
+ ...innerSchema,
507
+ nullable: true
508
+ };
509
+ }
510
+ if (typeName === "ZodLiteral") {
511
+ return {
512
+ type: typeof def.value,
513
+ enum: [def.value]
514
+ };
515
+ }
516
+ if (typeName === "ZodUnion") {
517
+ const options = def.options;
518
+ if (options && options.length > 0) {
519
+ return {
520
+ anyOf: options.map((opt) => zodToJsonSchema(opt))
521
+ };
522
+ }
523
+ }
524
+ return { type: "object", additionalProperties: true };
525
+ }
526
+
527
+ // src/NexvioWidgetElement.ts
528
+ var DEFAULT_WIDGET_URL = "https://chatwidget.app";
529
+ var WIDGET_VERSION = "0.1.0";
530
+ var styleContent = `
531
+ :host {
532
+ display: block;
533
+ position: relative;
534
+ width: 100%;
535
+ height: 100%;
536
+ }
537
+ .nx-wrapper {
538
+ position: absolute;
539
+ inset: 0;
540
+ width: 100%;
541
+ height: 100%;
542
+ opacity: 0;
543
+ transition: opacity 160ms ease-in-out;
544
+ }
545
+ :host([data-loaded='true']) .nx-wrapper {
546
+ opacity: 1;
547
+ }
548
+ .nx-frame {
549
+ border: none;
550
+ width: 100%;
551
+ height: 100%;
552
+ position: absolute;
553
+ inset: 0;
554
+ background: transparent;
555
+ }
556
+ `;
557
+ var BaseHTMLElement = typeof HTMLElement === "undefined" ? class {
558
+ } : HTMLElement;
559
+ var _shadowRootRef, _frame, _wrapper, _options, _sanitized, _messenger, _loadedResolve, _loaded, _targetOrigin2, _initialized, _frameReady, _pendingOptions, _NexvioWidgetElement_instances, sanitizeOptions_fn, ensureStructure_fn, initializeFrame_fn, _handleFrameLoad, ensureMessenger_fn, buildFrameUrl_fn, updateDataAttributes_fn, handleFrameEvent_fn, handleClientAction_fn, handleExecuteClientTool_fn, dispatchReady_fn, dispatchError_fn, dispatchEvent_fn, handleResize_fn, flushOptionsIfReady_fn;
560
+ var NexvioWidgetElement = class extends BaseHTMLElement {
561
+ constructor() {
562
+ super();
563
+ __privateAdd(this, _NexvioWidgetElement_instances);
564
+ __privateAdd(this, _shadowRootRef, null);
565
+ __privateAdd(this, _frame);
566
+ __privateAdd(this, _wrapper);
567
+ __privateAdd(this, _options);
568
+ __privateAdd(this, _sanitized);
569
+ __privateAdd(this, _messenger);
570
+ __privateAdd(this, _loadedResolve);
571
+ __privateAdd(this, _loaded);
572
+ __privateAdd(this, _targetOrigin2);
573
+ __privateAdd(this, _initialized, false);
574
+ __privateAdd(this, _frameReady, false);
575
+ __privateAdd(this, _pendingOptions);
576
+ __privateAdd(this, _handleFrameLoad, () => {
577
+ var _a;
578
+ debug("[NexvioWidget] frame load event");
579
+ this.dataset.loaded = "true";
580
+ (_a = __privateGet(this, _loadedResolve)) == null ? void 0 : _a.call(this);
581
+ __privateMethod(this, _NexvioWidgetElement_instances, flushOptionsIfReady_fn).call(this);
582
+ });
583
+ if (typeof window !== "undefined" && typeof this.attachShadow === "function") {
584
+ __privateSet(this, _shadowRootRef, this.attachShadow({ mode: "open" }));
585
+ }
586
+ log("[NexvioWidget] element: constructed");
587
+ __privateSet(this, _loaded, new Promise((resolve) => {
588
+ __privateSet(this, _loadedResolve, resolve);
589
+ }));
590
+ }
591
+ connectedCallback() {
592
+ log("[NexvioWidget] element: connectedCallback");
593
+ __privateMethod(this, _NexvioWidgetElement_instances, ensureStructure_fn).call(this);
594
+ if (__privateGet(this, _sanitized) && !__privateGet(this, _initialized)) {
595
+ __privateMethod(this, _NexvioWidgetElement_instances, initializeFrame_fn).call(this);
596
+ }
597
+ }
598
+ disconnectedCallback() {
599
+ log("[NexvioWidget] element: disconnectedCallback");
600
+ __privateGet(this, _messenger)?.disconnect();
601
+ }
602
+ setOptions(options) {
603
+ log("[NexvioWidget] setOptions: received", options);
604
+ const sanitized = __privateMethod(this, _NexvioWidgetElement_instances, sanitizeOptions_fn).call(this, options);
605
+ const previous = __privateGet(this, _sanitized);
606
+ const baseUrl = sanitized.host?.baseUrl ?? DEFAULT_WIDGET_URL;
607
+ debug("[NexvioWidget] setOptions: sanitized", sanitized);
608
+ __privateMethod(this, _NexvioWidgetElement_instances, ensureMessenger_fn).call(this, new URL(baseUrl).origin, options.fetch);
609
+ __privateSet(this, _options, options);
610
+ __privateSet(this, _sanitized, sanitized);
611
+ __privateSet(this, _pendingOptions, sanitized);
612
+ const requiresReload = !__privateGet(this, _initialized) || !previous || previous.publicKey !== sanitized.publicKey || (previous.host?.baseUrl ?? DEFAULT_WIDGET_URL) !== (sanitized.host?.baseUrl ?? DEFAULT_WIDGET_URL) || // Reload if clientTools changed (added, removed, or modified)
613
+ JSON.stringify(previous.clientTools) !== JSON.stringify(sanitized.clientTools);
614
+ debug("[NexvioWidget] setOptions: requiresReload", {
615
+ requiresReload,
616
+ reasons: {
617
+ notInitialized: !__privateGet(this, _initialized),
618
+ noPrevious: !previous,
619
+ publicKeyChanged: previous && previous.publicKey !== sanitized.publicKey,
620
+ baseUrlChanged: previous && (previous.host?.baseUrl ?? DEFAULT_WIDGET_URL) !== (sanitized.host?.baseUrl ?? DEFAULT_WIDGET_URL),
621
+ clientToolsChanged: previous && JSON.stringify(previous.clientTools) !== JSON.stringify(sanitized.clientTools)
622
+ }
623
+ });
624
+ __privateMethod(this, _NexvioWidgetElement_instances, updateDataAttributes_fn).call(this, sanitized);
625
+ if (requiresReload) {
626
+ __privateMethod(this, _NexvioWidgetElement_instances, initializeFrame_fn).call(this, true);
627
+ return;
628
+ }
629
+ __privateMethod(this, _NexvioWidgetElement_instances, flushOptionsIfReady_fn).call(this);
630
+ }
631
+ async focusInput() {
632
+ await __privateGet(this, _loaded);
633
+ await __privateGet(this, _messenger)?.commands.focusInput();
634
+ }
635
+ async refresh() {
636
+ await __privateGet(this, _loaded);
637
+ await __privateGet(this, _messenger)?.commands.refresh();
638
+ }
639
+ async setVisitor(visitor) {
640
+ await __privateGet(this, _loaded);
641
+ await __privateGet(this, _messenger)?.commands.updateVisitor(visitor);
642
+ }
643
+ async reload() {
644
+ if (!__privateGet(this, _sanitized)) return;
645
+ __privateSet(this, _initialized, false);
646
+ __privateMethod(this, _NexvioWidgetElement_instances, initializeFrame_fn).call(this, true);
647
+ }
648
+ get options() {
649
+ return __privateGet(this, _options);
650
+ }
651
+ };
652
+ _shadowRootRef = new WeakMap();
653
+ _frame = new WeakMap();
654
+ _wrapper = new WeakMap();
655
+ _options = new WeakMap();
656
+ _sanitized = new WeakMap();
657
+ _messenger = new WeakMap();
658
+ _loadedResolve = new WeakMap();
659
+ _loaded = new WeakMap();
660
+ _targetOrigin2 = new WeakMap();
661
+ _initialized = new WeakMap();
662
+ _frameReady = new WeakMap();
663
+ _pendingOptions = new WeakMap();
664
+ _NexvioWidgetElement_instances = new WeakSet();
665
+ sanitizeOptions_fn = function(options) {
666
+ if (!options || typeof options.publicKey !== "string" || options.publicKey.trim().length === 0) {
667
+ throw new Error("Nexvio widget requires a non-empty `publicKey`.");
668
+ }
669
+ const hostBase = options.host?.baseUrl ?? DEFAULT_WIDGET_URL;
670
+ let validatedHost;
671
+ try {
672
+ validatedHost = new URL(hostBase);
673
+ } catch (error) {
674
+ throw new Error(`Invalid host baseUrl provided to Nexvio widget: ${error}`);
675
+ }
676
+ const sanitized = stripFunctions({
677
+ publicKey: options.publicKey.trim(),
678
+ appearance: options.appearance,
679
+ messageActions: options.messageActions,
680
+ metadata: options.metadata,
681
+ context: options.context,
682
+ startScreen: options.startScreen,
683
+ host: {
684
+ baseUrl: validatedHost.toString().replace(/\/$/, ""),
685
+ query: options.host?.query
686
+ }
687
+ });
688
+ if (options.client?.tools && Array.isArray(options.client.tools)) {
689
+ log("[NexvioWidget] sanitizeOptions: converting client tools", options.client.tools);
690
+ sanitized.clientTools = options.client.tools.map((tool) => ({
691
+ name: tool.name,
692
+ description: tool.description,
693
+ parameters: zodToJsonSchema(tool.parameters)
694
+ }));
695
+ log("[NexvioWidget] sanitizeOptions: sanitized clientTools", sanitized.clientTools);
696
+ } else {
697
+ log("[NexvioWidget] sanitizeOptions: no client tools found", {
698
+ hasClient: !!options.client,
699
+ hasTools: !!options.client?.tools
700
+ });
701
+ }
702
+ return sanitized;
703
+ };
704
+ ensureStructure_fn = function() {
705
+ if (__privateGet(this, _wrapper)) return;
706
+ if (!__privateGet(this, _shadowRootRef)) return;
707
+ const style = document.createElement("style");
708
+ style.textContent = styleContent;
709
+ const wrapper = document.createElement("div");
710
+ wrapper.className = "nx-wrapper";
711
+ const frame = document.createElement("iframe");
712
+ frame.className = "nx-frame";
713
+ frame.setAttribute("allow", "clipboard-read; clipboard-write");
714
+ frame.setAttribute("referrerpolicy", "strict-origin-when-cross-origin");
715
+ frame.name = "nexvio-widget";
716
+ frame.tabIndex = -1;
717
+ wrapper.appendChild(frame);
718
+ __privateGet(this, _shadowRootRef).append(style, wrapper);
719
+ __privateSet(this, _frame, frame);
720
+ __privateSet(this, _wrapper, wrapper);
721
+ };
722
+ initializeFrame_fn = function(forceReload = false) {
723
+ if (!__privateGet(this, _frame) || !__privateGet(this, _sanitized)) return;
724
+ if (__privateGet(this, _initialized) && !forceReload) return;
725
+ __privateSet(this, _initialized, true);
726
+ __privateSet(this, _frameReady, false);
727
+ this.dataset.loaded = "false";
728
+ __privateSet(this, _loaded, new Promise((resolve) => {
729
+ __privateSet(this, _loadedResolve, resolve);
730
+ }));
731
+ const frameUrl = __privateMethod(this, _NexvioWidgetElement_instances, buildFrameUrl_fn).call(this, __privateGet(this, _sanitized));
732
+ debug("[NexvioWidget] initializeFrame", { forceReload, frameUrl: frameUrl.toString() });
733
+ __privateGet(this, _frame).addEventListener("load", __privateGet(this, _handleFrameLoad), { once: true });
734
+ __privateGet(this, _frame).src = frameUrl.toString();
735
+ __privateMethod(this, _NexvioWidgetElement_instances, updateDataAttributes_fn).call(this, __privateGet(this, _sanitized));
736
+ };
737
+ _handleFrameLoad = new WeakMap();
738
+ ensureMessenger_fn = function(origin, customFetch) {
739
+ if (__privateGet(this, _messenger) && __privateGet(this, _targetOrigin2) === origin) {
740
+ debug("[NexvioWidget] messenger: reuse", { origin });
741
+ return;
742
+ }
743
+ __privateGet(this, _messenger)?.disconnect();
744
+ __privateSet(this, _targetOrigin2, origin);
745
+ log("[NexvioWidget] messenger: create", { origin });
746
+ __privateSet(this, _messenger, new WidgetFrameMessenger({
747
+ target: () => __privateGet(this, _frame)?.contentWindow ?? null,
748
+ targetOrigin: origin,
749
+ fetch: customFetch,
750
+ handlers: {
751
+ onEmitEvent: (payload) => __privateMethod(this, _NexvioWidgetElement_instances, handleFrameEvent_fn).call(this, payload),
752
+ onRequestClientAction: (payload) => __privateMethod(this, _NexvioWidgetElement_instances, handleClientAction_fn).call(this, payload),
753
+ onExecuteClientTool: (payload) => __privateMethod(this, _NexvioWidgetElement_instances, handleExecuteClientTool_fn).call(this, payload)
754
+ }
755
+ }));
756
+ __privateGet(this, _messenger).connect();
757
+ __privateGet(this, _messenger).on("widget.ready", (payload) => __privateMethod(this, _NexvioWidgetElement_instances, dispatchReady_fn).call(this, payload));
758
+ __privateGet(this, _messenger).on("widget.error", (payload) => __privateMethod(this, _NexvioWidgetElement_instances, dispatchError_fn).call(this, payload));
759
+ __privateGet(this, _messenger).on("widget.event", (payload) => __privateMethod(this, _NexvioWidgetElement_instances, dispatchEvent_fn).call(this, payload));
760
+ __privateGet(this, _messenger).on("widget.resize", (payload) => __privateMethod(this, _NexvioWidgetElement_instances, handleResize_fn).call(this, payload));
761
+ };
762
+ buildFrameUrl_fn = function(options) {
763
+ const base = options.host?.baseUrl ?? DEFAULT_WIDGET_URL;
764
+ const trimmedBase = base.endsWith("/") ? base.slice(0, -1) : base;
765
+ const url = new URL(`${trimmedBase}/${encodeURIComponent(options.publicKey)}`);
766
+ url.searchParams.set("embed", "1");
767
+ const query = options.host?.query ?? {};
768
+ for (const [key, value] of Object.entries(query)) {
769
+ if (value === void 0) continue;
770
+ url.searchParams.set(key, String(value));
771
+ }
772
+ const payload = stripFunctions({
773
+ appearance: options.appearance,
774
+ metadata: options.metadata,
775
+ context: options.context,
776
+ startScreen: options.startScreen,
777
+ version: WIDGET_VERSION,
778
+ clientTools: options.clientTools
779
+ });
780
+ log("[NexvioWidget] buildFrameUrl: payload with clientTools", payload);
781
+ if (Object.values(payload).some((value) => value !== void 0)) {
782
+ url.hash = encodeBase64(payload);
783
+ }
784
+ debug("[NexvioWidget] buildFrameUrl", { url: url.toString() });
785
+ return url;
786
+ };
787
+ updateDataAttributes_fn = function(options) {
788
+ const colorScheme = typeof options.appearance?.colorScheme === "string" ? options.appearance.colorScheme : void 0;
789
+ if (colorScheme) {
790
+ this.dataset.colorScheme = colorScheme;
791
+ } else {
792
+ delete this.dataset.colorScheme;
793
+ }
794
+ };
795
+ handleFrameEvent_fn = function({ name, detail }) {
796
+ log("[NexvioWidget] event", { name, detail });
797
+ const event = { name, detail };
798
+ __privateGet(this, _options)?.onEvent?.(event);
799
+ this.dispatchEvent(
800
+ new CustomEvent("nexvio.event", {
801
+ detail: event,
802
+ bubbles: true,
803
+ composed: true
804
+ })
805
+ );
806
+ this.dispatchEvent(
807
+ new CustomEvent(`nexvio.${name}`, {
808
+ detail,
809
+ bubbles: true,
810
+ composed: true
811
+ })
812
+ );
813
+ };
814
+ handleClientAction_fn = async function({
815
+ action,
816
+ data
817
+ }) {
818
+ const handler = __privateGet(this, _options)?.clientActions?.[action];
819
+ if (!handler) {
820
+ throw new Error(`No client action handler registered for "${action}"`);
821
+ }
822
+ return handler(data);
823
+ };
824
+ handleExecuteClientTool_fn = async function({
825
+ toolName,
826
+ toolArgs
827
+ }) {
828
+ log("[NexvioWidget] executeClientTool", { toolName, toolArgs });
829
+ const tool = __privateGet(this, _options)?.client?.tools?.find((t) => t.name === toolName);
830
+ if (!tool) {
831
+ throw new Error(`No client tool registered with name "${toolName}"`);
832
+ }
833
+ try {
834
+ const validated = tool.parameters.parse(toolArgs);
835
+ const result = await Promise.resolve(tool.execute(validated));
836
+ log("[NexvioWidget] executeClientTool: success", { toolName, result });
837
+ return result;
838
+ } catch (error) {
839
+ console.error("[NexvioWidget] executeClientTool: error", { toolName, error });
840
+ throw new Error(`Tool execution failed for "${toolName}": ${error.message}`);
841
+ }
842
+ };
843
+ dispatchReady_fn = function(payload) {
844
+ log("[NexvioWidget] ready", payload);
845
+ __privateSet(this, _frameReady, true);
846
+ __privateMethod(this, _NexvioWidgetElement_instances, flushOptionsIfReady_fn).call(this);
847
+ this.dispatchEvent(
848
+ new CustomEvent("nexvio.ready", {
849
+ detail: payload,
850
+ bubbles: true,
851
+ composed: true
852
+ })
853
+ );
854
+ };
855
+ dispatchError_fn = function(payload) {
856
+ const error = new Error(payload.message);
857
+ if (payload.stack) {
858
+ error.stack = payload.stack;
859
+ }
860
+ log("[NexvioWidget] error", payload);
861
+ this.dispatchEvent(
862
+ new CustomEvent("nexvio.error", {
863
+ detail: { error },
864
+ bubbles: true,
865
+ composed: true
866
+ })
867
+ );
868
+ };
869
+ dispatchEvent_fn = function(payload) {
870
+ __privateMethod(this, _NexvioWidgetElement_instances, handleFrameEvent_fn).call(this, payload);
871
+ };
872
+ handleResize_fn = function(payload) {
873
+ if (typeof payload?.height === "number") {
874
+ this.style.setProperty("--nexvio-widget-height", `${payload.height}px`);
875
+ }
876
+ };
877
+ flushOptionsIfReady_fn = function() {
878
+ if (!__privateGet(this, _frameReady)) return;
879
+ if (!__privateGet(this, _pendingOptions)) return;
880
+ const options = __privateGet(this, _pendingOptions);
881
+ __privateSet(this, _pendingOptions, void 0);
882
+ if (!__privateGet(this, _messenger)) return;
883
+ debug("[NexvioWidget] flushOptionsIfReady: syncing options to frame");
884
+ void __privateGet(this, _messenger).commands.setOptions(options).catch((error) => {
885
+ console.error("Failed to sync widget options:", error);
886
+ });
887
+ };
888
+ function registerNexvioWidget(tagName = "nexvio-chat-widget") {
889
+ if (typeof customElements === "undefined") return;
890
+ if (!customElements.get(tagName)) {
891
+ customElements.define(tagName, NexvioWidgetElement);
892
+ }
893
+ }
894
+
895
+ // src/NexvioChatbotElement.ts
896
+ var styleContent2 = `
897
+ :host {
898
+ --chatbot-button-size: 60px;
899
+ --chatbot-button-bg: #3B82F6;
900
+ --chatbot-button-color: white;
901
+ --chatbot-widget-width: 420px;
902
+ --chatbot-widget-height: 600px;
903
+ --chatbot-widget-gap: 20px;
904
+
905
+ position: fixed;
906
+ bottom: var(--chatbot-widget-gap);
907
+ right: var(--chatbot-widget-gap);
908
+ z-index: 999999;
909
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
910
+ }
911
+
912
+ .nx-chatbot-button {
913
+ width: var(--chatbot-button-size);
914
+ height: var(--chatbot-button-size);
915
+ border-radius: 50%;
916
+ background: var(--chatbot-button-bg);
917
+ color: var(--chatbot-button-color);
918
+ border: none;
919
+ cursor: pointer;
920
+ display: flex;
921
+ align-items: center;
922
+ justify-content: center;
923
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
924
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
925
+ position: relative;
926
+ overflow: hidden;
927
+ }
928
+
929
+ .nx-chatbot-button:hover {
930
+ transform: scale(1.05);
931
+ box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
932
+ }
933
+
934
+ .nx-chatbot-button:active {
935
+ transform: scale(0.95);
936
+ }
937
+
938
+ .nx-chatbot-button svg {
939
+ width: 28px;
940
+ height: 28px;
941
+ transition: transform 0.3s ease, opacity 0.3s ease;
942
+ }
943
+
944
+ .nx-chatbot-button.open svg.icon-chat {
945
+ transform: rotate(90deg) scale(0);
946
+ opacity: 0;
947
+ }
948
+
949
+ .nx-chatbot-button svg.icon-close {
950
+ position: absolute;
951
+ transform: rotate(-90deg) scale(0);
952
+ opacity: 0;
953
+ }
954
+
955
+ .nx-chatbot-button.open svg.icon-close {
956
+ transform: rotate(0deg) scale(1);
957
+ opacity: 1;
958
+ }
959
+
960
+ .nx-chatbot-widget-container {
961
+ position: absolute;
962
+ bottom: calc(var(--chatbot-button-size) + 16px);
963
+ right: 0;
964
+ width: var(--chatbot-widget-width);
965
+ height: var(--chatbot-widget-height);
966
+ max-height: calc(100vh - var(--chatbot-button-size) - var(--chatbot-widget-gap) - 32px);
967
+ border-radius: 12px;
968
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
969
+ overflow: hidden;
970
+ transform-origin: bottom right;
971
+ transform: scale(0.8);
972
+ opacity: 0;
973
+ pointer-events: none;
974
+ transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1),
975
+ opacity 0.3s ease;
976
+ }
977
+
978
+ .nx-chatbot-widget-container.open {
979
+ transform: scale(1);
980
+ opacity: 1;
981
+ pointer-events: auto;
982
+ }
983
+
984
+ .nx-chatbot-widget-container nexvio-chat-widget {
985
+ display: block;
986
+ width: 100%;
987
+ height: 100%;
988
+ }
989
+
990
+ .nx-chatbot-badge {
991
+ position: absolute;
992
+ top: -4px;
993
+ right: -4px;
994
+ min-width: 20px;
995
+ height: 20px;
996
+ padding: 0 6px;
997
+ background: #EF4444;
998
+ color: white;
999
+ border-radius: 10px;
1000
+ font-size: 11px;
1001
+ font-weight: 600;
1002
+ display: flex;
1003
+ align-items: center;
1004
+ justify-content: center;
1005
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
1006
+ transform: scale(0);
1007
+ transition: transform 0.2s ease;
1008
+ }
1009
+
1010
+ .nx-chatbot-badge.visible {
1011
+ transform: scale(1);
1012
+ }
1013
+
1014
+ @media (max-width: 768px) {
1015
+ :host {
1016
+ bottom: 16px;
1017
+ right: 16px;
1018
+ --chatbot-widget-gap: 16px;
1019
+ }
1020
+
1021
+ .nx-chatbot-widget-container {
1022
+ position: fixed;
1023
+ bottom: 0;
1024
+ right: 0;
1025
+ left: 0;
1026
+ top: 0;
1027
+ width: 100%;
1028
+ height: 100%;
1029
+ max-width: 100%;
1030
+ max-height: 100%;
1031
+ border-radius: 0;
1032
+ }
1033
+
1034
+ .nx-chatbot-widget-container.open {
1035
+ transform: scale(1);
1036
+ }
1037
+ }
1038
+ `;
1039
+ var BaseHTMLElement2 = typeof HTMLElement === "undefined" ? class {
1040
+ } : HTMLElement;
1041
+ var _shadowRootRef2, _button, _widgetContainer, _widget, _badge, _isOpen, _options2, _initialized2, _NexvioChatbotElement_instances, ensureStructure_fn2, initialize_fn, updateWidget_fn, updateStyles_fn, updateBadge_fn;
1042
+ var NexvioChatbotElement = class extends BaseHTMLElement2 {
1043
+ constructor() {
1044
+ super();
1045
+ __privateAdd(this, _NexvioChatbotElement_instances);
1046
+ __privateAdd(this, _shadowRootRef2, null);
1047
+ __privateAdd(this, _button);
1048
+ __privateAdd(this, _widgetContainer);
1049
+ __privateAdd(this, _widget);
1050
+ __privateAdd(this, _badge);
1051
+ __privateAdd(this, _isOpen, false);
1052
+ __privateAdd(this, _options2);
1053
+ __privateAdd(this, _initialized2, false);
1054
+ if (typeof window !== "undefined" && typeof this.attachShadow === "function") {
1055
+ __privateSet(this, _shadowRootRef2, this.attachShadow({ mode: "open" }));
1056
+ }
1057
+ log("[NexvioChatbot] element: constructed");
1058
+ }
1059
+ connectedCallback() {
1060
+ log("[NexvioChatbot] element: connectedCallback");
1061
+ __privateMethod(this, _NexvioChatbotElement_instances, ensureStructure_fn2).call(this);
1062
+ if (__privateGet(this, _options2) && !__privateGet(this, _initialized2)) {
1063
+ __privateMethod(this, _NexvioChatbotElement_instances, initialize_fn).call(this);
1064
+ }
1065
+ }
1066
+ disconnectedCallback() {
1067
+ log("[NexvioChatbot] element: disconnectedCallback");
1068
+ }
1069
+ setOptions(options) {
1070
+ log("[NexvioChatbot] setOptions:", options);
1071
+ __privateSet(this, _options2, options);
1072
+ __privateMethod(this, _NexvioChatbotElement_instances, ensureStructure_fn2).call(this);
1073
+ if (!__privateGet(this, _initialized2)) {
1074
+ __privateMethod(this, _NexvioChatbotElement_instances, initialize_fn).call(this);
1075
+ } else {
1076
+ __privateMethod(this, _NexvioChatbotElement_instances, updateWidget_fn).call(this);
1077
+ }
1078
+ __privateMethod(this, _NexvioChatbotElement_instances, updateStyles_fn).call(this);
1079
+ __privateMethod(this, _NexvioChatbotElement_instances, updateBadge_fn).call(this);
1080
+ }
1081
+ open() {
1082
+ if (__privateGet(this, _isOpen)) return;
1083
+ __privateSet(this, _isOpen, true);
1084
+ __privateGet(this, _button)?.classList.add("open");
1085
+ __privateGet(this, _widgetContainer)?.classList.add("open");
1086
+ this.dispatchEvent(new CustomEvent("chatbot.opened", { bubbles: true, composed: true }));
1087
+ }
1088
+ close() {
1089
+ if (!__privateGet(this, _isOpen)) return;
1090
+ __privateSet(this, _isOpen, false);
1091
+ __privateGet(this, _button)?.classList.remove("open");
1092
+ __privateGet(this, _widgetContainer)?.classList.remove("open");
1093
+ this.dispatchEvent(new CustomEvent("chatbot.closed", { bubbles: true, composed: true }));
1094
+ }
1095
+ toggle() {
1096
+ if (__privateGet(this, _isOpen)) {
1097
+ this.close();
1098
+ } else {
1099
+ this.open();
1100
+ }
1101
+ }
1102
+ get isOpen() {
1103
+ return __privateGet(this, _isOpen);
1104
+ }
1105
+ get widget() {
1106
+ return __privateGet(this, _widget);
1107
+ }
1108
+ get options() {
1109
+ return __privateGet(this, _options2);
1110
+ }
1111
+ };
1112
+ _shadowRootRef2 = new WeakMap();
1113
+ _button = new WeakMap();
1114
+ _widgetContainer = new WeakMap();
1115
+ _widget = new WeakMap();
1116
+ _badge = new WeakMap();
1117
+ _isOpen = new WeakMap();
1118
+ _options2 = new WeakMap();
1119
+ _initialized2 = new WeakMap();
1120
+ _NexvioChatbotElement_instances = new WeakSet();
1121
+ ensureStructure_fn2 = function() {
1122
+ if (__privateGet(this, _button) && __privateGet(this, _widgetContainer)) return;
1123
+ if (!__privateGet(this, _shadowRootRef2)) return;
1124
+ if (typeof window !== "undefined" && typeof customElements !== "undefined") {
1125
+ registerNexvioWidget();
1126
+ }
1127
+ const style = document.createElement("style");
1128
+ style.textContent = styleContent2;
1129
+ const button = document.createElement("button");
1130
+ button.className = "nx-chatbot-button";
1131
+ button.setAttribute("aria-label", "Open chat");
1132
+ button.innerHTML = `
1133
+ <svg class="icon-chat" xmlns="http://www.w3.org/2000/svg"
1134
+ viewBox="0 0 24 24" fill="none" stroke="currentColor"
1135
+ stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1136
+ <path d="M6 4h12a3 3 0 0 1 3 3v7a3 3 0 0 1-3 3H9l-4 3v-3H6a3 3 0 0 1-3-3V7a3 3 0 0 1 3-3z"/>
1137
+ </svg>
1138
+ <svg class="icon-close" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1139
+ <path d="M18 6L6 18M6 6l12 12"></path>
1140
+ </svg>
1141
+ `;
1142
+ const badge = document.createElement("span");
1143
+ badge.className = "nx-chatbot-badge";
1144
+ button.appendChild(badge);
1145
+ const widgetContainer = document.createElement("div");
1146
+ widgetContainer.className = "nx-chatbot-widget-container";
1147
+ const widget = document.createElement("nexvio-chat-widget");
1148
+ widgetContainer.appendChild(widget);
1149
+ __privateGet(this, _shadowRootRef2).append(style, button, widgetContainer);
1150
+ __privateSet(this, _button, button);
1151
+ __privateSet(this, _widgetContainer, widgetContainer);
1152
+ __privateSet(this, _widget, widget);
1153
+ __privateSet(this, _badge, badge);
1154
+ button.addEventListener("click", () => this.toggle());
1155
+ widget.addEventListener("nexvio.event", ((event) => {
1156
+ this.dispatchEvent(
1157
+ new CustomEvent("nexvio.event", {
1158
+ detail: event.detail,
1159
+ bubbles: true,
1160
+ composed: true
1161
+ })
1162
+ );
1163
+ }));
1164
+ };
1165
+ initialize_fn = function() {
1166
+ if (__privateGet(this, _initialized2) || !__privateGet(this, _options2) || !__privateGet(this, _widget)) return;
1167
+ __privateSet(this, _initialized2, true);
1168
+ const widgetOptions = { ...__privateGet(this, _options2) };
1169
+ delete widgetOptions.position;
1170
+ delete widgetOptions.defaultOpen;
1171
+ delete widgetOptions.buttonColor;
1172
+ delete widgetOptions.badge;
1173
+ delete widgetOptions.buttonIcon;
1174
+ delete widgetOptions.gap;
1175
+ const setWidgetOptions = () => {
1176
+ if (__privateGet(this, _widget) && typeof __privateGet(this, _widget).setOptions === "function") {
1177
+ __privateGet(this, _widget).setOptions(widgetOptions);
1178
+ if (__privateGet(this, _options2)?.defaultOpen) {
1179
+ setTimeout(() => this.open(), 100);
1180
+ }
1181
+ debug("[NexvioChatbot] initialized");
1182
+ } else if (typeof window !== "undefined" && typeof customElements !== "undefined") {
1183
+ customElements.whenDefined("nexvio-chat-widget").then(() => {
1184
+ if (__privateGet(this, _widget) && typeof __privateGet(this, _widget).setOptions === "function") {
1185
+ __privateGet(this, _widget).setOptions(widgetOptions);
1186
+ if (__privateGet(this, _options2)?.defaultOpen) {
1187
+ setTimeout(() => this.open(), 100);
1188
+ }
1189
+ debug("[NexvioChatbot] initialized");
1190
+ }
1191
+ }).catch(() => {
1192
+ console.error("[NexvioChatbot] Failed to initialize widget element");
1193
+ });
1194
+ }
1195
+ };
1196
+ setWidgetOptions();
1197
+ };
1198
+ updateWidget_fn = function() {
1199
+ if (!__privateGet(this, _widget) || !__privateGet(this, _options2)) return;
1200
+ const widgetOptions = { ...__privateGet(this, _options2) };
1201
+ delete widgetOptions.position;
1202
+ delete widgetOptions.defaultOpen;
1203
+ delete widgetOptions.buttonColor;
1204
+ delete widgetOptions.badge;
1205
+ delete widgetOptions.buttonIcon;
1206
+ delete widgetOptions.gap;
1207
+ if (typeof __privateGet(this, _widget).setOptions === "function") {
1208
+ __privateGet(this, _widget).setOptions(widgetOptions);
1209
+ } else if (typeof window !== "undefined" && typeof customElements !== "undefined") {
1210
+ customElements.whenDefined("nexvio-chat-widget").then(() => {
1211
+ if (__privateGet(this, _widget) && typeof __privateGet(this, _widget).setOptions === "function") {
1212
+ __privateGet(this, _widget).setOptions(widgetOptions);
1213
+ }
1214
+ }).catch(() => {
1215
+ console.error("[NexvioChatbot] Failed to update widget element");
1216
+ });
1217
+ }
1218
+ };
1219
+ updateStyles_fn = function() {
1220
+ if (!__privateGet(this, _options2)) return;
1221
+ const host = __privateGet(this, _shadowRootRef2)?.host;
1222
+ if (!host) return;
1223
+ if (__privateGet(this, _options2).buttonColor) {
1224
+ host.style.setProperty("--chatbot-button-bg", __privateGet(this, _options2).buttonColor);
1225
+ }
1226
+ if (__privateGet(this, _options2).gap !== void 0) {
1227
+ host.style.setProperty("--chatbot-widget-gap", `${__privateGet(this, _options2).gap}px`);
1228
+ }
1229
+ if (__privateGet(this, _options2).position) {
1230
+ const positions = {
1231
+ "bottom-right": {
1232
+ bottom: "var(--chatbot-widget-gap)",
1233
+ right: "var(--chatbot-widget-gap)",
1234
+ top: "auto",
1235
+ left: "auto"
1236
+ },
1237
+ "bottom-left": {
1238
+ bottom: "var(--chatbot-widget-gap)",
1239
+ left: "var(--chatbot-widget-gap)",
1240
+ top: "auto",
1241
+ right: "auto"
1242
+ },
1243
+ "top-right": {
1244
+ top: "var(--chatbot-widget-gap)",
1245
+ right: "var(--chatbot-widget-gap)",
1246
+ bottom: "auto",
1247
+ left: "auto"
1248
+ },
1249
+ "top-left": {
1250
+ top: "var(--chatbot-widget-gap)",
1251
+ left: "var(--chatbot-widget-gap)",
1252
+ bottom: "auto",
1253
+ right: "auto"
1254
+ }
1255
+ };
1256
+ const pos = positions[__privateGet(this, _options2).position];
1257
+ Object.entries(pos).forEach(([key, value]) => {
1258
+ host.style.setProperty(key, value);
1259
+ });
1260
+ }
1261
+ if (__privateGet(this, _options2).buttonIcon && __privateGet(this, _button)) {
1262
+ const chatIcon = __privateGet(this, _button).querySelector(".icon-chat");
1263
+ if (chatIcon) {
1264
+ chatIcon.innerHTML = __privateGet(this, _options2).buttonIcon;
1265
+ }
1266
+ }
1267
+ };
1268
+ updateBadge_fn = function() {
1269
+ if (!__privateGet(this, _badge) || !__privateGet(this, _options2)) return;
1270
+ const badgeValue = __privateGet(this, _options2).badge;
1271
+ if (typeof badgeValue === "number" && badgeValue > 0) {
1272
+ __privateGet(this, _badge).textContent = badgeValue > 99 ? "99+" : String(badgeValue);
1273
+ __privateGet(this, _badge).classList.add("visible");
1274
+ } else if (badgeValue === true) {
1275
+ __privateGet(this, _badge).textContent = "";
1276
+ __privateGet(this, _badge).classList.add("visible");
1277
+ } else {
1278
+ __privateGet(this, _badge).classList.remove("visible");
1279
+ }
1280
+ };
1281
+ function registerNexvioChatbot(tagName = "nexvio-chat-bot") {
1282
+ if (typeof customElements === "undefined") return;
1283
+ if (!customElements.get(tagName)) {
1284
+ customElements.define(tagName, NexvioChatbotElement);
1285
+ }
1286
+ }
1287
+
1288
+ // src/react/useStableOptions.ts
1289
+ var import_react = require("react");
1290
+ function isPlainObject(value) {
1291
+ return typeof value === "object" && value !== null;
1292
+ }
1293
+ function toRecord(value) {
1294
+ return value;
1295
+ }
1296
+ function deepEqualIgnoringFunctions(a, b, seen = /* @__PURE__ */ new WeakMap()) {
1297
+ if (Object.is(a, b)) return true;
1298
+ const isArrayA = Array.isArray(a);
1299
+ const isArrayB = Array.isArray(b);
1300
+ if (isArrayA || isArrayB) {
1301
+ if (!isArrayA || !isArrayB || a.length !== b.length) return false;
1302
+ for (let i = 0; i < a.length; i += 1) {
1303
+ if (!deepEqualIgnoringFunctions(a[i], b[i], seen)) return false;
1304
+ }
1305
+ return true;
1306
+ }
1307
+ if (!isPlainObject(a) || !isPlainObject(b)) return false;
1308
+ if (seen.get(a) === b) return true;
1309
+ seen.set(a, b);
1310
+ const recordA = toRecord(a);
1311
+ const recordB = toRecord(b);
1312
+ const keysA = Object.keys(recordA);
1313
+ const keysB = Object.keys(recordB);
1314
+ if (keysA.length !== keysB.length) return false;
1315
+ for (const key of keysA) {
1316
+ if (!(key in recordB)) return false;
1317
+ const valueA = recordA[key];
1318
+ const valueB = recordB[key];
1319
+ if (typeof valueA === "function" && typeof valueB === "function") {
1320
+ continue;
1321
+ }
1322
+ if (!deepEqualIgnoringFunctions(valueA, valueB, seen)) return false;
1323
+ }
1324
+ return true;
1325
+ }
1326
+ function useStableOptions(options) {
1327
+ const cacheRef = (0, import_react.useRef)();
1328
+ const latestRef = (0, import_react.useRef)(options);
1329
+ latestRef.current = options;
1330
+ return (0, import_react.useMemo)(() => {
1331
+ const cache = cacheRef.current;
1332
+ if (!cache || !deepEqualIgnoringFunctions(cache.snapshot, options)) {
1333
+ const shaped = wrapFunctionsWithLatestReferences(options, latestRef);
1334
+ cacheRef.current = { snapshot: options, shaped };
1335
+ return shaped;
1336
+ }
1337
+ return cache.shaped;
1338
+ }, [options]);
1339
+ }
1340
+ function wrapFunctionsWithLatestReferences(obj, latestRef) {
1341
+ const path = [];
1342
+ const getByPath = (target, keys) => keys.reduce((acc, key) => acc == null ? acc : acc[key], target);
1343
+ const visit = (value) => {
1344
+ if (typeof value === "function") {
1345
+ const key = path[path.length - 1];
1346
+ const parentPath = path.slice(0, -1);
1347
+ return (...args) => {
1348
+ const latestParent = getByPath(latestRef.current, parentPath);
1349
+ const latestFn = latestParent?.[key];
1350
+ if (typeof latestFn === "function") {
1351
+ return latestFn.apply(latestParent, args);
1352
+ }
1353
+ return void 0;
1354
+ };
1355
+ }
1356
+ if (Array.isArray(value)) {
1357
+ const base = path.length;
1358
+ const result = new Array(value.length);
1359
+ for (let i = 0; i < value.length; i += 1) {
1360
+ path[base] = i;
1361
+ result[i] = visit(value[i]);
1362
+ }
1363
+ path.length = base;
1364
+ return result;
1365
+ }
1366
+ if (isPlainObject(value)) {
1367
+ const base = path.length;
1368
+ const record = toRecord(value);
1369
+ const result = {};
1370
+ for (const key of Object.keys(record)) {
1371
+ path[base] = key;
1372
+ result[key] = visit(record[key]);
1373
+ }
1374
+ path.length = base;
1375
+ return result;
1376
+ }
1377
+ return value;
1378
+ };
1379
+ return visit(optionsShallowClone(obj));
1380
+ }
1381
+ function optionsShallowClone(obj) {
1382
+ const record = toRecord(obj);
1383
+ const clone = {};
1384
+ for (const [key, value] of Object.entries(record)) {
1385
+ clone[key] = value;
1386
+ }
1387
+ return clone;
1388
+ }
1389
+
1390
+ // src/react/useNexvioChatbot.ts
1391
+ function useNexvioChatbot(options) {
1392
+ const elementRef = (0, import_react2.useRef)(null);
1393
+ const stableOptions = useStableOptions(options);
1394
+ (0, import_react2.useEffect)(() => {
1395
+ registerNexvioChatbot();
1396
+ }, []);
1397
+ (0, import_react2.useEffect)(() => {
1398
+ const element = elementRef.current;
1399
+ if (!element) return;
1400
+ if (typeof element.setOptions === "function") {
1401
+ element.setOptions(stableOptions);
1402
+ return;
1403
+ }
1404
+ if (typeof window !== "undefined") {
1405
+ const tagName = element.tagName.toLowerCase();
1406
+ customElements.whenDefined(tagName).then(() => {
1407
+ if (elementRef.current === element) {
1408
+ const definedElement = element;
1409
+ definedElement.setOptions?.(stableOptions);
1410
+ }
1411
+ }).catch(() => {
1412
+ });
1413
+ }
1414
+ }, [stableOptions]);
1415
+ const setElement = (0, import_react2.useCallback)(
1416
+ (element) => {
1417
+ elementRef.current = element;
1418
+ if (!element || !stableOptions) {
1419
+ return;
1420
+ }
1421
+ if (typeof element.setOptions === "function") {
1422
+ element.setOptions(stableOptions);
1423
+ return;
1424
+ }
1425
+ if (typeof window !== "undefined") {
1426
+ const tagName = element.tagName.toLowerCase();
1427
+ customElements.whenDefined(tagName).then(() => {
1428
+ if (elementRef.current === element) {
1429
+ const definedElement = element;
1430
+ definedElement.setOptions?.(stableOptions);
1431
+ }
1432
+ }).catch(() => {
1433
+ });
1434
+ }
1435
+ },
1436
+ [stableOptions]
1437
+ );
1438
+ return { ref: elementRef, setElement };
1439
+ }
1440
+
1441
+ // src/react/NexvioChatbot.tsx
1442
+ var NexvioChatbot = React.forwardRef(function NexvioChatbot2({ options, tagName = "nexvio-chat-bot", ...htmlProps }, forwardedRef) {
1443
+ const { setElement } = useNexvioChatbot(options);
1444
+ const handleRef = React.useCallback(
1445
+ (value) => {
1446
+ const element = value ?? null;
1447
+ if (forwardedRef) {
1448
+ if (typeof forwardedRef === "function") {
1449
+ forwardedRef(element);
1450
+ } else {
1451
+ ;
1452
+ forwardedRef.current = element;
1453
+ }
1454
+ }
1455
+ setElement(element);
1456
+ },
1457
+ [forwardedRef, setElement]
1458
+ );
1459
+ return React.createElement(tagName, {
1460
+ ...htmlProps,
1461
+ ref: handleRef
1462
+ });
1463
+ });
1464
+
1465
+ // src/react/NexvioWidget.tsx
1466
+ var React2 = __toESM(require("react"), 1);
1467
+
1468
+ // src/react/useNexvioWidget.ts
1469
+ var import_react3 = require("react");
1470
+ function useNexvioWidget(options) {
1471
+ const elementRef = (0, import_react3.useRef)(null);
1472
+ const stableOptions = useStableOptions(options);
1473
+ (0, import_react3.useEffect)(() => {
1474
+ registerNexvioWidget();
1475
+ }, []);
1476
+ (0, import_react3.useEffect)(() => {
1477
+ const element = elementRef.current;
1478
+ if (!element) return;
1479
+ if (typeof element.setOptions === "function") {
1480
+ element.setOptions(stableOptions);
1481
+ return;
1482
+ }
1483
+ if (typeof window !== "undefined") {
1484
+ const tagName = element.tagName.toLowerCase();
1485
+ customElements.whenDefined(tagName).then(() => {
1486
+ if (elementRef.current === element) {
1487
+ const definedElement = element;
1488
+ definedElement.setOptions?.(stableOptions);
1489
+ }
1490
+ }).catch(() => {
1491
+ });
1492
+ }
1493
+ }, [stableOptions]);
1494
+ const setElement = (0, import_react3.useCallback)(
1495
+ (element) => {
1496
+ elementRef.current = element;
1497
+ if (!element || !stableOptions) {
1498
+ return;
1499
+ }
1500
+ if (typeof element.setOptions === "function") {
1501
+ element.setOptions(stableOptions);
1502
+ return;
1503
+ }
1504
+ if (typeof window !== "undefined") {
1505
+ const tagName = element.tagName.toLowerCase();
1506
+ customElements.whenDefined(tagName).then(() => {
1507
+ if (elementRef.current === element) {
1508
+ const definedElement = element;
1509
+ definedElement.setOptions?.(stableOptions);
1510
+ }
1511
+ }).catch(() => {
1512
+ });
1513
+ }
1514
+ },
1515
+ [stableOptions]
1516
+ );
1517
+ return { ref: elementRef, setElement };
1518
+ }
1519
+
1520
+ // src/react/NexvioWidget.tsx
1521
+ var NexvioWidget = React2.forwardRef(function NexvioWidget2({ options, tagName = "nexvio-chat-widget", ...htmlProps }, forwardedRef) {
1522
+ const { setElement } = useNexvioWidget(options);
1523
+ const handleRef = React2.useCallback(
1524
+ (value) => {
1525
+ const element = value ?? null;
1526
+ if (forwardedRef) {
1527
+ if (typeof forwardedRef === "function") {
1528
+ forwardedRef(element);
1529
+ } else {
1530
+ ;
1531
+ forwardedRef.current = element;
1532
+ }
1533
+ }
1534
+ setElement(element);
1535
+ },
1536
+ [forwardedRef, setElement]
1537
+ );
1538
+ return React2.createElement(tagName, {
1539
+ ...htmlProps,
1540
+ ref: handleRef
1541
+ });
1542
+ });
1543
+ // Annotate the CommonJS export names for ESM import in node:
1544
+ 0 && (module.exports = {
1545
+ NexvioChatbot,
1546
+ NexvioWidget,
1547
+ useNexvioChatbot,
1548
+ useNexvioWidget
1549
+ });
1550
+ //# sourceMappingURL=react.cjs.map