brainerce 1.32.0 → 1.33.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/README.md +10 -7
- package/dist/bot/bootstrap.global.js +13 -4
- package/dist/bot/index.d.mts +14 -0
- package/dist/bot/index.d.ts +14 -0
- package/dist/bot/index.js +83 -28
- package/dist/bot/index.mjs +83 -28
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4867,11 +4867,12 @@ import { BrainerceBot } from 'brainerce/bot';
|
|
|
4867
4867
|
|
|
4868
4868
|
const bot = await BrainerceBot.mount({
|
|
4869
4869
|
connectionId: 'vc_abc123',
|
|
4870
|
-
// Optional: make
|
|
4871
|
-
//
|
|
4872
|
-
//
|
|
4873
|
-
|
|
4874
|
-
|
|
4870
|
+
// Optional: make cart adds (card buttons, the in-card variant picker, and
|
|
4871
|
+
// bot-initiated adds) go through YOUR cart so your header count stays in
|
|
4872
|
+
// sync. variantId is null for simple products. Return false to make the
|
|
4873
|
+
// widget fall back to navigating to the product page.
|
|
4874
|
+
onAddToCart: async ({ productId, variantId, quantity }) => {
|
|
4875
|
+
await client.smartAddToCart({ productId, variantId: variantId ?? undefined, quantity });
|
|
4875
4876
|
return true;
|
|
4876
4877
|
},
|
|
4877
4878
|
});
|
|
@@ -4879,9 +4880,11 @@ const bot = await BrainerceBot.mount({
|
|
|
4879
4880
|
bot?.destroy(); // optional teardown
|
|
4880
4881
|
```
|
|
4881
4882
|
|
|
4882
|
-
The widget persists an anonymous session in `localStorage`, restores conversations on revisit, streams answers, and shows product recommendation cards (image, price, add-to-cart / view buttons).
|
|
4883
|
+
The widget persists an anonymous session in `localStorage`, restores conversations on revisit, streams answers, and shows product recommendation cards (image, price, add-to-cart / view buttons). Multi-variant products get an **in-card variant picker** (attribute chips, live variant price/image) so shoppers can choose options and add without leaving the chat; shoppers can also just ask the assistant to add an item ("add the moka to my cart") and it happens through the same chain. A leave-a-message form lands in the merchant's Inquiries inbox, and zero-result searches feed the merchant's "unmet demand" analytics.
|
|
4884
|
+
|
|
4885
|
+
**Add to cart resolution** (never a dead button): the widget first calls your `onAddToCart` option; without one it dispatches a cancelable `brainerce:bot:add-to-cart` `CustomEvent` on `window` (`detail: { productId, variantId, quantity, connectionId }` — call `preventDefault()` after handling it); if nothing handles either, it navigates to the product page. Products too complex for in-chat picking (3+ attribute dimensions or 25+ variants) always navigate. Aside from your own cart handler, the widget is read-only by design — shoppers can never mutate the store through it.
|
|
4883
4886
|
|
|
4884
|
-
|
|
4887
|
+
Merchant-side display controls (Studio → Storefront Bot): chat size (compact / full screen / shopper's choice), auto-open, position, and whether shoppers may expand the window (`allowExpand`).
|
|
4885
4888
|
|
|
4886
4889
|
## Webhooks
|
|
4887
4890
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
"use strict";(()=>{var
|
|
2
|
-
`),t=null,i=null;for(let o of n){let r=/^\s*[-•*]\s+(.*)$/.exec(o);if(r){i=null,t||(t=document.createElement("ul"),b.appendChild(t));let d=document.createElement("li");
|
|
1
|
+
"use strict";(()=>{var R="https://api.brainerce.com",O=new Set(["he","ar"]),S={en:{online:"Online",placeholder:"Ask anything\u2026",error:"Something went wrong \u2014 please try again.",leaveMessage:"Leave a message for the team",yourEmail:"Your email",yourMessage:"Your message",send:"Send",sent:"Thanks! The team will get back to you by email.",close:"Close",expand:"Expand",collapse:"Collapse",searching:"Searching the store\u2026",addToCart:"Add to cart",added:"Added",view:"View",chooseOptions:"View product",results:"From the store",poweredBy:"Powered by Brainerce",addFailed:"I couldn\u2019t add that to the cart \u2014 try the button on the product card."},he:{online:"\u05DE\u05D7\u05D5\u05D1\u05E8",placeholder:"\u05E9\u05D0\u05DC\u05D5 \u05D0\u05D5\u05EA\u05D9 \u05D4\u05DB\u05DC\u2026",error:"\u05DE\u05E9\u05D4\u05D5 \u05D4\u05E9\u05EA\u05D1\u05E9 \u2014 \u05E0\u05E1\u05D5 \u05E9\u05D5\u05D1.",leaveMessage:"\u05D4\u05E9\u05D0\u05D9\u05E8\u05D5 \u05D4\u05D5\u05D3\u05E2\u05D4 \u05DC\u05E6\u05D5\u05D5\u05EA",yourEmail:"\u05D4\u05D0\u05D9\u05DE\u05D9\u05D9\u05DC \u05E9\u05DC\u05DB\u05DD",yourMessage:"\u05D4\u05D4\u05D5\u05D3\u05E2\u05D4 \u05E9\u05DC\u05DB\u05DD",send:"\u05E9\u05DC\u05D9\u05D7\u05D4",sent:"\u05EA\u05D5\u05D3\u05D4! \u05D4\u05E6\u05D5\u05D5\u05EA \u05D9\u05D7\u05D6\u05D5\u05E8 \u05D0\u05DC\u05D9\u05DB\u05DD \u05D1\u05DE\u05D9\u05D9\u05DC.",close:"\u05E1\u05D2\u05D9\u05E8\u05D4",expand:"\u05D4\u05E8\u05D7\u05D1\u05D4",collapse:"\u05DB\u05D9\u05D5\u05D5\u05E5",searching:"\u05DE\u05D7\u05E4\u05E9 \u05D1\u05D7\u05E0\u05D5\u05EA\u2026",addToCart:"\u05D4\u05D5\u05E1\u05E4\u05D4 \u05DC\u05E1\u05DC",added:"\u05E0\u05D5\u05E1\u05E3",view:"\u05E6\u05E4\u05D9\u05D9\u05D4",chooseOptions:"\u05DC\u05E6\u05E4\u05D5\u05EA \u05D1\u05DE\u05D5\u05E6\u05E8",results:"\u05DE\u05EA\u05D5\u05DA \u05D4\u05D7\u05E0\u05D5\u05EA",poweredBy:"\u05DE\u05D5\u05E4\u05E2\u05DC \u05E2\u05DC \u05D9\u05D3\u05D9 Brainerce",addFailed:"\u05DC\u05D0 \u05D4\u05E6\u05DC\u05D7\u05EA\u05D9 \u05DC\u05D4\u05D5\u05E1\u05D9\u05E3 \u05DC\u05E1\u05DC \u2014 \u05E0\u05E1\u05D5 \u05D3\u05E8\u05DA \u05D4\u05DB\u05E4\u05EA\u05D5\u05E8 \u05D1\u05DB\u05E8\u05D8\u05D9\u05E1 \u05D4\u05DE\u05D5\u05E6\u05E8."}},H={chat:'<svg viewBox="0 0 24 24" fill="none"><path d="M12 3C7.03 3 3 6.58 3 11c0 2.04.86 3.9 2.28 5.32-.15 1.23-.62 2.39-1.1 3.21-.13.23.05.52.31.47 1.56-.27 3.07-.93 4.13-1.62A10.6 10.6 0 0 0 12 19c4.97 0 9-3.58 9-8s-4.03-8-9-8Z" fill="currentColor"/></svg>',close:'<svg viewBox="0 0 24 24" fill="none"><path d="M6 6l12 12M18 6L6 18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>',expand:'<svg viewBox="0 0 24 24" fill="none"><path d="M14 4h6v6M10 20H4v-6M20 4l-7 7M4 20l7-7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>',collapse:'<svg viewBox="0 0 24 24" fill="none"><path d="M20 10h-6V4M4 14h6v6M20 4l-6 6M4 20l6-6" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>',mail:'<svg viewBox="0 0 24 24" fill="none"><rect x="3.5" y="5.5" width="17" height="13" rx="2.5" stroke="currentColor" stroke-width="1.7"/><path d="m4.5 7.5 7.5 5.5 7.5-5.5" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"/></svg>',send:'<svg viewBox="0 0 24 24" fill="none"><path d="M4.4 11.2 19 4.6c.7-.3 1.4.4 1.1 1.1l-6.6 14.6c-.3.7-1.3.6-1.5-.1l-1.7-5.4a1 1 0 0 0-.6-.6l-5.4-1.7c-.7-.2-.8-1.2-.1-1.5Z" fill="currentColor"/></svg>',cart:'<svg viewBox="0 0 24 24" fill="none"><path d="M3 4h2l2.4 11.2A2 2 0 0 0 9.36 17H17.5a2 2 0 0 0 1.95-1.55L21 8H6" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/><circle cx="10" cy="20.5" r="1.4" fill="currentColor"/><circle cx="17" cy="20.5" r="1.4" fill="currentColor"/></svg>',check:'<svg viewBox="0 0 24 24" fill="none"><path d="m5 12.5 4.5 4.5L19 7.5" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg>',arrow:'<svg viewBox="0 0 24 24" fill="none"><path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>',brand:'<svg viewBox="0 0 24 24"><defs><linearGradient id="bb-brand-g" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#34d399"/><stop offset="1" stop-color="#8b5cf6"/></linearGradient></defs><rect x="1.5" y="1.5" width="21" height="21" rx="6" fill="url(#bb-brand-g)"/><text x="12" y="17" text-anchor="middle" font-family="ui-sans-serif,system-ui,sans-serif" font-size="14" font-weight="700" fill="#fff">B</text></svg>'},z=typeof DOMParser<"u"?new DOMParser:null;function m(b){let e=(H[b]??H.chat).replace("<svg ",'<svg xmlns="http://www.w3.org/2000/svg" '),t=z?.parseFromString(e,"image/svg+xml")?.documentElement;return!t||t.nodeName==="parsererror"?document.createTextNode(""):(t.setAttribute("aria-hidden","true"),t.setAttribute("class","bb-ic"),t)}function P(b){let e=new Uint8Array(16);crypto.getRandomValues(e);let n=btoa(String.fromCharCode(...e)).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"");return`${b}${n}`}function T(b){return/^\/(?!\/)/.test(b)||/^https?:\/\//i.test(b)}var $=/\*\*([^*\n]+)\*\*|\[([^\]\n]+)\]\(([^)\s]+)\)/g;function A(b,e){let n=0;$.lastIndex=0;for(let t=$.exec(e);t;t=$.exec(e)){if(t.index>n&&b.appendChild(document.createTextNode(e.slice(n,t.index))),t[1]!==void 0){let i=document.createElement("strong");i.textContent=t[1],b.appendChild(i)}else if(T(t[3])){let i=document.createElement("a");i.href=t[3],i.target="_blank",i.rel="noopener noreferrer",i.textContent=t[2],b.appendChild(i)}else b.appendChild(document.createTextNode(t[2]));n=t.index+t[0].length}n<e.length&&b.appendChild(document.createTextNode(e.slice(n)))}function U(b,e){b.replaceChildren();let n=e.split(`
|
|
2
|
+
`),t=null,i=null;for(let o of n){let r=/^\s*[-•*]\s+(.*)$/.exec(o);if(r){i=null,t||(t=document.createElement("ul"),b.appendChild(t));let d=document.createElement("li");A(d,r[1]),t.appendChild(d);continue}if(t=null,!o.trim()){i=null;continue}i?i.appendChild(document.createElement("br")):(i=document.createElement("p"),b.appendChild(i)),A(i,o)}}var M=class b{constructor(e){this.settings={enabled:!1};this.locale="en";this.sessionId=null;this.conversationId=null;this.busy=!1;this.opened=!1;this.expanded=!1;this.destroyed=!1;this.pendingText="";this.cardsRow=null;this.cardIds=new Set;this.prevBodyOverflow=null;this.connectionId=e.connectionId,this.baseUrl=(e.baseUrl||R).replace(/\/$/,""),this.storageKey=`brainerce-bot:${this.connectionId}`,this.onAddToCart=e.onAddToCart}static async mount(e){if(!e?.connectionId)return console.warn("[BrainerceBot] connectionId is required"),null;let n=new b(e);return await n.boot(e.target??document.body)?n:null}destroy(){this.destroyed=!0,this.prevBodyOverflow!==null&&(document.body.style.overflow=this.prevBodyOverflow,this.prevBodyOverflow=null),this.host?.remove()}async boot(e){try{let n=await fetch(`${this.baseUrl}/api/storefront-bot/${encodeURIComponent(this.connectionId)}/settings`);if(!n.ok)return!1;this.settings=await n.json()}catch{return!1}return this.settings.enabled?(this.locale=this.settings.languages?.[0]??"en",this.restoreIds(),this.render(e),this.settings.displayMode==="auto_open"&&setTimeout(()=>!this.destroyed&&this.open(),3e3),!0):!1}t(e){return(S[this.locale]??S.en)[e]??S.en[e]??e}restoreIds(){try{let e=localStorage.getItem(this.storageKey);if(e){let n=JSON.parse(e);this.sessionId=n.sessionId??null,this.conversationId=n.conversationId??null}}catch{}}persistIds(){try{localStorage.setItem(this.storageKey,JSON.stringify({sessionId:this.sessionId,conversationId:this.conversationId}))}catch{}}css(e,n,t){let i=this.settings.bubbleShape==="square",o=i?"14px":"22px",r=i?"8px":"15px",d="5px",a=this.settings.displayMode??"floating",l=a==="side_rail",s=a==="full_screen";return`
|
|
3
3
|
:host { all: initial; }
|
|
4
4
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0;
|
|
5
5
|
font-family: -apple-system, "SF Pro Text", "Segoe UI Variable Text", "Segoe UI", system-ui, "Helvetica Neue", sans-serif;
|
|
@@ -237,6 +237,15 @@
|
|
|
237
237
|
.bb-send .bb-ic { width: 17px; height: 17px; ${n==="rtl"?"transform: scaleX(-1);":""} }
|
|
238
238
|
.bb-send:hover { filter: brightness(1.08); transform: scale(1.06); }
|
|
239
239
|
.bb-send:disabled { opacity: .4; pointer-events: none; }
|
|
240
|
-
`}render(e){let n=this.settings.accentColor||"#6366F1",t=R.has(this.locale)?"rtl":"ltr",i=this.settings.position==="start"?"left":"right",o=t==="rtl"?i==="left"?"right":"left":i,r=this.settings.displayName||"Assistant";this.host=document.createElement("div"),this.host.setAttribute("data-brainerce-bot",this.connectionId),this.root=this.host.attachShadow({mode:"open"});let d=document.createElement("style");d.textContent=this.css(n,t,o),this.root.appendChild(d);let a=document.createElement("div");a.className="bb",this.root.appendChild(a);let l=document.createElement("div");l.className="bb-scrim",l.addEventListener("click",()=>{this.expanded?this.toggleExpand():this.close()}),a.appendChild(l),this.windowEl=document.createElement("div"),this.windowEl.className="bb-window",a.appendChild(this.windowEl);let s=document.createElement("div");s.className="bb-header";let h=document.createElement("span");if(h.className="bb-avatar",this.settings.avatarUrl&&T(this.settings.avatarUrl)){let p=document.createElement("img");p.src=this.settings.avatarUrl,p.alt="",h.appendChild(p)}else h.appendChild(document.createTextNode(r.charAt(0).toUpperCase()));let u=document.createElement("span");u.className="bb-head-main";let g=document.createElement("span");g.className="bb-name",g.textContent=r;let v=document.createElement("span");v.className="bb-status",v.textContent=this.t("online"),u.appendChild(g),u.appendChild(v);let x=document.createElement("span");x.className="bb-actions",(this.settings.displayMode??"floating")!=="full_screen"&&this.settings.allowExpand!==!1&&(this.expandBtn=this.iconButton("expand",this.t("expand"),()=>this.toggleExpand()),x.appendChild(this.expandBtn)),x.appendChild(this.iconButton("mail",this.t("leaveMessage"),()=>this.toggleEscalation())),x.appendChild(this.iconButton("close",this.t("close"),()=>this.close())),s.appendChild(h),s.appendChild(u),s.appendChild(x),this.windowEl.appendChild(s),this.messagesEl=document.createElement("div"),this.messagesEl.className="bb-msgs",this.windowEl.appendChild(this.messagesEl),this.chipsEl=document.createElement("div"),this.chipsEl.className="bb-chips";for(let p of this.settings.starterQuestions??[]){let I=document.createElement("button");I.className="bb-chip",I.textContent=p,I.addEventListener("click",()=>this.send(p)),this.chipsEl.appendChild(I)}this.windowEl.appendChild(this.chipsEl);let c=document.createElement("div");c.className="bb-esc";let E=document.createElement("span");E.className="bb-esc-title",E.textContent=this.t("leaveMessage");let y=document.createElement("input");y.type="email",y.name="email",y.placeholder=this.t("yourEmail");let C=document.createElement("textarea");C.name="message",C.rows=2,C.placeholder=this.t("yourMessage");let k=document.createElement("button");k.type="button",k.className="bb-esc-send",k.textContent=this.t("send"),k.addEventListener("click",()=>this.submitEscalation(c)),c.appendChild(E),c.appendChild(y),c.appendChild(C),c.appendChild(k),this.windowEl.appendChild(c);let m=document.createElement("div");if(m.className="bb-composer",this.inputEl=document.createElement("textarea"),this.inputEl.className="bb-input",this.inputEl.rows=1,this.inputEl.placeholder=this.t("placeholder"),this.inputEl.addEventListener("keydown",p=>{p.key==="Enter"&&!p.shiftKey&&(p.preventDefault(),this.send(this.inputEl?.value??""))}),this.inputEl.addEventListener("input",()=>this.syncSendState()),this.sendBtn=document.createElement("button"),this.sendBtn.className="bb-send",this.sendBtn.disabled=!0,this.sendBtn.setAttribute("aria-label",this.t("send")),this.sendBtn.appendChild(f("send")),this.sendBtn.addEventListener("click",()=>this.send(this.inputEl?.value??"")),m.appendChild(this.inputEl),m.appendChild(this.sendBtn),this.windowEl.appendChild(m),this.launcherEl=document.createElement("button"),this.launcherEl.className="bb-launcher",this.launcherEl.setAttribute("aria-label",r),this.settings.avatarUrl&&T(this.settings.avatarUrl)){let p=document.createElement("img");p.src=this.settings.avatarUrl,p.alt="",this.launcherEl.appendChild(p)}else{let p=f("chat");p.classList.add("bb-l-chat"),this.launcherEl.appendChild(p)}let L=f("close");L.classList.add("bb-l-close"),this.launcherEl.appendChild(L),this.launcherEl.addEventListener("click",()=>this.opened?this.close():this.open()),a.appendChild(this.launcherEl),e.appendChild(this.host)}iconButton(e,n,t){let i=document.createElement("button");return i.className="bb-iconbtn",i.title=n,i.setAttribute("aria-label",n),i.appendChild(f(e)),i.addEventListener("click",t),i}syncSendState(){this.sendBtn&&(this.sendBtn.disabled=!(this.inputEl?.value??"").trim()||this.busy)}open(){if(!this.windowEl||this.opened)return;this.opened=!0;let e=this.root?.querySelector(".bb");e?.classList.add("open");let n=(this.settings.displayMode??"floating")==="full_screen"||window.innerWidth<=520;e?.classList.toggle("big",n||this.expanded),this.messagesEl&&this.messagesEl.childElementCount===0&&this.primeThread(),this.inputEl?.focus()}close(){this.opened=!1;let e=this.root?.querySelector(".bb");e?.classList.remove("open"),this.expanded||e?.classList.remove("big")}toggleExpand(){if(this.expanded=!this.expanded,this.root?.querySelector(".bb")?.classList.toggle("expanded",this.expanded),this.root?.querySelector(".bb")?.classList.toggle("big",this.expanded),this.expandBtn){this.expandBtn.replaceChildren(f(this.expanded?"collapse":"expand"));let e=this.t(this.expanded?"collapse":"expand");this.expandBtn.title=e,this.expandBtn.setAttribute("aria-label",e)}}async primeThread(){if(this.conversationId&&this.sessionId)try{let e=await fetch(`${this.baseUrl}/api/storefront-bot/${encodeURIComponent(this.connectionId)}/conversations/${encodeURIComponent(this.conversationId)}?limit=50`,{headers:{"X-Bot-Session":this.sessionId}});if(e.ok){let n=await e.json();for(let t of n.data){let i=this.appendMessage(t.role==="assistant"?"bot":"user","");B(i,t.content)}if(n.data.length>0){this.chipsEl?.remove();return}}else this.conversationId=null,this.sessionId=null,this.persistIds()}catch{}if(this.settings.greeting){let e=this.appendMessage("bot","");B(e,this.settings.greeting)}}async send(e){let n=e.trim();if(!n||this.busy)return;this.busy=!0,this.inputEl&&(this.inputEl.value=""),this.syncSendState(),this.chipsEl?.remove(),this.appendMessage("user",n);let t=this.appendTyping();this.pendingText="",this.cardsRow=null,this.cardIds=new Set;let i=null;try{let o=await fetch(`${this.baseUrl}/api/storefront-bot/${encodeURIComponent(this.connectionId)}/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({message:n,turnId:O("trn_"),...this.conversationId?{conversationId:this.conversationId}:{},...this.sessionId?{anonymousSessionId:this.sessionId}:{},locale:this.locale})});if(!o.ok||!o.body)throw new Error(`chat failed (${o.status})`);let r=o.body.getReader(),d=new TextDecoder,a="";for(;;){let{value:l,done:s}=await r.read();if(s)break;a+=d.decode(l,{stream:!0});let h;for(;(h=a.indexOf(`
|
|
241
240
|
|
|
242
|
-
|
|
241
|
+
/* Powered-by footer */
|
|
242
|
+
.bb-foot { flex-shrink: 0; display: flex; justify-content: center; align-items: center;
|
|
243
|
+
padding: 5px 12px 7px; background: #fff; }
|
|
244
|
+
.bb-foot a { display: inline-flex; align-items: center; gap: 5px; font-size: 10.5px;
|
|
245
|
+
font-weight: 500; color: #aab0bd; text-decoration: none; letter-spacing: .005em;
|
|
246
|
+
transition: color .12s ease; }
|
|
247
|
+
.bb-foot a:hover { color: #6b7280; }
|
|
248
|
+
.bb-foot .bb-ic { width: 13px; height: 13px; border-radius: 4px; }
|
|
249
|
+
`}render(e){let n=this.settings.accentColor||"#6366F1",t=O.has(this.locale)?"rtl":"ltr",i=this.settings.position==="start"?"left":"right",o=t==="rtl"?i==="left"?"right":"left":i,r=this.settings.displayName||"Assistant";this.host=document.createElement("div"),this.host.setAttribute("data-brainerce-bot",this.connectionId),this.root=this.host.attachShadow({mode:"open"});let d=document.createElement("style");d.textContent=this.css(n,t,o),this.root.appendChild(d);let a=document.createElement("div");a.className="bb",this.root.appendChild(a);let l=document.createElement("div");l.className="bb-scrim",l.addEventListener("click",()=>{this.expanded?this.toggleExpand():this.close()}),a.appendChild(l),this.windowEl=document.createElement("div"),this.windowEl.className="bb-window",a.appendChild(this.windowEl);let s=document.createElement("div");s.className="bb-header";let h=document.createElement("span");if(h.className="bb-avatar",this.settings.avatarUrl&&T(this.settings.avatarUrl)){let p=document.createElement("img");p.src=this.settings.avatarUrl,p.alt="",h.appendChild(p)}else h.appendChild(document.createTextNode(r.charAt(0).toUpperCase()));let u=document.createElement("span");u.className="bb-head-main";let g=document.createElement("span");g.className="bb-name",g.textContent=r;let w=document.createElement("span");w.className="bb-status",w.textContent=this.t("online"),u.appendChild(g),u.appendChild(w);let v=document.createElement("span");v.className="bb-actions",(this.settings.displayMode??"floating")!=="full_screen"&&this.settings.allowExpand!==!1&&(this.expandBtn=this.iconButton("expand",this.t("expand"),()=>this.toggleExpand()),v.appendChild(this.expandBtn)),v.appendChild(this.iconButton("mail",this.t("leaveMessage"),()=>this.toggleEscalation())),v.appendChild(this.iconButton("close",this.t("close"),()=>this.close())),s.appendChild(h),s.appendChild(u),s.appendChild(v),this.windowEl.appendChild(s),this.messagesEl=document.createElement("div"),this.messagesEl.className="bb-msgs",this.windowEl.appendChild(this.messagesEl),this.chipsEl=document.createElement("div"),this.chipsEl.className="bb-chips";for(let p of this.settings.starterQuestions??[]){let N=document.createElement("button");N.className="bb-chip",N.textContent=p,N.addEventListener("click",()=>this.send(p)),this.chipsEl.appendChild(N)}this.windowEl.appendChild(this.chipsEl);let c=document.createElement("div");c.className="bb-esc";let C=document.createElement("span");C.className="bb-esc-title",C.textContent=this.t("leaveMessage");let E=document.createElement("input");E.type="email",E.name="email",E.placeholder=this.t("yourEmail");let k=document.createElement("textarea");k.name="message",k.rows=2,k.placeholder=this.t("yourMessage");let I=document.createElement("button");I.type="button",I.className="bb-esc-send",I.textContent=this.t("send"),I.addEventListener("click",()=>this.submitEscalation(c)),c.appendChild(C),c.appendChild(E),c.appendChild(k),c.appendChild(I),this.windowEl.appendChild(c);let f=document.createElement("div");f.className="bb-composer",this.inputEl=document.createElement("textarea"),this.inputEl.className="bb-input",this.inputEl.rows=1,this.inputEl.placeholder=this.t("placeholder"),this.inputEl.addEventListener("keydown",p=>{p.key==="Enter"&&!p.shiftKey&&(p.preventDefault(),this.send(this.inputEl?.value??""))}),this.inputEl.addEventListener("input",()=>this.syncSendState()),this.sendBtn=document.createElement("button"),this.sendBtn.className="bb-send",this.sendBtn.disabled=!0,this.sendBtn.setAttribute("aria-label",this.t("send")),this.sendBtn.appendChild(m("send")),this.sendBtn.addEventListener("click",()=>this.send(this.inputEl?.value??"")),f.appendChild(this.inputEl),f.appendChild(this.sendBtn),this.windowEl.appendChild(f);let B=document.createElement("div");B.className="bb-foot";let x=document.createElement("a");if(x.href="https://brainerce.com",x.target="_blank",x.rel="noopener noreferrer",x.appendChild(m("brand")),x.appendChild(document.createTextNode(this.t("poweredBy"))),B.appendChild(x),this.windowEl.appendChild(B),this.launcherEl=document.createElement("button"),this.launcherEl.className="bb-launcher",this.launcherEl.setAttribute("aria-label",r),this.settings.avatarUrl&&T(this.settings.avatarUrl)){let p=document.createElement("img");p.src=this.settings.avatarUrl,p.alt="",this.launcherEl.appendChild(p)}else{let p=m("chat");p.classList.add("bb-l-chat"),this.launcherEl.appendChild(p)}let L=m("close");L.classList.add("bb-l-close"),this.launcherEl.appendChild(L),this.launcherEl.addEventListener("click",()=>this.opened?this.close():this.open()),a.appendChild(this.launcherEl),e.appendChild(this.host)}iconButton(e,n,t){let i=document.createElement("button");return i.className="bb-iconbtn",i.title=n,i.setAttribute("aria-label",n),i.appendChild(m(e)),i.addEventListener("click",t),i}syncSendState(){this.sendBtn&&(this.sendBtn.disabled=!(this.inputEl?.value??"").trim()||this.busy)}open(){if(!this.windowEl||this.opened)return;this.opened=!0;let e=this.root?.querySelector(".bb");e?.classList.add("open");let n=(this.settings.displayMode??"floating")==="full_screen"||window.innerWidth<=520;e?.classList.toggle("big",n||this.expanded),this.syncBodyScroll(),this.messagesEl&&this.messagesEl.childElementCount===0&&this.primeThread(),this.inputEl?.focus()}close(){this.opened=!1;let e=this.root?.querySelector(".bb");e?.classList.remove("open"),this.expanded||e?.classList.remove("big"),this.syncBodyScroll()}syncBodyScroll(){let e=this.opened&&!!this.root?.querySelector(".bb")?.classList.contains("big");e&&this.prevBodyOverflow===null?(this.prevBodyOverflow=document.body.style.overflow||"",document.body.style.overflow="hidden"):!e&&this.prevBodyOverflow!==null&&(document.body.style.overflow=this.prevBodyOverflow,this.prevBodyOverflow=null)}toggleExpand(){if(this.expanded=!this.expanded,this.root?.querySelector(".bb")?.classList.toggle("expanded",this.expanded),this.root?.querySelector(".bb")?.classList.toggle("big",this.expanded),this.syncBodyScroll(),this.expandBtn){this.expandBtn.replaceChildren(m(this.expanded?"collapse":"expand"));let e=this.t(this.expanded?"collapse":"expand");this.expandBtn.title=e,this.expandBtn.setAttribute("aria-label",e)}}async primeThread(){if(this.conversationId&&this.sessionId)try{let e=await fetch(`${this.baseUrl}/api/storefront-bot/${encodeURIComponent(this.connectionId)}/conversations/${encodeURIComponent(this.conversationId)}?limit=50`,{headers:{"X-Bot-Session":this.sessionId}});if(e.ok){let n=await e.json();for(let t of n.data){let i=this.appendMessage(t.role==="assistant"?"bot":"user","");U(i,t.content)}if(n.data.length>0){this.chipsEl?.remove();return}}else this.conversationId=null,this.sessionId=null,this.persistIds()}catch{}if(this.settings.greeting){let e=this.appendMessage("bot","");U(e,this.settings.greeting)}}async send(e){let n=e.trim();if(!n||this.busy)return;this.busy=!0,this.inputEl&&(this.inputEl.value=""),this.syncSendState(),this.chipsEl?.remove(),this.appendMessage("user",n);let t=this.appendTyping();this.pendingText="",this.cardsRow=null,this.cardIds=new Set;let i=null;try{let o=await fetch(`${this.baseUrl}/api/storefront-bot/${encodeURIComponent(this.connectionId)}/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({message:n,turnId:P("trn_"),...this.conversationId?{conversationId:this.conversationId}:{},...this.sessionId?{anonymousSessionId:this.sessionId}:{},locale:this.locale})});if(!o.ok||!o.body)throw new Error(`chat failed (${o.status})`);let r=o.body.getReader(),d=new TextDecoder,a="";for(;;){let{value:l,done:s}=await r.read();if(s)break;a+=d.decode(l,{stream:!0});let h;for(;(h=a.indexOf(`
|
|
250
|
+
|
|
251
|
+
`))>=0;){let u=a.slice(0,h);if(a=a.slice(h+2),!u.startsWith("data: "))continue;let g;try{g=JSON.parse(u.slice(6))}catch{continue}i=this.handleFrame(g,t,i)}}i&&this.pendingText&&U(i,this.pendingText)}catch{this.appendMessage("err",this.t("error"))}finally{t.remove(),this.busy=!1,this.syncSendState()}}handleFrame(e,n,t){switch(e.type){case"connected":return this.conversationId=e.conversationId||this.conversationId,this.sessionId=e.anonymousSessionId||this.sessionId,this.persistIds(),t;case"token":return t||(n.remove(),t=this.appendMessage("bot","")),this.pendingText+=e.text,t.textContent=this.pendingText,this.scrollDown(),t;case"tool":return n.classList.toggle("searching",e.status==="running"),t;case"card":return this.appendCard(e.card),t;case"action":return this.handleAction(e),t;case"error":return this.appendMessage("err",e.message||this.t("error")),t;case"done":default:return t}}appendCard(e){if(!this.messagesEl||this.cardIds.has(e.productId))return;if(this.cardIds.add(e.productId),!this.cardsRow){let s=document.createElement("div");s.className="bb-shelf";let h=document.createElement("div");h.className="bb-shelf-cap",h.textContent=this.t("results"),this.cardsRow=document.createElement("div"),this.cardsRow.className="bb-cards",s.appendChild(h),s.appendChild(this.cardsRow),this.messagesEl.appendChild(s)}let n=T(e.url)?e.url:null,t=document.createElement("div");t.className="bb-card";let i=()=>{this.beacon(e.botRef),n&&(window.location.href=n)},o=document.createElement("span");if(o.className="bb-card-img",e.imageUrl&&T(e.imageUrl)){let s=document.createElement("img");s.src=e.imageUrl,s.alt="",s.loading="lazy",o.appendChild(s)}else o.appendChild(m("cart"));o.addEventListener("click",i),t.appendChild(o);let r=document.createElement("span");r.className="bb-card-body";let d=document.createElement("span");d.className="bb-card-title",d.textContent=e.title,d.addEventListener("click",i);let a=document.createElement("span");a.className="bb-card-price",a.textContent=e.price.formatted,r.appendChild(d),r.appendChild(a);let l=document.createElement("span");if(l.className="bb-card-cta",e.requiresOptions){let s=document.createElement("button");s.className="bb-btn bb-btn-add",s.setAttribute("aria-label",this.t("addToCart")),s.appendChild(m("cart")),e.variants?.length?s.addEventListener("click",()=>this.togglePicker(r,e,o)):s.addEventListener("click",i),l.appendChild(s)}else{let s=document.createElement("button");s.className="bb-btn bb-btn-add",s.appendChild(m("cart")),s.appendChild(document.createTextNode(this.t("addToCart"))),s.addEventListener("click",()=>void this.addToCart(e,s));let h=document.createElement("button");h.className="bb-btn bb-btn-ghost",h.appendChild(document.createTextNode(this.t("view"))),h.addEventListener("click",i),l.appendChild(s),l.appendChild(h)}r.appendChild(l),t.appendChild(r),this.cardsRow.appendChild(t),this.scrollDown()}togglePicker(e,n,t){let i=e.parentElement,o=e.querySelector(".bb-pick");if(o){o.remove(),i?.classList.remove("picking");return}i?.classList.add("picking");let r=n.variants??[],d=[];for(let u of r)for(let g of Object.keys(u.attributes))d.includes(g)||d.push(g);let a={},l=document.createElement("span");l.className="bb-pick";let s=()=>r.find(u=>d.every(g=>a[g]&&u.attributes[g]===a[g]))??null,h=()=>{l.replaceChildren();for(let c of d){let C=document.createElement("span");C.className="bb-pick-key",C.textContent=c;let E=document.createElement("span");E.className="bb-pick-vals";let k=new Set;for(let I of r){let f=I.attributes[c];if(!f||k.has(f))continue;k.add(f);let B=r.some(L=>L.attributes[c]===f&&d.every(p=>p===c||!a[p]||L.attributes[p]===a[p])),x=document.createElement("button");x.className=`bb-chipv${a[c]===f?" sel":""}${B?"":" off"}`,x.textContent=f,x.addEventListener("click",()=>{a[c]===f?delete a[c]:a[c]=f,h()}),E.appendChild(x)}l.appendChild(C),l.appendChild(E)}let u=document.createElement("button");u.className="bb-pick-close",u.setAttribute("aria-label",this.t("close")),u.appendChild(m("close")),u.addEventListener("click",()=>{l.remove(),i?.classList.remove("picking")}),l.appendChild(u);let g=s(),w=document.createElement("span");w.className="bb-pick-foot";let v=document.createElement("span");v.className="bb-pick-price",v.textContent=g?g.price.formatted:"";let y=document.createElement("button");if(y.className="bb-btn bb-btn-add",y.appendChild(m("cart")),y.appendChild(document.createTextNode(this.t("addToCart"))),g||(y.disabled=!0),y.addEventListener("click",()=>{let c=s();c&&this.addToCart(n,y,c.id)}),w.appendChild(v),w.appendChild(y),l.appendChild(w),g?.imageUrl&&T(g.imageUrl)){let c=t.querySelector("img");c&&(c.src=g.imageUrl)}this.scrollDown()};h(),e.appendChild(l),this.scrollDown()}async addToCart(e,n,t){this.beacon(e.botRef),n.dataset.state="busy",await this.dispatchAdd(e.productId,t??null)?(n.dataset.state="done",n.replaceChildren(m("check"),document.createTextNode(this.t("added"))),setTimeout(()=>{!this.destroyed&&n.isConnected&&(delete n.dataset.state,n.replaceChildren(m("cart"),document.createTextNode(this.t("addToCart"))))},2200)):(delete n.dataset.state,T(e.url)&&(window.location.href=e.url))}async dispatchAdd(e,n){try{if(this.onAddToCart)return await this.onAddToCart({productId:e,variantId:n,quantity:1})!==!1;let t=new CustomEvent("brainerce:bot:add-to-cart",{detail:{productId:e,variantId:n,quantity:1,connectionId:this.connectionId},cancelable:!0,bubbles:!0,composed:!0});return!window.dispatchEvent(t)}catch{return!1}}async handleAction(e){if(e.action!=="add_to_cart")return;e.botRef&&this.beacon(e.botRef),await this.dispatchAdd(e.productId,e.variantId)||this.appendMessage("err",this.t("addFailed"))}beacon(e){try{navigator.sendBeacon?.(`${this.baseUrl}/api/storefront-bot/attribution/click`,new Blob([JSON.stringify({botRef:e})],{type:"application/json"}))}catch{}}toggleEscalation(){this.root?.querySelector(".bb-esc")?.classList.toggle("open")}async submitEscalation(e){let n=e.querySelector('input[name="email"]')?.value.trim(),t=e.querySelector('textarea[name="message"]')?.value.trim();if(!(!n||!t||!this.conversationId||!this.sessionId))try{if((await fetch(`${this.baseUrl}/api/storefront-bot/${encodeURIComponent(this.connectionId)}/escalate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:n,message:t,conversationId:this.conversationId,anonymousSessionId:this.sessionId,locale:this.locale})})).ok){let o=document.createElement("span");o.className="bb-esc-note",o.appendChild(m("check")),o.appendChild(document.createTextNode(this.t("sent"))),e.replaceChildren(o)}}catch{}}appendMessage(e,n){let t=document.createElement("div");return t.className=`bb-msg ${e}`,t.setAttribute("dir","auto"),t.textContent=n,this.messagesEl?.appendChild(t),this.scrollDown(),t}appendTyping(){let e=document.createElement("div");e.className="bb-typing";let n=document.createElement("span");n.className="bb-dots";for(let i=0;i<3;i++)n.appendChild(document.createElement("i"));let t=document.createElement("span");return t.className="bb-tool",t.textContent=this.t("searching"),e.appendChild(n),e.appendChild(t),this.messagesEl?.appendChild(e),this.scrollDown(),e}scrollDown(){this.messagesEl&&(this.messagesEl.scrollTop=this.messagesEl.scrollHeight)}};(()=>{let b=document.currentScript,e=b?.dataset.connectionId;if(!e){console.warn("[BrainerceBot] missing data-connection-id on the bot.js script tag");return}let n=b?.dataset.apiBase||void 0,t=()=>void M.mount({connectionId:e,baseUrl:n});document.readyState==="loading"?document.addEventListener("DOMContentLoaded",t,{once:!0}):t()})();})();
|
package/dist/bot/index.d.mts
CHANGED
|
@@ -74,6 +74,12 @@ declare class BrainerceBot {
|
|
|
74
74
|
private syncSendState;
|
|
75
75
|
private open;
|
|
76
76
|
private close;
|
|
77
|
+
/**
|
|
78
|
+
* The large dialog owns the screen — the page behind must not scroll.
|
|
79
|
+
* Locks <body> while a big surface is open; restores on close/collapse.
|
|
80
|
+
*/
|
|
81
|
+
private prevBodyOverflow;
|
|
82
|
+
private syncBodyScroll;
|
|
77
83
|
private toggleExpand;
|
|
78
84
|
/** First open: restore the server thread, or show the greeting. */
|
|
79
85
|
private primeThread;
|
|
@@ -93,6 +99,14 @@ declare class BrainerceBot {
|
|
|
93
99
|
* 3. fallback: navigate to the product page
|
|
94
100
|
*/
|
|
95
101
|
private addToCart;
|
|
102
|
+
/**
|
|
103
|
+
* The host-cart chain shared by card buttons and bot-initiated actions:
|
|
104
|
+
* onAddToCart option -> cancelable CustomEvent. Returns whether a host
|
|
105
|
+
* took the add.
|
|
106
|
+
*/
|
|
107
|
+
private dispatchAdd;
|
|
108
|
+
/** Bot-initiated widget actions (the model called the addToCart tool). */
|
|
109
|
+
private handleAction;
|
|
96
110
|
/** The durable conversion signal — fire-and-forget, never blocks. */
|
|
97
111
|
private beacon;
|
|
98
112
|
private toggleEscalation;
|
package/dist/bot/index.d.ts
CHANGED
|
@@ -74,6 +74,12 @@ declare class BrainerceBot {
|
|
|
74
74
|
private syncSendState;
|
|
75
75
|
private open;
|
|
76
76
|
private close;
|
|
77
|
+
/**
|
|
78
|
+
* The large dialog owns the screen — the page behind must not scroll.
|
|
79
|
+
* Locks <body> while a big surface is open; restores on close/collapse.
|
|
80
|
+
*/
|
|
81
|
+
private prevBodyOverflow;
|
|
82
|
+
private syncBodyScroll;
|
|
77
83
|
private toggleExpand;
|
|
78
84
|
/** First open: restore the server thread, or show the greeting. */
|
|
79
85
|
private primeThread;
|
|
@@ -93,6 +99,14 @@ declare class BrainerceBot {
|
|
|
93
99
|
* 3. fallback: navigate to the product page
|
|
94
100
|
*/
|
|
95
101
|
private addToCart;
|
|
102
|
+
/**
|
|
103
|
+
* The host-cart chain shared by card buttons and bot-initiated actions:
|
|
104
|
+
* onAddToCart option -> cancelable CustomEvent. Returns whether a host
|
|
105
|
+
* took the add.
|
|
106
|
+
*/
|
|
107
|
+
private dispatchAdd;
|
|
108
|
+
/** Bot-initiated widget actions (the model called the addToCart tool). */
|
|
109
|
+
private handleAction;
|
|
96
110
|
/** The durable conversion signal — fire-and-forget, never blocks. */
|
|
97
111
|
private beacon;
|
|
98
112
|
private toggleEscalation;
|
package/dist/bot/index.js
CHANGED
|
@@ -45,7 +45,9 @@ var CHROME = {
|
|
|
45
45
|
added: "Added",
|
|
46
46
|
view: "View",
|
|
47
47
|
chooseOptions: "View product",
|
|
48
|
-
results: "From the store"
|
|
48
|
+
results: "From the store",
|
|
49
|
+
poweredBy: "Powered by Brainerce",
|
|
50
|
+
addFailed: "I couldn\u2019t add that to the cart \u2014 try the button on the product card."
|
|
49
51
|
},
|
|
50
52
|
he: {
|
|
51
53
|
online: "\u05DE\u05D7\u05D5\u05D1\u05E8",
|
|
@@ -64,7 +66,9 @@ var CHROME = {
|
|
|
64
66
|
added: "\u05E0\u05D5\u05E1\u05E3",
|
|
65
67
|
view: "\u05E6\u05E4\u05D9\u05D9\u05D4",
|
|
66
68
|
chooseOptions: "\u05DC\u05E6\u05E4\u05D5\u05EA \u05D1\u05DE\u05D5\u05E6\u05E8",
|
|
67
|
-
results: "\u05DE\u05EA\u05D5\u05DA \u05D4\u05D7\u05E0\u05D5\u05EA"
|
|
69
|
+
results: "\u05DE\u05EA\u05D5\u05DA \u05D4\u05D7\u05E0\u05D5\u05EA",
|
|
70
|
+
poweredBy: "\u05DE\u05D5\u05E4\u05E2\u05DC \u05E2\u05DC \u05D9\u05D3\u05D9 Brainerce",
|
|
71
|
+
addFailed: "\u05DC\u05D0 \u05D4\u05E6\u05DC\u05D7\u05EA\u05D9 \u05DC\u05D4\u05D5\u05E1\u05D9\u05E3 \u05DC\u05E1\u05DC \u2014 \u05E0\u05E1\u05D5 \u05D3\u05E8\u05DA \u05D4\u05DB\u05E4\u05EA\u05D5\u05E8 \u05D1\u05DB\u05E8\u05D8\u05D9\u05E1 \u05D4\u05DE\u05D5\u05E6\u05E8."
|
|
68
72
|
}
|
|
69
73
|
};
|
|
70
74
|
var ICONS = {
|
|
@@ -76,7 +80,10 @@ var ICONS = {
|
|
|
76
80
|
send: '<svg viewBox="0 0 24 24" fill="none"><path d="M4.4 11.2 19 4.6c.7-.3 1.4.4 1.1 1.1l-6.6 14.6c-.3.7-1.3.6-1.5-.1l-1.7-5.4a1 1 0 0 0-.6-.6l-5.4-1.7c-.7-.2-.8-1.2-.1-1.5Z" fill="currentColor"/></svg>',
|
|
77
81
|
cart: '<svg viewBox="0 0 24 24" fill="none"><path d="M3 4h2l2.4 11.2A2 2 0 0 0 9.36 17H17.5a2 2 0 0 0 1.95-1.55L21 8H6" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/><circle cx="10" cy="20.5" r="1.4" fill="currentColor"/><circle cx="17" cy="20.5" r="1.4" fill="currentColor"/></svg>',
|
|
78
82
|
check: '<svg viewBox="0 0 24 24" fill="none"><path d="m5 12.5 4.5 4.5L19 7.5" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg>',
|
|
79
|
-
arrow: '<svg viewBox="0 0 24 24" fill="none"><path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>'
|
|
83
|
+
arrow: '<svg viewBox="0 0 24 24" fill="none"><path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>',
|
|
84
|
+
// Brainerce brand mark for the Powered-by footer: the gradient "B"
|
|
85
|
+
// (emerald→violet), matching the dashboard BrandedLoader identity.
|
|
86
|
+
brand: '<svg viewBox="0 0 24 24"><defs><linearGradient id="bb-brand-g" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#34d399"/><stop offset="1" stop-color="#8b5cf6"/></linearGradient></defs><rect x="1.5" y="1.5" width="21" height="21" rx="6" fill="url(#bb-brand-g)"/><text x="12" y="17" text-anchor="middle" font-family="ui-sans-serif,system-ui,sans-serif" font-size="14" font-weight="700" fill="#fff">B</text></svg>'
|
|
80
87
|
};
|
|
81
88
|
var svgParser = typeof DOMParser !== "undefined" ? new DOMParser() : null;
|
|
82
89
|
function icon(name) {
|
|
@@ -170,6 +177,11 @@ var BrainerceBot = class _BrainerceBot {
|
|
|
170
177
|
this.pendingText = "";
|
|
171
178
|
this.cardsRow = null;
|
|
172
179
|
this.cardIds = /* @__PURE__ */ new Set();
|
|
180
|
+
/**
|
|
181
|
+
* The large dialog owns the screen — the page behind must not scroll.
|
|
182
|
+
* Locks <body> while a big surface is open; restores on close/collapse.
|
|
183
|
+
*/
|
|
184
|
+
this.prevBodyOverflow = null;
|
|
173
185
|
this.connectionId = options.connectionId;
|
|
174
186
|
this.baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
175
187
|
this.storageKey = `brainerce-bot:${this.connectionId}`;
|
|
@@ -187,6 +199,10 @@ var BrainerceBot = class _BrainerceBot {
|
|
|
187
199
|
}
|
|
188
200
|
destroy() {
|
|
189
201
|
this.destroyed = true;
|
|
202
|
+
if (this.prevBodyOverflow !== null) {
|
|
203
|
+
document.body.style.overflow = this.prevBodyOverflow;
|
|
204
|
+
this.prevBodyOverflow = null;
|
|
205
|
+
}
|
|
190
206
|
this.host?.remove();
|
|
191
207
|
}
|
|
192
208
|
// ---------------------------------------------------------------------------
|
|
@@ -481,6 +497,15 @@ var BrainerceBot = class _BrainerceBot {
|
|
|
481
497
|
.bb-send .bb-ic { width: 17px; height: 17px; ${dir === "rtl" ? "transform: scaleX(-1);" : ""} }
|
|
482
498
|
.bb-send:hover { filter: brightness(1.08); transform: scale(1.06); }
|
|
483
499
|
.bb-send:disabled { opacity: .4; pointer-events: none; }
|
|
500
|
+
|
|
501
|
+
/* Powered-by footer */
|
|
502
|
+
.bb-foot { flex-shrink: 0; display: flex; justify-content: center; align-items: center;
|
|
503
|
+
padding: 5px 12px 7px; background: #fff; }
|
|
504
|
+
.bb-foot a { display: inline-flex; align-items: center; gap: 5px; font-size: 10.5px;
|
|
505
|
+
font-weight: 500; color: #aab0bd; text-decoration: none; letter-spacing: .005em;
|
|
506
|
+
transition: color .12s ease; }
|
|
507
|
+
.bb-foot a:hover { color: #6b7280; }
|
|
508
|
+
.bb-foot .bb-ic { width: 13px; height: 13px; border-radius: 4px; }
|
|
484
509
|
`;
|
|
485
510
|
}
|
|
486
511
|
render(target) {
|
|
@@ -601,6 +626,16 @@ var BrainerceBot = class _BrainerceBot {
|
|
|
601
626
|
composer.appendChild(this.inputEl);
|
|
602
627
|
composer.appendChild(this.sendBtn);
|
|
603
628
|
this.windowEl.appendChild(composer);
|
|
629
|
+
const foot = document.createElement("div");
|
|
630
|
+
foot.className = "bb-foot";
|
|
631
|
+
const credit = document.createElement("a");
|
|
632
|
+
credit.href = "https://brainerce.com";
|
|
633
|
+
credit.target = "_blank";
|
|
634
|
+
credit.rel = "noopener noreferrer";
|
|
635
|
+
credit.appendChild(icon("brand"));
|
|
636
|
+
credit.appendChild(document.createTextNode(this.t("poweredBy")));
|
|
637
|
+
foot.appendChild(credit);
|
|
638
|
+
this.windowEl.appendChild(foot);
|
|
604
639
|
this.launcherEl = document.createElement("button");
|
|
605
640
|
this.launcherEl.className = "bb-launcher";
|
|
606
641
|
this.launcherEl.setAttribute("aria-label", name);
|
|
@@ -640,6 +675,7 @@ var BrainerceBot = class _BrainerceBot {
|
|
|
640
675
|
el?.classList.add("open");
|
|
641
676
|
const takeover = (this.settings.displayMode ?? "floating") === "full_screen" || window.innerWidth <= 520;
|
|
642
677
|
el?.classList.toggle("big", takeover || this.expanded);
|
|
678
|
+
this.syncBodyScroll();
|
|
643
679
|
if (this.messagesEl && this.messagesEl.childElementCount === 0) {
|
|
644
680
|
void this.primeThread();
|
|
645
681
|
}
|
|
@@ -650,11 +686,23 @@ var BrainerceBot = class _BrainerceBot {
|
|
|
650
686
|
const el = this.root?.querySelector(".bb");
|
|
651
687
|
el?.classList.remove("open");
|
|
652
688
|
if (!this.expanded) el?.classList.remove("big");
|
|
689
|
+
this.syncBodyScroll();
|
|
690
|
+
}
|
|
691
|
+
syncBodyScroll() {
|
|
692
|
+
const big = this.opened && !!this.root?.querySelector(".bb")?.classList.contains("big");
|
|
693
|
+
if (big && this.prevBodyOverflow === null) {
|
|
694
|
+
this.prevBodyOverflow = document.body.style.overflow || "";
|
|
695
|
+
document.body.style.overflow = "hidden";
|
|
696
|
+
} else if (!big && this.prevBodyOverflow !== null) {
|
|
697
|
+
document.body.style.overflow = this.prevBodyOverflow;
|
|
698
|
+
this.prevBodyOverflow = null;
|
|
699
|
+
}
|
|
653
700
|
}
|
|
654
701
|
toggleExpand() {
|
|
655
702
|
this.expanded = !this.expanded;
|
|
656
703
|
this.root?.querySelector(".bb")?.classList.toggle("expanded", this.expanded);
|
|
657
704
|
this.root?.querySelector(".bb")?.classList.toggle("big", this.expanded);
|
|
705
|
+
this.syncBodyScroll();
|
|
658
706
|
if (this.expandBtn) {
|
|
659
707
|
this.expandBtn.replaceChildren(icon(this.expanded ? "collapse" : "expand"));
|
|
660
708
|
const label = this.t(this.expanded ? "collapse" : "expand");
|
|
@@ -780,6 +828,9 @@ var BrainerceBot = class _BrainerceBot {
|
|
|
780
828
|
case "card":
|
|
781
829
|
this.appendCard(frame.card);
|
|
782
830
|
return botBubble;
|
|
831
|
+
case "action":
|
|
832
|
+
void this.handleAction(frame);
|
|
833
|
+
return botBubble;
|
|
783
834
|
case "error":
|
|
784
835
|
this.appendMessage("err", frame.message || this.t("error"));
|
|
785
836
|
return botBubble;
|
|
@@ -967,31 +1018,7 @@ var BrainerceBot = class _BrainerceBot {
|
|
|
967
1018
|
async addToCart(card, btn, variantId) {
|
|
968
1019
|
this.beacon(card.botRef);
|
|
969
1020
|
btn.dataset.state = "busy";
|
|
970
|
-
|
|
971
|
-
try {
|
|
972
|
-
if (this.onAddToCart) {
|
|
973
|
-
handled = await this.onAddToCart({
|
|
974
|
-
productId: card.productId,
|
|
975
|
-
variantId: variantId ?? null,
|
|
976
|
-
quantity: 1
|
|
977
|
-
}) !== false;
|
|
978
|
-
} else {
|
|
979
|
-
const ev = new CustomEvent("brainerce:bot:add-to-cart", {
|
|
980
|
-
detail: {
|
|
981
|
-
productId: card.productId,
|
|
982
|
-
variantId: variantId ?? null,
|
|
983
|
-
quantity: 1,
|
|
984
|
-
connectionId: this.connectionId
|
|
985
|
-
},
|
|
986
|
-
cancelable: true,
|
|
987
|
-
bubbles: true,
|
|
988
|
-
composed: true
|
|
989
|
-
});
|
|
990
|
-
handled = !window.dispatchEvent(ev);
|
|
991
|
-
}
|
|
992
|
-
} catch {
|
|
993
|
-
handled = false;
|
|
994
|
-
}
|
|
1021
|
+
const handled = await this.dispatchAdd(card.productId, variantId ?? null);
|
|
995
1022
|
if (handled) {
|
|
996
1023
|
btn.dataset.state = "done";
|
|
997
1024
|
btn.replaceChildren(icon("check"), document.createTextNode(this.t("added")));
|
|
@@ -1006,6 +1033,34 @@ var BrainerceBot = class _BrainerceBot {
|
|
|
1006
1033
|
if (isSafeUrl(card.url)) window.location.href = card.url;
|
|
1007
1034
|
}
|
|
1008
1035
|
}
|
|
1036
|
+
/**
|
|
1037
|
+
* The host-cart chain shared by card buttons and bot-initiated actions:
|
|
1038
|
+
* onAddToCart option -> cancelable CustomEvent. Returns whether a host
|
|
1039
|
+
* took the add.
|
|
1040
|
+
*/
|
|
1041
|
+
async dispatchAdd(productId, variantId) {
|
|
1042
|
+
try {
|
|
1043
|
+
if (this.onAddToCart) {
|
|
1044
|
+
return await this.onAddToCart({ productId, variantId, quantity: 1 }) !== false;
|
|
1045
|
+
}
|
|
1046
|
+
const ev = new CustomEvent("brainerce:bot:add-to-cart", {
|
|
1047
|
+
detail: { productId, variantId, quantity: 1, connectionId: this.connectionId },
|
|
1048
|
+
cancelable: true,
|
|
1049
|
+
bubbles: true,
|
|
1050
|
+
composed: true
|
|
1051
|
+
});
|
|
1052
|
+
return !window.dispatchEvent(ev);
|
|
1053
|
+
} catch {
|
|
1054
|
+
return false;
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
/** Bot-initiated widget actions (the model called the addToCart tool). */
|
|
1058
|
+
async handleAction(frame) {
|
|
1059
|
+
if (frame.action !== "add_to_cart") return;
|
|
1060
|
+
if (frame.botRef) this.beacon(frame.botRef);
|
|
1061
|
+
const ok = await this.dispatchAdd(frame.productId, frame.variantId);
|
|
1062
|
+
if (!ok) this.appendMessage("err", this.t("addFailed"));
|
|
1063
|
+
}
|
|
1009
1064
|
/** The durable conversion signal — fire-and-forget, never blocks. */
|
|
1010
1065
|
beacon(botRef) {
|
|
1011
1066
|
try {
|
package/dist/bot/index.mjs
CHANGED
|
@@ -19,7 +19,9 @@ var CHROME = {
|
|
|
19
19
|
added: "Added",
|
|
20
20
|
view: "View",
|
|
21
21
|
chooseOptions: "View product",
|
|
22
|
-
results: "From the store"
|
|
22
|
+
results: "From the store",
|
|
23
|
+
poweredBy: "Powered by Brainerce",
|
|
24
|
+
addFailed: "I couldn\u2019t add that to the cart \u2014 try the button on the product card."
|
|
23
25
|
},
|
|
24
26
|
he: {
|
|
25
27
|
online: "\u05DE\u05D7\u05D5\u05D1\u05E8",
|
|
@@ -38,7 +40,9 @@ var CHROME = {
|
|
|
38
40
|
added: "\u05E0\u05D5\u05E1\u05E3",
|
|
39
41
|
view: "\u05E6\u05E4\u05D9\u05D9\u05D4",
|
|
40
42
|
chooseOptions: "\u05DC\u05E6\u05E4\u05D5\u05EA \u05D1\u05DE\u05D5\u05E6\u05E8",
|
|
41
|
-
results: "\u05DE\u05EA\u05D5\u05DA \u05D4\u05D7\u05E0\u05D5\u05EA"
|
|
43
|
+
results: "\u05DE\u05EA\u05D5\u05DA \u05D4\u05D7\u05E0\u05D5\u05EA",
|
|
44
|
+
poweredBy: "\u05DE\u05D5\u05E4\u05E2\u05DC \u05E2\u05DC \u05D9\u05D3\u05D9 Brainerce",
|
|
45
|
+
addFailed: "\u05DC\u05D0 \u05D4\u05E6\u05DC\u05D7\u05EA\u05D9 \u05DC\u05D4\u05D5\u05E1\u05D9\u05E3 \u05DC\u05E1\u05DC \u2014 \u05E0\u05E1\u05D5 \u05D3\u05E8\u05DA \u05D4\u05DB\u05E4\u05EA\u05D5\u05E8 \u05D1\u05DB\u05E8\u05D8\u05D9\u05E1 \u05D4\u05DE\u05D5\u05E6\u05E8."
|
|
42
46
|
}
|
|
43
47
|
};
|
|
44
48
|
var ICONS = {
|
|
@@ -50,7 +54,10 @@ var ICONS = {
|
|
|
50
54
|
send: '<svg viewBox="0 0 24 24" fill="none"><path d="M4.4 11.2 19 4.6c.7-.3 1.4.4 1.1 1.1l-6.6 14.6c-.3.7-1.3.6-1.5-.1l-1.7-5.4a1 1 0 0 0-.6-.6l-5.4-1.7c-.7-.2-.8-1.2-.1-1.5Z" fill="currentColor"/></svg>',
|
|
51
55
|
cart: '<svg viewBox="0 0 24 24" fill="none"><path d="M3 4h2l2.4 11.2A2 2 0 0 0 9.36 17H17.5a2 2 0 0 0 1.95-1.55L21 8H6" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/><circle cx="10" cy="20.5" r="1.4" fill="currentColor"/><circle cx="17" cy="20.5" r="1.4" fill="currentColor"/></svg>',
|
|
52
56
|
check: '<svg viewBox="0 0 24 24" fill="none"><path d="m5 12.5 4.5 4.5L19 7.5" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg>',
|
|
53
|
-
arrow: '<svg viewBox="0 0 24 24" fill="none"><path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>'
|
|
57
|
+
arrow: '<svg viewBox="0 0 24 24" fill="none"><path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>',
|
|
58
|
+
// Brainerce brand mark for the Powered-by footer: the gradient "B"
|
|
59
|
+
// (emerald→violet), matching the dashboard BrandedLoader identity.
|
|
60
|
+
brand: '<svg viewBox="0 0 24 24"><defs><linearGradient id="bb-brand-g" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#34d399"/><stop offset="1" stop-color="#8b5cf6"/></linearGradient></defs><rect x="1.5" y="1.5" width="21" height="21" rx="6" fill="url(#bb-brand-g)"/><text x="12" y="17" text-anchor="middle" font-family="ui-sans-serif,system-ui,sans-serif" font-size="14" font-weight="700" fill="#fff">B</text></svg>'
|
|
54
61
|
};
|
|
55
62
|
var svgParser = typeof DOMParser !== "undefined" ? new DOMParser() : null;
|
|
56
63
|
function icon(name) {
|
|
@@ -144,6 +151,11 @@ var BrainerceBot = class _BrainerceBot {
|
|
|
144
151
|
this.pendingText = "";
|
|
145
152
|
this.cardsRow = null;
|
|
146
153
|
this.cardIds = /* @__PURE__ */ new Set();
|
|
154
|
+
/**
|
|
155
|
+
* The large dialog owns the screen — the page behind must not scroll.
|
|
156
|
+
* Locks <body> while a big surface is open; restores on close/collapse.
|
|
157
|
+
*/
|
|
158
|
+
this.prevBodyOverflow = null;
|
|
147
159
|
this.connectionId = options.connectionId;
|
|
148
160
|
this.baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
149
161
|
this.storageKey = `brainerce-bot:${this.connectionId}`;
|
|
@@ -161,6 +173,10 @@ var BrainerceBot = class _BrainerceBot {
|
|
|
161
173
|
}
|
|
162
174
|
destroy() {
|
|
163
175
|
this.destroyed = true;
|
|
176
|
+
if (this.prevBodyOverflow !== null) {
|
|
177
|
+
document.body.style.overflow = this.prevBodyOverflow;
|
|
178
|
+
this.prevBodyOverflow = null;
|
|
179
|
+
}
|
|
164
180
|
this.host?.remove();
|
|
165
181
|
}
|
|
166
182
|
// ---------------------------------------------------------------------------
|
|
@@ -455,6 +471,15 @@ var BrainerceBot = class _BrainerceBot {
|
|
|
455
471
|
.bb-send .bb-ic { width: 17px; height: 17px; ${dir === "rtl" ? "transform: scaleX(-1);" : ""} }
|
|
456
472
|
.bb-send:hover { filter: brightness(1.08); transform: scale(1.06); }
|
|
457
473
|
.bb-send:disabled { opacity: .4; pointer-events: none; }
|
|
474
|
+
|
|
475
|
+
/* Powered-by footer */
|
|
476
|
+
.bb-foot { flex-shrink: 0; display: flex; justify-content: center; align-items: center;
|
|
477
|
+
padding: 5px 12px 7px; background: #fff; }
|
|
478
|
+
.bb-foot a { display: inline-flex; align-items: center; gap: 5px; font-size: 10.5px;
|
|
479
|
+
font-weight: 500; color: #aab0bd; text-decoration: none; letter-spacing: .005em;
|
|
480
|
+
transition: color .12s ease; }
|
|
481
|
+
.bb-foot a:hover { color: #6b7280; }
|
|
482
|
+
.bb-foot .bb-ic { width: 13px; height: 13px; border-radius: 4px; }
|
|
458
483
|
`;
|
|
459
484
|
}
|
|
460
485
|
render(target) {
|
|
@@ -575,6 +600,16 @@ var BrainerceBot = class _BrainerceBot {
|
|
|
575
600
|
composer.appendChild(this.inputEl);
|
|
576
601
|
composer.appendChild(this.sendBtn);
|
|
577
602
|
this.windowEl.appendChild(composer);
|
|
603
|
+
const foot = document.createElement("div");
|
|
604
|
+
foot.className = "bb-foot";
|
|
605
|
+
const credit = document.createElement("a");
|
|
606
|
+
credit.href = "https://brainerce.com";
|
|
607
|
+
credit.target = "_blank";
|
|
608
|
+
credit.rel = "noopener noreferrer";
|
|
609
|
+
credit.appendChild(icon("brand"));
|
|
610
|
+
credit.appendChild(document.createTextNode(this.t("poweredBy")));
|
|
611
|
+
foot.appendChild(credit);
|
|
612
|
+
this.windowEl.appendChild(foot);
|
|
578
613
|
this.launcherEl = document.createElement("button");
|
|
579
614
|
this.launcherEl.className = "bb-launcher";
|
|
580
615
|
this.launcherEl.setAttribute("aria-label", name);
|
|
@@ -614,6 +649,7 @@ var BrainerceBot = class _BrainerceBot {
|
|
|
614
649
|
el?.classList.add("open");
|
|
615
650
|
const takeover = (this.settings.displayMode ?? "floating") === "full_screen" || window.innerWidth <= 520;
|
|
616
651
|
el?.classList.toggle("big", takeover || this.expanded);
|
|
652
|
+
this.syncBodyScroll();
|
|
617
653
|
if (this.messagesEl && this.messagesEl.childElementCount === 0) {
|
|
618
654
|
void this.primeThread();
|
|
619
655
|
}
|
|
@@ -624,11 +660,23 @@ var BrainerceBot = class _BrainerceBot {
|
|
|
624
660
|
const el = this.root?.querySelector(".bb");
|
|
625
661
|
el?.classList.remove("open");
|
|
626
662
|
if (!this.expanded) el?.classList.remove("big");
|
|
663
|
+
this.syncBodyScroll();
|
|
664
|
+
}
|
|
665
|
+
syncBodyScroll() {
|
|
666
|
+
const big = this.opened && !!this.root?.querySelector(".bb")?.classList.contains("big");
|
|
667
|
+
if (big && this.prevBodyOverflow === null) {
|
|
668
|
+
this.prevBodyOverflow = document.body.style.overflow || "";
|
|
669
|
+
document.body.style.overflow = "hidden";
|
|
670
|
+
} else if (!big && this.prevBodyOverflow !== null) {
|
|
671
|
+
document.body.style.overflow = this.prevBodyOverflow;
|
|
672
|
+
this.prevBodyOverflow = null;
|
|
673
|
+
}
|
|
627
674
|
}
|
|
628
675
|
toggleExpand() {
|
|
629
676
|
this.expanded = !this.expanded;
|
|
630
677
|
this.root?.querySelector(".bb")?.classList.toggle("expanded", this.expanded);
|
|
631
678
|
this.root?.querySelector(".bb")?.classList.toggle("big", this.expanded);
|
|
679
|
+
this.syncBodyScroll();
|
|
632
680
|
if (this.expandBtn) {
|
|
633
681
|
this.expandBtn.replaceChildren(icon(this.expanded ? "collapse" : "expand"));
|
|
634
682
|
const label = this.t(this.expanded ? "collapse" : "expand");
|
|
@@ -754,6 +802,9 @@ var BrainerceBot = class _BrainerceBot {
|
|
|
754
802
|
case "card":
|
|
755
803
|
this.appendCard(frame.card);
|
|
756
804
|
return botBubble;
|
|
805
|
+
case "action":
|
|
806
|
+
void this.handleAction(frame);
|
|
807
|
+
return botBubble;
|
|
757
808
|
case "error":
|
|
758
809
|
this.appendMessage("err", frame.message || this.t("error"));
|
|
759
810
|
return botBubble;
|
|
@@ -941,31 +992,7 @@ var BrainerceBot = class _BrainerceBot {
|
|
|
941
992
|
async addToCart(card, btn, variantId) {
|
|
942
993
|
this.beacon(card.botRef);
|
|
943
994
|
btn.dataset.state = "busy";
|
|
944
|
-
|
|
945
|
-
try {
|
|
946
|
-
if (this.onAddToCart) {
|
|
947
|
-
handled = await this.onAddToCart({
|
|
948
|
-
productId: card.productId,
|
|
949
|
-
variantId: variantId ?? null,
|
|
950
|
-
quantity: 1
|
|
951
|
-
}) !== false;
|
|
952
|
-
} else {
|
|
953
|
-
const ev = new CustomEvent("brainerce:bot:add-to-cart", {
|
|
954
|
-
detail: {
|
|
955
|
-
productId: card.productId,
|
|
956
|
-
variantId: variantId ?? null,
|
|
957
|
-
quantity: 1,
|
|
958
|
-
connectionId: this.connectionId
|
|
959
|
-
},
|
|
960
|
-
cancelable: true,
|
|
961
|
-
bubbles: true,
|
|
962
|
-
composed: true
|
|
963
|
-
});
|
|
964
|
-
handled = !window.dispatchEvent(ev);
|
|
965
|
-
}
|
|
966
|
-
} catch {
|
|
967
|
-
handled = false;
|
|
968
|
-
}
|
|
995
|
+
const handled = await this.dispatchAdd(card.productId, variantId ?? null);
|
|
969
996
|
if (handled) {
|
|
970
997
|
btn.dataset.state = "done";
|
|
971
998
|
btn.replaceChildren(icon("check"), document.createTextNode(this.t("added")));
|
|
@@ -980,6 +1007,34 @@ var BrainerceBot = class _BrainerceBot {
|
|
|
980
1007
|
if (isSafeUrl(card.url)) window.location.href = card.url;
|
|
981
1008
|
}
|
|
982
1009
|
}
|
|
1010
|
+
/**
|
|
1011
|
+
* The host-cart chain shared by card buttons and bot-initiated actions:
|
|
1012
|
+
* onAddToCart option -> cancelable CustomEvent. Returns whether a host
|
|
1013
|
+
* took the add.
|
|
1014
|
+
*/
|
|
1015
|
+
async dispatchAdd(productId, variantId) {
|
|
1016
|
+
try {
|
|
1017
|
+
if (this.onAddToCart) {
|
|
1018
|
+
return await this.onAddToCart({ productId, variantId, quantity: 1 }) !== false;
|
|
1019
|
+
}
|
|
1020
|
+
const ev = new CustomEvent("brainerce:bot:add-to-cart", {
|
|
1021
|
+
detail: { productId, variantId, quantity: 1, connectionId: this.connectionId },
|
|
1022
|
+
cancelable: true,
|
|
1023
|
+
bubbles: true,
|
|
1024
|
+
composed: true
|
|
1025
|
+
});
|
|
1026
|
+
return !window.dispatchEvent(ev);
|
|
1027
|
+
} catch {
|
|
1028
|
+
return false;
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
/** Bot-initiated widget actions (the model called the addToCart tool). */
|
|
1032
|
+
async handleAction(frame) {
|
|
1033
|
+
if (frame.action !== "add_to_cart") return;
|
|
1034
|
+
if (frame.botRef) this.beacon(frame.botRef);
|
|
1035
|
+
const ok = await this.dispatchAdd(frame.productId, frame.variantId);
|
|
1036
|
+
if (!ok) this.appendMessage("err", this.t("addFailed"));
|
|
1037
|
+
}
|
|
983
1038
|
/** The durable conversion signal — fire-and-forget, never blocks. */
|
|
984
1039
|
beacon(botRef) {
|
|
985
1040
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brainerce",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.33.0",
|
|
4
4
|
"description": "Official SDK for building e-commerce storefronts with Brainerce Platform. Perfect for vibe-coded sites, AI-built stores (Cursor, Lovable, v0), and custom storefronts.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|