@yassirbenmoussa/aicommerce-sdk 1.9.3 → 1.9.10
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/ai-commerce.min.js +251 -84
- package/dist/index.cjs +235 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.min.js.map +1 -1
- package/dist/index.mjs +235 -31
- package/dist/index.mjs.map +1 -1
- package/dist/widget.min.js +251 -84
- package/dist/widget.min.js.map +1 -1
- package/package.json +6 -4
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var marked = require('marked');
|
|
4
|
+
|
|
3
5
|
var __defProp = Object.defineProperty;
|
|
4
6
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
7
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -767,7 +769,7 @@ function createWidgetStyles(config) {
|
|
|
767
769
|
display: flex;
|
|
768
770
|
align-items: center;
|
|
769
771
|
gap: 2px;
|
|
770
|
-
height:
|
|
772
|
+
height: 32px;
|
|
771
773
|
cursor: pointer;
|
|
772
774
|
width: 100%;
|
|
773
775
|
}
|
|
@@ -775,9 +777,10 @@ function createWidgetStyles(config) {
|
|
|
775
777
|
.aicommerce-waveform-bar {
|
|
776
778
|
width: 3px;
|
|
777
779
|
border-radius: 2px;
|
|
778
|
-
min-height:
|
|
780
|
+
min-height: 4px;
|
|
779
781
|
transition: background-color 0.1s;
|
|
780
|
-
flex
|
|
782
|
+
flex: 0 0 3px;
|
|
783
|
+
display: block !important;
|
|
781
784
|
}
|
|
782
785
|
|
|
783
786
|
.aicommerce-audio-time {
|
|
@@ -1232,6 +1235,42 @@ function createWidgetStyles(config) {
|
|
|
1232
1235
|
flex-shrink: 0;
|
|
1233
1236
|
}
|
|
1234
1237
|
|
|
1238
|
+
.aicommerce-product-actions {
|
|
1239
|
+
display: flex;
|
|
1240
|
+
flex-direction: column;
|
|
1241
|
+
gap: 8px;
|
|
1242
|
+
margin-top: 8px;
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
.aicommerce-product-actions .aicommerce-add-to-cart {
|
|
1246
|
+
margin-top: 0;
|
|
1247
|
+
flex: 1;
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
.aicommerce-buy-now {
|
|
1251
|
+
width: 100%;
|
|
1252
|
+
padding: 8px 12px;
|
|
1253
|
+
background: transparent;
|
|
1254
|
+
color: var(--aic-primary);
|
|
1255
|
+
border: 1px solid var(--aic-primary);
|
|
1256
|
+
border-radius: 6px;
|
|
1257
|
+
font-size: 12px;
|
|
1258
|
+
font-weight: 500;
|
|
1259
|
+
cursor: pointer;
|
|
1260
|
+
transition: all 0.2s;
|
|
1261
|
+
display: flex;
|
|
1262
|
+
align-items: center;
|
|
1263
|
+
justify-content: center;
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
.aicommerce-buy-now:hover {
|
|
1267
|
+
background: rgba(0, 0, 0, 0.05);
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
.aicommerce-buy-now:active {
|
|
1271
|
+
transform: translateY(1px);
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1235
1274
|
/* Spinner animation for loading state */
|
|
1236
1275
|
@keyframes aicommerce-spin {
|
|
1237
1276
|
to { transform: rotate(360deg); }
|
|
@@ -1240,6 +1279,63 @@ function createWidgetStyles(config) {
|
|
|
1240
1279
|
.aicommerce-spinner {
|
|
1241
1280
|
animation: aicommerce-spin 1s linear infinite;
|
|
1242
1281
|
}
|
|
1282
|
+
|
|
1283
|
+
/* ============================================
|
|
1284
|
+
Markdown Content Styles
|
|
1285
|
+
============================================ */
|
|
1286
|
+
.aicommerce-message-content p {
|
|
1287
|
+
margin: 0 0 0.5em 0;
|
|
1288
|
+
}
|
|
1289
|
+
.aicommerce-message-content p:last-child {
|
|
1290
|
+
margin-bottom: 0;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
.aicommerce-message-content strong {
|
|
1294
|
+
font-weight: 600;
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
.aicommerce-message-content em {
|
|
1298
|
+
font-style: italic;
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
.aicommerce-message-content a {
|
|
1302
|
+
text-decoration: underline;
|
|
1303
|
+
color: inherit;
|
|
1304
|
+
}
|
|
1305
|
+
.aicommerce-user .aicommerce-message-content a {
|
|
1306
|
+
color: rgba(255, 255, 255, 0.95);
|
|
1307
|
+
}
|
|
1308
|
+
.aicommerce-assistant .aicommerce-message-content a {
|
|
1309
|
+
color: var(--aic-primary);
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
.aicommerce-message-content code {
|
|
1313
|
+
background: rgba(0, 0, 0, 0.1);
|
|
1314
|
+
padding: 0.1em 0.4em;
|
|
1315
|
+
border-radius: 4px;
|
|
1316
|
+
font-family: 'Courier New', Courier, monospace;
|
|
1317
|
+
font-size: 0.9em;
|
|
1318
|
+
}
|
|
1319
|
+
.aicommerce-user .aicommerce-message-content code {
|
|
1320
|
+
background: rgba(255, 255, 255, 0.2);
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
.aicommerce-message-content ul,
|
|
1324
|
+
.aicommerce-message-content ol {
|
|
1325
|
+
margin: 0.5em 0;
|
|
1326
|
+
padding-left: 1.5em;
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
.aicommerce-message-content li {
|
|
1330
|
+
margin-bottom: 0.25em;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
.aicommerce-message-content blockquote {
|
|
1334
|
+
border-left: 3px solid var(--aic-primary);
|
|
1335
|
+
margin: 0.5em 0;
|
|
1336
|
+
padding-left: 1em;
|
|
1337
|
+
opacity: 0.9;
|
|
1338
|
+
}
|
|
1243
1339
|
`;
|
|
1244
1340
|
}
|
|
1245
1341
|
function injectStyles(css) {
|
|
@@ -1271,14 +1367,15 @@ function createWidget(config) {
|
|
|
1271
1367
|
const client = new exports.AICommerce({
|
|
1272
1368
|
apiKey: config.apiKey,
|
|
1273
1369
|
storeId: config.storeId,
|
|
1274
|
-
baseUrl: config.baseUrl
|
|
1370
|
+
baseUrl: config.baseUrl,
|
|
1371
|
+
timeout: 12e4
|
|
1372
|
+
// 60s timeout for audio processing
|
|
1275
1373
|
});
|
|
1276
1374
|
const state = {
|
|
1277
1375
|
isOpen: false,
|
|
1278
1376
|
isLoading: true,
|
|
1279
1377
|
isRecording: false,
|
|
1280
|
-
messages: []
|
|
1281
|
-
storeConfig: null
|
|
1378
|
+
messages: []
|
|
1282
1379
|
};
|
|
1283
1380
|
let mediaRecorder = null;
|
|
1284
1381
|
let audioChunks = [];
|
|
@@ -1309,7 +1406,7 @@ function createWidget(config) {
|
|
|
1309
1406
|
return "https://api.aicommerce.dev";
|
|
1310
1407
|
}
|
|
1311
1408
|
async function initialize() {
|
|
1312
|
-
state.storeConfig = await fetchStoreConfig();
|
|
1409
|
+
state.storeConfig = await fetchStoreConfig() || void 0;
|
|
1313
1410
|
const displayMode = config.displayMode || "widget";
|
|
1314
1411
|
const isEmbedded = displayMode === "embedded";
|
|
1315
1412
|
resolvedConfig = {
|
|
@@ -1333,6 +1430,9 @@ function createWidget(config) {
|
|
|
1333
1430
|
onClose: config.onClose,
|
|
1334
1431
|
onProductClick: config.onProductClick,
|
|
1335
1432
|
onAddToCart: config.onAddToCart,
|
|
1433
|
+
showAddToCart: config.showAddToCart,
|
|
1434
|
+
onBuyNow: config.onBuyNow,
|
|
1435
|
+
showBuyNow: config.showBuyNow,
|
|
1336
1436
|
onMessage: config.onMessage
|
|
1337
1437
|
};
|
|
1338
1438
|
const styles = createWidgetStyles(resolvedConfig);
|
|
@@ -1392,6 +1492,62 @@ function createWidget(config) {
|
|
|
1392
1492
|
throw new Error("Failed to add to cart");
|
|
1393
1493
|
}
|
|
1394
1494
|
document.dispatchEvent(new CustomEvent("cart:refresh"));
|
|
1495
|
+
document.dispatchEvent(new CustomEvent("cart:change"));
|
|
1496
|
+
document.dispatchEvent(new CustomEvent("cart:add"));
|
|
1497
|
+
document.dispatchEvent(new CustomEvent("cart:updated"));
|
|
1498
|
+
document.dispatchEvent(new CustomEvent("CartJS:change"));
|
|
1499
|
+
const win = window;
|
|
1500
|
+
if (win.Shopify && win.Shopify.onCartUpdate) {
|
|
1501
|
+
win.Shopify.onCartUpdate();
|
|
1502
|
+
}
|
|
1503
|
+
fetch("/cart.js").then((res) => res.json()).then((cart) => {
|
|
1504
|
+
document.dispatchEvent(new CustomEvent("cart:build", { detail: { cart } }));
|
|
1505
|
+
document.dispatchEvent(new CustomEvent("ajaxCart.afterCartLoad", { detail: { cart } }));
|
|
1506
|
+
const count = cart.item_count;
|
|
1507
|
+
const selectors = [
|
|
1508
|
+
".cart-count",
|
|
1509
|
+
"#cart-count",
|
|
1510
|
+
".site-header__cart-count",
|
|
1511
|
+
"[data-cart-count]",
|
|
1512
|
+
".cart-count-bubble",
|
|
1513
|
+
".header__cart-count",
|
|
1514
|
+
".header-cart__count"
|
|
1515
|
+
];
|
|
1516
|
+
selectors.forEach((selector) => {
|
|
1517
|
+
document.querySelectorAll(selector).forEach((el) => {
|
|
1518
|
+
el.textContent = count.toString();
|
|
1519
|
+
el.classList.remove("hide", "hidden");
|
|
1520
|
+
});
|
|
1521
|
+
});
|
|
1522
|
+
const cartIconBubble = document.getElementById("cart-icon-bubble");
|
|
1523
|
+
if (cartIconBubble) {
|
|
1524
|
+
let countBubble = cartIconBubble.querySelector(".cart-count-bubble");
|
|
1525
|
+
if (count > 0) {
|
|
1526
|
+
if (!countBubble) {
|
|
1527
|
+
countBubble = document.createElement("div");
|
|
1528
|
+
countBubble.className = "cart-count-bubble";
|
|
1529
|
+
countBubble.innerHTML = `<span aria-hidden="true">${count}</span><span class="visually-hidden">${count} item</span>`;
|
|
1530
|
+
cartIconBubble.appendChild(countBubble);
|
|
1531
|
+
} else {
|
|
1532
|
+
countBubble.innerHTML = `<span aria-hidden="true">${count}</span><span class="visually-hidden">${count} item</span>`;
|
|
1533
|
+
countBubble.classList.remove("hidden", "hide");
|
|
1534
|
+
}
|
|
1535
|
+
} else if (countBubble) {
|
|
1536
|
+
countBubble.classList.add("hidden");
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
}).catch(() => {
|
|
1540
|
+
});
|
|
1541
|
+
}
|
|
1542
|
+
function handleBuyNow(variantId) {
|
|
1543
|
+
let numericVariantId = variantId;
|
|
1544
|
+
if (variantId.includes("gid://")) {
|
|
1545
|
+
const match = variantId.match(/\/(\d+)$/);
|
|
1546
|
+
if (match) {
|
|
1547
|
+
numericVariantId = match[1];
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
window.location.href = `/cart/${numericVariantId}:1`;
|
|
1395
1551
|
}
|
|
1396
1552
|
function render() {
|
|
1397
1553
|
if (!container) return;
|
|
@@ -1471,7 +1627,7 @@ function createWidget(config) {
|
|
|
1471
1627
|
return `
|
|
1472
1628
|
<div class="aicommerce-message aicommerce-${msg.role}">
|
|
1473
1629
|
<div class="aicommerce-message-content ${isRtl ? "aicommerce-rtl" : "aicommerce-ltr"}">
|
|
1474
|
-
${msg.audioUrl ? renderAudioPlayer(msg, index, isUser) :
|
|
1630
|
+
${msg.audioUrl ? renderAudioPlayer(msg, index, isUser) : marked.marked.parse(msg.content)}
|
|
1475
1631
|
</div>
|
|
1476
1632
|
${msg.products && msg.products.length > 0 ? `
|
|
1477
1633
|
<div class="aicommerce-products">
|
|
@@ -1486,13 +1642,22 @@ function createWidget(config) {
|
|
|
1486
1642
|
<span class="aicommerce-product-name" title="${escapeHtml(product.name)}">${escapeHtml(product.name)}</span>
|
|
1487
1643
|
${product.description ? `<p class="aicommerce-product-desc">${escapeHtml(product.description)}</p>` : ""}
|
|
1488
1644
|
<span class="aicommerce-product-price">${formatPrice(product.price, product.currency)}</span>
|
|
1489
|
-
<
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
<
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1645
|
+
<div class="aicommerce-product-actions">
|
|
1646
|
+
${resolvedConfig.showAddToCart !== false ? `
|
|
1647
|
+
<button class="aicommerce-add-to-cart" data-product-id="${product.id}">
|
|
1648
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
1649
|
+
<circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/>
|
|
1650
|
+
<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/>
|
|
1651
|
+
</svg>
|
|
1652
|
+
${resolvedConfig.addToCartText || "Add to Cart"}
|
|
1653
|
+
</button>
|
|
1654
|
+
` : ""}
|
|
1655
|
+
${resolvedConfig.showBuyNow !== false ? `
|
|
1656
|
+
<button class="aicommerce-buy-now" data-variant-id="${product.variantId || ""}">
|
|
1657
|
+
Buy Now
|
|
1658
|
+
</button>
|
|
1659
|
+
` : ""}
|
|
1660
|
+
</div>
|
|
1496
1661
|
</div>
|
|
1497
1662
|
</div>
|
|
1498
1663
|
`).join("")}
|
|
@@ -1519,7 +1684,7 @@ function createWidget(config) {
|
|
|
1519
1684
|
return `
|
|
1520
1685
|
<div class="aicommerce-message aicommerce-${msg.role}">
|
|
1521
1686
|
<div class="aicommerce-message-content ${isRtl ? "aicommerce-rtl" : "aicommerce-ltr"}">
|
|
1522
|
-
${msg.audioUrl ? renderAudioPlayer(msg, index, isUser) :
|
|
1687
|
+
${msg.audioUrl ? renderAudioPlayer(msg, index, isUser) : marked.marked.parse(msg.content)}
|
|
1523
1688
|
</div>
|
|
1524
1689
|
${msg.products && msg.products.length > 0 ? `
|
|
1525
1690
|
<div class="aicommerce-products">
|
|
@@ -1534,13 +1699,22 @@ function createWidget(config) {
|
|
|
1534
1699
|
<span class="aicommerce-product-name" title="${escapeHtml(product.name)}">${escapeHtml(product.name)}</span>
|
|
1535
1700
|
${product.description ? `<p class="aicommerce-product-desc">${escapeHtml(product.description)}</p>` : ""}
|
|
1536
1701
|
<span class="aicommerce-product-price">${formatPrice(product.price, product.currency)}</span>
|
|
1537
|
-
<
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
<
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1702
|
+
<div class="aicommerce-product-actions">
|
|
1703
|
+
${resolvedConfig.showAddToCart !== false ? `
|
|
1704
|
+
<button class="aicommerce-add-to-cart" data-product-id="${product.id}">
|
|
1705
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
1706
|
+
<circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/>
|
|
1707
|
+
<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/>
|
|
1708
|
+
</svg>
|
|
1709
|
+
${resolvedConfig.addToCartText || "Add to Cart"}
|
|
1710
|
+
</button>
|
|
1711
|
+
` : ""}
|
|
1712
|
+
${resolvedConfig.showBuyNow !== false ? `
|
|
1713
|
+
<button class="aicommerce-buy-now" data-variant-id="${product.variantId || ""}">
|
|
1714
|
+
Buy Now
|
|
1715
|
+
</button>
|
|
1716
|
+
` : ""}
|
|
1717
|
+
</div>
|
|
1544
1718
|
</div>
|
|
1545
1719
|
</div>
|
|
1546
1720
|
`).join("")}
|
|
@@ -1706,6 +1880,21 @@ function createWidget(config) {
|
|
|
1706
1880
|
}
|
|
1707
1881
|
});
|
|
1708
1882
|
});
|
|
1883
|
+
const buyNowBtns = container.querySelectorAll(".aicommerce-buy-now");
|
|
1884
|
+
buyNowBtns.forEach((btn) => {
|
|
1885
|
+
btn.addEventListener("click", async (e) => {
|
|
1886
|
+
e.stopPropagation();
|
|
1887
|
+
const productCard = btn.closest(".aicommerce-product-card");
|
|
1888
|
+
const productId = productCard?.getAttribute("data-product-id");
|
|
1889
|
+
const variantId = btn.getAttribute("data-variant-id");
|
|
1890
|
+
const product = state.messages.flatMap((m) => m.products || []).find((p) => p.id === productId);
|
|
1891
|
+
if (product && resolvedConfig.onBuyNow) {
|
|
1892
|
+
await resolvedConfig.onBuyNow(product);
|
|
1893
|
+
} else if (variantId) {
|
|
1894
|
+
handleBuyNow(variantId);
|
|
1895
|
+
}
|
|
1896
|
+
});
|
|
1897
|
+
});
|
|
1709
1898
|
const sliders = container.querySelectorAll(".aicommerce-products");
|
|
1710
1899
|
sliders.forEach((slider) => {
|
|
1711
1900
|
let isDown = false;
|
|
@@ -1797,8 +1986,9 @@ function createWidget(config) {
|
|
|
1797
1986
|
try {
|
|
1798
1987
|
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
1799
1988
|
audioChunks = [];
|
|
1989
|
+
const mimeType = MediaRecorder.isTypeSupported("audio/webm") ? "audio/webm" : "audio/mp4";
|
|
1800
1990
|
mediaRecorder = new MediaRecorder(stream, {
|
|
1801
|
-
mimeType
|
|
1991
|
+
mimeType
|
|
1802
1992
|
});
|
|
1803
1993
|
mediaRecorder.ondataavailable = (e) => {
|
|
1804
1994
|
if (e.data.size > 0) {
|
|
@@ -1806,13 +1996,17 @@ function createWidget(config) {
|
|
|
1806
1996
|
}
|
|
1807
1997
|
};
|
|
1808
1998
|
mediaRecorder.onstop = async () => {
|
|
1809
|
-
stream.getTracks().forEach((track) => track.stop());
|
|
1810
|
-
if (audioChunks.length > 0) {
|
|
1811
|
-
const audioBlob = new Blob(audioChunks, { type: mediaRecorder?.mimeType || "audio/webm" });
|
|
1812
|
-
await handleAudioSend(audioBlob);
|
|
1813
|
-
}
|
|
1814
1999
|
state.isRecording = false;
|
|
1815
2000
|
render();
|
|
2001
|
+
stream.getTracks().forEach((track) => track.stop());
|
|
2002
|
+
try {
|
|
2003
|
+
if (audioChunks.length > 0) {
|
|
2004
|
+
const audioBlob = new Blob(audioChunks, { type: mimeType });
|
|
2005
|
+
await handleAudioSend(audioBlob);
|
|
2006
|
+
}
|
|
2007
|
+
} catch (error) {
|
|
2008
|
+
console.error("Failed to process audio:", error);
|
|
2009
|
+
}
|
|
1816
2010
|
};
|
|
1817
2011
|
mediaRecorder.start();
|
|
1818
2012
|
state.isRecording = true;
|
|
@@ -1829,10 +2023,8 @@ function createWidget(config) {
|
|
|
1829
2023
|
}
|
|
1830
2024
|
async function handleAudioSend(audioBlob) {
|
|
1831
2025
|
const audioUrl = URL.createObjectURL(audioBlob);
|
|
1832
|
-
let waveformBars = Array(40).fill(10);
|
|
1833
2026
|
let audioDuration = 0;
|
|
1834
2027
|
try {
|
|
1835
|
-
waveformBars = await analyzeAudio(audioBlob);
|
|
1836
2028
|
const audio = new Audio(audioUrl);
|
|
1837
2029
|
await new Promise((resolve) => {
|
|
1838
2030
|
audio.onloadedmetadata = () => {
|
|
@@ -1841,6 +2033,12 @@ function createWidget(config) {
|
|
|
1841
2033
|
};
|
|
1842
2034
|
audio.onerror = () => resolve();
|
|
1843
2035
|
});
|
|
2036
|
+
} catch (e) {
|
|
2037
|
+
console.error("Audio duration check failed", e);
|
|
2038
|
+
}
|
|
2039
|
+
let waveformBars = Array(40).fill(10);
|
|
2040
|
+
try {
|
|
2041
|
+
waveformBars = await analyzeAudio(audioBlob);
|
|
1844
2042
|
} catch (e) {
|
|
1845
2043
|
console.error("Audio analysis failed", e);
|
|
1846
2044
|
}
|
|
@@ -2010,6 +2208,12 @@ var init_widget = __esm({
|
|
|
2010
2208
|
"src/widget.ts"() {
|
|
2011
2209
|
init_client();
|
|
2012
2210
|
init_widget_styles();
|
|
2211
|
+
marked.marked.setOptions({
|
|
2212
|
+
breaks: true,
|
|
2213
|
+
// Convert \n to <br>
|
|
2214
|
+
gfm: true
|
|
2215
|
+
// GitHub Flavored Markdown
|
|
2216
|
+
});
|
|
2013
2217
|
exports.AICommerceWidget = {
|
|
2014
2218
|
init: createWidget,
|
|
2015
2219
|
VERSION: "1.0.0"
|