@holaboss/client 0.2.0-beta.20 → 0.2.0-beta.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  'use client'
2
- var Q=Object.defineProperty;var Ve=Object.getOwnPropertyDescriptor;var je=Object.getOwnPropertyNames;var Ge=Object.prototype.hasOwnProperty;var Be=(e,t)=>{for(var r in t)Q(e,r,{get:t[r],enumerable:!0})},ze=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of je(t))!Ge.call(e,i)&&i!==r&&Q(e,i,{get:()=>t[i],enumerable:!(o=Ve(t,i))||o.enumerable});return e};var Je=e=>ze(Q({},"__esModule",{value:!0}),e);var wt={};Be(wt,{Chat:()=>He,GRID_COLS:()=>te,GRID_MAX_COLS:()=>ne,GRID_MAX_ROWS:()=>re,HolaProvider:()=>Ce,PortalConflict:()=>A,bandOfKind:()=>M,bandOfType:()=>oe,cellValue:()=>he,createApiTransport:()=>Pe,createHolaClient:()=>Ae,createPortalData:()=>Oe,createPortalShop:()=>Ue,createWidgetTransport:()=>B,deliverableCellText:()=>fe,deliverableStatus:()=>ce,deriveFields:()=>Z,emptyTableResponses:()=>$,footprintOf:()=>se,footprintWith:()=>z,formatDeliverableDate:()=>ve,groupDeliverableVersions:()=>X,inferSpec:()=>ee,isDeliverableChecked:()=>ye,mergeMessage:()=>Se,normalizeDeliverableColType:()=>q,normalizeDeliverableItem:()=>K,parseDashboardSpec:()=>de,parseDeliverableItems:()=>pe,parseDeliverableTable:()=>me,parseTableResponses:()=>be,placeWidgets:()=>J,publishedVersionOf:()=>ge,renderModel:()=>ue,setResponse:()=>we,setTableReview:()=>xe,splitLayout:()=>ie,textDeltaOf:()=>_,thinkingDeltaOf:()=>O,toolEventOf:()=>U,useArtifactUrl:()=>F,useChat:()=>j,useHolaClient:()=>V,useShop:()=>Le,useThread:()=>Ne});module.exports=Je(wt);var Re=e=>{if(!e||typeof e!="object")return null;let t=e;return t.type==="message_update"?t.assistantMessageEvent??null:null},_=e=>{let t=Re(e);return t?.type==="text_delta"&&typeof t.delta=="string"?t.delta:null},O=e=>{let t=Re(e);return t?.type==="thinking_delta"&&typeof t.delta=="string"?t.delta:null},U=e=>{if(!e||typeof e!="object")return null;let t=e;return t.type==="tool_execution_start"&&t.toolCallId?{phase:"start",id:t.toolCallId,name:t.toolName}:t.type==="tool_execution_end"&&t.toolCallId?{phase:"end",id:t.toolCallId,isError:t.isError}:null};var Ke=/^ /,w=e=>{if(e&&typeof e=="object"){let t=e,r=typeof t.error=="string"?t.error:"request_failed";return typeof t.retryable=="boolean"?{error:r,retryable:t.retryable}:{error:r}}return{error:"request_failed"}},Xe=e=>{let t="message",r=[];for(let o of e.split(`
3
- `))o.startsWith(":")||(o.startsWith("event:")?t=o.slice(6).trim():o.startsWith("data:")&&r.push(o.slice(5).replace(Ke,"")));return r.length>0?{event:t,data:r.join(`
4
- `)}:null},qe=(e,t,r)=>{let o;try{o=JSON.parse(e.data)}catch{return}if(e.event==="session"){let i=o.sessionId;i&&(r(i),t.onSession?.(i));return}if(e.event==="turn_event"){t.onEvent?.(o);let i=_(o);i&&t.onText?.(i);let a=O(o);a&&t.onThinking?.(a);let n=U(o);n&&t.onTool?.(n);return}if(e.event==="chat_completed"){let i=o;r(i.sessionId),t.onComplete?.(i);return}e.event==="chat_error"&&t.onError?.(w(o))},R=async(e,t)=>{let r=await fetch(e,{headers:t});if(!r.ok)throw new Error(`hola: request failed (${r.status})`);return await r.json()},Te=async e=>{let t=await fetch(e.url,{method:"POST",headers:e.headers,body:e.body});if(!t.ok)throw new Error(`hola: message failed (${t.status})`);return await t.json()},ke=async(e,t,r,o)=>{let i=await fetch(e.url,{method:"POST",headers:e.headers,body:e.body,signal:o});if(!(i.ok&&i.body)){t.onError?.({error:`stream_failed_${i.status}`});return}let a=i.body.getReader(),n=new TextDecoder,s="",l=()=>{let d=s.indexOf(`
2
+ var ee=Object.defineProperty;var ot=Object.getOwnPropertyDescriptor;var st=Object.getOwnPropertyNames;var it=Object.prototype.hasOwnProperty;var at=(e,t)=>{for(var r in t)ee(e,r,{get:t[r],enumerable:!0})},lt=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of st(t))!it.call(e,s)&&s!==r&&ee(e,s,{get:()=>t[s],enumerable:!(n=ot(t,s))||n.enumerable});return e};var ut=e=>lt(ee({},"__esModule",{value:!0}),e);var Ft={};at(Ft,{Chat:()=>We,CreditRefused:()=>$,GRID_COLS:()=>oe,GRID_MAX_COLS:()=>se,GRID_MAX_ROWS:()=>ie,HolaProvider:()=>Me,PortalConflict:()=>M,bandOfKind:()=>W,bandOfType:()=>ae,buyRequestText:()=>Ze,cellValue:()=>ve,createApiTransport:()=>He,createHolaClient:()=>Ee,createPortalCredits:()=>je,createPortalData:()=>Ne,createPortalShop:()=>Ve,createWidgetTransport:()=>J,deliverableCellText:()=>he,deliverableStatus:()=>fe,deriveFields:()=>re,emptyTableResponses:()=>_,facetValues:()=>Ye,footprintOf:()=>le,footprintWith:()=>K,formatDeliverableDate:()=>Pe,groupDeliverableVersions:()=>Y,includesFor:()=>Qe,inferSpec:()=>ne,isDeliverableChecked:()=>xe,mergeMessage:()=>Re,modeOf:()=>Be,money:()=>L,normalizeDeliverableColType:()=>Z,normalizeDeliverableItem:()=>Q,parseDashboardSpec:()=>me,parseDeliverableItems:()=>ge,parseDeliverableTable:()=>be,parseTableResponses:()=>we,placeWidgets:()=>X,priceFor:()=>Je,priceLabel:()=>Te,publishedVersionOf:()=>ye,quantityRange:()=>Xe,renderModel:()=>ce,setResponse:()=>Se,setTableReview:()=>ke,shelfPriceLabel:()=>qe,shelfProblem:()=>et,splitLayout:()=>ue,textDeltaOf:()=>F,thinkingDeltaOf:()=>U,toolEventOf:()=>N,totalFor:()=>Ke,useArtifactUrl:()=>j,useChat:()=>z,useCredits:()=>Ge,useHolaClient:()=>B,useShop:()=>tt,useThread:()=>nt});module.exports=ut(Ft);var Ce=e=>{if(!e||typeof e!="object")return null;let t=e;return t.type==="message_update"?t.assistantMessageEvent??null:null},F=e=>{let t=Ce(e);return t?.type==="text_delta"&&typeof t.delta=="string"?t.delta:null},U=e=>{let t=Ce(e);return t?.type==="thinking_delta"&&typeof t.delta=="string"?t.delta:null},N=e=>{if(!e||typeof e!="object")return null;let t=e;return t.type==="tool_execution_start"&&t.toolCallId?{phase:"start",id:t.toolCallId,name:t.toolName}:t.type==="tool_execution_end"&&t.toolCallId?{phase:"end",id:t.toolCallId,isError:t.isError}:null};var dt=/^ /,x=e=>{if(e&&typeof e=="object"){let t=e,r=typeof t.error=="string"?t.error:"request_failed";return typeof t.retryable=="boolean"?{error:r,retryable:t.retryable}:{error:r}}return{error:"request_failed"}},pt=e=>{let t="message",r=[];for(let n of e.split(`
3
+ `))n.startsWith(":")||(n.startsWith("event:")?t=n.slice(6).trim():n.startsWith("data:")&&r.push(n.slice(5).replace(dt,"")));return r.length>0?{event:t,data:r.join(`
4
+ `)}:null},ct=(e,t,r)=>{let n;try{n=JSON.parse(e.data)}catch{return}if(e.event==="session"){let s=n.sessionId;s&&(r(s),t.onSession?.(s));return}if(e.event==="turn_event"){t.onEvent?.(n);let s=F(n);s&&t.onText?.(s);let a=U(n);a&&t.onThinking?.(a);let o=N(n);o&&t.onTool?.(o);return}if(e.event==="chat_completed"){let s=n;r(s.sessionId),t.onComplete?.(s);return}e.event==="chat_error"&&t.onError?.(x(n))},k=async(e,t)=>{let r=await fetch(e,{headers:t});if(!r.ok)throw new Error(`hola: request failed (${r.status})`);return await r.json()},De=async e=>{let t=await fetch(e.url,{method:"POST",headers:e.headers,body:e.body});if(!t.ok)throw new Error(`hola: message failed (${t.status})`);return await t.json()},Ie=async(e,t,r,n)=>{let s=await fetch(e.url,{method:"POST",headers:e.headers,body:e.body,signal:n});if(!(s.ok&&s.body)){t.onError?.({error:`stream_failed_${s.status}`});return}let a=s.body.getReader(),o=new TextDecoder,i="",l=()=>{let d=i.indexOf(`
5
5
 
6
- `);for(;d!==-1;){let c=s.slice(0,d);s=s.slice(d+2);let g=Xe(c);g&&qe(g,t,r),d=s.indexOf(`
6
+ `);for(;d!==-1;){let c=i.slice(0,d);i=i.slice(d+2);let m=pt(c);m&&ct(m,t,r),d=i.indexOf(`
7
7
 
8
- `)}},u=async()=>{let d=await a.read();if(!d.done)return s+=n.decode(d.value,{stream:!0}),l(),u()};await u()};var Qe=/\/+$/,Y="/api/v1/end-user",Pe=e=>{let t=e.baseUrl.replace(Qe,""),r=()=>typeof e.token=="function"?e.token():e.token,o=n=>e.project?`${n}project=${encodeURIComponent(e.project)}`:"",i=async()=>({"content-type":"application/json",authorization:`Bearer ${await r()}`}),a=async n=>{let s=await fetch(`${t}${Y}/chat${o("?")}`,{method:"POST",headers:await i(),body:JSON.stringify({message:n})});if(!s.ok)throw new Error(`hola: message failed (${s.status})`);return{reply:(await s.json()).reply??"",sessionId:"",artifacts:[]}};return{sessionId:()=>"",getInfo:async()=>R(`${t}${Y}/chat/info${o("?")}`,await i()),sendMessage:a,streamMessage:async(n,s)=>{try{let l=await a(n);s.onText?.(l.reply),s.onComplete?.(l)}catch(l){s.onError?.(w(l))}},subscribe:(n,s)=>{let l=s?.since??"0",u=!1,d,c=s?.intervalMs??3e3,g=typeof document<"u",p=()=>g&&document.visibilityState==="hidden",y=!1,x=()=>{if(!u){if(p()){y=!0;return}d=setTimeout(f,c)}},f=async()=>{try{let h=await R(`${t}${Y}/chat/thread?since=${encodeURIComponent(l)}${o("&")}`,await i());for(let I of h.messages)n.onMessage(I);l=h.cursor,n.onHealthy?.()}catch(h){n.onError?.(w(h))}x()},P=()=>{u||!y||p()||(y=!1,d&&clearTimeout(d),d=setTimeout(f,0))};g&&document.addEventListener("visibilitychange",P);let m=()=>{u=!0,d&&clearTimeout(d),g&&document.removeEventListener("visibilitychange",P)};return s?.signal?.addEventListener("abort",m),d=setTimeout(f,0),m}}};var L=require("react"),F=(e,t)=>{let[r,o]=(0,L.useState)("");return(0,L.useEffect)(()=>{if(!e){o("");return}let i=Uint8Array.from(atob(e),n=>n.charCodeAt(0)),a=URL.createObjectURL(new Blob([i],{type:t}));return o(a),()=>URL.revokeObjectURL(a)},[e,t]),r};var G=require("react");var N=require("react"),Ie=require("react/jsx-runtime"),De=(0,N.createContext)(null),Ce=({client:e,children:t})=>(0,Ie.jsx)(De.Provider,{value:e,children:t}),V=()=>{let e=(0,N.useContext)(De);if(!e)throw new Error("useHolaClient must be used within <HolaProvider>");return e};var v=require("react"),j=e=>{let[t,r]=(0,v.useState)([]),[o,i]=(0,v.useState)(""),[a,n]=(0,v.useState)(!1),[s,l]=(0,v.useState)(null),u=(0,v.useRef)(0),d=(0,v.useRef)(null);(0,v.useEffect)(()=>()=>d.current?.abort(),[]);let c=(0,v.useCallback)(()=>{let p=u.current;return u.current+=1,p},[]);(0,v.useEffect)(()=>{let p=!0;return e.getInfo().then(y=>{p&&y.greeting&&r([{id:c(),role:"assistant",text:y.greeting}])}).catch(()=>{}),()=>{p=!1}},[e,c]);let g=(0,v.useCallback)(()=>{let p=o.trim();if(!p||a)return;i(""),l(null),n(!0);let y=c(),x=c();r(m=>[...m,{id:y,role:"user",text:p},{id:x,role:"assistant",text:"",streaming:!0}]);let f=m=>{r(h=>h.map(I=>I.id===x?m(I):I))},P=new AbortController;d.current=P,e.streamMessage(p,{onText:m=>f(h=>({...h,text:h.text+m})),onComplete:m=>{f(h=>({...h,text:m.reply||h.text,artifacts:m.artifacts,streaming:!1})),n(!1)},onError:m=>{f(h=>({...h,streaming:!1})),l(m.error),n(!1)}},P.signal).catch(m=>{f(h=>({...h,streaming:!1})),l(m instanceof Error?m.message:"stream_failed"),n(!1)}).finally(()=>{n(!1),f(m=>m.streaming?{...m,streaming:!1}:m)})},[o,a,e,c]);return{messages:t,input:o,setInput:i,send:g,sending:a,error:s}};var S=require("react/jsx-runtime"),k={root:{display:"flex",flexDirection:"column",height:"100%",fontFamily:"system-ui, -apple-system, sans-serif",fontSize:14,color:"#111827"},log:{flex:1,overflowY:"auto",padding:12,display:"flex",flexDirection:"column",gap:8},user:{alignSelf:"flex-end",background:"#111827",color:"#ffffff",borderRadius:12,padding:"8px 12px",maxWidth:"80%",whiteSpace:"pre-wrap"},assistant:{alignSelf:"flex-start",background:"#f1f1f4",color:"#111827",borderRadius:12,padding:"8px 12px",maxWidth:"80%",whiteSpace:"pre-wrap"},artifacts:{display:"flex",flexDirection:"column",gap:6,marginTop:6},image:{maxHeight:220,borderRadius:8,border:"1px solid #e5e7eb"},link:{color:"#2563eb",textDecoration:"underline",wordBreak:"break-all"},error:{color:"#b91c1c",padding:"4px 12px",fontSize:13},form:{display:"flex",gap:8,borderTop:"1px solid #e5e7eb",padding:8},input:{flex:1,border:"1px solid #d1d5db",borderRadius:8,padding:"8px 10px",fontSize:14,outline:"none"},button:{border:"none",background:"#111827",color:"#ffffff",borderRadius:8,padding:"8px 14px",fontSize:14,cursor:"pointer"}},Ye=({artifact:e})=>{let t=F(e.dataBase64??"",e.mimeType),r=e.url??t;return r?e.mimeType.startsWith("image/")?(0,S.jsx)("a",{href:r,rel:"noopener noreferrer",target:"_blank",children:(0,S.jsx)("img",{alt:e.filename,src:r,style:k.image})}):(0,S.jsx)("a",{download:e.filename,href:r,style:k.link,children:e.filename}):null},He=()=>{let e=V(),{messages:t,input:r,setInput:o,send:i,sending:a,error:n}=j(e),s=(0,G.useRef)(null);(0,G.useEffect)(()=>{let u=s.current;u&&(u.scrollTop=u.scrollHeight)},[t]);let l=u=>{u.preventDefault(),i()};return(0,S.jsxs)("div",{style:k.root,children:[(0,S.jsx)("div",{ref:s,style:k.log,children:t.map(u=>(0,S.jsxs)("div",{style:u.role==="user"?k.user:k.assistant,children:[u.text||(u.streaming?"\u2026":""),u.artifacts&&u.artifacts.length>0?(0,S.jsx)("div",{style:k.artifacts,children:u.artifacts.map(d=>(0,S.jsx)(Ye,{artifact:d},d.filename))}):null]},u.id))}),n?(0,S.jsx)("div",{style:k.error,children:n}):null,(0,S.jsxs)("form",{onSubmit:l,style:k.form,children:[(0,S.jsx)("input",{"aria-label":"Message",onChange:u=>o(u.target.value),placeholder:"Type a message\u2026",style:k.input,value:r}),(0,S.jsx)("button",{disabled:a||r.trim().length===0,style:k.button,type:"submit",children:"Send"})]})]})};var Ze=/\/+$/,B=e=>{let t=e.sessionId,r=e.baseUrl.replace(Ze,""),o=n=>`${r}/endpoint/${encodeURIComponent(e.token)}${n}`,i={"content-type":"application/json"},a=(n,s)=>({url:o(n),headers:i,body:JSON.stringify({message:s,...t?{sessionId:t}:{},...e.identity?{externalUserId:e.identity.externalUserId,userHmac:e.identity.userHmac}:{}})});return{sessionId:()=>t,getInfo:()=>R(o("/config"),{}),sendMessage:async n=>{let s=await Te(a("/message",n));return t=s.sessionId,s},streamMessage:(n,s,l)=>ke(a("/message/stream",n),s,u=>{t=u},l),subscribe:(n,s)=>{let l=s?.since??"0",u=!1,d,c=s?.intervalMs??3e3,g=async()=>{let y=t;if(y)try{let x=await R(o(`/messages?session=${encodeURIComponent(y)}&since=${encodeURIComponent(l)}`),{});for(let f of x.messages)n.onMessage(f);l=x.cursor,n.onHealthy?.()}catch(x){n.onError?.(w(x))}u||(d=setTimeout(g,c))},p=()=>{u=!0,d&&clearTimeout(d)};return s?.signal?.addEventListener("abort",p),d=setTimeout(g,0),p}}};var Ae=e=>"transport"in e?e.transport:B(e);var et=/^https?:\/\//i,tt=/^\d{4}-\d{2}-\d{2}(?:[T ]|$)/,nt=e=>e.replace(/_/g," ").replace(/\b\w/g,t=>t.toUpperCase());function rt(e){if(typeof e=="number")return"number";if(typeof e=="boolean")return"boolean";if(typeof e=="string"){if(et.test(e))return"url";if(tt.test(e))return"date"}return"text"}function Z(e){let t=[],r=new Map;for(let o of e)for(let[i,a]of Object.entries(o.data??{})){if(a==null)continue;let n=r.get(i);n||(n=new Map,r.set(i,n),t.push(i));let s=rt(a);n.set(s,(n.get(s)??0)+1)}return t.map(o=>{let i=r.get(o)??new Map,a="text",n=-1;for(let[s,l]of i)l>n&&(n=l,a=s);return{key:o,label:nt(o),type:a}})}var ot=e=>typeof e=="number"?e:Number(e)||0,Me=e=>/rate|position|rank|score|percent|avg/i.test(e),st=/posted|published|sent|completed|shipped|launched|_at/i,it=new Set(["service","order","end_user_id"]);function ee(e,t){let r=e.filter(l=>!it.has(l.key)),o=r.filter(l=>l.type==="number").slice(0,3),i=r.find(l=>l.key==="status")??r.find(l=>l.type==="select"),a=r.find(l=>l.type==="date"&&st.test(l.key))??r.find(l=>l.type==="date"),n=r.filter(l=>l.type==="number"&&!Me(l.key)).map(l=>({field:l,total:t.reduce((u,d)=>u+ot(d.data[l.key]),0)})).sort((l,u)=>u.total-l.total).find(l=>l.total>0)?.field??null,s=[{type:"stat",label:"Items",agg:"count"}];for(let l of o){let u=Me(l.key);s.push({type:"stat",metric:l.key,agg:u?"avg":"sum",label:u?`Avg ${l.label.toLowerCase()}`:l.label})}return a&&s.push({type:"line",x:a.key,y:n?.key,agg:"sum",title:n?`${n.label} by day`:"Items by day"}),i&&s.push({type:"donut",groupBy:i.key,title:i.label}),s.push({type:"table",columns:r.map(l=>l.key)}),{version:1,widgets:s}}var te=6,ne=6,re=4,We={stat:{w:1,h:1},chart:{w:2,h:2},block:{w:6,h:2}},at=e=>Math.max(1,Math.min(6,Math.round(e))),lt=e=>Math.max(1,Math.min(4,Math.round(e)));function M(e){return e==="stat"?"stat":e==="series"||e==="donut"?"chart":"block"}function oe(e){return e==="stat"?"stat":e==="line"||e==="bar"||e==="donut"?"chart":"block"}function se(e){return We[e]}function z(e,t,r){let o=We[e];return{w:t===void 0?o.w:at(t),h:r===void 0?o.h:lt(r)}}function J(e){let t=[],r=[],o=(n,s,l,u)=>{if(n<0||n+l>6)return!1;for(let d=0;d<u;d+=1){let c=r[s+d];if(c){for(let g=0;g<l;g+=1)if(c[n+g])return!1}}return!0},i=(n,s,l,u)=>{for(let d=0;d<u;d+=1){let c=r[s+d]??[];for(let g=0;g<l;g+=1)c[n+g]=!0;r[s+d]=c}},a=(n,s)=>{for(let l=0;;l+=1)for(let u=0;u+n<=6;u+=1)if(o(u,l,n,s))return{gx:u,gy:l}};for(let n of e){let s=z(M(n.kind),n.w,n.h),u=n.gx!==void 0&&n.gy!==void 0&&o(n.gx,n.gy,s.w,s.h)&&n.gx!==void 0&&n.gy!==void 0?{gx:n.gx,gy:n.gy}:a(s.w,s.h);i(u.gx,u.gy,s.w,s.h),t.push({widget:n,gx:u.gx,gy:u.gy,w:s.w,h:s.h})}return t}function ie(e){let t=[],r=[];for(let o of e)M(o.kind)==="block"?r.push(o):t.push(o);return{tiles:J(t),blocks:r}}var Ee=new Set(["service","order","end_user_id"]),ae=e=>typeof e=="number"?e:Number(e)||0,$e=e=>e==null?"":String(e);function le(e,t){if(e==="count")return t.length;if(t.length===0)return 0;if(e==="last")return t[t.length-1]??0;if(e==="min")return Math.min(...t);if(e==="max")return Math.max(...t);let r=t.reduce((o,i)=>o+i,0);return e==="avg"?Math.round(r/t.length*100)/100:r}function ut(e,t,r,o){let i=new Map;for(let a of e){let n=new Date($e(a.data[t]));if(Number.isNaN(n.getTime()))continue;let s=n.toISOString().slice(0,10),l=i.get(s)??[];l.push(r?ae(a.data[r]):1),i.set(s,l)}return[...i.entries()].sort((a,n)=>a[0]<n[0]?-1:1).map(([a,n])=>({label:new Date(`${a}T00:00:00`).toLocaleDateString(void 0,{month:"short",day:"numeric"}),value:r?le(o,n):n.length}))}function dt(e,t,r,o="sum"){let i=new Map;for(let a of e){let n=$e(a.data[t]).trim();if(!n)continue;let s=i.get(n)??[];s.push(r?ae(a.data[r]):1),i.set(n,s)}return[...i.entries()].map(([a,n])=>({label:a,value:r?le(o,n):n.length})).sort((a,n)=>n.value-a.value)}function pt(e,t,r,o){switch(e.type){case"stat":{let i=e.metric?t.get(e.metric):void 0;if(e.metric&&!i)return null;if(!i)return{kind:"stat",label:e.label??"Items",value:o.length};let a=o.map(n=>ae(n.data[i.key]));return{kind:"stat",label:e.label??i.label,value:le(e.agg??"sum",a)}}case"line":case"bar":{if(!t.has(e.x)||e.y&&!t.has(e.y))return null;let i=ut(o,e.x,e.y,e.agg??"sum");return i.length<2?null:{kind:"series",draw:e.type,title:e.title??"By day",points:i}}case"donut":{if(!t.has(e.groupBy))return null;let i=dt(o,e.groupBy,e.metric,e.agg??"sum");return i.length===0?null:{kind:"donut",title:e.title??t.get(e.groupBy)?.label??"Breakdown",points:i}}case"table":{let i=e.columns?e.columns.map(a=>t.get(a)).filter(a=>a!==void 0&&!Ee.has(a.key)):r;return i.length===0?null:{kind:"table",title:e.title,columns:i,rows:o}}case"text":return{kind:"text",title:e.title,body:e.body};default:return null}}function ue(e,t,r,o={}){let i=new Map,a=l=>({byKey:new Map(l.fields.map(u=>[u.key,u])),cols:l.fields.filter(u=>!Ee.has(u.key)),rows:l.rows}),n=a({fields:t,rows:r});for(let[l,u]of Object.entries(o))i.set(l,a(u));let s=[];for(let l of e.widgets){let u=l.type==="text"?void 0:l.source,d=u?i.get(u):n;if(!d)continue;let c=pt(l,d.byKey,d.cols,d.rows);c&&s.push({...c,w:l.w,h:l.h,gx:l.gx,gy:l.gy})}return s}var ct=new Set(["sum","avg","count","min","max","last"]),_e=e=>typeof e=="string"&&ct.has(e)?e:void 0,b=e=>typeof e=="string"&&e!==""?e:void 0,W=e=>typeof e=="number"&&e>=1?Math.min(6,Math.round(e)):void 0,E=e=>typeof e=="number"&&e>=1?Math.min(4,Math.round(e)):void 0,D=e=>typeof e=="number"&&e>=0?Math.round(e):void 0;function gt(e){if(typeof e!="object"||e===null)return null;let t=e;switch(t.type){case"stat":return{type:"stat",source:b(t.source),label:b(t.label),metric:b(t.metric)??b(t.column),agg:_e(t.agg),w:W(t.w),h:E(t.h),gx:D(t.gx),gy:D(t.gy)};case"line":case"bar":{let r=b(t.x);return r?{type:t.type,source:b(t.source),title:b(t.title),x:r,y:b(t.y)??b(t.column),agg:_e(t.agg),w:W(t.w),h:E(t.h),gx:D(t.gx),gy:D(t.gy)}:null}case"donut":{let r=b(t.groupBy)??b(t.column);return r?{type:"donut",source:b(t.source),title:b(t.title),groupBy:r,w:W(t.w),h:E(t.h),gx:D(t.gx),gy:D(t.gy)}:null}case"table":{let r=Array.isArray(t.columns)?t.columns.filter(o=>typeof o=="string"):void 0;return{type:"table",source:b(t.source),title:b(t.title),columns:r,w:W(t.w),h:E(t.h),gx:D(t.gx),gy:D(t.gy)}}case"text":{let r=b(t.body);return r?{type:"text",title:b(t.title),body:r,w:W(t.w),h:E(t.h),gx:D(t.gx),gy:D(t.gy)}:null}default:return null}}function de(e){let t=e;if(typeof e=="string"){if(e.trim()==="")return null;try{t=JSON.parse(e)}catch{return null}}if(typeof t!="object"||t===null)return null;let r=t.widgets;if(!Array.isArray(r))return null;let o=r.map(gt).filter(a=>a!==null);if(o.length===0)return null;let i=t.version;return{version:typeof i=="number"?i:1,title:b(t.title),widgets:o}}function K(e){if(typeof e=="string")return e?{kind:"file",value:e}:null;if(e&&typeof e=="object"){let t=e,r=typeof t.value=="string"?t.value:"",o=t.kind==="link"||t.kind==="text"||t.kind==="table"?t.kind:"file",i=typeof t.v=="number"&&t.v>=1?Math.floor(t.v):void 0;return r?{kind:o,value:r,...i?{v:i}:{}}:null}return null}function X(e){let t=new Map;for(let r of e){let o=r.v??1,i=t.get(o)??[];i.push(r),t.set(o,i)}return[...t.entries()].sort(([r],[o])=>r-o).map(([r,o])=>({v:r,items:o}))}function pe(e){let t=e.files;if(typeof t=="string"&&t.trim()!=="")try{let o=JSON.parse(t);if(Array.isArray(o))return o.map(K).filter(i=>i!==null)}catch{}let r=String(e.file??"");return r?[{kind:"file",value:r}]:[]}function ce(e,t,r,o=""){let a=X(e).find(s=>s.v===t)?.items??[],n=a.filter(s=>s.kind==="file").map(s=>r.get(s.value)??"");return a.some(s=>s.kind==="table")&&n.push(o),n.length===0||n.some(s=>s==="")?"awaiting":n.some(s=>s==="revise")?"revise":"accepted"}function ge(e){return Number(e.published_version)||0}function q(e){return e==="number"||e==="date"||e==="boolean"||e==="select"||e==="url"?e:e==="link"?"url":e==="checkbox"?"boolean":"text"}function me(e){try{let t=JSON.parse(e);if(Array.isArray(t.columns)&&Array.isArray(t.rows)&&t.columns.length){let r=t.columns.map((a,n)=>({key:typeof a.key=="string"&&a.key?a.key:typeof a.id=="string"&&a.id?a.id:`column_${n+1}`,label:typeof a.label=="string"?a.label:"",type:q(a.type),...a.clientEditable===!0?{clientEditable:!0}:{}})),o=t.rows.map((a,n)=>({id:typeof a.id=="string"&&a.id?a.id:`row_${n}`,cells:a.cells&&typeof a.cells=="object"?a.cells:{}})),i=typeof t.name=="string"?t.name:void 0;return{columns:r,rows:o,...i?{name:i}:{}}}}catch{}return null}function fe(e){return e==null?"":String(e)}function ye(e){return e===!0||e==="true"||e==="1"||e==="yes"||e==="\u2713"}function $(){return{cells:{},verdict:"",comment:""}}function be(e){if(typeof e!="string"||e.trim()==="")return $();try{let t=JSON.parse(e);if(t&&typeof t=="object"&&!Array.isArray(t)){let r=t;return{cells:r.cells&&typeof r.cells=="object"?r.cells:r,verdict:r.verdict==="accepted"||r.verdict==="revise"?r.verdict:"",comment:typeof r.comment=="string"?r.comment:""}}}catch{}return $()}function he(e,t,r){if(e.clientEditable){let o=r.cells[t.id];if(o&&e.key in o)return o[e.key]}return t.cells[e.key]}function we(e,t,r,o){return{...e,cells:{...e.cells,[t]:{...e.cells[t]??{},[r]:o}}}}function xe(e,t,r){return{...e,verdict:t,comment:r}}function ve(e){let t=new Date(`${e}T00:00:00`);return Number.isNaN(t.getTime())?e:t.toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"})}var mt=/\/+$/,H="/api/v1/end-user",A=class extends Error{constructor(t){super(t),this.name="PortalConflict"}};function ft(e){let t="";for(let o=0;o<e.length;o+=32768)t+=String.fromCharCode(...e.subarray(o,o+32768));return btoa(t)}var Oe=e=>{let t=e.baseUrl.replace(mt,""),r=()=>typeof e.token=="function"?e.token():e.token,o=async()=>({"content-type":"application/json",authorization:`Bearer ${await r()}`}),i=async(n,s)=>{try{let l=await fetch(`${t}${H}${n}`,{method:s.method,headers:await o(),...s.body===void 0?{}:{body:JSON.stringify(s.body)}});if(l.status===409){let u=await l.json().catch(()=>({}));throw new A(u.message??"Someone else saved this first.")}if(!l.ok){let u=await l.text().catch(()=>""),d=`${s.method} ${n} \u2192 ${String(l.status)}`;try{let c=JSON.parse(u);c.message&&(d=c.message)}catch{d=u?`${d}: ${u}`:d}throw w({error:d})}return await l.json()}catch(l){throw l instanceof A?l:w(l)}},a=n=>`/tables/${encodeURIComponent(n)}`;return{listTables:async()=>(await R(`${t}${H}/tables`,await o())).tables,listRows:async(n,s)=>await R(`${t}${H}${a(n)}/rows?limit=${String(s??100)}`,await o()),insertRow:async(n,s)=>{let{rowIds:l}=await i(`${a(n)}/rows`,{method:"POST",body:{rows:[s]}}),u=l[0];if(!u)throw w(new Error("The row was not created."));return u},patchRow:async(n,s,l)=>(await i(`${a(n)}/rows/${encodeURIComponent(s)}`,{method:"PATCH",body:l})).updated,deleteRow:async(n,s)=>(await i(`/${encodeURIComponent(n)}/${encodeURIComponent(s)}`,{method:"DELETE"})).deleted,listFiles:async()=>(await R(`${t}${H}/tables/files/rows?limit=200`,await o())).rows.map(s=>({id:s.rowId,filename:String(s.data.filename??""),source:String(s.data.source??"client"),campaign:String(s.data.campaign??""),size:typeof s.data.size=="number"?s.data.size:0,createdAt:s.createdAt})),uploadFile:async(n,s)=>{let l=new Uint8Array(await n.arrayBuffer());return await i("/files",{method:"POST",body:{filename:n.name,mime:n.type||"application/octet-stream",data:ft(l),...s===void 0?{}:{message:s}}})},fileLink:async n=>await R(`${t}${H}/files/${encodeURIComponent(n)}/url`,await o()),deleteFile:async n=>(await i(`/files/${encodeURIComponent(n)}`,{method:"DELETE"})).deleted,listDocuments:async()=>(await R(`${t}${H}/documents`,await o())).documents,readDocument:async n=>(await R(`${t}${H}/documents/${encodeURIComponent(n)}`,await o())).document,saveDocument:async(n,s)=>await i(`/documents/${encodeURIComponent(n)}`,{method:"PATCH",body:s})}};var yt=/\/+$/,bt="/api/v1/end-user",Ue=e=>{let t=e.baseUrl.replace(yt,""),r=async(o,i)=>{let a;try{a=await fetch(`${t}${bt}${o}`,i===void 0?{}:{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(i)})}catch(n){throw w(n)}if(a.status===429)throw w({error:"rate_limited",retryable:!0});if(!a.ok)throw w({error:`shop_request_failed_${String(a.status)}`});try{return await a.json()}catch(n){throw w(n)}};return{listProducts:async()=>{let o=await r(`/shop/products?publishable_key=${encodeURIComponent(e.publishableKey)}`);return{products:o.products.map(i=>({...i,currency:typeof i.currency=="string"?i.currency:""})),truncated:o.truncated===!0}},apply:async o=>await r("/shop/apply",{publishable_key:e.publishableKey,name:o.name,email:o.email,...o.phone?{phone:o.phone}:{},...o.message?{message:o.message}:{},...o.productId?{productId:o.productId}:{}})}};var C=require("react"),ht=e=>e&&typeof e=="object"&&typeof e.error=="string"?e.error:e instanceof Error?e.message:"shop_unavailable",Le=e=>{let[t,r]=(0,C.useState)([]),[o,i]=(0,C.useState)(!1),[a,n]=(0,C.useState)(!0),[s,l]=(0,C.useState)(null),[u,d]=(0,C.useState)(0);(0,C.useEffect)(()=>{let g=!0;return n(!0),e.listProducts().then(p=>{g&&(r(p.products),i(p.truncated),l(null))}).catch(p=>{g&&l(ht(p))}).finally(()=>{g&&n(!1)}),()=>{g=!1}},[e,u]);let c=(0,C.useCallback)(()=>d(g=>g+1),[]);return{products:t,truncated:o,loading:a,error:s,reload:c}};var T=require("react"),Fe="greeting";function Se(e,t){if(e.some(a=>a.id===t.id))return e;let r=e.filter(a=>a.id!==Fe),o=a=>a.author==="client"==(t.author==="client");return[...r.filter(a=>!(a.pending&&o(a)&&a.text===t.text)),t]}var Ne=(e,t)=>{let[r,o]=(0,T.useState)([]),[i,a]=(0,T.useState)(""),[n,s]=(0,T.useState)(!1),[l,u]=(0,T.useState)(null),d=(0,T.useRef)(0),c=t?.pollMs??2e3;(0,T.useEffect)(()=>{let p=!0;return e.getInfo().then(y=>{p&&y.greeting&&o(x=>x.length===0?[{id:Fe,cursor:"",author:"agent",text:y.greeting}]:x)}).catch(()=>{}),()=>{p=!1}},[e]),(0,T.useEffect)(()=>e.subscribe?.({onMessage:p=>o(y=>Se(y,p)),onError:p=>u(p.error),onHealthy:()=>u(null)},{intervalMs:c}),[e,c]);let g=(0,T.useCallback)(()=>{let p=i.trim();if(!p||n)return;a(""),u(null),s(!0),d.current+=1;let y=`pending-${d.current}`,x={id:y,cursor:"",author:"client",text:p,pending:!0};o(f=>[...f,x]),e.sendMessage(p).then(f=>{s(!1),f.reply.trim()&&o(m=>m.some(I=>!I.pending&&I.author!=="client"&&I.text===f.reply)?m:(d.current+=1,[...m,{id:`pending-agent-${d.current}`,cursor:"",author:"agent",text:f.reply,pending:!0}]))}).catch(f=>{u(f instanceof Error?f.message:"send_failed"),s(!1),o(P=>P.filter(m=>m.id!==y)),a(P=>P||p)})},[i,n,e]);return{messages:r,input:i,setInput:a,send:g,sending:n,error:l}};0&&(module.exports={Chat,GRID_COLS,GRID_MAX_COLS,GRID_MAX_ROWS,HolaProvider,PortalConflict,bandOfKind,bandOfType,cellValue,createApiTransport,createHolaClient,createPortalData,createPortalShop,createWidgetTransport,deliverableCellText,deliverableStatus,deriveFields,emptyTableResponses,footprintOf,footprintWith,formatDeliverableDate,groupDeliverableVersions,inferSpec,isDeliverableChecked,mergeMessage,normalizeDeliverableColType,normalizeDeliverableItem,parseDashboardSpec,parseDeliverableItems,parseDeliverableTable,parseTableResponses,placeWidgets,publishedVersionOf,renderModel,setResponse,setTableReview,splitLayout,textDeltaOf,thinkingDeltaOf,toolEventOf,useArtifactUrl,useChat,useHolaClient,useShop,useThread});
8
+ `)}},u=async()=>{let d=await a.read();if(!d.done)return i+=o.decode(d.value,{stream:!0}),l(),u()};await u()};var mt=/\/+$/,te="/api/v1/end-user",He=e=>{let t=e.baseUrl.replace(mt,""),r=()=>typeof e.token=="function"?e.token():e.token,n=o=>e.project?`${o}project=${encodeURIComponent(e.project)}`:"",s=async()=>({"content-type":"application/json",authorization:`Bearer ${await r()}`}),a=async o=>{let i=await fetch(`${t}${te}/chat${n("?")}`,{method:"POST",headers:await s(),body:JSON.stringify({message:o})});if(!i.ok)throw new Error(`hola: message failed (${i.status})`);return{reply:(await i.json()).reply??"",sessionId:"",artifacts:[]}};return{sessionId:()=>"",getInfo:async()=>k(`${t}${te}/chat/info${n("?")}`,await s()),sendMessage:a,streamMessage:async(o,i)=>{try{let l=await a(o);i.onText?.(l.reply),i.onComplete?.(l)}catch(l){i.onError?.(x(l))}},subscribe:(o,i)=>{let l=i?.since??"0",u=!1,d,c=i?.intervalMs??3e3,m=typeof document<"u",p=()=>m&&document.visibilityState==="hidden",y=!1,w=()=>{if(!u){if(p()){y=!0;return}d=setTimeout(f,c)}},f=async()=>{try{let h=await k(`${t}${te}/chat/thread?since=${encodeURIComponent(l)}${n("&")}`,await s());for(let I of h.messages)o.onMessage(I);l=h.cursor,o.onHealthy?.()}catch(h){o.onError?.(x(h))}w()},R=()=>{u||!y||p()||(y=!1,d&&clearTimeout(d),d=setTimeout(f,0))};m&&document.addEventListener("visibilitychange",R);let g=()=>{u=!0,d&&clearTimeout(d),m&&document.removeEventListener("visibilitychange",R)};return i?.signal?.addEventListener("abort",g),d=setTimeout(f,0),g}}};var V=require("react"),j=(e,t)=>{let[r,n]=(0,V.useState)("");return(0,V.useEffect)(()=>{if(!e){n("");return}let s=Uint8Array.from(atob(e),o=>o.charCodeAt(0)),a=URL.createObjectURL(new Blob([s],{type:t}));return n(a),()=>URL.revokeObjectURL(a)},[e,t]),r};var q=require("react");var G=require("react"),$e=require("react/jsx-runtime"),Ae=(0,G.createContext)(null),Me=({client:e,children:t})=>(0,$e.jsx)(Ae.Provider,{value:e,children:t}),B=()=>{let e=(0,G.useContext)(Ae);if(!e)throw new Error("useHolaClient must be used within <HolaProvider>");return e};var v=require("react"),z=e=>{let[t,r]=(0,v.useState)([]),[n,s]=(0,v.useState)(""),[a,o]=(0,v.useState)(!1),[i,l]=(0,v.useState)(null),u=(0,v.useRef)(0),d=(0,v.useRef)(null);(0,v.useEffect)(()=>()=>d.current?.abort(),[]);let c=(0,v.useCallback)(()=>{let p=u.current;return u.current+=1,p},[]);(0,v.useEffect)(()=>{let p=!0;return e.getInfo().then(y=>{p&&y.greeting&&r([{id:c(),role:"assistant",text:y.greeting}])}).catch(()=>{}),()=>{p=!1}},[e,c]);let m=(0,v.useCallback)(()=>{let p=n.trim();if(!p||a)return;s(""),l(null),o(!0);let y=c(),w=c();r(g=>[...g,{id:y,role:"user",text:p},{id:w,role:"assistant",text:"",streaming:!0}]);let f=g=>{r(h=>h.map(I=>I.id===w?g(I):I))},R=new AbortController;d.current=R,e.streamMessage(p,{onText:g=>f(h=>({...h,text:h.text+g})),onComplete:g=>{f(h=>({...h,text:g.reply||h.text,artifacts:g.artifacts,streaming:!1})),o(!1)},onError:g=>{f(h=>({...h,streaming:!1})),l(g.error),o(!1)}},R.signal).catch(g=>{f(h=>({...h,streaming:!1})),l(g instanceof Error?g.message:"stream_failed"),o(!1)}).finally(()=>{o(!1),f(g=>g.streaming?{...g,streaming:!1}:g)})},[n,a,e,c]);return{messages:t,input:n,setInput:s,send:m,sending:a,error:i}};var S=require("react/jsx-runtime"),T={root:{display:"flex",flexDirection:"column",height:"100%",fontFamily:"system-ui, -apple-system, sans-serif",fontSize:14,color:"#111827"},log:{flex:1,overflowY:"auto",padding:12,display:"flex",flexDirection:"column",gap:8},user:{alignSelf:"flex-end",background:"#111827",color:"#ffffff",borderRadius:12,padding:"8px 12px",maxWidth:"80%",whiteSpace:"pre-wrap"},assistant:{alignSelf:"flex-start",background:"#f1f1f4",color:"#111827",borderRadius:12,padding:"8px 12px",maxWidth:"80%",whiteSpace:"pre-wrap"},artifacts:{display:"flex",flexDirection:"column",gap:6,marginTop:6},image:{maxHeight:220,borderRadius:8,border:"1px solid #e5e7eb"},link:{color:"#2563eb",textDecoration:"underline",wordBreak:"break-all"},error:{color:"#b91c1c",padding:"4px 12px",fontSize:13},form:{display:"flex",gap:8,borderTop:"1px solid #e5e7eb",padding:8},input:{flex:1,border:"1px solid #d1d5db",borderRadius:8,padding:"8px 10px",fontSize:14,outline:"none"},button:{border:"none",background:"#111827",color:"#ffffff",borderRadius:8,padding:"8px 14px",fontSize:14,cursor:"pointer"}},gt=({artifact:e})=>{let t=j(e.dataBase64??"",e.mimeType),r=e.url??t;return r?e.mimeType.startsWith("image/")?(0,S.jsx)("a",{href:r,rel:"noopener noreferrer",target:"_blank",children:(0,S.jsx)("img",{alt:e.filename,src:r,style:T.image})}):(0,S.jsx)("a",{download:e.filename,href:r,style:T.link,children:e.filename}):null},We=()=>{let e=B(),{messages:t,input:r,setInput:n,send:s,sending:a,error:o}=z(e),i=(0,q.useRef)(null);(0,q.useEffect)(()=>{let u=i.current;u&&(u.scrollTop=u.scrollHeight)},[t]);let l=u=>{u.preventDefault(),s()};return(0,S.jsxs)("div",{style:T.root,children:[(0,S.jsx)("div",{ref:i,style:T.log,children:t.map(u=>(0,S.jsxs)("div",{style:u.role==="user"?T.user:T.assistant,children:[u.text||(u.streaming?"\u2026":""),u.artifacts&&u.artifacts.length>0?(0,S.jsx)("div",{style:T.artifacts,children:u.artifacts.map(d=>(0,S.jsx)(gt,{artifact:d},d.filename))}):null]},u.id))}),o?(0,S.jsx)("div",{style:T.error,children:o}):null,(0,S.jsxs)("form",{onSubmit:l,style:T.form,children:[(0,S.jsx)("input",{"aria-label":"Message",onChange:u=>n(u.target.value),placeholder:"Type a message\u2026",style:T.input,value:r}),(0,S.jsx)("button",{disabled:a||r.trim().length===0,style:T.button,type:"submit",children:"Send"})]})]})};var ft=/\/+$/,J=e=>{let t=e.sessionId,r=e.baseUrl.replace(ft,""),n=o=>`${r}/endpoint/${encodeURIComponent(e.token)}${o}`,s={"content-type":"application/json"},a=(o,i)=>({url:n(o),headers:s,body:JSON.stringify({message:i,...t?{sessionId:t}:{},...e.identity?{externalUserId:e.identity.externalUserId,userHmac:e.identity.userHmac}:{}})});return{sessionId:()=>t,getInfo:()=>k(n("/config"),{}),sendMessage:async o=>{let i=await De(a("/message",o));return t=i.sessionId,i},streamMessage:(o,i,l)=>Ie(a("/message/stream",o),i,u=>{t=u},l),subscribe:(o,i)=>{let l=i?.since??"0",u=!1,d,c=i?.intervalMs??3e3,m=async()=>{let y=t;if(y)try{let w=await k(n(`/messages?session=${encodeURIComponent(y)}&since=${encodeURIComponent(l)}`),{});for(let f of w.messages)o.onMessage(f);l=w.cursor,o.onHealthy?.()}catch(w){o.onError?.(x(w))}u||(d=setTimeout(m,c))},p=()=>{u=!0,d&&clearTimeout(d)};return i?.signal?.addEventListener("abort",p),d=setTimeout(m,0),p}}};var Ee=e=>"transport"in e?e.transport:J(e);var yt=/^https?:\/\//i,bt=/^\d{4}-\d{2}-\d{2}(?:[T ]|$)/,ht=e=>e.replace(/_/g," ").replace(/\b\w/g,t=>t.toUpperCase());function xt(e){if(typeof e=="number")return"number";if(typeof e=="boolean")return"boolean";if(typeof e=="string"){if(yt.test(e))return"url";if(bt.test(e))return"date"}return"text"}function re(e){let t=[],r=new Map;for(let n of e)for(let[s,a]of Object.entries(n.data??{})){if(a==null)continue;let o=r.get(s);o||(o=new Map,r.set(s,o),t.push(s));let i=xt(a);o.set(i,(o.get(i)??0)+1)}return t.map(n=>{let s=r.get(n)??new Map,a="text",o=-1;for(let[i,l]of s)l>o&&(o=l,a=i);return{key:n,label:ht(n),type:a}})}var wt=e=>typeof e=="number"?e:Number(e)||0,Oe=e=>/rate|position|rank|score|percent|avg/i.test(e),vt=/posted|published|sent|completed|shipped|launched|_at/i,St=new Set(["service","order","end_user_id"]);function ne(e,t){let r=e.filter(l=>!St.has(l.key)),n=r.filter(l=>l.type==="number").slice(0,3),s=r.find(l=>l.key==="status")??r.find(l=>l.type==="select"),a=r.find(l=>l.type==="date"&&vt.test(l.key))??r.find(l=>l.type==="date"),o=r.filter(l=>l.type==="number"&&!Oe(l.key)).map(l=>({field:l,total:t.reduce((u,d)=>u+wt(d.data[l.key]),0)})).sort((l,u)=>u.total-l.total).find(l=>l.total>0)?.field??null,i=[{type:"stat",label:"Items",agg:"count"}];for(let l of n){let u=Oe(l.key);i.push({type:"stat",metric:l.key,agg:u?"avg":"sum",label:u?`Avg ${l.label.toLowerCase()}`:l.label})}return a&&i.push({type:"line",x:a.key,y:o?.key,agg:"sum",title:o?`${o.label} by day`:"Items by day"}),s&&i.push({type:"donut",groupBy:s.key,title:s.label}),i.push({type:"table",columns:r.map(l=>l.key)}),{version:1,widgets:i}}var oe=6,se=6,ie=4,_e={stat:{w:1,h:1},chart:{w:2,h:2},block:{w:6,h:2}},kt=e=>Math.max(1,Math.min(6,Math.round(e))),Pt=e=>Math.max(1,Math.min(4,Math.round(e)));function W(e){return e==="stat"?"stat":e==="series"||e==="donut"?"chart":"block"}function ae(e){return e==="stat"?"stat":e==="line"||e==="bar"||e==="donut"?"chart":"block"}function le(e){return _e[e]}function K(e,t,r){let n=_e[e];return{w:t===void 0?n.w:kt(t),h:r===void 0?n.h:Pt(r)}}function X(e){let t=[],r=[],n=(o,i,l,u)=>{if(o<0||o+l>6)return!1;for(let d=0;d<u;d+=1){let c=r[i+d];if(c){for(let m=0;m<l;m+=1)if(c[o+m])return!1}}return!0},s=(o,i,l,u)=>{for(let d=0;d<u;d+=1){let c=r[i+d]??[];for(let m=0;m<l;m+=1)c[o+m]=!0;r[i+d]=c}},a=(o,i)=>{for(let l=0;;l+=1)for(let u=0;u+o<=6;u+=1)if(n(u,l,o,i))return{gx:u,gy:l}};for(let o of e){let i=K(W(o.kind),o.w,o.h),u=o.gx!==void 0&&o.gy!==void 0&&n(o.gx,o.gy,i.w,i.h)&&o.gx!==void 0&&o.gy!==void 0?{gx:o.gx,gy:o.gy}:a(i.w,i.h);s(u.gx,u.gy,i.w,i.h),t.push({widget:o,gx:u.gx,gy:u.gy,w:i.w,h:i.h})}return t}function ue(e){let t=[],r=[];for(let n of e)W(n.kind)==="block"?r.push(n):t.push(n);return{tiles:X(t),blocks:r}}var Le=new Set(["service","order","end_user_id"]),de=e=>typeof e=="number"?e:Number(e)||0,Fe=e=>e==null?"":String(e);function pe(e,t){if(e==="count")return t.length;if(t.length===0)return 0;if(e==="last")return t[t.length-1]??0;if(e==="min")return Math.min(...t);if(e==="max")return Math.max(...t);let r=t.reduce((n,s)=>n+s,0);return e==="avg"?Math.round(r/t.length*100)/100:r}function Tt(e,t,r,n){let s=new Map;for(let a of e){let o=new Date(Fe(a.data[t]));if(Number.isNaN(o.getTime()))continue;let i=o.toISOString().slice(0,10),l=s.get(i)??[];l.push(r?de(a.data[r]):1),s.set(i,l)}return[...s.entries()].sort((a,o)=>a[0]<o[0]?-1:1).map(([a,o])=>({label:new Date(`${a}T00:00:00`).toLocaleDateString(void 0,{month:"short",day:"numeric"}),value:r?pe(n,o):o.length}))}function Rt(e,t,r,n="sum"){let s=new Map;for(let a of e){let o=Fe(a.data[t]).trim();if(!o)continue;let i=s.get(o)??[];i.push(r?de(a.data[r]):1),s.set(o,i)}return[...s.entries()].map(([a,o])=>({label:a,value:r?pe(n,o):o.length})).sort((a,o)=>o.value-a.value)}function Ct(e,t,r,n){switch(e.type){case"stat":{let s=e.metric?t.get(e.metric):void 0;if(e.metric&&!s)return null;if(!s)return{kind:"stat",label:e.label??"Items",value:n.length};let a=n.map(o=>de(o.data[s.key]));return{kind:"stat",label:e.label??s.label,value:pe(e.agg??"sum",a)}}case"line":case"bar":{if(!t.has(e.x)||e.y&&!t.has(e.y))return null;let s=Tt(n,e.x,e.y,e.agg??"sum");return s.length<2?null:{kind:"series",draw:e.type,title:e.title??"By day",points:s}}case"donut":{if(!t.has(e.groupBy))return null;let s=Rt(n,e.groupBy,e.metric,e.agg??"sum");return s.length===0?null:{kind:"donut",title:e.title??t.get(e.groupBy)?.label??"Breakdown",points:s}}case"table":{let s=e.columns?e.columns.map(a=>t.get(a)).filter(a=>a!==void 0&&!Le.has(a.key)):r;return s.length===0?null:{kind:"table",title:e.title,columns:s,rows:n}}case"text":return{kind:"text",title:e.title,body:e.body};default:return null}}function ce(e,t,r,n={}){let s=new Map,a=l=>({byKey:new Map(l.fields.map(u=>[u.key,u])),cols:l.fields.filter(u=>!Le.has(u.key)),rows:l.rows}),o=a({fields:t,rows:r});for(let[l,u]of Object.entries(n))s.set(l,a(u));let i=[];for(let l of e.widgets){let u=l.type==="text"?void 0:l.source,d=u?s.get(u):o;if(!d)continue;let c=Ct(l,d.byKey,d.cols,d.rows);c&&i.push({...c,w:l.w,h:l.h,gx:l.gx,gy:l.gy})}return i}var Dt=new Set(["sum","avg","count","min","max","last"]),Ue=e=>typeof e=="string"&&Dt.has(e)?e:void 0,b=e=>typeof e=="string"&&e!==""?e:void 0,E=e=>typeof e=="number"&&e>=1?Math.min(6,Math.round(e)):void 0,O=e=>typeof e=="number"&&e>=1?Math.min(4,Math.round(e)):void 0,C=e=>typeof e=="number"&&e>=0?Math.round(e):void 0;function It(e){if(typeof e!="object"||e===null)return null;let t=e;switch(t.type){case"stat":return{type:"stat",source:b(t.source),label:b(t.label),metric:b(t.metric)??b(t.column),agg:Ue(t.agg),w:E(t.w),h:O(t.h),gx:C(t.gx),gy:C(t.gy)};case"line":case"bar":{let r=b(t.x);return r?{type:t.type,source:b(t.source),title:b(t.title),x:r,y:b(t.y)??b(t.column),agg:Ue(t.agg),w:E(t.w),h:O(t.h),gx:C(t.gx),gy:C(t.gy)}:null}case"donut":{let r=b(t.groupBy)??b(t.column);return r?{type:"donut",source:b(t.source),title:b(t.title),groupBy:r,w:E(t.w),h:O(t.h),gx:C(t.gx),gy:C(t.gy)}:null}case"table":{let r=Array.isArray(t.columns)?t.columns.filter(n=>typeof n=="string"):void 0;return{type:"table",source:b(t.source),title:b(t.title),columns:r,w:E(t.w),h:O(t.h),gx:C(t.gx),gy:C(t.gy)}}case"text":{let r=b(t.body);return r?{type:"text",title:b(t.title),body:r,w:E(t.w),h:O(t.h),gx:C(t.gx),gy:C(t.gy)}:null}default:return null}}function me(e){let t=e;if(typeof e=="string"){if(e.trim()==="")return null;try{t=JSON.parse(e)}catch{return null}}if(typeof t!="object"||t===null)return null;let r=t.widgets;if(!Array.isArray(r))return null;let n=r.map(It).filter(a=>a!==null);if(n.length===0)return null;let s=t.version;return{version:typeof s=="number"?s:1,title:b(t.title),widgets:n}}function Q(e){if(typeof e=="string")return e?{kind:"file",value:e}:null;if(e&&typeof e=="object"){let t=e,r=typeof t.value=="string"?t.value:"",n=t.kind==="link"||t.kind==="text"||t.kind==="table"?t.kind:"file",s=typeof t.v=="number"&&t.v>=1?Math.floor(t.v):void 0;return r?{kind:n,value:r,...s?{v:s}:{}}:null}return null}function Y(e){let t=new Map;for(let r of e){let n=r.v??1,s=t.get(n)??[];s.push(r),t.set(n,s)}return[...t.entries()].sort(([r],[n])=>r-n).map(([r,n])=>({v:r,items:n}))}function ge(e){let t=e.files;if(typeof t=="string"&&t.trim()!=="")try{let n=JSON.parse(t);if(Array.isArray(n))return n.map(Q).filter(s=>s!==null)}catch{}let r=String(e.file??"");return r?[{kind:"file",value:r}]:[]}function fe(e,t,r,n=""){let a=Y(e).find(i=>i.v===t)?.items??[],o=a.filter(i=>i.kind==="file").map(i=>r.get(i.value)??"");return a.some(i=>i.kind==="table")&&o.push(n),o.length===0||o.some(i=>i==="")?"awaiting":o.some(i=>i==="revise")?"revise":"accepted"}function ye(e){return Number(e.published_version)||0}function Z(e){return e==="number"||e==="date"||e==="boolean"||e==="select"||e==="url"?e:e==="link"?"url":e==="checkbox"?"boolean":"text"}function be(e){try{let t=JSON.parse(e);if(Array.isArray(t.columns)&&Array.isArray(t.rows)&&t.columns.length){let r=t.columns.map((a,o)=>({key:typeof a.key=="string"&&a.key?a.key:typeof a.id=="string"&&a.id?a.id:`column_${o+1}`,label:typeof a.label=="string"?a.label:"",type:Z(a.type),...a.clientEditable===!0?{clientEditable:!0}:{}})),n=t.rows.map((a,o)=>({id:typeof a.id=="string"&&a.id?a.id:`row_${o}`,cells:a.cells&&typeof a.cells=="object"?a.cells:{}})),s=typeof t.name=="string"?t.name:void 0;return{columns:r,rows:n,...s?{name:s}:{}}}}catch{}return null}function he(e){return e==null?"":String(e)}function xe(e){return e===!0||e==="true"||e==="1"||e==="yes"||e==="\u2713"}function _(){return{cells:{},verdict:"",comment:""}}function we(e){if(typeof e!="string"||e.trim()==="")return _();try{let t=JSON.parse(e);if(t&&typeof t=="object"&&!Array.isArray(t)){let r=t;return{cells:r.cells&&typeof r.cells=="object"?r.cells:r,verdict:r.verdict==="accepted"||r.verdict==="revise"?r.verdict:"",comment:typeof r.comment=="string"?r.comment:""}}}catch{}return _()}function ve(e,t,r){if(e.clientEditable){let n=r.cells[t.id];if(n&&e.key in n)return n[e.key]}return t.cells[e.key]}function Se(e,t,r,n){return{...e,cells:{...e.cells,[t]:{...e.cells[t]??{},[r]:n}}}}function ke(e,t,r){return{...e,verdict:t,comment:r}}function Pe(e){let t=new Date(`${e}T00:00:00`);return Number.isNaN(t.getTime())?e:t.toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"})}var Ht=/\/+$/,A="/api/v1/end-user",M=class extends Error{constructor(t){super(t),this.name="PortalConflict"}};function At(e){let t="";for(let n=0;n<e.length;n+=32768)t+=String.fromCharCode(...e.subarray(n,n+32768));return btoa(t)}var Ne=e=>{let t=e.baseUrl.replace(Ht,""),r=()=>typeof e.token=="function"?e.token():e.token,n=async()=>({"content-type":"application/json",authorization:`Bearer ${await r()}`}),s=async(o,i)=>{try{let l=await fetch(`${t}${A}${o}`,{method:i.method,headers:await n(),...i.body===void 0?{}:{body:JSON.stringify(i.body)}});if(l.status===409){let u=await l.json().catch(()=>({}));throw new M(u.message??"Someone else saved this first.")}if(!l.ok){let u=await l.text().catch(()=>""),d=`${i.method} ${o} \u2192 ${String(l.status)}`;try{let c=JSON.parse(u);c.message&&(d=c.message)}catch{d=u?`${d}: ${u}`:d}throw x({error:d})}return await l.json()}catch(l){throw l instanceof M?l:x(l)}},a=o=>`/tables/${encodeURIComponent(o)}`;return{listTables:async()=>(await k(`${t}${A}/tables`,await n())).tables,listRows:async(o,i)=>await k(`${t}${A}${a(o)}/rows?limit=${String(i??100)}`,await n()),insertRow:async(o,i)=>{let{rowIds:l}=await s(`${a(o)}/rows`,{method:"POST",body:{rows:[i]}}),u=l[0];if(!u)throw x(new Error("The row was not created."));return u},patchRow:async(o,i,l)=>(await s(`${a(o)}/rows/${encodeURIComponent(i)}`,{method:"PATCH",body:l})).updated,deleteRow:async(o,i)=>(await s(`/${encodeURIComponent(o)}/${encodeURIComponent(i)}`,{method:"DELETE"})).deleted,listFiles:async()=>(await k(`${t}${A}/tables/files/rows?limit=200`,await n())).rows.map(i=>({id:i.rowId,filename:String(i.data.filename??""),source:String(i.data.source??"client"),campaign:String(i.data.campaign??""),size:typeof i.data.size=="number"?i.data.size:0,createdAt:i.createdAt})),uploadFile:async(o,i)=>{let l=new Uint8Array(await o.arrayBuffer());return await s("/files",{method:"POST",body:{filename:o.name,mime:o.type||"application/octet-stream",data:At(l),...i===void 0?{}:{message:i}}})},fileLink:async o=>await k(`${t}${A}/files/${encodeURIComponent(o)}/url`,await n()),deleteFile:async o=>(await s(`/files/${encodeURIComponent(o)}`,{method:"DELETE"})).deleted,listDocuments:async()=>(await k(`${t}${A}/documents`,await n())).documents,readDocument:async o=>(await k(`${t}${A}/documents/${encodeURIComponent(o)}`,await n())).document,saveDocument:async(o,i)=>await s(`/documents/${encodeURIComponent(o)}`,{method:"PATCH",body:i})}};var Mt=/\/+$/,$t="/api/v1/end-user",Ve=e=>{let t=e.baseUrl.replace(Mt,""),r=async(n,s)=>{let a;try{a=await fetch(`${t}${$t}${n}`,s===void 0?{}:{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(s)})}catch(o){throw x(o)}if(a.status===429)throw x({error:"rate_limited",retryable:!0});if(!a.ok)throw x({error:`shop_request_failed_${String(a.status)}`});try{return await a.json()}catch(o){throw x(o)}};return{listProducts:async()=>{let n=await r(`/shop/products?publishable_key=${encodeURIComponent(e.publishableKey)}`);return{products:n.products.map(s=>({...s,currency:typeof s.currency=="string"?s.currency:""})),truncated:n.truncated===!0}},apply:async n=>await r("/shop/apply",{publishable_key:e.publishableKey,name:n.name,email:n.email,...n.phone?{phone:n.phone}:{},...n.message?{message:n.message}:{},...n.productId?{productId:n.productId}:{}})}};var $=class extends Error{code;status;constructor(t,r,n){super(r),this.name="CreditRefused",this.code=t,this.status=n}},Wt=/\/+$/,Et="/api/v1/end-user",je=e=>{let t=e.baseUrl.replace(Wt,""),r=()=>typeof e.token=="function"?e.token():e.token,n=async(s,a={method:"GET"})=>{try{let o=await fetch(`${t}${Et}${s}`,{method:a.method,headers:{"content-type":"application/json",authorization:`Bearer ${await r()}`},...a.body===void 0?{}:{body:JSON.stringify(a.body)}});if(!o.ok){let i=await o.json().catch(()=>({}));throw new $(i.error??"request_failed",i.message??`${a.method} ${s} \u2192 ${String(o.status)}`,o.status)}return await o.json()}catch(o){throw o instanceof $?o:x(o)}};return{wallet:()=>n("/credits"),history:()=>n("/credits/history"),topup:s=>n("/credits/checkout",{method:"POST",body:{packId:s}}),checkout:s=>n("/shop/checkout",{method:"POST",body:s})}};var H=require("react"),Ge=e=>{let[t,r]=(0,H.useState)(null),[n,s]=(0,H.useState)(!0),[a,o]=(0,H.useState)(null),i=(0,H.useCallback)(async()=>{try{r(await e.wallet()),o(null)}catch{o("Couldn't read your balance just now.")}finally{s(!1)}},[e]),l=(0,H.useCallback)(()=>{i().catch(()=>{})},[i]);return(0,H.useEffect)(()=>(l(),window.addEventListener("focus",l),()=>{window.removeEventListener("focus",l)}),[l]),{wallet:t,loading:n,failure:a,refresh:l}};var Ot=new Set(["buy","ask","apply"]);function Be(e){return Ot.has(e.mode)?e.mode:"ask"}var _t={kind:"quoted"};function L(e,t){if(!t)return e.toLocaleString();if(t.toLowerCase()==="credits")return`${e.toLocaleString()} ${e===1?"credit":"credits"}`;let r=Number.isInteger(e)?0:2;try{return new Intl.NumberFormat(void 0,{style:"currency",currency:t,minimumFractionDigits:r,maximumFractionDigits:r}).format(e)}catch{return`${t} ${e.toLocaleString()}`}}function ze(e,t){let r=/^[a-z]+$/i.test(t)&&!t.endsWith("s")?"s":"";return`${e.toLocaleString()} ${t}${r}`}function Te(e,t){return e.kind==="quoted"?"Priced on enquiry":e.kind==="flat"?L(e.price,t):`${L(e.unitPrice,t)} per ${e.unitStep===1?e.unit:ze(e.unitStep,e.unit)}`}function qe(e){let t=e.currency,r=e.pricing;if(r.kind!=="variants")return Te(r,t);let n=r.variants.map(s=>s.price).filter(s=>typeof s=="number");return n.length>0?`From ${L(Math.min(...n),t)}`:"Priced on enquiry"}function Je(e,t){if(e.kind!=="variants")return e;let r=e.variants.find(n=>n.name===t);return typeof r?.price=="number"?{kind:"flat",price:r.price}:_t}function Ke(e,t){return e.kind==="flat"?e.price:e.kind==="per_unit"?e.unitPrice*Math.ceil(t/Math.max(e.unitStep,1)):null}function Xe(e,t){let r=t.kind==="per_unit"?Math.max(t.unitStep,1):1;return{min:Math.max(e.minQty??r,r),max:e.maxQty??null,step:r}}function Qe(e,t){let r=e.variants?.find(n=>n.name===t);return r&&r.includes.length>0?r.includes:e.includes}function Ye(e,t){let r=[];for(let n of e){let s=t(n).trim();s&&!r.includes(s)&&r.push(s)}return r}function Ze(e,t,r,n){let s=t?`${e.name} \u2014 ${t}`:e.name,a=r.kind==="per_unit"?`, ${ze(n,r.unit)}`:"";return`I'd like to buy ${s}${a}. How do I go ahead?`}function et(e){return e?(e&&typeof e=="object"&&"error"in e?String(e.error):"")==="rate_limited"?"That's a lot of looking at once \u2014 give it a moment, then reload.":"The shop isn't loading right now. Please try again shortly.":null}var D=require("react"),Lt=e=>e&&typeof e=="object"&&typeof e.error=="string"?e.error:e instanceof Error?e.message:"shop_unavailable",tt=e=>{let[t,r]=(0,D.useState)([]),[n,s]=(0,D.useState)(!1),[a,o]=(0,D.useState)(!0),[i,l]=(0,D.useState)(null),[u,d]=(0,D.useState)(0);(0,D.useEffect)(()=>{let m=!0;return o(!0),e.listProducts().then(p=>{m&&(r(p.products),s(p.truncated),l(null))}).catch(p=>{m&&l(Lt(p))}).finally(()=>{m&&o(!1)}),()=>{m=!1}},[e,u]);let c=(0,D.useCallback)(()=>d(m=>m+1),[]);return{products:t,truncated:n,loading:a,error:i,reload:c}};var P=require("react"),rt="greeting";function Re(e,t){if(e.some(a=>a.id===t.id))return e;let r=e.filter(a=>a.id!==rt),n=a=>a.author==="client"==(t.author==="client");return[...r.filter(a=>!(a.pending&&n(a)&&a.text===t.text)),t]}var nt=(e,t)=>{let[r,n]=(0,P.useState)([]),[s,a]=(0,P.useState)(""),[o,i]=(0,P.useState)(!1),[l,u]=(0,P.useState)(null),d=(0,P.useRef)(0),c=t?.pollMs??2e3;(0,P.useEffect)(()=>{let p=!0;return e.getInfo().then(y=>{p&&y.greeting&&n(w=>w.length===0?[{id:rt,cursor:"",author:"agent",text:y.greeting}]:w)}).catch(()=>{}),()=>{p=!1}},[e]),(0,P.useEffect)(()=>e.subscribe?.({onMessage:p=>n(y=>Re(y,p)),onError:p=>u(p.error),onHealthy:()=>u(null)},{intervalMs:c}),[e,c]);let m=(0,P.useCallback)(()=>{let p=s.trim();if(!p||o)return;a(""),u(null),i(!0),d.current+=1;let y=`pending-${d.current}`,w={id:y,cursor:"",author:"client",text:p,pending:!0};n(f=>[...f,w]),e.sendMessage(p).then(f=>{i(!1),f.reply.trim()&&n(g=>g.some(I=>!I.pending&&I.author!=="client"&&I.text===f.reply)?g:(d.current+=1,[...g,{id:`pending-agent-${d.current}`,cursor:"",author:"agent",text:f.reply,pending:!0}]))}).catch(f=>{u(f instanceof Error?f.message:"send_failed"),i(!1),n(R=>R.filter(g=>g.id!==y)),a(R=>R||p)})},[s,o,e]);return{messages:r,input:s,setInput:a,send:m,sending:o,error:l}};0&&(module.exports={Chat,CreditRefused,GRID_COLS,GRID_MAX_COLS,GRID_MAX_ROWS,HolaProvider,PortalConflict,bandOfKind,bandOfType,buyRequestText,cellValue,createApiTransport,createHolaClient,createPortalCredits,createPortalData,createPortalShop,createWidgetTransport,deliverableCellText,deliverableStatus,deriveFields,emptyTableResponses,facetValues,footprintOf,footprintWith,formatDeliverableDate,groupDeliverableVersions,includesFor,inferSpec,isDeliverableChecked,mergeMessage,modeOf,money,normalizeDeliverableColType,normalizeDeliverableItem,parseDashboardSpec,parseDeliverableItems,parseDeliverableTable,parseTableResponses,placeWidgets,priceFor,priceLabel,publishedVersionOf,quantityRange,renderModel,setResponse,setTableReview,shelfPriceLabel,shelfProblem,splitLayout,textDeltaOf,thinkingDeltaOf,toolEventOf,totalFor,useArtifactUrl,useChat,useCredits,useHolaClient,useShop,useThread});
package/dist/index.d.cts CHANGED
@@ -763,6 +763,263 @@ type PortalShop = {
763
763
  };
764
764
  declare const createPortalShop: (config: PortalShopConfig) => PortalShop;
765
765
 
766
+ /**
767
+ * A refusal this surface makes on purpose, carrying both halves of it.
768
+ *
769
+ * `toHolaError` reads only `.error` and `.retryable`, so routing these through it would keep the
770
+ * code and drop the sentence — and the sentence is the part worth showing. `insufficient_credits`
771
+ * NAMES THE SHORTFALL ("that costs 100 credits and you have 0; top up 100 more"), which is the whole
772
+ * of what the customer needs and strictly more than a portal could say for itself.
773
+ *
774
+ * The code is what a caller branches on, and the branches are not cosmetic: `insufficient_credits`
775
+ * is fixed by topping up, `stripe_not_connected` is the company's own setup and no amount of trying
776
+ * again will move it, `rate_limited` wants a pause, and a `pack_*` refusal means the list on screen
777
+ * is stale. Answering all of them with "please try again" is wrong for every one but the last.
778
+ */
779
+ declare class CreditRefused extends Error {
780
+ readonly code: string;
781
+ readonly status: number;
782
+ constructor(code: string, message: string, status: number);
783
+ }
784
+ /** One pack on sale: what it grants, and what it costs in real money.
785
+ *
786
+ * `credits` and `price` are different units and the pair is the point — 500 credits for $99 is a
787
+ * rate, not a discount. `currency` belongs to the PRICE; the balance those credits land in is
788
+ * denominated in credits and nothing else. */
789
+ type CreditPack = {
790
+ packId: string;
791
+ name: string;
792
+ credits: number;
793
+ price: number;
794
+ currency: string;
795
+ };
796
+ /** A top-up started and not finished. */
797
+ type PendingTopup = {
798
+ txnId: string;
799
+ credits: number;
800
+ packId: string | null;
801
+ /** The money is known to have arrived and only the grant is outstanding. The difference between
802
+ * "we are waiting for you" and "we are waiting for us", which a customer should never have to
803
+ * guess at. */
804
+ paid: boolean;
805
+ createdAt: string;
806
+ /** The server's own sentence for the state above. Rendered rather than re-derived: a second
807
+ * account of it written portal-side is one that can disagree with the first. */
808
+ note: string;
809
+ /** Where to go to finish paying, when there is somewhere.
810
+ *
811
+ * Stripe payment links neither expire nor refuse a second visit, so the one this top-up was
812
+ * minted with is still good. Null once `paid` — the money is in, and a link back to a payment
813
+ * page invites paying twice — and null for a top-up started before the link was recorded. */
814
+ resumeUrl?: string | null;
815
+ };
816
+ /** What the customer has, what they can buy, and what they have started. */
817
+ type CreditWallet = {
818
+ balance: number;
819
+ packs: CreditPack[];
820
+ pending: PendingTopup[];
821
+ /** What the BALANCE is in, which is `credits` however the shelf happens to be priced. */
822
+ currency: string;
823
+ /** What one unit of currency is worth in credits on this company's books — 1 means 1 credit = $1.
824
+ *
825
+ * Nominal by design: it is what values a credit-priced order on the operator's money surfaces,
826
+ * NOT what any particular customer paid, because two customers can legitimately pay different
827
+ * money for the same credit — that is what a volume bonus IS. So a portal may show the balance
828
+ * in money beside it, and should not present that figure as what they spent. */
829
+ bookRate?: number;
830
+ /** Whether this company prices in credits AT ALL.
831
+ *
832
+ * Ask this, never `packs.length`. An empty list is what a company selling for money gets (it is
833
+ * never asked) and equally what a credits company that has not priced a pack yet gets — and a
834
+ * portal reading the two as one hides its credits surface from the operator who has just turned
835
+ * credits on and gone looking for it. Optional, so a portal pointed at a backend older than the
836
+ * field still works; absent, the count is the only signal left. */
837
+ sellsCredits?: boolean;
838
+ };
839
+ /** One movement of the balance, with what it left the customer on. */
840
+ type CreditEntry = {
841
+ id: string;
842
+ /** Signed: negative spent it, positive added to it. The sign IS the direction, so a portal never
843
+ * has to decide which way a row goes from its reason. */
844
+ delta: number;
845
+ /** What they were on immediately AFTER this one — computed server-side by working backwards from
846
+ * the current balance, so it cannot disagree with the number at the top of the page. */
847
+ balance: number;
848
+ /** Why: `topup`, `purchase`, or whatever an operator recorded by hand. */
849
+ reason: string;
850
+ /** The order this bought, when it bought one. Null for a top-up or an adjustment. */
851
+ orderId: string | null;
852
+ /** That order's name, when it still exists. Absent for a top-up, and absent for an order deleted
853
+ * since — a ledger row for a purchase that happened is not made wrong by that, so it falls back
854
+ * to a generic label rather than disappearing or showing a row id. */
855
+ orderName?: string;
856
+ createdAt: string;
857
+ };
858
+ /** What a balance has taken in and paid out over its whole life. Both POSITIVE — a customer reads
859
+ * "spent 1,275", not "spent −1,275". */
860
+ type CreditTotals = {
861
+ purchased: number;
862
+ spent: number;
863
+ };
864
+ type CreditHistory = {
865
+ entries: CreditEntry[];
866
+ totals: CreditTotals;
867
+ /** The same figure `wallet()` answers, returned here so a page drawing both cannot show two. */
868
+ balance: number;
869
+ };
870
+ /** A started top-up: where to pay, and what it will grant. */
871
+ type TopupStarted = {
872
+ /** The Stripe payment link. It ends on Stripe's own confirmation page and never returns here, so
873
+ * open it in a NEW TAB and leave the portal standing — and re-read the wallet when the customer
874
+ * comes back, because the credits land on the webhook and not on their return. */
875
+ url: string;
876
+ txnId: string;
877
+ credits: number;
878
+ amount: number;
879
+ currency: string;
880
+ /** This handed back a link the customer already had rather than minting another. Not an error and
881
+ * usually not worth saying out loud — the same tab opens either way. */
882
+ resumed?: boolean;
883
+ };
884
+ /** What a purchase comes back as. Every figure is the server's own: a quantity in the request is a
885
+ * request and never a price, so the amount is recomputed from the product row. */
886
+ type Purchased = {
887
+ /** The order the credits bought, ready to open at `/orders/:orderId`. */
888
+ orderId: string;
889
+ /** Credits actually taken, at the price the server recomputed. */
890
+ credits: number;
891
+ /** What is left afterwards. */
892
+ balance: number;
893
+ /** What the order is worth in money at the company's book rate — the figure that lands on the
894
+ * operator's money surfaces. NOT what the customer paid: they paid credits. */
895
+ value: number;
896
+ };
897
+ type PortalCredits = {
898
+ /** Balance, packs and anything in flight — one call, because they are one question. A balance
899
+ * without the packs cannot be acted on, and a balance without the pending top-ups looks wrong to
900
+ * anyone who has just paid. */
901
+ wallet(): Promise<CreditWallet>;
902
+ /** Start buying a pack, by ID alone — the price is read from the pack row server-side, so there
903
+ * is no amount here for a client to choose. */
904
+ topup(packId: string): Promise<TopupStarted>;
905
+ /** The ledger behind the balance. Its OWN call, not part of `wallet()`: the wallet is read on
906
+ * every page that draws a balance, and hanging a fifty-row scan off it would make the cheapest
907
+ * read on this surface the most expensive one. */
908
+ history(): Promise<CreditHistory>;
909
+ /**
910
+ * Buy something from the shelf.
911
+ *
912
+ * NOT a redirect. On a credits shelf the money moved at the top-up, so this is a synchronous
913
+ * debit: it takes the credits, writes the order and its services, and answers `Purchased`.
914
+ *
915
+ * Refuses with `insufficient_credits` when they cannot cover it, and that refusal names the
916
+ * shortfall — it is the one message worth showing verbatim, because "not enough credits" is all a
917
+ * portal could say for itself.
918
+ */
919
+ checkout(purchase: {
920
+ productId: string;
921
+ variant?: string;
922
+ qty?: number;
923
+ }): Promise<Purchased>;
924
+ };
925
+ declare const createPortalCredits: (config: ApiTransportConfig) => PortalCredits;
926
+
927
+ type UseCredits = {
928
+ wallet: CreditWallet | null;
929
+ /** The FIRST read only. A refresh keeps the numbers on screen and swaps them when the answer
930
+ * lands: blanking a balance somebody is reading, to show a spinner, to show the same balance
931
+ * again, is a flicker that reads as a fault. */
932
+ loading: boolean;
933
+ failure: string | null;
934
+ refresh: () => void;
935
+ };
936
+ declare const useCredits: (credits: PortalCredits) => UseCredits;
937
+
938
+ /**
939
+ * How this product is taken.
940
+ *
941
+ * The wire carries the row's own value rather than the union, because a product authored before
942
+ * the field existed answers `""`. A shelf that switched on the three names and fell through would
943
+ * render a product with no action at all, so an unrecognised mode becomes `ask`: it is the one
944
+ * path that needs no money, writes nothing, and always has somebody at the other end of it.
945
+ */
946
+ declare function modeOf(product: ShopProduct): ShopMode;
947
+ /** The price that applies once a tier has been chosen. A tiered product is not a price until then;
948
+ * every other shape already was one. */
949
+ type ChosenPrice = {
950
+ kind: "flat";
951
+ price: number;
952
+ } | {
953
+ kind: "per_unit";
954
+ unit: string;
955
+ unitPrice: number;
956
+ unitStep: number;
957
+ } | {
958
+ kind: "quoted";
959
+ };
960
+ /**
961
+ * The figure the shelf carries, printed in the unit the ORG prices in.
962
+ *
963
+ * `currency` comes off the shelf payload and from nowhere else. It used to be a line of portal
964
+ * config on the portal itself, which is a portal guessing at somebody else's rate card: the
965
+ * numbers belong to the org and so does what they MEAN, and those two travelling separately is how
966
+ * a catalogue ends up wrong by an exchange rate. An ISO code prints money; the literal "credits"
967
+ * prints credits, which is the other unit an operator can price in.
968
+ *
969
+ * A shelf that names no unit prints the bare figure. That is a backend older than the field, and an
970
+ * ambiguous number is a far smaller lie than a confident "$" in front of a price in RMB.
971
+ *
972
+ * An unusable code is caught rather than left to throw: one bad value would otherwise raise a
973
+ * RangeError from inside a price label and take the whole shelf down with it.
974
+ */
975
+ declare function money(amount: number, currency: string): string;
976
+ /** What a customer is quoted, in words. `quoted` is deliberately not a number: it is the honest
977
+ * answer for a catalogue line that reads `20k+` or 待定, and it must never sit behind a button
978
+ * that cannot compute a total. */
979
+ declare function priceLabel(price: ChosenPrice, currency: string): string;
980
+ /** The one line a card shows about money. A tiered product is a RANGE until a tier is picked, so
981
+ * the card says "From" and the product page says which — a card that printed one tier's figure
982
+ * would be quoting a price that half the buyers do not pay. */
983
+ declare function shelfPriceLabel(product: ShopProduct): string;
984
+ /** The chosen tier's price, matched to it BY NAME — the tier's scope and the tier's money are two
985
+ * fields on the wire, and this is the join. A tier nobody priced is quoted, which is a real state:
986
+ * 基础 / 标准 published, 高阶 still being costed. */
987
+ declare function priceFor(pricing: ShopPricing, variant: string | null): ChosenPrice;
988
+ /** What the customer would pay for `qty` units, or null where there is no total to compute. Steps,
989
+ * not units: 50 upvotes at a time is what is actually sold, so a request for 60 is charged as two
990
+ * steps — the same arithmetic the server does when it recomputes this from the row. */
991
+ declare function totalFor(price: ChosenPrice, qty: number): number | null;
992
+ /** How much of a per-unit product may be bought, and in what increments. The bounds are the
993
+ * product's own, and they are shown as well as enforced: a customer who hits a limit they were
994
+ * never told about reads it as a broken shop rather than a rule. */
995
+ declare function quantityRange(product: ShopProduct, price: ChosenPrice): {
996
+ min: number;
997
+ max: number | null;
998
+ step: number;
999
+ };
1000
+ /**
1001
+ * What the chosen tier covers.
1002
+ *
1003
+ * A tier with nothing listed falls back to the product's own inclusions rather than showing an
1004
+ * empty list. That is not a guess: `variants` is authored only where the tiers DIFFER in scope, so
1005
+ * a tier that lists nothing is one that adds nothing to what the product already says it includes —
1006
+ * and an empty "What's included" reads as a bundle containing nothing at all.
1007
+ */
1008
+ declare function includesFor(product: ShopProduct, variant: string | null): ShopInclusion[];
1009
+ /** The values a facet actually has on this shelf, in the operator's own order. Not sorted: `sort`
1010
+ * on the product rows is a decision somebody made about what to show first, and re-ordering these
1011
+ * alphabetically throws it away. Products with the facet unset are simply not counted. */
1012
+ declare function facetValues(products: ShopProduct[], of: (product: ShopProduct) => string): string[];
1013
+ /** The message a "buy this" enquiry sends when a portal cannot take the money itself.
1014
+ *
1015
+ * Named rather than described by id: an operator reads this in the same thread as everything else,
1016
+ * and a row id is not a thing anyone can answer. It is a SENTENCE and not a product because the
1017
+ * same text opens the apply form for a signed-out visitor — a request that read differently
1018
+ * depending on which door it came through would be two requests to reconcile.
1019
+ */
1020
+ declare function buyRequestText(product: ShopProduct, variant: string | null, price: ChosenPrice, qty: number): string;
1021
+ declare function shelfProblem(error: unknown): string | null;
1022
+
766
1023
  /** Provides a `HolaClient` (from `createHolaClient`) to `useChat` / `<Chat/>`.
767
1024
  * Create the client once (e.g. `useMemo`) so its session persists across renders. */
768
1025
  declare const HolaProvider: ({ client, children, }: {
@@ -836,4 +1093,4 @@ declare const useThread: (client: HolaClient, options?: {
836
1093
  pollMs?: number;
837
1094
  }) => UseThread;
838
1095
 
839
- export { type Agg, type ApiTransportConfig, type Band, type ChartView, Chat, type ChatMessage, type CreateHolaClientOptions, type DashboardLayout, type DashboardSpec, type DataSource, type DeliverableColType, type DeliverableColumn, type DeliverableItem, type DeliverableItemKind, type DeliverableReviewState, type DeliverableRow, type DeliverableTable, type DeliverableVersion, type DonutWidget, GRID_COLS, GRID_MAX_COLS, GRID_MAX_ROWS, type HolaArtifact, type HolaAuthor, type HolaClient, type HolaCompletion, type HolaEmployeeInfo, type HolaError, type HolaIdentity, type HolaMessage, HolaProvider, type HolaStreamHandlers, type HolaSubscribeHandlers, type HolaSubscribeOptions, type HolaToolEvent, type HolaTransport, type PlacedWidget, type Point, PortalConflict, type PortalData, type PortalDocument, type PortalDocumentSummary, type PortalField, type PortalFile, type PortalRow, type PortalRowAuthor, type PortalRowPage, type PortalShop, type PortalShopConfig, type PortalTable, type ResolvedWidget, type SeriesWidget, type ShopApplication, type ShopApplyResult, type ShopInclusion, type ShopMode, type ShopPricing, type ShopProduct, type ShopShelf, type ShopVariant, type StatView, type StatWidget, type TableResponses, type TableReviewVerdict, type TableWidget, type TextWidget, type ThreadMessage, type UseChat, type UseShop, type UseThread, type Widget, type WidgetTransportConfig, type WidgetType, bandOfKind, bandOfType, cellValue, createApiTransport, createHolaClient, createPortalData, createPortalShop, createWidgetTransport, deliverableCellText, deliverableStatus, deriveFields, emptyTableResponses, footprintOf, footprintWith, formatDeliverableDate, groupDeliverableVersions, inferSpec, isDeliverableChecked, mergeMessage, normalizeDeliverableColType, normalizeDeliverableItem, parseDashboardSpec, parseDeliverableItems, parseDeliverableTable, parseTableResponses, placeWidgets, publishedVersionOf, renderModel, setResponse, setTableReview, splitLayout, textDeltaOf, thinkingDeltaOf, toolEventOf, useArtifactUrl, useChat, useHolaClient, useShop, useThread };
1096
+ export { type Agg, type ApiTransportConfig, type Band, type ChartView, Chat, type ChatMessage, type ChosenPrice, type CreateHolaClientOptions, type CreditEntry, type CreditHistory, type CreditPack, CreditRefused, type CreditTotals, type CreditWallet, type DashboardLayout, type DashboardSpec, type DataSource, type DeliverableColType, type DeliverableColumn, type DeliverableItem, type DeliverableItemKind, type DeliverableReviewState, type DeliverableRow, type DeliverableTable, type DeliverableVersion, type DonutWidget, GRID_COLS, GRID_MAX_COLS, GRID_MAX_ROWS, type HolaArtifact, type HolaAuthor, type HolaClient, type HolaCompletion, type HolaEmployeeInfo, type HolaError, type HolaIdentity, type HolaMessage, HolaProvider, type HolaStreamHandlers, type HolaSubscribeHandlers, type HolaSubscribeOptions, type HolaToolEvent, type HolaTransport, type PendingTopup, type PlacedWidget, type Point, PortalConflict, type PortalCredits, type PortalData, type PortalDocument, type PortalDocumentSummary, type PortalField, type PortalFile, type PortalRow, type PortalRowAuthor, type PortalRowPage, type PortalShop, type PortalShopConfig, type PortalTable, type Purchased, type ResolvedWidget, type SeriesWidget, type ShopApplication, type ShopApplyResult, type ShopInclusion, type ShopMode, type ShopPricing, type ShopProduct, type ShopShelf, type ShopVariant, type StatView, type StatWidget, type TableResponses, type TableReviewVerdict, type TableWidget, type TextWidget, type ThreadMessage, type TopupStarted, type UseChat, type UseCredits, type UseShop, type UseThread, type Widget, type WidgetTransportConfig, type WidgetType, bandOfKind, bandOfType, buyRequestText, cellValue, createApiTransport, createHolaClient, createPortalCredits, createPortalData, createPortalShop, createWidgetTransport, deliverableCellText, deliverableStatus, deriveFields, emptyTableResponses, facetValues, footprintOf, footprintWith, formatDeliverableDate, groupDeliverableVersions, includesFor, inferSpec, isDeliverableChecked, mergeMessage, modeOf, money, normalizeDeliverableColType, normalizeDeliverableItem, parseDashboardSpec, parseDeliverableItems, parseDeliverableTable, parseTableResponses, placeWidgets, priceFor, priceLabel, publishedVersionOf, quantityRange, renderModel, setResponse, setTableReview, shelfPriceLabel, shelfProblem, splitLayout, textDeltaOf, thinkingDeltaOf, toolEventOf, totalFor, useArtifactUrl, useChat, useCredits, useHolaClient, useShop, useThread };
package/dist/index.d.ts CHANGED
@@ -763,6 +763,263 @@ type PortalShop = {
763
763
  };
764
764
  declare const createPortalShop: (config: PortalShopConfig) => PortalShop;
765
765
 
766
+ /**
767
+ * A refusal this surface makes on purpose, carrying both halves of it.
768
+ *
769
+ * `toHolaError` reads only `.error` and `.retryable`, so routing these through it would keep the
770
+ * code and drop the sentence — and the sentence is the part worth showing. `insufficient_credits`
771
+ * NAMES THE SHORTFALL ("that costs 100 credits and you have 0; top up 100 more"), which is the whole
772
+ * of what the customer needs and strictly more than a portal could say for itself.
773
+ *
774
+ * The code is what a caller branches on, and the branches are not cosmetic: `insufficient_credits`
775
+ * is fixed by topping up, `stripe_not_connected` is the company's own setup and no amount of trying
776
+ * again will move it, `rate_limited` wants a pause, and a `pack_*` refusal means the list on screen
777
+ * is stale. Answering all of them with "please try again" is wrong for every one but the last.
778
+ */
779
+ declare class CreditRefused extends Error {
780
+ readonly code: string;
781
+ readonly status: number;
782
+ constructor(code: string, message: string, status: number);
783
+ }
784
+ /** One pack on sale: what it grants, and what it costs in real money.
785
+ *
786
+ * `credits` and `price` are different units and the pair is the point — 500 credits for $99 is a
787
+ * rate, not a discount. `currency` belongs to the PRICE; the balance those credits land in is
788
+ * denominated in credits and nothing else. */
789
+ type CreditPack = {
790
+ packId: string;
791
+ name: string;
792
+ credits: number;
793
+ price: number;
794
+ currency: string;
795
+ };
796
+ /** A top-up started and not finished. */
797
+ type PendingTopup = {
798
+ txnId: string;
799
+ credits: number;
800
+ packId: string | null;
801
+ /** The money is known to have arrived and only the grant is outstanding. The difference between
802
+ * "we are waiting for you" and "we are waiting for us", which a customer should never have to
803
+ * guess at. */
804
+ paid: boolean;
805
+ createdAt: string;
806
+ /** The server's own sentence for the state above. Rendered rather than re-derived: a second
807
+ * account of it written portal-side is one that can disagree with the first. */
808
+ note: string;
809
+ /** Where to go to finish paying, when there is somewhere.
810
+ *
811
+ * Stripe payment links neither expire nor refuse a second visit, so the one this top-up was
812
+ * minted with is still good. Null once `paid` — the money is in, and a link back to a payment
813
+ * page invites paying twice — and null for a top-up started before the link was recorded. */
814
+ resumeUrl?: string | null;
815
+ };
816
+ /** What the customer has, what they can buy, and what they have started. */
817
+ type CreditWallet = {
818
+ balance: number;
819
+ packs: CreditPack[];
820
+ pending: PendingTopup[];
821
+ /** What the BALANCE is in, which is `credits` however the shelf happens to be priced. */
822
+ currency: string;
823
+ /** What one unit of currency is worth in credits on this company's books — 1 means 1 credit = $1.
824
+ *
825
+ * Nominal by design: it is what values a credit-priced order on the operator's money surfaces,
826
+ * NOT what any particular customer paid, because two customers can legitimately pay different
827
+ * money for the same credit — that is what a volume bonus IS. So a portal may show the balance
828
+ * in money beside it, and should not present that figure as what they spent. */
829
+ bookRate?: number;
830
+ /** Whether this company prices in credits AT ALL.
831
+ *
832
+ * Ask this, never `packs.length`. An empty list is what a company selling for money gets (it is
833
+ * never asked) and equally what a credits company that has not priced a pack yet gets — and a
834
+ * portal reading the two as one hides its credits surface from the operator who has just turned
835
+ * credits on and gone looking for it. Optional, so a portal pointed at a backend older than the
836
+ * field still works; absent, the count is the only signal left. */
837
+ sellsCredits?: boolean;
838
+ };
839
+ /** One movement of the balance, with what it left the customer on. */
840
+ type CreditEntry = {
841
+ id: string;
842
+ /** Signed: negative spent it, positive added to it. The sign IS the direction, so a portal never
843
+ * has to decide which way a row goes from its reason. */
844
+ delta: number;
845
+ /** What they were on immediately AFTER this one — computed server-side by working backwards from
846
+ * the current balance, so it cannot disagree with the number at the top of the page. */
847
+ balance: number;
848
+ /** Why: `topup`, `purchase`, or whatever an operator recorded by hand. */
849
+ reason: string;
850
+ /** The order this bought, when it bought one. Null for a top-up or an adjustment. */
851
+ orderId: string | null;
852
+ /** That order's name, when it still exists. Absent for a top-up, and absent for an order deleted
853
+ * since — a ledger row for a purchase that happened is not made wrong by that, so it falls back
854
+ * to a generic label rather than disappearing or showing a row id. */
855
+ orderName?: string;
856
+ createdAt: string;
857
+ };
858
+ /** What a balance has taken in and paid out over its whole life. Both POSITIVE — a customer reads
859
+ * "spent 1,275", not "spent −1,275". */
860
+ type CreditTotals = {
861
+ purchased: number;
862
+ spent: number;
863
+ };
864
+ type CreditHistory = {
865
+ entries: CreditEntry[];
866
+ totals: CreditTotals;
867
+ /** The same figure `wallet()` answers, returned here so a page drawing both cannot show two. */
868
+ balance: number;
869
+ };
870
+ /** A started top-up: where to pay, and what it will grant. */
871
+ type TopupStarted = {
872
+ /** The Stripe payment link. It ends on Stripe's own confirmation page and never returns here, so
873
+ * open it in a NEW TAB and leave the portal standing — and re-read the wallet when the customer
874
+ * comes back, because the credits land on the webhook and not on their return. */
875
+ url: string;
876
+ txnId: string;
877
+ credits: number;
878
+ amount: number;
879
+ currency: string;
880
+ /** This handed back a link the customer already had rather than minting another. Not an error and
881
+ * usually not worth saying out loud — the same tab opens either way. */
882
+ resumed?: boolean;
883
+ };
884
+ /** What a purchase comes back as. Every figure is the server's own: a quantity in the request is a
885
+ * request and never a price, so the amount is recomputed from the product row. */
886
+ type Purchased = {
887
+ /** The order the credits bought, ready to open at `/orders/:orderId`. */
888
+ orderId: string;
889
+ /** Credits actually taken, at the price the server recomputed. */
890
+ credits: number;
891
+ /** What is left afterwards. */
892
+ balance: number;
893
+ /** What the order is worth in money at the company's book rate — the figure that lands on the
894
+ * operator's money surfaces. NOT what the customer paid: they paid credits. */
895
+ value: number;
896
+ };
897
+ type PortalCredits = {
898
+ /** Balance, packs and anything in flight — one call, because they are one question. A balance
899
+ * without the packs cannot be acted on, and a balance without the pending top-ups looks wrong to
900
+ * anyone who has just paid. */
901
+ wallet(): Promise<CreditWallet>;
902
+ /** Start buying a pack, by ID alone — the price is read from the pack row server-side, so there
903
+ * is no amount here for a client to choose. */
904
+ topup(packId: string): Promise<TopupStarted>;
905
+ /** The ledger behind the balance. Its OWN call, not part of `wallet()`: the wallet is read on
906
+ * every page that draws a balance, and hanging a fifty-row scan off it would make the cheapest
907
+ * read on this surface the most expensive one. */
908
+ history(): Promise<CreditHistory>;
909
+ /**
910
+ * Buy something from the shelf.
911
+ *
912
+ * NOT a redirect. On a credits shelf the money moved at the top-up, so this is a synchronous
913
+ * debit: it takes the credits, writes the order and its services, and answers `Purchased`.
914
+ *
915
+ * Refuses with `insufficient_credits` when they cannot cover it, and that refusal names the
916
+ * shortfall — it is the one message worth showing verbatim, because "not enough credits" is all a
917
+ * portal could say for itself.
918
+ */
919
+ checkout(purchase: {
920
+ productId: string;
921
+ variant?: string;
922
+ qty?: number;
923
+ }): Promise<Purchased>;
924
+ };
925
+ declare const createPortalCredits: (config: ApiTransportConfig) => PortalCredits;
926
+
927
+ type UseCredits = {
928
+ wallet: CreditWallet | null;
929
+ /** The FIRST read only. A refresh keeps the numbers on screen and swaps them when the answer
930
+ * lands: blanking a balance somebody is reading, to show a spinner, to show the same balance
931
+ * again, is a flicker that reads as a fault. */
932
+ loading: boolean;
933
+ failure: string | null;
934
+ refresh: () => void;
935
+ };
936
+ declare const useCredits: (credits: PortalCredits) => UseCredits;
937
+
938
+ /**
939
+ * How this product is taken.
940
+ *
941
+ * The wire carries the row's own value rather than the union, because a product authored before
942
+ * the field existed answers `""`. A shelf that switched on the three names and fell through would
943
+ * render a product with no action at all, so an unrecognised mode becomes `ask`: it is the one
944
+ * path that needs no money, writes nothing, and always has somebody at the other end of it.
945
+ */
946
+ declare function modeOf(product: ShopProduct): ShopMode;
947
+ /** The price that applies once a tier has been chosen. A tiered product is not a price until then;
948
+ * every other shape already was one. */
949
+ type ChosenPrice = {
950
+ kind: "flat";
951
+ price: number;
952
+ } | {
953
+ kind: "per_unit";
954
+ unit: string;
955
+ unitPrice: number;
956
+ unitStep: number;
957
+ } | {
958
+ kind: "quoted";
959
+ };
960
+ /**
961
+ * The figure the shelf carries, printed in the unit the ORG prices in.
962
+ *
963
+ * `currency` comes off the shelf payload and from nowhere else. It used to be a line of portal
964
+ * config on the portal itself, which is a portal guessing at somebody else's rate card: the
965
+ * numbers belong to the org and so does what they MEAN, and those two travelling separately is how
966
+ * a catalogue ends up wrong by an exchange rate. An ISO code prints money; the literal "credits"
967
+ * prints credits, which is the other unit an operator can price in.
968
+ *
969
+ * A shelf that names no unit prints the bare figure. That is a backend older than the field, and an
970
+ * ambiguous number is a far smaller lie than a confident "$" in front of a price in RMB.
971
+ *
972
+ * An unusable code is caught rather than left to throw: one bad value would otherwise raise a
973
+ * RangeError from inside a price label and take the whole shelf down with it.
974
+ */
975
+ declare function money(amount: number, currency: string): string;
976
+ /** What a customer is quoted, in words. `quoted` is deliberately not a number: it is the honest
977
+ * answer for a catalogue line that reads `20k+` or 待定, and it must never sit behind a button
978
+ * that cannot compute a total. */
979
+ declare function priceLabel(price: ChosenPrice, currency: string): string;
980
+ /** The one line a card shows about money. A tiered product is a RANGE until a tier is picked, so
981
+ * the card says "From" and the product page says which — a card that printed one tier's figure
982
+ * would be quoting a price that half the buyers do not pay. */
983
+ declare function shelfPriceLabel(product: ShopProduct): string;
984
+ /** The chosen tier's price, matched to it BY NAME — the tier's scope and the tier's money are two
985
+ * fields on the wire, and this is the join. A tier nobody priced is quoted, which is a real state:
986
+ * 基础 / 标准 published, 高阶 still being costed. */
987
+ declare function priceFor(pricing: ShopPricing, variant: string | null): ChosenPrice;
988
+ /** What the customer would pay for `qty` units, or null where there is no total to compute. Steps,
989
+ * not units: 50 upvotes at a time is what is actually sold, so a request for 60 is charged as two
990
+ * steps — the same arithmetic the server does when it recomputes this from the row. */
991
+ declare function totalFor(price: ChosenPrice, qty: number): number | null;
992
+ /** How much of a per-unit product may be bought, and in what increments. The bounds are the
993
+ * product's own, and they are shown as well as enforced: a customer who hits a limit they were
994
+ * never told about reads it as a broken shop rather than a rule. */
995
+ declare function quantityRange(product: ShopProduct, price: ChosenPrice): {
996
+ min: number;
997
+ max: number | null;
998
+ step: number;
999
+ };
1000
+ /**
1001
+ * What the chosen tier covers.
1002
+ *
1003
+ * A tier with nothing listed falls back to the product's own inclusions rather than showing an
1004
+ * empty list. That is not a guess: `variants` is authored only where the tiers DIFFER in scope, so
1005
+ * a tier that lists nothing is one that adds nothing to what the product already says it includes —
1006
+ * and an empty "What's included" reads as a bundle containing nothing at all.
1007
+ */
1008
+ declare function includesFor(product: ShopProduct, variant: string | null): ShopInclusion[];
1009
+ /** The values a facet actually has on this shelf, in the operator's own order. Not sorted: `sort`
1010
+ * on the product rows is a decision somebody made about what to show first, and re-ordering these
1011
+ * alphabetically throws it away. Products with the facet unset are simply not counted. */
1012
+ declare function facetValues(products: ShopProduct[], of: (product: ShopProduct) => string): string[];
1013
+ /** The message a "buy this" enquiry sends when a portal cannot take the money itself.
1014
+ *
1015
+ * Named rather than described by id: an operator reads this in the same thread as everything else,
1016
+ * and a row id is not a thing anyone can answer. It is a SENTENCE and not a product because the
1017
+ * same text opens the apply form for a signed-out visitor — a request that read differently
1018
+ * depending on which door it came through would be two requests to reconcile.
1019
+ */
1020
+ declare function buyRequestText(product: ShopProduct, variant: string | null, price: ChosenPrice, qty: number): string;
1021
+ declare function shelfProblem(error: unknown): string | null;
1022
+
766
1023
  /** Provides a `HolaClient` (from `createHolaClient`) to `useChat` / `<Chat/>`.
767
1024
  * Create the client once (e.g. `useMemo`) so its session persists across renders. */
768
1025
  declare const HolaProvider: ({ client, children, }: {
@@ -836,4 +1093,4 @@ declare const useThread: (client: HolaClient, options?: {
836
1093
  pollMs?: number;
837
1094
  }) => UseThread;
838
1095
 
839
- export { type Agg, type ApiTransportConfig, type Band, type ChartView, Chat, type ChatMessage, type CreateHolaClientOptions, type DashboardLayout, type DashboardSpec, type DataSource, type DeliverableColType, type DeliverableColumn, type DeliverableItem, type DeliverableItemKind, type DeliverableReviewState, type DeliverableRow, type DeliverableTable, type DeliverableVersion, type DonutWidget, GRID_COLS, GRID_MAX_COLS, GRID_MAX_ROWS, type HolaArtifact, type HolaAuthor, type HolaClient, type HolaCompletion, type HolaEmployeeInfo, type HolaError, type HolaIdentity, type HolaMessage, HolaProvider, type HolaStreamHandlers, type HolaSubscribeHandlers, type HolaSubscribeOptions, type HolaToolEvent, type HolaTransport, type PlacedWidget, type Point, PortalConflict, type PortalData, type PortalDocument, type PortalDocumentSummary, type PortalField, type PortalFile, type PortalRow, type PortalRowAuthor, type PortalRowPage, type PortalShop, type PortalShopConfig, type PortalTable, type ResolvedWidget, type SeriesWidget, type ShopApplication, type ShopApplyResult, type ShopInclusion, type ShopMode, type ShopPricing, type ShopProduct, type ShopShelf, type ShopVariant, type StatView, type StatWidget, type TableResponses, type TableReviewVerdict, type TableWidget, type TextWidget, type ThreadMessage, type UseChat, type UseShop, type UseThread, type Widget, type WidgetTransportConfig, type WidgetType, bandOfKind, bandOfType, cellValue, createApiTransport, createHolaClient, createPortalData, createPortalShop, createWidgetTransport, deliverableCellText, deliverableStatus, deriveFields, emptyTableResponses, footprintOf, footprintWith, formatDeliverableDate, groupDeliverableVersions, inferSpec, isDeliverableChecked, mergeMessage, normalizeDeliverableColType, normalizeDeliverableItem, parseDashboardSpec, parseDeliverableItems, parseDeliverableTable, parseTableResponses, placeWidgets, publishedVersionOf, renderModel, setResponse, setTableReview, splitLayout, textDeltaOf, thinkingDeltaOf, toolEventOf, useArtifactUrl, useChat, useHolaClient, useShop, useThread };
1096
+ export { type Agg, type ApiTransportConfig, type Band, type ChartView, Chat, type ChatMessage, type ChosenPrice, type CreateHolaClientOptions, type CreditEntry, type CreditHistory, type CreditPack, CreditRefused, type CreditTotals, type CreditWallet, type DashboardLayout, type DashboardSpec, type DataSource, type DeliverableColType, type DeliverableColumn, type DeliverableItem, type DeliverableItemKind, type DeliverableReviewState, type DeliverableRow, type DeliverableTable, type DeliverableVersion, type DonutWidget, GRID_COLS, GRID_MAX_COLS, GRID_MAX_ROWS, type HolaArtifact, type HolaAuthor, type HolaClient, type HolaCompletion, type HolaEmployeeInfo, type HolaError, type HolaIdentity, type HolaMessage, HolaProvider, type HolaStreamHandlers, type HolaSubscribeHandlers, type HolaSubscribeOptions, type HolaToolEvent, type HolaTransport, type PendingTopup, type PlacedWidget, type Point, PortalConflict, type PortalCredits, type PortalData, type PortalDocument, type PortalDocumentSummary, type PortalField, type PortalFile, type PortalRow, type PortalRowAuthor, type PortalRowPage, type PortalShop, type PortalShopConfig, type PortalTable, type Purchased, type ResolvedWidget, type SeriesWidget, type ShopApplication, type ShopApplyResult, type ShopInclusion, type ShopMode, type ShopPricing, type ShopProduct, type ShopShelf, type ShopVariant, type StatView, type StatWidget, type TableResponses, type TableReviewVerdict, type TableWidget, type TextWidget, type ThreadMessage, type TopupStarted, type UseChat, type UseCredits, type UseShop, type UseThread, type Widget, type WidgetTransportConfig, type WidgetType, bandOfKind, bandOfType, buyRequestText, cellValue, createApiTransport, createHolaClient, createPortalCredits, createPortalData, createPortalShop, createWidgetTransport, deliverableCellText, deliverableStatus, deriveFields, emptyTableResponses, facetValues, footprintOf, footprintWith, formatDeliverableDate, groupDeliverableVersions, includesFor, inferSpec, isDeliverableChecked, mergeMessage, modeOf, money, normalizeDeliverableColType, normalizeDeliverableItem, parseDashboardSpec, parseDeliverableItems, parseDeliverableTable, parseTableResponses, placeWidgets, priceFor, priceLabel, publishedVersionOf, quantityRange, renderModel, setResponse, setTableReview, shelfPriceLabel, shelfProblem, splitLayout, textDeltaOf, thinkingDeltaOf, toolEventOf, totalFor, useArtifactUrl, useChat, useCredits, useHolaClient, useShop, useThread };
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  'use client'
2
- var Y=e=>{if(!e||typeof e!="object")return null;let t=e;return t.type==="message_update"?t.assistantMessageEvent??null:null},_=e=>{let t=Y(e);return t?.type==="text_delta"&&typeof t.delta=="string"?t.delta:null},O=e=>{let t=Y(e);return t?.type==="thinking_delta"&&typeof t.delta=="string"?t.delta:null},U=e=>{if(!e||typeof e!="object")return null;let t=e;return t.type==="tool_execution_start"&&t.toolCallId?{phase:"start",id:t.toolCallId,name:t.toolName}:t.type==="tool_execution_end"&&t.toolCallId?{phase:"end",id:t.toolCallId,isError:t.isError}:null};var Ee=/^ /,w=e=>{if(e&&typeof e=="object"){let t=e,o=typeof t.error=="string"?t.error:"request_failed";return typeof t.retryable=="boolean"?{error:o,retryable:t.retryable}:{error:o}}return{error:"request_failed"}},$e=e=>{let t="message",o=[];for(let r of e.split(`
3
- `))r.startsWith(":")||(r.startsWith("event:")?t=r.slice(6).trim():r.startsWith("data:")&&o.push(r.slice(5).replace(Ee,"")));return o.length>0?{event:t,data:o.join(`
4
- `)}:null},_e=(e,t,o)=>{let r;try{r=JSON.parse(e.data)}catch{return}if(e.event==="session"){let l=r.sessionId;l&&(o(l),t.onSession?.(l));return}if(e.event==="turn_event"){t.onEvent?.(r);let l=_(r);l&&t.onText?.(l);let i=O(r);i&&t.onThinking?.(i);let n=U(r);n&&t.onTool?.(n);return}if(e.event==="chat_completed"){let l=r;o(l.sessionId),t.onComplete?.(l);return}e.event==="chat_error"&&t.onError?.(w(r))},v=async(e,t)=>{let o=await fetch(e,{headers:t});if(!o.ok)throw new Error(`hola: request failed (${o.status})`);return await o.json()},Z=async e=>{let t=await fetch(e.url,{method:"POST",headers:e.headers,body:e.body});if(!t.ok)throw new Error(`hola: message failed (${t.status})`);return await t.json()},ee=async(e,t,o,r)=>{let l=await fetch(e.url,{method:"POST",headers:e.headers,body:e.body,signal:r});if(!(l.ok&&l.body)){t.onError?.({error:`stream_failed_${l.status}`});return}let i=l.body.getReader(),n=new TextDecoder,s="",a=()=>{let d=s.indexOf(`
2
+ var te=e=>{if(!e||typeof e!="object")return null;let t=e;return t.type==="message_update"?t.assistantMessageEvent??null:null},L=e=>{let t=te(e);return t?.type==="text_delta"&&typeof t.delta=="string"?t.delta:null},F=e=>{let t=te(e);return t?.type==="thinking_delta"&&typeof t.delta=="string"?t.delta:null},U=e=>{if(!e||typeof e!="object")return null;let t=e;return t.type==="tool_execution_start"&&t.toolCallId?{phase:"start",id:t.toolCallId,name:t.toolName}:t.type==="tool_execution_end"&&t.toolCallId?{phase:"end",id:t.toolCallId,isError:t.isError}:null};var Ue=/^ /,x=e=>{if(e&&typeof e=="object"){let t=e,r=typeof t.error=="string"?t.error:"request_failed";return typeof t.retryable=="boolean"?{error:r,retryable:t.retryable}:{error:r}}return{error:"request_failed"}},Ne=e=>{let t="message",r=[];for(let o of e.split(`
3
+ `))o.startsWith(":")||(o.startsWith("event:")?t=o.slice(6).trim():o.startsWith("data:")&&r.push(o.slice(5).replace(Ue,"")));return r.length>0?{event:t,data:r.join(`
4
+ `)}:null},Ve=(e,t,r)=>{let o;try{o=JSON.parse(e.data)}catch{return}if(e.event==="session"){let s=o.sessionId;s&&(r(s),t.onSession?.(s));return}if(e.event==="turn_event"){t.onEvent?.(o);let s=L(o);s&&t.onText?.(s);let a=F(o);a&&t.onThinking?.(a);let n=U(o);n&&t.onTool?.(n);return}if(e.event==="chat_completed"){let s=o;r(s.sessionId),t.onComplete?.(s);return}e.event==="chat_error"&&t.onError?.(x(o))},v=async(e,t)=>{let r=await fetch(e,{headers:t});if(!r.ok)throw new Error(`hola: request failed (${r.status})`);return await r.json()},re=async e=>{let t=await fetch(e.url,{method:"POST",headers:e.headers,body:e.body});if(!t.ok)throw new Error(`hola: message failed (${t.status})`);return await t.json()},ne=async(e,t,r,o)=>{let s=await fetch(e.url,{method:"POST",headers:e.headers,body:e.body,signal:o});if(!(s.ok&&s.body)){t.onError?.({error:`stream_failed_${s.status}`});return}let a=s.body.getReader(),n=new TextDecoder,i="",l=()=>{let d=i.indexOf(`
5
5
 
6
- `);for(;d!==-1;){let c=s.slice(0,d);s=s.slice(d+2);let g=$e(c);g&&_e(g,t,o),d=s.indexOf(`
6
+ `);for(;d!==-1;){let c=i.slice(0,d);i=i.slice(d+2);let m=Ne(c);m&&Ve(m,t,r),d=i.indexOf(`
7
7
 
8
- `)}},u=async()=>{let d=await i.read();if(!d.done)return s+=n.decode(d.value,{stream:!0}),a(),u()};await u()};var Oe=/\/+$/,L="/api/v1/end-user",Ue=e=>{let t=e.baseUrl.replace(Oe,""),o=()=>typeof e.token=="function"?e.token():e.token,r=n=>e.project?`${n}project=${encodeURIComponent(e.project)}`:"",l=async()=>({"content-type":"application/json",authorization:`Bearer ${await o()}`}),i=async n=>{let s=await fetch(`${t}${L}/chat${r("?")}`,{method:"POST",headers:await l(),body:JSON.stringify({message:n})});if(!s.ok)throw new Error(`hola: message failed (${s.status})`);return{reply:(await s.json()).reply??"",sessionId:"",artifacts:[]}};return{sessionId:()=>"",getInfo:async()=>v(`${t}${L}/chat/info${r("?")}`,await l()),sendMessage:i,streamMessage:async(n,s)=>{try{let a=await i(n);s.onText?.(a.reply),s.onComplete?.(a)}catch(a){s.onError?.(w(a))}},subscribe:(n,s)=>{let a=s?.since??"0",u=!1,d,c=s?.intervalMs??3e3,g=typeof document<"u",p=()=>g&&document.visibilityState==="hidden",y=!1,x=()=>{if(!u){if(p()){y=!0;return}d=setTimeout(f,c)}},f=async()=>{try{let h=await v(`${t}${L}/chat/thread?since=${encodeURIComponent(a)}${r("&")}`,await l());for(let k of h.messages)n.onMessage(k);a=h.cursor,n.onHealthy?.()}catch(h){n.onError?.(w(h))}x()},R=()=>{u||!y||p()||(y=!1,d&&clearTimeout(d),d=setTimeout(f,0))};g&&document.addEventListener("visibilitychange",R);let m=()=>{u=!0,d&&clearTimeout(d),g&&document.removeEventListener("visibilitychange",R)};return s?.signal?.addEventListener("abort",m),d=setTimeout(f,0),m}}};import{useEffect as Le,useState as Fe}from"react";var F=(e,t)=>{let[o,r]=Fe("");return Le(()=>{if(!e){r("");return}let l=Uint8Array.from(atob(e),n=>n.charCodeAt(0)),i=URL.createObjectURL(new Blob([l],{type:t}));return r(i),()=>URL.revokeObjectURL(i)},[e,t]),o};import{useEffect as Be,useRef as ze}from"react";import{createContext as Ne,useContext as Ve}from"react";import{jsx as Ge}from"react/jsx-runtime";var te=Ne(null),je=({client:e,children:t})=>Ge(te.Provider,{value:e,children:t}),N=()=>{let e=Ve(te);if(!e)throw new Error("useHolaClient must be used within <HolaProvider>");return e};import{useCallback as ne,useEffect as re,useRef as oe,useState as M}from"react";var V=e=>{let[t,o]=M([]),[r,l]=M(""),[i,n]=M(!1),[s,a]=M(null),u=oe(0),d=oe(null);re(()=>()=>d.current?.abort(),[]);let c=ne(()=>{let p=u.current;return u.current+=1,p},[]);re(()=>{let p=!0;return e.getInfo().then(y=>{p&&y.greeting&&o([{id:c(),role:"assistant",text:y.greeting}])}).catch(()=>{}),()=>{p=!1}},[e,c]);let g=ne(()=>{let p=r.trim();if(!p||i)return;l(""),a(null),n(!0);let y=c(),x=c();o(m=>[...m,{id:y,role:"user",text:p},{id:x,role:"assistant",text:"",streaming:!0}]);let f=m=>{o(h=>h.map(k=>k.id===x?m(k):k))},R=new AbortController;d.current=R,e.streamMessage(p,{onText:m=>f(h=>({...h,text:h.text+m})),onComplete:m=>{f(h=>({...h,text:m.reply||h.text,artifacts:m.artifacts,streaming:!1})),n(!1)},onError:m=>{f(h=>({...h,streaming:!1})),a(m.error),n(!1)}},R.signal).catch(m=>{f(h=>({...h,streaming:!1})),a(m instanceof Error?m.message:"stream_failed"),n(!1)}).finally(()=>{n(!1),f(m=>m.streaming?{...m,streaming:!1}:m)})},[r,i,e,c]);return{messages:t,input:r,setInput:l,send:g,sending:i,error:s}};import{jsx as P,jsxs as j}from"react/jsx-runtime";var S={root:{display:"flex",flexDirection:"column",height:"100%",fontFamily:"system-ui, -apple-system, sans-serif",fontSize:14,color:"#111827"},log:{flex:1,overflowY:"auto",padding:12,display:"flex",flexDirection:"column",gap:8},user:{alignSelf:"flex-end",background:"#111827",color:"#ffffff",borderRadius:12,padding:"8px 12px",maxWidth:"80%",whiteSpace:"pre-wrap"},assistant:{alignSelf:"flex-start",background:"#f1f1f4",color:"#111827",borderRadius:12,padding:"8px 12px",maxWidth:"80%",whiteSpace:"pre-wrap"},artifacts:{display:"flex",flexDirection:"column",gap:6,marginTop:6},image:{maxHeight:220,borderRadius:8,border:"1px solid #e5e7eb"},link:{color:"#2563eb",textDecoration:"underline",wordBreak:"break-all"},error:{color:"#b91c1c",padding:"4px 12px",fontSize:13},form:{display:"flex",gap:8,borderTop:"1px solid #e5e7eb",padding:8},input:{flex:1,border:"1px solid #d1d5db",borderRadius:8,padding:"8px 10px",fontSize:14,outline:"none"},button:{border:"none",background:"#111827",color:"#ffffff",borderRadius:8,padding:"8px 14px",fontSize:14,cursor:"pointer"}},Je=({artifact:e})=>{let t=F(e.dataBase64??"",e.mimeType),o=e.url??t;return o?e.mimeType.startsWith("image/")?P("a",{href:o,rel:"noopener noreferrer",target:"_blank",children:P("img",{alt:e.filename,src:o,style:S.image})}):P("a",{download:e.filename,href:o,style:S.link,children:e.filename}):null},Ke=()=>{let e=N(),{messages:t,input:o,setInput:r,send:l,sending:i,error:n}=V(e),s=ze(null);Be(()=>{let u=s.current;u&&(u.scrollTop=u.scrollHeight)},[t]);let a=u=>{u.preventDefault(),l()};return j("div",{style:S.root,children:[P("div",{ref:s,style:S.log,children:t.map(u=>j("div",{style:u.role==="user"?S.user:S.assistant,children:[u.text||(u.streaming?"\u2026":""),u.artifacts&&u.artifacts.length>0?P("div",{style:S.artifacts,children:u.artifacts.map(d=>P(Je,{artifact:d},d.filename))}):null]},u.id))}),n?P("div",{style:S.error,children:n}):null,j("form",{onSubmit:a,style:S.form,children:[P("input",{"aria-label":"Message",onChange:u=>r(u.target.value),placeholder:"Type a message\u2026",style:S.input,value:o}),P("button",{disabled:i||o.trim().length===0,style:S.button,type:"submit",children:"Send"})]})]})};var Xe=/\/+$/,G=e=>{let t=e.sessionId,o=e.baseUrl.replace(Xe,""),r=n=>`${o}/endpoint/${encodeURIComponent(e.token)}${n}`,l={"content-type":"application/json"},i=(n,s)=>({url:r(n),headers:l,body:JSON.stringify({message:s,...t?{sessionId:t}:{},...e.identity?{externalUserId:e.identity.externalUserId,userHmac:e.identity.userHmac}:{}})});return{sessionId:()=>t,getInfo:()=>v(r("/config"),{}),sendMessage:async n=>{let s=await Z(i("/message",n));return t=s.sessionId,s},streamMessage:(n,s,a)=>ee(i("/message/stream",n),s,u=>{t=u},a),subscribe:(n,s)=>{let a=s?.since??"0",u=!1,d,c=s?.intervalMs??3e3,g=async()=>{let y=t;if(y)try{let x=await v(r(`/messages?session=${encodeURIComponent(y)}&since=${encodeURIComponent(a)}`),{});for(let f of x.messages)n.onMessage(f);a=x.cursor,n.onHealthy?.()}catch(x){n.onError?.(w(x))}u||(d=setTimeout(g,c))},p=()=>{u=!0,d&&clearTimeout(d)};return s?.signal?.addEventListener("abort",p),d=setTimeout(g,0),p}}};var qe=e=>"transport"in e?e.transport:G(e);var Qe=/^https?:\/\//i,Ye=/^\d{4}-\d{2}-\d{2}(?:[T ]|$)/,Ze=e=>e.replace(/_/g," ").replace(/\b\w/g,t=>t.toUpperCase());function et(e){if(typeof e=="number")return"number";if(typeof e=="boolean")return"boolean";if(typeof e=="string"){if(Qe.test(e))return"url";if(Ye.test(e))return"date"}return"text"}function se(e){let t=[],o=new Map;for(let r of e)for(let[l,i]of Object.entries(r.data??{})){if(i==null)continue;let n=o.get(l);n||(n=new Map,o.set(l,n),t.push(l));let s=et(i);n.set(s,(n.get(s)??0)+1)}return t.map(r=>{let l=o.get(r)??new Map,i="text",n=-1;for(let[s,a]of l)a>n&&(n=a,i=s);return{key:r,label:Ze(r),type:i}})}var tt=e=>typeof e=="number"?e:Number(e)||0,ie=e=>/rate|position|rank|score|percent|avg/i.test(e),nt=/posted|published|sent|completed|shipped|launched|_at/i,rt=new Set(["service","order","end_user_id"]);function ae(e,t){let o=e.filter(a=>!rt.has(a.key)),r=o.filter(a=>a.type==="number").slice(0,3),l=o.find(a=>a.key==="status")??o.find(a=>a.type==="select"),i=o.find(a=>a.type==="date"&&nt.test(a.key))??o.find(a=>a.type==="date"),n=o.filter(a=>a.type==="number"&&!ie(a.key)).map(a=>({field:a,total:t.reduce((u,d)=>u+tt(d.data[a.key]),0)})).sort((a,u)=>u.total-a.total).find(a=>a.total>0)?.field??null,s=[{type:"stat",label:"Items",agg:"count"}];for(let a of r){let u=ie(a.key);s.push({type:"stat",metric:a.key,agg:u?"avg":"sum",label:u?`Avg ${a.label.toLowerCase()}`:a.label})}return i&&s.push({type:"line",x:i.key,y:n?.key,agg:"sum",title:n?`${n.label} by day`:"Items by day"}),l&&s.push({type:"donut",groupBy:l.key,title:l.label}),s.push({type:"table",columns:o.map(a=>a.key)}),{version:1,widgets:s}}var le=6,ue=6,de=4,pe={stat:{w:1,h:1},chart:{w:2,h:2},block:{w:6,h:2}},ot=e=>Math.max(1,Math.min(6,Math.round(e))),st=e=>Math.max(1,Math.min(4,Math.round(e)));function W(e){return e==="stat"?"stat":e==="series"||e==="donut"?"chart":"block"}function ce(e){return e==="stat"?"stat":e==="line"||e==="bar"||e==="donut"?"chart":"block"}function ge(e){return pe[e]}function B(e,t,o){let r=pe[e];return{w:t===void 0?r.w:ot(t),h:o===void 0?r.h:st(o)}}function z(e){let t=[],o=[],r=(n,s,a,u)=>{if(n<0||n+a>6)return!1;for(let d=0;d<u;d+=1){let c=o[s+d];if(c){for(let g=0;g<a;g+=1)if(c[n+g])return!1}}return!0},l=(n,s,a,u)=>{for(let d=0;d<u;d+=1){let c=o[s+d]??[];for(let g=0;g<a;g+=1)c[n+g]=!0;o[s+d]=c}},i=(n,s)=>{for(let a=0;;a+=1)for(let u=0;u+n<=6;u+=1)if(r(u,a,n,s))return{gx:u,gy:a}};for(let n of e){let s=B(W(n.kind),n.w,n.h),u=n.gx!==void 0&&n.gy!==void 0&&r(n.gx,n.gy,s.w,s.h)&&n.gx!==void 0&&n.gy!==void 0?{gx:n.gx,gy:n.gy}:i(s.w,s.h);l(u.gx,u.gy,s.w,s.h),t.push({widget:n,gx:u.gx,gy:u.gy,w:s.w,h:s.h})}return t}function me(e){let t=[],o=[];for(let r of e)W(r.kind)==="block"?o.push(r):t.push(r);return{tiles:z(t),blocks:o}}var fe=new Set(["service","order","end_user_id"]),J=e=>typeof e=="number"?e:Number(e)||0,ye=e=>e==null?"":String(e);function K(e,t){if(e==="count")return t.length;if(t.length===0)return 0;if(e==="last")return t[t.length-1]??0;if(e==="min")return Math.min(...t);if(e==="max")return Math.max(...t);let o=t.reduce((r,l)=>r+l,0);return e==="avg"?Math.round(o/t.length*100)/100:o}function it(e,t,o,r){let l=new Map;for(let i of e){let n=new Date(ye(i.data[t]));if(Number.isNaN(n.getTime()))continue;let s=n.toISOString().slice(0,10),a=l.get(s)??[];a.push(o?J(i.data[o]):1),l.set(s,a)}return[...l.entries()].sort((i,n)=>i[0]<n[0]?-1:1).map(([i,n])=>({label:new Date(`${i}T00:00:00`).toLocaleDateString(void 0,{month:"short",day:"numeric"}),value:o?K(r,n):n.length}))}function at(e,t,o,r="sum"){let l=new Map;for(let i of e){let n=ye(i.data[t]).trim();if(!n)continue;let s=l.get(n)??[];s.push(o?J(i.data[o]):1),l.set(n,s)}return[...l.entries()].map(([i,n])=>({label:i,value:o?K(r,n):n.length})).sort((i,n)=>n.value-i.value)}function lt(e,t,o,r){switch(e.type){case"stat":{let l=e.metric?t.get(e.metric):void 0;if(e.metric&&!l)return null;if(!l)return{kind:"stat",label:e.label??"Items",value:r.length};let i=r.map(n=>J(n.data[l.key]));return{kind:"stat",label:e.label??l.label,value:K(e.agg??"sum",i)}}case"line":case"bar":{if(!t.has(e.x)||e.y&&!t.has(e.y))return null;let l=it(r,e.x,e.y,e.agg??"sum");return l.length<2?null:{kind:"series",draw:e.type,title:e.title??"By day",points:l}}case"donut":{if(!t.has(e.groupBy))return null;let l=at(r,e.groupBy,e.metric,e.agg??"sum");return l.length===0?null:{kind:"donut",title:e.title??t.get(e.groupBy)?.label??"Breakdown",points:l}}case"table":{let l=e.columns?e.columns.map(i=>t.get(i)).filter(i=>i!==void 0&&!fe.has(i.key)):o;return l.length===0?null:{kind:"table",title:e.title,columns:l,rows:r}}case"text":return{kind:"text",title:e.title,body:e.body};default:return null}}function be(e,t,o,r={}){let l=new Map,i=a=>({byKey:new Map(a.fields.map(u=>[u.key,u])),cols:a.fields.filter(u=>!fe.has(u.key)),rows:a.rows}),n=i({fields:t,rows:o});for(let[a,u]of Object.entries(r))l.set(a,i(u));let s=[];for(let a of e.widgets){let u=a.type==="text"?void 0:a.source,d=u?l.get(u):n;if(!d)continue;let c=lt(a,d.byKey,d.cols,d.rows);c&&s.push({...c,w:a.w,h:a.h,gx:a.gx,gy:a.gy})}return s}var ut=new Set(["sum","avg","count","min","max","last"]),he=e=>typeof e=="string"&&ut.has(e)?e:void 0,b=e=>typeof e=="string"&&e!==""?e:void 0,C=e=>typeof e=="number"&&e>=1?Math.min(6,Math.round(e)):void 0,I=e=>typeof e=="number"&&e>=1?Math.min(4,Math.round(e)):void 0,T=e=>typeof e=="number"&&e>=0?Math.round(e):void 0;function dt(e){if(typeof e!="object"||e===null)return null;let t=e;switch(t.type){case"stat":return{type:"stat",source:b(t.source),label:b(t.label),metric:b(t.metric)??b(t.column),agg:he(t.agg),w:C(t.w),h:I(t.h),gx:T(t.gx),gy:T(t.gy)};case"line":case"bar":{let o=b(t.x);return o?{type:t.type,source:b(t.source),title:b(t.title),x:o,y:b(t.y)??b(t.column),agg:he(t.agg),w:C(t.w),h:I(t.h),gx:T(t.gx),gy:T(t.gy)}:null}case"donut":{let o=b(t.groupBy)??b(t.column);return o?{type:"donut",source:b(t.source),title:b(t.title),groupBy:o,w:C(t.w),h:I(t.h),gx:T(t.gx),gy:T(t.gy)}:null}case"table":{let o=Array.isArray(t.columns)?t.columns.filter(r=>typeof r=="string"):void 0;return{type:"table",source:b(t.source),title:b(t.title),columns:o,w:C(t.w),h:I(t.h),gx:T(t.gx),gy:T(t.gy)}}case"text":{let o=b(t.body);return o?{type:"text",title:b(t.title),body:o,w:C(t.w),h:I(t.h),gx:T(t.gx),gy:T(t.gy)}:null}default:return null}}function we(e){let t=e;if(typeof e=="string"){if(e.trim()==="")return null;try{t=JSON.parse(e)}catch{return null}}if(typeof t!="object"||t===null)return null;let o=t.widgets;if(!Array.isArray(o))return null;let r=o.map(dt).filter(i=>i!==null);if(r.length===0)return null;let l=t.version;return{version:typeof l=="number"?l:1,title:b(t.title),widgets:r}}function X(e){if(typeof e=="string")return e?{kind:"file",value:e}:null;if(e&&typeof e=="object"){let t=e,o=typeof t.value=="string"?t.value:"",r=t.kind==="link"||t.kind==="text"||t.kind==="table"?t.kind:"file",l=typeof t.v=="number"&&t.v>=1?Math.floor(t.v):void 0;return o?{kind:r,value:o,...l?{v:l}:{}}:null}return null}function q(e){let t=new Map;for(let o of e){let r=o.v??1,l=t.get(r)??[];l.push(o),t.set(r,l)}return[...t.entries()].sort(([o],[r])=>o-r).map(([o,r])=>({v:o,items:r}))}function xe(e){let t=e.files;if(typeof t=="string"&&t.trim()!=="")try{let r=JSON.parse(t);if(Array.isArray(r))return r.map(X).filter(l=>l!==null)}catch{}let o=String(e.file??"");return o?[{kind:"file",value:o}]:[]}function ve(e,t,o,r=""){let i=q(e).find(s=>s.v===t)?.items??[],n=i.filter(s=>s.kind==="file").map(s=>o.get(s.value)??"");return i.some(s=>s.kind==="table")&&n.push(r),n.length===0||n.some(s=>s==="")?"awaiting":n.some(s=>s==="revise")?"revise":"accepted"}function Se(e){return Number(e.published_version)||0}function Q(e){return e==="number"||e==="date"||e==="boolean"||e==="select"||e==="url"?e:e==="link"?"url":e==="checkbox"?"boolean":"text"}function Re(e){try{let t=JSON.parse(e);if(Array.isArray(t.columns)&&Array.isArray(t.rows)&&t.columns.length){let o=t.columns.map((i,n)=>({key:typeof i.key=="string"&&i.key?i.key:typeof i.id=="string"&&i.id?i.id:`column_${n+1}`,label:typeof i.label=="string"?i.label:"",type:Q(i.type),...i.clientEditable===!0?{clientEditable:!0}:{}})),r=t.rows.map((i,n)=>({id:typeof i.id=="string"&&i.id?i.id:`row_${n}`,cells:i.cells&&typeof i.cells=="object"?i.cells:{}})),l=typeof t.name=="string"?t.name:void 0;return{columns:o,rows:r,...l?{name:l}:{}}}}catch{}return null}function Te(e){return e==null?"":String(e)}function ke(e){return e===!0||e==="true"||e==="1"||e==="yes"||e==="\u2713"}function E(){return{cells:{},verdict:"",comment:""}}function Pe(e){if(typeof e!="string"||e.trim()==="")return E();try{let t=JSON.parse(e);if(t&&typeof t=="object"&&!Array.isArray(t)){let o=t;return{cells:o.cells&&typeof o.cells=="object"?o.cells:o,verdict:o.verdict==="accepted"||o.verdict==="revise"?o.verdict:"",comment:typeof o.comment=="string"?o.comment:""}}}catch{}return E()}function De(e,t,o){if(e.clientEditable){let r=o.cells[t.id];if(r&&e.key in r)return r[e.key]}return t.cells[e.key]}function Ce(e,t,o,r){return{...e,cells:{...e.cells,[t]:{...e.cells[t]??{},[o]:r}}}}function Ie(e,t,o){return{...e,verdict:t,comment:o}}function He(e){let t=new Date(`${e}T00:00:00`);return Number.isNaN(t.getTime())?e:t.toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"})}var pt=/\/+$/,D="/api/v1/end-user",H=class extends Error{constructor(t){super(t),this.name="PortalConflict"}};function ct(e){let t="";for(let r=0;r<e.length;r+=32768)t+=String.fromCharCode(...e.subarray(r,r+32768));return btoa(t)}var gt=e=>{let t=e.baseUrl.replace(pt,""),o=()=>typeof e.token=="function"?e.token():e.token,r=async()=>({"content-type":"application/json",authorization:`Bearer ${await o()}`}),l=async(n,s)=>{try{let a=await fetch(`${t}${D}${n}`,{method:s.method,headers:await r(),...s.body===void 0?{}:{body:JSON.stringify(s.body)}});if(a.status===409){let u=await a.json().catch(()=>({}));throw new H(u.message??"Someone else saved this first.")}if(!a.ok){let u=await a.text().catch(()=>""),d=`${s.method} ${n} \u2192 ${String(a.status)}`;try{let c=JSON.parse(u);c.message&&(d=c.message)}catch{d=u?`${d}: ${u}`:d}throw w({error:d})}return await a.json()}catch(a){throw a instanceof H?a:w(a)}},i=n=>`/tables/${encodeURIComponent(n)}`;return{listTables:async()=>(await v(`${t}${D}/tables`,await r())).tables,listRows:async(n,s)=>await v(`${t}${D}${i(n)}/rows?limit=${String(s??100)}`,await r()),insertRow:async(n,s)=>{let{rowIds:a}=await l(`${i(n)}/rows`,{method:"POST",body:{rows:[s]}}),u=a[0];if(!u)throw w(new Error("The row was not created."));return u},patchRow:async(n,s,a)=>(await l(`${i(n)}/rows/${encodeURIComponent(s)}`,{method:"PATCH",body:a})).updated,deleteRow:async(n,s)=>(await l(`/${encodeURIComponent(n)}/${encodeURIComponent(s)}`,{method:"DELETE"})).deleted,listFiles:async()=>(await v(`${t}${D}/tables/files/rows?limit=200`,await r())).rows.map(s=>({id:s.rowId,filename:String(s.data.filename??""),source:String(s.data.source??"client"),campaign:String(s.data.campaign??""),size:typeof s.data.size=="number"?s.data.size:0,createdAt:s.createdAt})),uploadFile:async(n,s)=>{let a=new Uint8Array(await n.arrayBuffer());return await l("/files",{method:"POST",body:{filename:n.name,mime:n.type||"application/octet-stream",data:ct(a),...s===void 0?{}:{message:s}}})},fileLink:async n=>await v(`${t}${D}/files/${encodeURIComponent(n)}/url`,await r()),deleteFile:async n=>(await l(`/files/${encodeURIComponent(n)}`,{method:"DELETE"})).deleted,listDocuments:async()=>(await v(`${t}${D}/documents`,await r())).documents,readDocument:async n=>(await v(`${t}${D}/documents/${encodeURIComponent(n)}`,await r())).document,saveDocument:async(n,s)=>await l(`/documents/${encodeURIComponent(n)}`,{method:"PATCH",body:s})}};var mt=/\/+$/,ft="/api/v1/end-user",yt=e=>{let t=e.baseUrl.replace(mt,""),o=async(r,l)=>{let i;try{i=await fetch(`${t}${ft}${r}`,l===void 0?{}:{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(l)})}catch(n){throw w(n)}if(i.status===429)throw w({error:"rate_limited",retryable:!0});if(!i.ok)throw w({error:`shop_request_failed_${String(i.status)}`});try{return await i.json()}catch(n){throw w(n)}};return{listProducts:async()=>{let r=await o(`/shop/products?publishable_key=${encodeURIComponent(e.publishableKey)}`);return{products:r.products.map(l=>({...l,currency:typeof l.currency=="string"?l.currency:""})),truncated:r.truncated===!0}},apply:async r=>await o("/shop/apply",{publishable_key:e.publishableKey,name:r.name,email:r.email,...r.phone?{phone:r.phone}:{},...r.message?{message:r.message}:{},...r.productId?{productId:r.productId}:{}})}};import{useCallback as bt,useEffect as ht,useState as A}from"react";var wt=e=>e&&typeof e=="object"&&typeof e.error=="string"?e.error:e instanceof Error?e.message:"shop_unavailable",xt=e=>{let[t,o]=A([]),[r,l]=A(!1),[i,n]=A(!0),[s,a]=A(null),[u,d]=A(0);ht(()=>{let g=!0;return n(!0),e.listProducts().then(p=>{g&&(o(p.products),l(p.truncated),a(null))}).catch(p=>{g&&a(wt(p))}).finally(()=>{g&&n(!1)}),()=>{g=!1}},[e,u]);let c=bt(()=>d(g=>g+1),[]);return{products:t,truncated:r,loading:i,error:s,reload:c}};import{useCallback as vt,useEffect as Ae,useRef as St,useState as $}from"react";var Me="greeting";function We(e,t){if(e.some(i=>i.id===t.id))return e;let o=e.filter(i=>i.id!==Me),r=i=>i.author==="client"==(t.author==="client");return[...o.filter(i=>!(i.pending&&r(i)&&i.text===t.text)),t]}var Rt=(e,t)=>{let[o,r]=$([]),[l,i]=$(""),[n,s]=$(!1),[a,u]=$(null),d=St(0),c=t?.pollMs??2e3;Ae(()=>{let p=!0;return e.getInfo().then(y=>{p&&y.greeting&&r(x=>x.length===0?[{id:Me,cursor:"",author:"agent",text:y.greeting}]:x)}).catch(()=>{}),()=>{p=!1}},[e]),Ae(()=>e.subscribe?.({onMessage:p=>r(y=>We(y,p)),onError:p=>u(p.error),onHealthy:()=>u(null)},{intervalMs:c}),[e,c]);let g=vt(()=>{let p=l.trim();if(!p||n)return;i(""),u(null),s(!0),d.current+=1;let y=`pending-${d.current}`,x={id:y,cursor:"",author:"client",text:p,pending:!0};r(f=>[...f,x]),e.sendMessage(p).then(f=>{s(!1),f.reply.trim()&&r(m=>m.some(k=>!k.pending&&k.author!=="client"&&k.text===f.reply)?m:(d.current+=1,[...m,{id:`pending-agent-${d.current}`,cursor:"",author:"agent",text:f.reply,pending:!0}]))}).catch(f=>{u(f instanceof Error?f.message:"send_failed"),s(!1),r(R=>R.filter(m=>m.id!==y)),i(R=>R||p)})},[l,n,e]);return{messages:o,input:l,setInput:i,send:g,sending:n,error:a}};export{Ke as Chat,le as GRID_COLS,ue as GRID_MAX_COLS,de as GRID_MAX_ROWS,je as HolaProvider,H as PortalConflict,W as bandOfKind,ce as bandOfType,De as cellValue,Ue as createApiTransport,qe as createHolaClient,gt as createPortalData,yt as createPortalShop,G as createWidgetTransport,Te as deliverableCellText,ve as deliverableStatus,se as deriveFields,E as emptyTableResponses,ge as footprintOf,B as footprintWith,He as formatDeliverableDate,q as groupDeliverableVersions,ae as inferSpec,ke as isDeliverableChecked,We as mergeMessage,Q as normalizeDeliverableColType,X as normalizeDeliverableItem,we as parseDashboardSpec,xe as parseDeliverableItems,Re as parseDeliverableTable,Pe as parseTableResponses,z as placeWidgets,Se as publishedVersionOf,be as renderModel,Ce as setResponse,Ie as setTableReview,me as splitLayout,_ as textDeltaOf,O as thinkingDeltaOf,U as toolEventOf,F as useArtifactUrl,V as useChat,N as useHolaClient,xt as useShop,Rt as useThread};
8
+ `)}},u=async()=>{let d=await a.read();if(!d.done)return i+=n.decode(d.value,{stream:!0}),l(),u()};await u()};var je=/\/+$/,N="/api/v1/end-user",Ge=e=>{let t=e.baseUrl.replace(je,""),r=()=>typeof e.token=="function"?e.token():e.token,o=n=>e.project?`${n}project=${encodeURIComponent(e.project)}`:"",s=async()=>({"content-type":"application/json",authorization:`Bearer ${await r()}`}),a=async n=>{let i=await fetch(`${t}${N}/chat${o("?")}`,{method:"POST",headers:await s(),body:JSON.stringify({message:n})});if(!i.ok)throw new Error(`hola: message failed (${i.status})`);return{reply:(await i.json()).reply??"",sessionId:"",artifacts:[]}};return{sessionId:()=>"",getInfo:async()=>v(`${t}${N}/chat/info${o("?")}`,await s()),sendMessage:a,streamMessage:async(n,i)=>{try{let l=await a(n);i.onText?.(l.reply),i.onComplete?.(l)}catch(l){i.onError?.(x(l))}},subscribe:(n,i)=>{let l=i?.since??"0",u=!1,d,c=i?.intervalMs??3e3,m=typeof document<"u",p=()=>m&&document.visibilityState==="hidden",y=!1,w=()=>{if(!u){if(p()){y=!0;return}d=setTimeout(f,c)}},f=async()=>{try{let h=await v(`${t}${N}/chat/thread?since=${encodeURIComponent(l)}${o("&")}`,await s());for(let T of h.messages)n.onMessage(T);l=h.cursor,n.onHealthy?.()}catch(h){n.onError?.(x(h))}w()},k=()=>{u||!y||p()||(y=!1,d&&clearTimeout(d),d=setTimeout(f,0))};m&&document.addEventListener("visibilitychange",k);let g=()=>{u=!0,d&&clearTimeout(d),m&&document.removeEventListener("visibilitychange",k)};return i?.signal?.addEventListener("abort",g),d=setTimeout(f,0),g}}};import{useEffect as Be,useState as ze}from"react";var V=(e,t)=>{let[r,o]=ze("");return Be(()=>{if(!e){o("");return}let s=Uint8Array.from(atob(e),n=>n.charCodeAt(0)),a=URL.createObjectURL(new Blob([s],{type:t}));return o(a),()=>URL.revokeObjectURL(a)},[e,t]),r};import{useEffect as Qe,useRef as Ye}from"react";import{createContext as qe,useContext as Je}from"react";import{jsx as Xe}from"react/jsx-runtime";var oe=qe(null),Ke=({client:e,children:t})=>Xe(oe.Provider,{value:e,children:t}),j=()=>{let e=Je(oe);if(!e)throw new Error("useHolaClient must be used within <HolaProvider>");return e};import{useCallback as se,useEffect as ie,useRef as ae,useState as $}from"react";var G=e=>{let[t,r]=$([]),[o,s]=$(""),[a,n]=$(!1),[i,l]=$(null),u=ae(0),d=ae(null);ie(()=>()=>d.current?.abort(),[]);let c=se(()=>{let p=u.current;return u.current+=1,p},[]);ie(()=>{let p=!0;return e.getInfo().then(y=>{p&&y.greeting&&r([{id:c(),role:"assistant",text:y.greeting}])}).catch(()=>{}),()=>{p=!1}},[e,c]);let m=se(()=>{let p=o.trim();if(!p||a)return;s(""),l(null),n(!0);let y=c(),w=c();r(g=>[...g,{id:y,role:"user",text:p},{id:w,role:"assistant",text:"",streaming:!0}]);let f=g=>{r(h=>h.map(T=>T.id===w?g(T):T))},k=new AbortController;d.current=k,e.streamMessage(p,{onText:g=>f(h=>({...h,text:h.text+g})),onComplete:g=>{f(h=>({...h,text:g.reply||h.text,artifacts:g.artifacts,streaming:!1})),n(!1)},onError:g=>{f(h=>({...h,streaming:!1})),l(g.error),n(!1)}},k.signal).catch(g=>{f(h=>({...h,streaming:!1})),l(g instanceof Error?g.message:"stream_failed"),n(!1)}).finally(()=>{n(!1),f(g=>g.streaming?{...g,streaming:!1}:g)})},[o,a,e,c]);return{messages:t,input:o,setInput:s,send:m,sending:a,error:i}};import{jsx as R,jsxs as B}from"react/jsx-runtime";var S={root:{display:"flex",flexDirection:"column",height:"100%",fontFamily:"system-ui, -apple-system, sans-serif",fontSize:14,color:"#111827"},log:{flex:1,overflowY:"auto",padding:12,display:"flex",flexDirection:"column",gap:8},user:{alignSelf:"flex-end",background:"#111827",color:"#ffffff",borderRadius:12,padding:"8px 12px",maxWidth:"80%",whiteSpace:"pre-wrap"},assistant:{alignSelf:"flex-start",background:"#f1f1f4",color:"#111827",borderRadius:12,padding:"8px 12px",maxWidth:"80%",whiteSpace:"pre-wrap"},artifacts:{display:"flex",flexDirection:"column",gap:6,marginTop:6},image:{maxHeight:220,borderRadius:8,border:"1px solid #e5e7eb"},link:{color:"#2563eb",textDecoration:"underline",wordBreak:"break-all"},error:{color:"#b91c1c",padding:"4px 12px",fontSize:13},form:{display:"flex",gap:8,borderTop:"1px solid #e5e7eb",padding:8},input:{flex:1,border:"1px solid #d1d5db",borderRadius:8,padding:"8px 10px",fontSize:14,outline:"none"},button:{border:"none",background:"#111827",color:"#ffffff",borderRadius:8,padding:"8px 14px",fontSize:14,cursor:"pointer"}},Ze=({artifact:e})=>{let t=V(e.dataBase64??"",e.mimeType),r=e.url??t;return r?e.mimeType.startsWith("image/")?R("a",{href:r,rel:"noopener noreferrer",target:"_blank",children:R("img",{alt:e.filename,src:r,style:S.image})}):R("a",{download:e.filename,href:r,style:S.link,children:e.filename}):null},et=()=>{let e=j(),{messages:t,input:r,setInput:o,send:s,sending:a,error:n}=G(e),i=Ye(null);Qe(()=>{let u=i.current;u&&(u.scrollTop=u.scrollHeight)},[t]);let l=u=>{u.preventDefault(),s()};return B("div",{style:S.root,children:[R("div",{ref:i,style:S.log,children:t.map(u=>B("div",{style:u.role==="user"?S.user:S.assistant,children:[u.text||(u.streaming?"\u2026":""),u.artifacts&&u.artifacts.length>0?R("div",{style:S.artifacts,children:u.artifacts.map(d=>R(Ze,{artifact:d},d.filename))}):null]},u.id))}),n?R("div",{style:S.error,children:n}):null,B("form",{onSubmit:l,style:S.form,children:[R("input",{"aria-label":"Message",onChange:u=>o(u.target.value),placeholder:"Type a message\u2026",style:S.input,value:r}),R("button",{disabled:a||r.trim().length===0,style:S.button,type:"submit",children:"Send"})]})]})};var tt=/\/+$/,z=e=>{let t=e.sessionId,r=e.baseUrl.replace(tt,""),o=n=>`${r}/endpoint/${encodeURIComponent(e.token)}${n}`,s={"content-type":"application/json"},a=(n,i)=>({url:o(n),headers:s,body:JSON.stringify({message:i,...t?{sessionId:t}:{},...e.identity?{externalUserId:e.identity.externalUserId,userHmac:e.identity.userHmac}:{}})});return{sessionId:()=>t,getInfo:()=>v(o("/config"),{}),sendMessage:async n=>{let i=await re(a("/message",n));return t=i.sessionId,i},streamMessage:(n,i,l)=>ne(a("/message/stream",n),i,u=>{t=u},l),subscribe:(n,i)=>{let l=i?.since??"0",u=!1,d,c=i?.intervalMs??3e3,m=async()=>{let y=t;if(y)try{let w=await v(o(`/messages?session=${encodeURIComponent(y)}&since=${encodeURIComponent(l)}`),{});for(let f of w.messages)n.onMessage(f);l=w.cursor,n.onHealthy?.()}catch(w){n.onError?.(x(w))}u||(d=setTimeout(m,c))},p=()=>{u=!0,d&&clearTimeout(d)};return i?.signal?.addEventListener("abort",p),d=setTimeout(m,0),p}}};var rt=e=>"transport"in e?e.transport:z(e);var nt=/^https?:\/\//i,ot=/^\d{4}-\d{2}-\d{2}(?:[T ]|$)/,st=e=>e.replace(/_/g," ").replace(/\b\w/g,t=>t.toUpperCase());function it(e){if(typeof e=="number")return"number";if(typeof e=="boolean")return"boolean";if(typeof e=="string"){if(nt.test(e))return"url";if(ot.test(e))return"date"}return"text"}function le(e){let t=[],r=new Map;for(let o of e)for(let[s,a]of Object.entries(o.data??{})){if(a==null)continue;let n=r.get(s);n||(n=new Map,r.set(s,n),t.push(s));let i=it(a);n.set(i,(n.get(i)??0)+1)}return t.map(o=>{let s=r.get(o)??new Map,a="text",n=-1;for(let[i,l]of s)l>n&&(n=l,a=i);return{key:o,label:st(o),type:a}})}var at=e=>typeof e=="number"?e:Number(e)||0,ue=e=>/rate|position|rank|score|percent|avg/i.test(e),lt=/posted|published|sent|completed|shipped|launched|_at/i,ut=new Set(["service","order","end_user_id"]);function de(e,t){let r=e.filter(l=>!ut.has(l.key)),o=r.filter(l=>l.type==="number").slice(0,3),s=r.find(l=>l.key==="status")??r.find(l=>l.type==="select"),a=r.find(l=>l.type==="date"&&lt.test(l.key))??r.find(l=>l.type==="date"),n=r.filter(l=>l.type==="number"&&!ue(l.key)).map(l=>({field:l,total:t.reduce((u,d)=>u+at(d.data[l.key]),0)})).sort((l,u)=>u.total-l.total).find(l=>l.total>0)?.field??null,i=[{type:"stat",label:"Items",agg:"count"}];for(let l of o){let u=ue(l.key);i.push({type:"stat",metric:l.key,agg:u?"avg":"sum",label:u?`Avg ${l.label.toLowerCase()}`:l.label})}return a&&i.push({type:"line",x:a.key,y:n?.key,agg:"sum",title:n?`${n.label} by day`:"Items by day"}),s&&i.push({type:"donut",groupBy:s.key,title:s.label}),i.push({type:"table",columns:r.map(l=>l.key)}),{version:1,widgets:i}}var pe=6,ce=6,me=4,ge={stat:{w:1,h:1},chart:{w:2,h:2},block:{w:6,h:2}},dt=e=>Math.max(1,Math.min(6,Math.round(e))),pt=e=>Math.max(1,Math.min(4,Math.round(e)));function W(e){return e==="stat"?"stat":e==="series"||e==="donut"?"chart":"block"}function fe(e){return e==="stat"?"stat":e==="line"||e==="bar"||e==="donut"?"chart":"block"}function ye(e){return ge[e]}function q(e,t,r){let o=ge[e];return{w:t===void 0?o.w:dt(t),h:r===void 0?o.h:pt(r)}}function J(e){let t=[],r=[],o=(n,i,l,u)=>{if(n<0||n+l>6)return!1;for(let d=0;d<u;d+=1){let c=r[i+d];if(c){for(let m=0;m<l;m+=1)if(c[n+m])return!1}}return!0},s=(n,i,l,u)=>{for(let d=0;d<u;d+=1){let c=r[i+d]??[];for(let m=0;m<l;m+=1)c[n+m]=!0;r[i+d]=c}},a=(n,i)=>{for(let l=0;;l+=1)for(let u=0;u+n<=6;u+=1)if(o(u,l,n,i))return{gx:u,gy:l}};for(let n of e){let i=q(W(n.kind),n.w,n.h),u=n.gx!==void 0&&n.gy!==void 0&&o(n.gx,n.gy,i.w,i.h)&&n.gx!==void 0&&n.gy!==void 0?{gx:n.gx,gy:n.gy}:a(i.w,i.h);s(u.gx,u.gy,i.w,i.h),t.push({widget:n,gx:u.gx,gy:u.gy,w:i.w,h:i.h})}return t}function be(e){let t=[],r=[];for(let o of e)W(o.kind)==="block"?r.push(o):t.push(o);return{tiles:J(t),blocks:r}}var he=new Set(["service","order","end_user_id"]),K=e=>typeof e=="number"?e:Number(e)||0,xe=e=>e==null?"":String(e);function X(e,t){if(e==="count")return t.length;if(t.length===0)return 0;if(e==="last")return t[t.length-1]??0;if(e==="min")return Math.min(...t);if(e==="max")return Math.max(...t);let r=t.reduce((o,s)=>o+s,0);return e==="avg"?Math.round(r/t.length*100)/100:r}function ct(e,t,r,o){let s=new Map;for(let a of e){let n=new Date(xe(a.data[t]));if(Number.isNaN(n.getTime()))continue;let i=n.toISOString().slice(0,10),l=s.get(i)??[];l.push(r?K(a.data[r]):1),s.set(i,l)}return[...s.entries()].sort((a,n)=>a[0]<n[0]?-1:1).map(([a,n])=>({label:new Date(`${a}T00:00:00`).toLocaleDateString(void 0,{month:"short",day:"numeric"}),value:r?X(o,n):n.length}))}function mt(e,t,r,o="sum"){let s=new Map;for(let a of e){let n=xe(a.data[t]).trim();if(!n)continue;let i=s.get(n)??[];i.push(r?K(a.data[r]):1),s.set(n,i)}return[...s.entries()].map(([a,n])=>({label:a,value:r?X(o,n):n.length})).sort((a,n)=>n.value-a.value)}function gt(e,t,r,o){switch(e.type){case"stat":{let s=e.metric?t.get(e.metric):void 0;if(e.metric&&!s)return null;if(!s)return{kind:"stat",label:e.label??"Items",value:o.length};let a=o.map(n=>K(n.data[s.key]));return{kind:"stat",label:e.label??s.label,value:X(e.agg??"sum",a)}}case"line":case"bar":{if(!t.has(e.x)||e.y&&!t.has(e.y))return null;let s=ct(o,e.x,e.y,e.agg??"sum");return s.length<2?null:{kind:"series",draw:e.type,title:e.title??"By day",points:s}}case"donut":{if(!t.has(e.groupBy))return null;let s=mt(o,e.groupBy,e.metric,e.agg??"sum");return s.length===0?null:{kind:"donut",title:e.title??t.get(e.groupBy)?.label??"Breakdown",points:s}}case"table":{let s=e.columns?e.columns.map(a=>t.get(a)).filter(a=>a!==void 0&&!he.has(a.key)):r;return s.length===0?null:{kind:"table",title:e.title,columns:s,rows:o}}case"text":return{kind:"text",title:e.title,body:e.body};default:return null}}function we(e,t,r,o={}){let s=new Map,a=l=>({byKey:new Map(l.fields.map(u=>[u.key,u])),cols:l.fields.filter(u=>!he.has(u.key)),rows:l.rows}),n=a({fields:t,rows:r});for(let[l,u]of Object.entries(o))s.set(l,a(u));let i=[];for(let l of e.widgets){let u=l.type==="text"?void 0:l.source,d=u?s.get(u):n;if(!d)continue;let c=gt(l,d.byKey,d.cols,d.rows);c&&i.push({...c,w:l.w,h:l.h,gx:l.gx,gy:l.gy})}return i}var ft=new Set(["sum","avg","count","min","max","last"]),ve=e=>typeof e=="string"&&ft.has(e)?e:void 0,b=e=>typeof e=="string"&&e!==""?e:void 0,D=e=>typeof e=="number"&&e>=1?Math.min(6,Math.round(e)):void 0,I=e=>typeof e=="number"&&e>=1?Math.min(4,Math.round(e)):void 0,P=e=>typeof e=="number"&&e>=0?Math.round(e):void 0;function yt(e){if(typeof e!="object"||e===null)return null;let t=e;switch(t.type){case"stat":return{type:"stat",source:b(t.source),label:b(t.label),metric:b(t.metric)??b(t.column),agg:ve(t.agg),w:D(t.w),h:I(t.h),gx:P(t.gx),gy:P(t.gy)};case"line":case"bar":{let r=b(t.x);return r?{type:t.type,source:b(t.source),title:b(t.title),x:r,y:b(t.y)??b(t.column),agg:ve(t.agg),w:D(t.w),h:I(t.h),gx:P(t.gx),gy:P(t.gy)}:null}case"donut":{let r=b(t.groupBy)??b(t.column);return r?{type:"donut",source:b(t.source),title:b(t.title),groupBy:r,w:D(t.w),h:I(t.h),gx:P(t.gx),gy:P(t.gy)}:null}case"table":{let r=Array.isArray(t.columns)?t.columns.filter(o=>typeof o=="string"):void 0;return{type:"table",source:b(t.source),title:b(t.title),columns:r,w:D(t.w),h:I(t.h),gx:P(t.gx),gy:P(t.gy)}}case"text":{let r=b(t.body);return r?{type:"text",title:b(t.title),body:r,w:D(t.w),h:I(t.h),gx:P(t.gx),gy:P(t.gy)}:null}default:return null}}function Se(e){let t=e;if(typeof e=="string"){if(e.trim()==="")return null;try{t=JSON.parse(e)}catch{return null}}if(typeof t!="object"||t===null)return null;let r=t.widgets;if(!Array.isArray(r))return null;let o=r.map(yt).filter(a=>a!==null);if(o.length===0)return null;let s=t.version;return{version:typeof s=="number"?s:1,title:b(t.title),widgets:o}}function Q(e){if(typeof e=="string")return e?{kind:"file",value:e}:null;if(e&&typeof e=="object"){let t=e,r=typeof t.value=="string"?t.value:"",o=t.kind==="link"||t.kind==="text"||t.kind==="table"?t.kind:"file",s=typeof t.v=="number"&&t.v>=1?Math.floor(t.v):void 0;return r?{kind:o,value:r,...s?{v:s}:{}}:null}return null}function Y(e){let t=new Map;for(let r of e){let o=r.v??1,s=t.get(o)??[];s.push(r),t.set(o,s)}return[...t.entries()].sort(([r],[o])=>r-o).map(([r,o])=>({v:r,items:o}))}function ke(e){let t=e.files;if(typeof t=="string"&&t.trim()!=="")try{let o=JSON.parse(t);if(Array.isArray(o))return o.map(Q).filter(s=>s!==null)}catch{}let r=String(e.file??"");return r?[{kind:"file",value:r}]:[]}function Pe(e,t,r,o=""){let a=Y(e).find(i=>i.v===t)?.items??[],n=a.filter(i=>i.kind==="file").map(i=>r.get(i.value)??"");return a.some(i=>i.kind==="table")&&n.push(o),n.length===0||n.some(i=>i==="")?"awaiting":n.some(i=>i==="revise")?"revise":"accepted"}function Te(e){return Number(e.published_version)||0}function Z(e){return e==="number"||e==="date"||e==="boolean"||e==="select"||e==="url"?e:e==="link"?"url":e==="checkbox"?"boolean":"text"}function Re(e){try{let t=JSON.parse(e);if(Array.isArray(t.columns)&&Array.isArray(t.rows)&&t.columns.length){let r=t.columns.map((a,n)=>({key:typeof a.key=="string"&&a.key?a.key:typeof a.id=="string"&&a.id?a.id:`column_${n+1}`,label:typeof a.label=="string"?a.label:"",type:Z(a.type),...a.clientEditable===!0?{clientEditable:!0}:{}})),o=t.rows.map((a,n)=>({id:typeof a.id=="string"&&a.id?a.id:`row_${n}`,cells:a.cells&&typeof a.cells=="object"?a.cells:{}})),s=typeof t.name=="string"?t.name:void 0;return{columns:r,rows:o,...s?{name:s}:{}}}}catch{}return null}function Ce(e){return e==null?"":String(e)}function De(e){return e===!0||e==="true"||e==="1"||e==="yes"||e==="\u2713"}function E(){return{cells:{},verdict:"",comment:""}}function Ie(e){if(typeof e!="string"||e.trim()==="")return E();try{let t=JSON.parse(e);if(t&&typeof t=="object"&&!Array.isArray(t)){let r=t;return{cells:r.cells&&typeof r.cells=="object"?r.cells:r,verdict:r.verdict==="accepted"||r.verdict==="revise"?r.verdict:"",comment:typeof r.comment=="string"?r.comment:""}}}catch{}return E()}function He(e,t,r){if(e.clientEditable){let o=r.cells[t.id];if(o&&e.key in o)return o[e.key]}return t.cells[e.key]}function Ae(e,t,r,o){return{...e,cells:{...e.cells,[t]:{...e.cells[t]??{},[r]:o}}}}function Me(e,t,r){return{...e,verdict:t,comment:r}}function $e(e){let t=new Date(`${e}T00:00:00`);return Number.isNaN(t.getTime())?e:t.toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"})}var bt=/\/+$/,C="/api/v1/end-user",H=class extends Error{constructor(t){super(t),this.name="PortalConflict"}};function ht(e){let t="";for(let o=0;o<e.length;o+=32768)t+=String.fromCharCode(...e.subarray(o,o+32768));return btoa(t)}var xt=e=>{let t=e.baseUrl.replace(bt,""),r=()=>typeof e.token=="function"?e.token():e.token,o=async()=>({"content-type":"application/json",authorization:`Bearer ${await r()}`}),s=async(n,i)=>{try{let l=await fetch(`${t}${C}${n}`,{method:i.method,headers:await o(),...i.body===void 0?{}:{body:JSON.stringify(i.body)}});if(l.status===409){let u=await l.json().catch(()=>({}));throw new H(u.message??"Someone else saved this first.")}if(!l.ok){let u=await l.text().catch(()=>""),d=`${i.method} ${n} \u2192 ${String(l.status)}`;try{let c=JSON.parse(u);c.message&&(d=c.message)}catch{d=u?`${d}: ${u}`:d}throw x({error:d})}return await l.json()}catch(l){throw l instanceof H?l:x(l)}},a=n=>`/tables/${encodeURIComponent(n)}`;return{listTables:async()=>(await v(`${t}${C}/tables`,await o())).tables,listRows:async(n,i)=>await v(`${t}${C}${a(n)}/rows?limit=${String(i??100)}`,await o()),insertRow:async(n,i)=>{let{rowIds:l}=await s(`${a(n)}/rows`,{method:"POST",body:{rows:[i]}}),u=l[0];if(!u)throw x(new Error("The row was not created."));return u},patchRow:async(n,i,l)=>(await s(`${a(n)}/rows/${encodeURIComponent(i)}`,{method:"PATCH",body:l})).updated,deleteRow:async(n,i)=>(await s(`/${encodeURIComponent(n)}/${encodeURIComponent(i)}`,{method:"DELETE"})).deleted,listFiles:async()=>(await v(`${t}${C}/tables/files/rows?limit=200`,await o())).rows.map(i=>({id:i.rowId,filename:String(i.data.filename??""),source:String(i.data.source??"client"),campaign:String(i.data.campaign??""),size:typeof i.data.size=="number"?i.data.size:0,createdAt:i.createdAt})),uploadFile:async(n,i)=>{let l=new Uint8Array(await n.arrayBuffer());return await s("/files",{method:"POST",body:{filename:n.name,mime:n.type||"application/octet-stream",data:ht(l),...i===void 0?{}:{message:i}}})},fileLink:async n=>await v(`${t}${C}/files/${encodeURIComponent(n)}/url`,await o()),deleteFile:async n=>(await s(`/files/${encodeURIComponent(n)}`,{method:"DELETE"})).deleted,listDocuments:async()=>(await v(`${t}${C}/documents`,await o())).documents,readDocument:async n=>(await v(`${t}${C}/documents/${encodeURIComponent(n)}`,await o())).document,saveDocument:async(n,i)=>await s(`/documents/${encodeURIComponent(n)}`,{method:"PATCH",body:i})}};var wt=/\/+$/,vt="/api/v1/end-user",St=e=>{let t=e.baseUrl.replace(wt,""),r=async(o,s)=>{let a;try{a=await fetch(`${t}${vt}${o}`,s===void 0?{}:{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(s)})}catch(n){throw x(n)}if(a.status===429)throw x({error:"rate_limited",retryable:!0});if(!a.ok)throw x({error:`shop_request_failed_${String(a.status)}`});try{return await a.json()}catch(n){throw x(n)}};return{listProducts:async()=>{let o=await r(`/shop/products?publishable_key=${encodeURIComponent(e.publishableKey)}`);return{products:o.products.map(s=>({...s,currency:typeof s.currency=="string"?s.currency:""})),truncated:o.truncated===!0}},apply:async o=>await r("/shop/apply",{publishable_key:e.publishableKey,name:o.name,email:o.email,...o.phone?{phone:o.phone}:{},...o.message?{message:o.message}:{},...o.productId?{productId:o.productId}:{}})}};var A=class extends Error{code;status;constructor(t,r,o){super(r),this.name="CreditRefused",this.code=t,this.status=o}},kt=/\/+$/,Pt="/api/v1/end-user",Tt=e=>{let t=e.baseUrl.replace(kt,""),r=()=>typeof e.token=="function"?e.token():e.token,o=async(s,a={method:"GET"})=>{try{let n=await fetch(`${t}${Pt}${s}`,{method:a.method,headers:{"content-type":"application/json",authorization:`Bearer ${await r()}`},...a.body===void 0?{}:{body:JSON.stringify(a.body)}});if(!n.ok){let i=await n.json().catch(()=>({}));throw new A(i.error??"request_failed",i.message??`${a.method} ${s} \u2192 ${String(n.status)}`,n.status)}return await n.json()}catch(n){throw n instanceof A?n:x(n)}};return{wallet:()=>o("/credits"),history:()=>o("/credits/history"),topup:s=>o("/credits/checkout",{method:"POST",body:{packId:s}}),checkout:s=>o("/shop/checkout",{method:"POST",body:s})}};import{useCallback as We,useEffect as Rt,useState as ee}from"react";var Ct=e=>{let[t,r]=ee(null),[o,s]=ee(!0),[a,n]=ee(null),i=We(async()=>{try{r(await e.wallet()),n(null)}catch{n("Couldn't read your balance just now.")}finally{s(!1)}},[e]),l=We(()=>{i().catch(()=>{})},[i]);return Rt(()=>(l(),window.addEventListener("focus",l),()=>{window.removeEventListener("focus",l)}),[l]),{wallet:t,loading:o,failure:a,refresh:l}};var Dt=new Set(["buy","ask","apply"]);function It(e){return Dt.has(e.mode)?e.mode:"ask"}var Ht={kind:"quoted"};function O(e,t){if(!t)return e.toLocaleString();if(t.toLowerCase()==="credits")return`${e.toLocaleString()} ${e===1?"credit":"credits"}`;let r=Number.isInteger(e)?0:2;try{return new Intl.NumberFormat(void 0,{style:"currency",currency:t,minimumFractionDigits:r,maximumFractionDigits:r}).format(e)}catch{return`${t} ${e.toLocaleString()}`}}function Ee(e,t){let r=/^[a-z]+$/i.test(t)&&!t.endsWith("s")?"s":"";return`${e.toLocaleString()} ${t}${r}`}function Oe(e,t){return e.kind==="quoted"?"Priced on enquiry":e.kind==="flat"?O(e.price,t):`${O(e.unitPrice,t)} per ${e.unitStep===1?e.unit:Ee(e.unitStep,e.unit)}`}function At(e){let t=e.currency,r=e.pricing;if(r.kind!=="variants")return Oe(r,t);let o=r.variants.map(s=>s.price).filter(s=>typeof s=="number");return o.length>0?`From ${O(Math.min(...o),t)}`:"Priced on enquiry"}function Mt(e,t){if(e.kind!=="variants")return e;let r=e.variants.find(o=>o.name===t);return typeof r?.price=="number"?{kind:"flat",price:r.price}:Ht}function $t(e,t){return e.kind==="flat"?e.price:e.kind==="per_unit"?e.unitPrice*Math.ceil(t/Math.max(e.unitStep,1)):null}function Wt(e,t){let r=t.kind==="per_unit"?Math.max(t.unitStep,1):1;return{min:Math.max(e.minQty??r,r),max:e.maxQty??null,step:r}}function Et(e,t){let r=e.variants?.find(o=>o.name===t);return r&&r.includes.length>0?r.includes:e.includes}function Ot(e,t){let r=[];for(let o of e){let s=t(o).trim();s&&!r.includes(s)&&r.push(s)}return r}function _t(e,t,r,o){let s=t?`${e.name} \u2014 ${t}`:e.name,a=r.kind==="per_unit"?`, ${Ee(o,r.unit)}`:"";return`I'd like to buy ${s}${a}. How do I go ahead?`}function Lt(e){return e?(e&&typeof e=="object"&&"error"in e?String(e.error):"")==="rate_limited"?"That's a lot of looking at once \u2014 give it a moment, then reload.":"The shop isn't loading right now. Please try again shortly.":null}import{useCallback as Ft,useEffect as Ut,useState as M}from"react";var Nt=e=>e&&typeof e=="object"&&typeof e.error=="string"?e.error:e instanceof Error?e.message:"shop_unavailable",Vt=e=>{let[t,r]=M([]),[o,s]=M(!1),[a,n]=M(!0),[i,l]=M(null),[u,d]=M(0);Ut(()=>{let m=!0;return n(!0),e.listProducts().then(p=>{m&&(r(p.products),s(p.truncated),l(null))}).catch(p=>{m&&l(Nt(p))}).finally(()=>{m&&n(!1)}),()=>{m=!1}},[e,u]);let c=Ft(()=>d(m=>m+1),[]);return{products:t,truncated:o,loading:a,error:i,reload:c}};import{useCallback as jt,useEffect as _e,useRef as Gt,useState as _}from"react";var Le="greeting";function Fe(e,t){if(e.some(a=>a.id===t.id))return e;let r=e.filter(a=>a.id!==Le),o=a=>a.author==="client"==(t.author==="client");return[...r.filter(a=>!(a.pending&&o(a)&&a.text===t.text)),t]}var Bt=(e,t)=>{let[r,o]=_([]),[s,a]=_(""),[n,i]=_(!1),[l,u]=_(null),d=Gt(0),c=t?.pollMs??2e3;_e(()=>{let p=!0;return e.getInfo().then(y=>{p&&y.greeting&&o(w=>w.length===0?[{id:Le,cursor:"",author:"agent",text:y.greeting}]:w)}).catch(()=>{}),()=>{p=!1}},[e]),_e(()=>e.subscribe?.({onMessage:p=>o(y=>Fe(y,p)),onError:p=>u(p.error),onHealthy:()=>u(null)},{intervalMs:c}),[e,c]);let m=jt(()=>{let p=s.trim();if(!p||n)return;a(""),u(null),i(!0),d.current+=1;let y=`pending-${d.current}`,w={id:y,cursor:"",author:"client",text:p,pending:!0};o(f=>[...f,w]),e.sendMessage(p).then(f=>{i(!1),f.reply.trim()&&o(g=>g.some(T=>!T.pending&&T.author!=="client"&&T.text===f.reply)?g:(d.current+=1,[...g,{id:`pending-agent-${d.current}`,cursor:"",author:"agent",text:f.reply,pending:!0}]))}).catch(f=>{u(f instanceof Error?f.message:"send_failed"),i(!1),o(k=>k.filter(g=>g.id!==y)),a(k=>k||p)})},[s,n,e]);return{messages:r,input:s,setInput:a,send:m,sending:n,error:l}};export{et as Chat,A as CreditRefused,pe as GRID_COLS,ce as GRID_MAX_COLS,me as GRID_MAX_ROWS,Ke as HolaProvider,H as PortalConflict,W as bandOfKind,fe as bandOfType,_t as buyRequestText,He as cellValue,Ge as createApiTransport,rt as createHolaClient,Tt as createPortalCredits,xt as createPortalData,St as createPortalShop,z as createWidgetTransport,Ce as deliverableCellText,Pe as deliverableStatus,le as deriveFields,E as emptyTableResponses,Ot as facetValues,ye as footprintOf,q as footprintWith,$e as formatDeliverableDate,Y as groupDeliverableVersions,Et as includesFor,de as inferSpec,De as isDeliverableChecked,Fe as mergeMessage,It as modeOf,O as money,Z as normalizeDeliverableColType,Q as normalizeDeliverableItem,Se as parseDashboardSpec,ke as parseDeliverableItems,Re as parseDeliverableTable,Ie as parseTableResponses,J as placeWidgets,Mt as priceFor,Oe as priceLabel,Te as publishedVersionOf,Wt as quantityRange,we as renderModel,Ae as setResponse,Me as setTableReview,At as shelfPriceLabel,Lt as shelfProblem,be as splitLayout,L as textDeltaOf,F as thinkingDeltaOf,U as toolEventOf,$t as totalFor,V as useArtifactUrl,G as useChat,Ct as useCredits,j as useHolaClient,Vt as useShop,Bt as useThread};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@holaboss/client",
3
- "version": "0.2.0-beta.20",
3
+ "version": "0.2.0-beta.22",
4
4
  "description": "Injectable client SDK for embedding a Holaboss AI employee (chat + configurable dashboards today; artifacts next) into your own web app.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",