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