@yassirbenmoussa/aicommerce-sdk 1.1.0 → 1.2.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.mjs CHANGED
@@ -31,6 +31,68 @@ var init_client = __esm({
31
31
  AICommerce = class _AICommerce {
32
32
  constructor(config) {
33
33
  this.sessionToken = null;
34
+ // ============================================
35
+ // Products API
36
+ // ============================================
37
+ /**
38
+ * Products API namespace
39
+ */
40
+ this.products = {
41
+ /**
42
+ * Create a new product
43
+ */
44
+ create: async (product) => {
45
+ return this.request("/api/v1/products", {
46
+ method: "POST",
47
+ body: JSON.stringify(product)
48
+ });
49
+ },
50
+ /**
51
+ * Batch upsert products (create or update)
52
+ */
53
+ batchUpsert: async (products) => {
54
+ return this.request("/api/v1/products", {
55
+ method: "POST",
56
+ body: JSON.stringify({ products })
57
+ });
58
+ },
59
+ /**
60
+ * List products with pagination
61
+ */
62
+ list: async (options) => {
63
+ const params = new URLSearchParams();
64
+ if (options?.page) params.set("page", String(options.page));
65
+ if (options?.perPage) params.set("perPage", String(options.perPage));
66
+ if (options?.search) params.set("search", options.search);
67
+ if (options?.categoryId) params.set("categoryId", options.categoryId);
68
+ if (options?.isActive !== void 0) params.set("isActive", String(options.isActive));
69
+ const query = params.toString();
70
+ return this.request(`/api/v1/products${query ? `?${query}` : ""}`);
71
+ },
72
+ /**
73
+ * Get a single product by ID
74
+ */
75
+ get: async (productId) => {
76
+ return this.request(`/api/v1/products/${productId}`);
77
+ },
78
+ /**
79
+ * Update a product
80
+ */
81
+ update: async (productId, data) => {
82
+ return this.request(`/api/v1/products/${productId}`, {
83
+ method: "PUT",
84
+ body: JSON.stringify(data)
85
+ });
86
+ },
87
+ /**
88
+ * Delete a product
89
+ */
90
+ delete: async (productId) => {
91
+ return this.request(`/api/v1/products/${productId}`, {
92
+ method: "DELETE"
93
+ });
94
+ }
95
+ };
34
96
  if (!config.apiKey) {
35
97
  throw new Error("AICommerce: apiKey is required");
36
98
  }
@@ -157,6 +219,47 @@ var init_client = __esm({
157
219
  setSessionToken(token) {
158
220
  this.sessionToken = token;
159
221
  }
222
+ // ============================================
223
+ // Upload API
224
+ // ============================================
225
+ /**
226
+ * Upload an image file
227
+ *
228
+ * @example
229
+ * ```typescript
230
+ * // Upload from File input
231
+ * const file = document.querySelector('input[type="file"]').files[0];
232
+ * const result = await client.upload(file);
233
+ * console.log(result.url);
234
+ *
235
+ * // Upload and associate with product
236
+ * const result = await client.upload(file, { productId: 'prod_123', isPrimary: true });
237
+ * ```
238
+ */
239
+ async upload(file, options) {
240
+ const formData = new FormData();
241
+ formData.append("file", file);
242
+ if (options?.folder) formData.append("folder", options.folder);
243
+ if (options?.productId) formData.append("productId", options.productId);
244
+ if (options?.isPrimary) formData.append("isPrimary", "true");
245
+ const url = `${this.baseUrl}/api/v1/upload`;
246
+ const response = await fetch(url, {
247
+ method: "POST",
248
+ headers: {
249
+ "X-API-Key": this.apiKey
250
+ },
251
+ body: formData
252
+ });
253
+ if (!response.ok) {
254
+ const errorData = await response.json().catch(() => ({}));
255
+ throw new AICommerceError(
256
+ errorData.message || errorData.error || `HTTP ${response.status}`,
257
+ errorData.code || "UPLOAD_ERROR",
258
+ response.status
259
+ );
260
+ }
261
+ return response.json();
262
+ }
160
263
  /**
161
264
  * Static method for one-off chat requests
162
265
  *
@@ -188,14 +291,748 @@ var init_client = __esm({
188
291
  }
189
292
  });
190
293
 
294
+ // src/widget-styles.ts
295
+ function hexToRgb(hex) {
296
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
297
+ return result ? {
298
+ r: parseInt(result[1], 16),
299
+ g: parseInt(result[2], 16),
300
+ b: parseInt(result[3], 16)
301
+ } : { r: 99, g: 102, b: 241 };
302
+ }
303
+ function createWidgetStyles(config) {
304
+ const primary = config.primaryColor;
305
+ const rgb = hexToRgb(primary);
306
+ const isLeft = config.position === "bottom-left";
307
+ return `
308
+ /* AI Commerce Widget Styles */
309
+ #aicommerce-widget {
310
+ --aic-primary: ${primary};
311
+ --aic-primary-rgb: ${rgb.r}, ${rgb.g}, ${rgb.b};
312
+ --aic-primary-light: rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.1);
313
+ --aic-primary-dark: rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.9);
314
+ --aic-bg: #ffffff;
315
+ --aic-bg-secondary: #f8fafc;
316
+ --aic-text: #1e293b;
317
+ --aic-text-secondary: #64748b;
318
+ --aic-border: #e2e8f0;
319
+ --aic-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
320
+ --aic-radius: 16px;
321
+ --aic-z-index: ${config.zIndex};
322
+
323
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
324
+ font-size: 14px;
325
+ line-height: 1.5;
326
+ position: fixed;
327
+ bottom: 20px;
328
+ ${isLeft ? "left: 20px;" : "right: 20px;"}
329
+ z-index: var(--aic-z-index);
330
+ }
331
+
332
+ /* Dark theme */
333
+ #aicommerce-widget.aicommerce-theme-dark,
334
+ @media (prefers-color-scheme: dark) {
335
+ #aicommerce-widget.aicommerce-theme-auto {
336
+ --aic-bg: #1e293b;
337
+ --aic-bg-secondary: #0f172a;
338
+ --aic-text: #f1f5f9;
339
+ --aic-text-secondary: #94a3b8;
340
+ --aic-border: #334155;
341
+ }
342
+ }
343
+
344
+ /* Launcher Button */
345
+ .aicommerce-launcher {
346
+ width: 60px;
347
+ height: 60px;
348
+ border-radius: 50%;
349
+ background: linear-gradient(135deg, var(--aic-primary), var(--aic-primary-dark));
350
+ border: none;
351
+ cursor: pointer;
352
+ box-shadow: 0 4px 20px rgba(var(--aic-primary-rgb), 0.4);
353
+ display: flex;
354
+ align-items: center;
355
+ justify-content: center;
356
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
357
+ animation: aic-pulse 2s infinite;
358
+ }
359
+
360
+ .aicommerce-launcher:hover {
361
+ transform: scale(1.1);
362
+ box-shadow: 0 6px 30px rgba(var(--aic-primary-rgb), 0.5);
363
+ }
364
+
365
+ .aicommerce-launcher-icon {
366
+ font-size: 24px;
367
+ }
368
+
369
+ .aicommerce-hidden {
370
+ display: none !important;
371
+ }
372
+
373
+ @keyframes aic-pulse {
374
+ 0%, 100% { box-shadow: 0 4px 20px rgba(var(--aic-primary-rgb), 0.4); }
375
+ 50% { box-shadow: 0 4px 30px rgba(var(--aic-primary-rgb), 0.6); }
376
+ }
377
+
378
+ /* Chat Window */
379
+ .aicommerce-chat {
380
+ position: absolute;
381
+ bottom: 0;
382
+ ${isLeft ? "left: 0;" : "right: 0;"}
383
+ width: 380px;
384
+ max-width: calc(100vw - 40px);
385
+ height: 600px;
386
+ max-height: calc(100vh - 100px);
387
+ background: var(--aic-bg);
388
+ border-radius: var(--aic-radius);
389
+ box-shadow: var(--aic-shadow);
390
+ display: flex;
391
+ flex-direction: column;
392
+ overflow: hidden;
393
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
394
+ transform-origin: bottom ${isLeft ? "left" : "right"};
395
+ }
396
+
397
+ .aicommerce-chat.aicommerce-closed {
398
+ opacity: 0;
399
+ transform: scale(0.9) translateY(20px);
400
+ pointer-events: none;
401
+ }
402
+
403
+ .aicommerce-chat.aicommerce-open {
404
+ opacity: 1;
405
+ transform: scale(1) translateY(0);
406
+ }
407
+
408
+ /* Header */
409
+ .aicommerce-header {
410
+ background: linear-gradient(135deg, var(--aic-primary), var(--aic-primary-dark));
411
+ color: white;
412
+ padding: 16px 20px;
413
+ display: flex;
414
+ align-items: center;
415
+ justify-content: space-between;
416
+ }
417
+
418
+ .aicommerce-header-info {
419
+ display: flex;
420
+ align-items: center;
421
+ gap: 12px;
422
+ }
423
+
424
+ .aicommerce-avatar {
425
+ width: 40px;
426
+ height: 40px;
427
+ border-radius: 50%;
428
+ background: rgba(255, 255, 255, 0.2);
429
+ display: flex;
430
+ align-items: center;
431
+ justify-content: center;
432
+ font-size: 20px;
433
+ overflow: hidden;
434
+ }
435
+
436
+ .aicommerce-avatar img {
437
+ width: 100%;
438
+ height: 100%;
439
+ object-fit: cover;
440
+ }
441
+
442
+ .aicommerce-header-text {
443
+ display: flex;
444
+ flex-direction: column;
445
+ }
446
+
447
+ .aicommerce-bot-name {
448
+ font-weight: 600;
449
+ font-size: 16px;
450
+ }
451
+
452
+ .aicommerce-status {
453
+ font-size: 12px;
454
+ opacity: 0.9;
455
+ }
456
+
457
+ .aicommerce-close {
458
+ width: 32px;
459
+ height: 32px;
460
+ border-radius: 50%;
461
+ background: rgba(255, 255, 255, 0.2);
462
+ border: none;
463
+ color: white;
464
+ cursor: pointer;
465
+ display: flex;
466
+ align-items: center;
467
+ justify-content: center;
468
+ font-size: 16px;
469
+ transition: background 0.2s;
470
+ }
471
+
472
+ .aicommerce-close:hover {
473
+ background: rgba(255, 255, 255, 0.3);
474
+ }
475
+
476
+ /* Messages */
477
+ .aicommerce-messages {
478
+ flex: 1;
479
+ overflow-y: auto;
480
+ padding: 20px;
481
+ display: flex;
482
+ flex-direction: column;
483
+ gap: 16px;
484
+ background: var(--aic-bg-secondary);
485
+ }
486
+
487
+ .aicommerce-message {
488
+ max-width: 85%;
489
+ animation: aic-slide-in 0.3s ease-out;
490
+ }
491
+
492
+ .aicommerce-message.aicommerce-user {
493
+ align-self: flex-end;
494
+ }
495
+
496
+ .aicommerce-message.aicommerce-assistant {
497
+ align-self: flex-start;
498
+ }
499
+
500
+ .aicommerce-message-content {
501
+ padding: 12px 16px;
502
+ border-radius: 16px;
503
+ line-height: 1.5;
504
+ }
505
+
506
+ .aicommerce-user .aicommerce-message-content {
507
+ background: var(--aic-primary);
508
+ color: white;
509
+ border-bottom-right-radius: 4px;
510
+ }
511
+
512
+ .aicommerce-assistant .aicommerce-message-content {
513
+ background: var(--aic-bg);
514
+ color: var(--aic-text);
515
+ border-bottom-left-radius: 4px;
516
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
517
+ }
518
+
519
+ @keyframes aic-slide-in {
520
+ from { opacity: 0; transform: translateY(10px); }
521
+ to { opacity: 1; transform: translateY(0); }
522
+ }
523
+
524
+ /* Typing Indicator */
525
+ .aicommerce-typing {
526
+ display: flex;
527
+ gap: 4px;
528
+ padding: 12px 16px;
529
+ background: var(--aic-bg);
530
+ border-radius: 16px;
531
+ width: fit-content;
532
+ }
533
+
534
+ .aicommerce-typing span {
535
+ width: 8px;
536
+ height: 8px;
537
+ background: var(--aic-text-secondary);
538
+ border-radius: 50%;
539
+ animation: aic-bounce 1.4s infinite ease-in-out;
540
+ }
541
+
542
+ .aicommerce-typing span:nth-child(1) { animation-delay: -0.32s; }
543
+ .aicommerce-typing span:nth-child(2) { animation-delay: -0.16s; }
544
+
545
+ @keyframes aic-bounce {
546
+ 0%, 80%, 100% { transform: scale(0); }
547
+ 40% { transform: scale(1); }
548
+ }
549
+
550
+ /* Product Cards */
551
+ .aicommerce-products {
552
+ display: flex;
553
+ gap: 8px;
554
+ margin-top: 12px;
555
+ overflow-x: auto;
556
+ padding-bottom: 4px;
557
+ }
558
+
559
+ .aicommerce-product-card {
560
+ flex-shrink: 0;
561
+ width: 140px;
562
+ background: var(--aic-bg);
563
+ border-radius: 12px;
564
+ overflow: hidden;
565
+ cursor: pointer;
566
+ transition: all 0.2s;
567
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
568
+ }
569
+
570
+ .aicommerce-product-card:hover {
571
+ transform: translateY(-2px);
572
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
573
+ }
574
+
575
+ .aicommerce-product-image {
576
+ width: 100%;
577
+ height: 100px;
578
+ object-fit: cover;
579
+ }
580
+
581
+ .aicommerce-product-placeholder {
582
+ width: 100%;
583
+ height: 100px;
584
+ background: var(--aic-bg-secondary);
585
+ display: flex;
586
+ align-items: center;
587
+ justify-content: center;
588
+ font-size: 32px;
589
+ }
590
+
591
+ .aicommerce-product-info {
592
+ padding: 10px;
593
+ display: flex;
594
+ flex-direction: column;
595
+ gap: 4px;
596
+ }
597
+
598
+ .aicommerce-product-name {
599
+ font-weight: 500;
600
+ font-size: 13px;
601
+ color: var(--aic-text);
602
+ white-space: nowrap;
603
+ overflow: hidden;
604
+ text-overflow: ellipsis;
605
+ }
606
+
607
+ .aicommerce-product-price {
608
+ font-weight: 600;
609
+ font-size: 14px;
610
+ color: var(--aic-primary);
611
+ }
612
+
613
+ /* Input Area */
614
+ .aicommerce-input-container {
615
+ padding: 16px 20px;
616
+ background: var(--aic-bg);
617
+ border-top: 1px solid var(--aic-border);
618
+ display: flex;
619
+ gap: 12px;
620
+ }
621
+
622
+ .aicommerce-input {
623
+ flex: 1;
624
+ padding: 12px 16px;
625
+ border: 1px solid var(--aic-border);
626
+ border-radius: 24px;
627
+ background: var(--aic-bg-secondary);
628
+ color: var(--aic-text);
629
+ font-size: 14px;
630
+ outline: none;
631
+ transition: all 0.2s;
632
+ }
633
+
634
+ .aicommerce-input:focus {
635
+ border-color: var(--aic-primary);
636
+ box-shadow: 0 0 0 3px var(--aic-primary-light);
637
+ }
638
+
639
+ .aicommerce-input::placeholder {
640
+ color: var(--aic-text-secondary);
641
+ }
642
+
643
+ .aicommerce-send {
644
+ width: 44px;
645
+ height: 44px;
646
+ border-radius: 50%;
647
+ background: var(--aic-primary);
648
+ border: none;
649
+ color: white;
650
+ cursor: pointer;
651
+ display: flex;
652
+ align-items: center;
653
+ justify-content: center;
654
+ transition: all 0.2s;
655
+ }
656
+
657
+ .aicommerce-send:hover:not(:disabled) {
658
+ background: var(--aic-primary-dark);
659
+ transform: scale(1.05);
660
+ }
661
+
662
+ .aicommerce-send:disabled {
663
+ opacity: 0.6;
664
+ cursor: not-allowed;
665
+ }
666
+
667
+ /* Mobile Responsive */
668
+ @media (max-width: 420px) {
669
+ #aicommerce-widget {
670
+ bottom: 16px;
671
+ ${isLeft ? "left: 16px;" : "right: 16px;"}
672
+ }
673
+
674
+ .aicommerce-chat {
675
+ width: calc(100vw - 32px);
676
+ height: calc(100vh - 100px);
677
+ border-radius: 12px;
678
+ }
679
+
680
+ .aicommerce-launcher {
681
+ width: 56px;
682
+ height: 56px;
683
+ }
684
+ }
685
+
686
+ /* Scrollbar */
687
+ .aicommerce-messages::-webkit-scrollbar {
688
+ width: 6px;
689
+ }
690
+
691
+ .aicommerce-messages::-webkit-scrollbar-track {
692
+ background: transparent;
693
+ }
694
+
695
+ .aicommerce-messages::-webkit-scrollbar-thumb {
696
+ background: var(--aic-border);
697
+ border-radius: 3px;
698
+ }
699
+
700
+ .aicommerce-messages::-webkit-scrollbar-thumb:hover {
701
+ background: var(--aic-text-secondary);
702
+ }
703
+ `;
704
+ }
705
+ function injectStyles(css) {
706
+ const style = document.createElement("style");
707
+ style.id = "aicommerce-widget-styles";
708
+ style.textContent = css;
709
+ const existing = document.getElementById("aicommerce-widget-styles");
710
+ if (existing) {
711
+ existing.remove();
712
+ }
713
+ document.head.appendChild(style);
714
+ return style;
715
+ }
716
+ var init_widget_styles = __esm({
717
+ "src/widget-styles.ts"() {
718
+ }
719
+ });
720
+
721
+ // src/widget.ts
722
+ var widget_exports = {};
723
+ __export(widget_exports, {
724
+ AICommerceWidget: () => AICommerceWidget,
725
+ createWidget: () => createWidget
726
+ });
727
+ function createWidget(config) {
728
+ if (!config.apiKey) {
729
+ throw new Error("AICommerceWidget: apiKey is required");
730
+ }
731
+ const client = new AICommerce({
732
+ apiKey: config.apiKey,
733
+ baseUrl: config.baseUrl
734
+ });
735
+ const state = {
736
+ isOpen: false,
737
+ isLoading: true,
738
+ messages: [],
739
+ storeConfig: null
740
+ };
741
+ let container = null;
742
+ let styleElement = null;
743
+ let resolvedConfig;
744
+ async function fetchStoreConfig() {
745
+ try {
746
+ const baseUrl = config.baseUrl || detectBaseUrl();
747
+ const response = await fetch(`${baseUrl}/api/v1/store`, {
748
+ headers: { "x-api-key": config.apiKey }
749
+ });
750
+ if (!response.ok) return null;
751
+ const data = await response.json();
752
+ return data.store;
753
+ } catch (error) {
754
+ console.error("Failed to fetch store config:", error);
755
+ return null;
756
+ }
757
+ }
758
+ function detectBaseUrl() {
759
+ if (typeof window !== "undefined") {
760
+ const script = document.querySelector("script[data-aicommerce-url]");
761
+ if (script) {
762
+ return script.getAttribute("data-aicommerce-url") || "";
763
+ }
764
+ }
765
+ return "https://api.aicommerce.dev";
766
+ }
767
+ async function initialize() {
768
+ state.storeConfig = await fetchStoreConfig();
769
+ resolvedConfig = {
770
+ apiKey: config.apiKey,
771
+ baseUrl: config.baseUrl || detectBaseUrl(),
772
+ position: config.position || "bottom-right",
773
+ theme: config.theme || "auto",
774
+ primaryColor: config.primaryColor || state.storeConfig?.primaryColor || "#6366f1",
775
+ welcomeMessage: config.welcomeMessage || state.storeConfig?.welcomeMessage || "Hi! How can I help you find the perfect product today?",
776
+ botName: config.botName || state.storeConfig?.chatBotName || "Shopping Assistant",
777
+ zIndex: config.zIndex || 9999,
778
+ buttonText: config.buttonText || "\u{1F4AC}",
779
+ hideLauncher: config.hideLauncher || false,
780
+ onOpen: config.onOpen,
781
+ onClose: config.onClose,
782
+ onProductClick: config.onProductClick,
783
+ onMessage: config.onMessage
784
+ };
785
+ const styles = createWidgetStyles(resolvedConfig);
786
+ styleElement = injectStyles(styles);
787
+ container = document.createElement("div");
788
+ container.id = "aicommerce-widget";
789
+ container.className = `aicommerce-widget aicommerce-${resolvedConfig.position} aicommerce-theme-${resolvedConfig.theme}`;
790
+ document.body.appendChild(container);
791
+ render();
792
+ state.messages.push({
793
+ role: "assistant",
794
+ content: resolvedConfig.welcomeMessage
795
+ });
796
+ state.isLoading = false;
797
+ render();
798
+ }
799
+ function render() {
800
+ if (!container) return;
801
+ const html = `
802
+ ${!resolvedConfig.hideLauncher ? `
803
+ <button class="aicommerce-launcher ${state.isOpen ? "aicommerce-hidden" : ""}" aria-label="Open chat">
804
+ <span class="aicommerce-launcher-icon">${resolvedConfig.buttonText}</span>
805
+ </button>
806
+ ` : ""}
807
+
808
+ <div class="aicommerce-chat ${state.isOpen ? "aicommerce-open" : "aicommerce-closed"}">
809
+ <div class="aicommerce-header">
810
+ <div class="aicommerce-header-info">
811
+ <div class="aicommerce-avatar">
812
+ ${state.storeConfig?.logo ? `<img src="${state.storeConfig.logo}" alt="${resolvedConfig.botName}" />` : `<span>\u{1F916}</span>`}
813
+ </div>
814
+ <div class="aicommerce-header-text">
815
+ <span class="aicommerce-bot-name">${resolvedConfig.botName}</span>
816
+ <span class="aicommerce-status">Online</span>
817
+ </div>
818
+ </div>
819
+ <button class="aicommerce-close" aria-label="Close chat">\u2715</button>
820
+ </div>
821
+
822
+ <div class="aicommerce-messages">
823
+ ${state.messages.map((msg) => `
824
+ <div class="aicommerce-message aicommerce-${msg.role}">
825
+ <div class="aicommerce-message-content">${escapeHtml(msg.content)}</div>
826
+ ${msg.products && msg.products.length > 0 ? `
827
+ <div class="aicommerce-products">
828
+ ${msg.products.map((product) => `
829
+ <div class="aicommerce-product-card" data-product-id="${product.id}">
830
+ ${product.imageUrl ? `
831
+ <img src="${product.imageUrl}" alt="${escapeHtml(product.name)}" class="aicommerce-product-image" />
832
+ ` : `
833
+ <div class="aicommerce-product-placeholder">\u{1F4E6}</div>
834
+ `}
835
+ <div class="aicommerce-product-info">
836
+ <span class="aicommerce-product-name">${escapeHtml(product.name)}</span>
837
+ <span class="aicommerce-product-price">${formatPrice(product.price, product.currency)}</span>
838
+ </div>
839
+ </div>
840
+ `).join("")}
841
+ </div>
842
+ ` : ""}
843
+ </div>
844
+ `).join("")}
845
+ ${state.isLoading ? `
846
+ <div class="aicommerce-message aicommerce-assistant">
847
+ <div class="aicommerce-typing">
848
+ <span></span><span></span><span></span>
849
+ </div>
850
+ </div>
851
+ ` : ""}
852
+ </div>
853
+
854
+ <div class="aicommerce-input-container">
855
+ <input
856
+ type="text"
857
+ class="aicommerce-input"
858
+ placeholder="Type your message..."
859
+ ${state.isLoading ? "disabled" : ""}
860
+ />
861
+ <button class="aicommerce-send" ${state.isLoading ? "disabled" : ""} aria-label="Send message">
862
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
863
+ <path d="M22 2L11 13M22 2L15 22L11 13M22 2L2 9L11 13"/>
864
+ </svg>
865
+ </button>
866
+ </div>
867
+ </div>
868
+ `;
869
+ container.innerHTML = html;
870
+ attachEventListeners();
871
+ const messagesEl = container.querySelector(".aicommerce-messages");
872
+ if (messagesEl) {
873
+ messagesEl.scrollTop = messagesEl.scrollHeight;
874
+ }
875
+ }
876
+ function attachEventListeners() {
877
+ if (!container) return;
878
+ const launcherEl = container.querySelector(".aicommerce-launcher");
879
+ if (launcherEl) {
880
+ launcherEl.addEventListener("click", () => open());
881
+ }
882
+ const closeEl = container.querySelector(".aicommerce-close");
883
+ if (closeEl) {
884
+ closeEl.addEventListener("click", () => close());
885
+ }
886
+ const inputEl = container.querySelector(".aicommerce-input");
887
+ const sendEl = container.querySelector(".aicommerce-send");
888
+ if (inputEl) {
889
+ inputEl.addEventListener("keypress", (e) => {
890
+ if (e.key === "Enter" && inputEl.value.trim()) {
891
+ handleSend(inputEl.value.trim());
892
+ inputEl.value = "";
893
+ }
894
+ });
895
+ }
896
+ if (sendEl && inputEl) {
897
+ sendEl.addEventListener("click", () => {
898
+ if (inputEl.value.trim()) {
899
+ handleSend(inputEl.value.trim());
900
+ inputEl.value = "";
901
+ }
902
+ });
903
+ }
904
+ const productCards = container.querySelectorAll(".aicommerce-product-card");
905
+ productCards.forEach((card) => {
906
+ card.addEventListener("click", () => {
907
+ const productId = card.getAttribute("data-product-id");
908
+ const product = state.messages.flatMap((m) => m.products || []).find((p) => p.id === productId);
909
+ if (product && resolvedConfig.onProductClick) {
910
+ resolvedConfig.onProductClick(product);
911
+ }
912
+ });
913
+ });
914
+ }
915
+ async function handleSend(message) {
916
+ state.messages.push({ role: "user", content: message });
917
+ state.isLoading = true;
918
+ render();
919
+ try {
920
+ const response = await client.chat(message);
921
+ state.messages.push({
922
+ role: "assistant",
923
+ content: response.reply,
924
+ products: response.products
925
+ });
926
+ if (resolvedConfig.onMessage) {
927
+ resolvedConfig.onMessage(message, response);
928
+ }
929
+ return response;
930
+ } catch (error) {
931
+ state.messages.push({
932
+ role: "assistant",
933
+ content: "Sorry, I encountered an error. Please try again."
934
+ });
935
+ throw error;
936
+ } finally {
937
+ state.isLoading = false;
938
+ render();
939
+ }
940
+ }
941
+ function open() {
942
+ state.isOpen = true;
943
+ render();
944
+ resolvedConfig.onOpen?.();
945
+ setTimeout(() => {
946
+ const input = container?.querySelector(".aicommerce-input");
947
+ input?.focus();
948
+ }, 100);
949
+ }
950
+ function close() {
951
+ state.isOpen = false;
952
+ render();
953
+ resolvedConfig.onClose?.();
954
+ }
955
+ function toggle() {
956
+ if (state.isOpen) {
957
+ close();
958
+ } else {
959
+ open();
960
+ }
961
+ }
962
+ function destroy() {
963
+ if (container) {
964
+ container.remove();
965
+ container = null;
966
+ }
967
+ if (styleElement) {
968
+ styleElement.remove();
969
+ styleElement = null;
970
+ }
971
+ }
972
+ function updateConfig(newConfig) {
973
+ Object.assign(resolvedConfig, newConfig);
974
+ if (newConfig.primaryColor) {
975
+ const styles = createWidgetStyles(resolvedConfig);
976
+ if (styleElement) {
977
+ styleElement.textContent = styles;
978
+ }
979
+ }
980
+ render();
981
+ }
982
+ function escapeHtml(text) {
983
+ const div = document.createElement("div");
984
+ div.textContent = text;
985
+ return div.innerHTML;
986
+ }
987
+ function formatPrice(price, currency) {
988
+ const symbols = {
989
+ USD: "$",
990
+ EUR: "\u20AC",
991
+ GBP: "\xA3",
992
+ MAD: "DH",
993
+ SAR: "SAR",
994
+ AED: "AED",
995
+ JPY: "\xA5",
996
+ CNY: "\xA5"
997
+ };
998
+ const symbol = symbols[currency || "USD"] || currency || "$";
999
+ return `${price.toFixed(2)} ${symbol}`;
1000
+ }
1001
+ initialize();
1002
+ return {
1003
+ open,
1004
+ close,
1005
+ toggle,
1006
+ destroy,
1007
+ sendMessage: handleSend,
1008
+ updateConfig
1009
+ };
1010
+ }
1011
+ var AICommerceWidget;
1012
+ var init_widget = __esm({
1013
+ "src/widget.ts"() {
1014
+ init_client();
1015
+ init_widget_styles();
1016
+ AICommerceWidget = {
1017
+ init: createWidget,
1018
+ VERSION: "1.0.0"
1019
+ };
1020
+ if (typeof window !== "undefined") {
1021
+ window.AICommerceWidget = AICommerceWidget;
1022
+ }
1023
+ }
1024
+ });
1025
+
191
1026
  // src/index.ts
192
1027
  init_client();
1028
+ init_widget();
193
1029
  var VERSION = "1.0.0";
194
1030
  if (typeof window !== "undefined") {
195
1031
  window.AICommerce = (init_client(), __toCommonJS(client_exports)).AICommerce;
196
1032
  window.AICommerceError = (init_client(), __toCommonJS(client_exports)).AICommerceError;
1033
+ window.AICommerceWidget = (init_widget(), __toCommonJS(widget_exports)).AICommerceWidget;
197
1034
  }
198
1035
 
199
- export { AICommerce, AICommerceError, VERSION };
1036
+ export { AICommerce, AICommerceError, AICommerceWidget, VERSION, createWidget };
200
1037
  //# sourceMappingURL=index.mjs.map
201
1038
  //# sourceMappingURL=index.mjs.map