@holaboss/client 0.2.0-beta.6 → 0.2.0-beta.7

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 _=Object.defineProperty;var de=Object.getOwnPropertyDescriptor;var ue=Object.getOwnPropertyNames;var pe=Object.prototype.hasOwnProperty;var ce=(e,t)=>{for(var o in t)_(e,o,{get:t[o],enumerable:!0})},ge=(e,t,o,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of ue(t))!pe.call(e,r)&&r!==o&&_(e,r,{get:()=>t[r],enumerable:!(s=de(t,r))||s.enumerable});return e};var me=e=>ge(_({},"__esModule",{value:!0}),e);var De={};ce(De,{Chat:()=>Z,HolaProvider:()=>Q,PortalConflict:()=>S,createApiTransport:()=>V,createHolaClient:()=>K,createPortalData:()=>ae,createWidgetTransport:()=>F,deriveFields:()=>N,inferSpec:()=>L,mergeMessage:()=>z,parseDashboardSpec:()=>B,renderModel:()=>j,textDeltaOf:()=>v,thinkingDeltaOf:()=>R,toolEventOf:()=>I,useArtifactUrl:()=>A,useChat:()=>D,useHolaClient:()=>W,useThread:()=>le});module.exports=me(De);var G=e=>{if(!e||typeof e!="object")return null;let t=e;return t.type==="message_update"?t.assistantMessageEvent??null:null},v=e=>{let t=G(e);return t?.type==="text_delta"&&typeof t.delta=="string"?t.delta:null},R=e=>{let t=G(e);return t?.type==="thinking_delta"&&typeof t.delta=="string"?t.delta:null},I=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 fe=/^ /,k=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"}},ye=e=>{let t="message",o=[];for(let s of e.split(`
3
- `))s.startsWith(":")||(s.startsWith("event:")?t=s.slice(6).trim():s.startsWith("data:")&&o.push(s.slice(5).replace(fe,"")));return o.length>0?{event:t,data:o.join(`
4
- `)}:null},be=(e,t,o)=>{let s;try{s=JSON.parse(e.data)}catch{return}if(e.event==="session"){let r=s.sessionId;r&&(o(r),t.onSession?.(r));return}if(e.event==="turn_event"){t.onEvent?.(s);let r=v(s);r&&t.onText?.(r);let l=R(s);l&&t.onThinking?.(l);let n=I(s);n&&t.onTool?.(n);return}if(e.event==="chat_completed"){let r=s;o(r.sessionId),t.onComplete?.(r);return}e.event==="chat_error"&&t.onError?.(k(s))},h=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()},J=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()},q=async(e,t,o,s)=>{let r=await fetch(e.url,{method:"POST",headers:e.headers,body:e.body,signal:s});if(!(r.ok&&r.body)){t.onError?.({error:`stream_failed_${r.status}`});return}let l=r.body.getReader(),n=new TextDecoder,a="",i=()=>{let u=a.indexOf(`
2
+ var L=Object.defineProperty;var ce=Object.getOwnPropertyDescriptor;var ge=Object.getOwnPropertyNames;var me=Object.prototype.hasOwnProperty;var fe=(e,t)=>{for(var r in t)L(e,r,{get:t[r],enumerable:!0})},ye=(e,t,r,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of ge(t))!me.call(e,n)&&n!==r&&L(e,n,{get:()=>t[n],enumerable:!(s=ce(t,n))||s.enumerable});return e};var be=e=>ye(L({},"__esModule",{value:!0}),e);var Oe={};fe(Oe,{Chat:()=>te,HolaProvider:()=>K,PortalConflict:()=>v,createApiTransport:()=>X,createHolaClient:()=>re,createPortalData:()=>de,createWidgetTransport:()=>O,deriveFields:()=>N,inferSpec:()=>j,layoutGroups:()=>G,mergeMessage:()=>V,parseDashboardSpec:()=>J,renderModel:()=>B,textDeltaOf:()=>R,thinkingDeltaOf:()=>I,toolEventOf:()=>E,useArtifactUrl:()=>A,useChat:()=>U,useHolaClient:()=>D,useThread:()=>pe,widgetSpan:()=>z});module.exports=be(Oe);var q=e=>{if(!e||typeof e!="object")return null;let t=e;return t.type==="message_update"?t.assistantMessageEvent??null:null},R=e=>{let t=q(e);return t?.type==="text_delta"&&typeof t.delta=="string"?t.delta:null},I=e=>{let t=q(e);return t?.type==="thinking_delta"&&typeof t.delta=="string"?t.delta:null},E=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 he=/^ /,H=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"}},we=e=>{let t="message",r=[];for(let s of e.split(`
3
+ `))s.startsWith(":")||(s.startsWith("event:")?t=s.slice(6).trim():s.startsWith("data:")&&r.push(s.slice(5).replace(he,"")));return r.length>0?{event:t,data:r.join(`
4
+ `)}:null},xe=(e,t,r)=>{let s;try{s=JSON.parse(e.data)}catch{return}if(e.event==="session"){let n=s.sessionId;n&&(r(n),t.onSession?.(n));return}if(e.event==="turn_event"){t.onEvent?.(s);let n=R(s);n&&t.onText?.(n);let l=I(s);l&&t.onThinking?.(l);let o=E(s);o&&t.onTool?.(o);return}if(e.event==="chat_completed"){let n=s;r(n.sessionId),t.onComplete?.(n);return}e.event==="chat_error"&&t.onError?.(H(s))},h=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()},Y=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()},Q=async(e,t,r,s)=>{let n=await fetch(e.url,{method:"POST",headers:e.headers,body:e.body,signal:s});if(!(n.ok&&n.body)){t.onError?.({error:`stream_failed_${n.status}`});return}let l=n.body.getReader(),o=new TextDecoder,a="",i=()=>{let u=a.indexOf(`
5
5
 
6
- `);for(;u!==-1;){let b=a.slice(0,u);a=a.slice(u+2);let c=ye(b);c&&be(c,t,o),u=a.indexOf(`
6
+ `);for(;u!==-1;){let b=a.slice(0,u);a=a.slice(u+2);let c=we(b);c&&xe(c,t,r),u=a.indexOf(`
7
7
 
8
- `)}},d=async()=>{let u=await l.read();if(!u.done)return a+=n.decode(u.value,{stream:!0}),i(),d()};await d()};var he=/\/+$/,E="/api/v1/end-user",V=e=>{let t=e.baseUrl.replace(he,""),o=()=>typeof e.token=="function"?e.token():e.token,s=n=>e.project?`${n}project=${encodeURIComponent(e.project)}`:"",r=async()=>({"content-type":"application/json",authorization:`Bearer ${await o()}`}),l=async n=>{let a=await fetch(`${t}${E}/chat${s("?")}`,{method:"POST",headers:await r(),body:JSON.stringify({message:n})});if(!a.ok)throw new Error(`hola: message failed (${a.status})`);return{reply:(await a.json()).reply??"",sessionId:"",artifacts:[]}};return{sessionId:()=>"",getInfo:async()=>h(`${t}${E}/chat/info${s("?")}`,await r()),sendMessage:l,streamMessage:async(n,a)=>{try{let i=await l(n);a.onText?.(i.reply),a.onComplete?.(i)}catch(i){a.onError?.(k(i))}},subscribe:(n,a)=>{let i=a?.since??"0",d=!1,u,b=a?.intervalMs??3e3,c=async()=>{try{let m=await h(`${t}${E}/chat/thread?since=${encodeURIComponent(i)}${s("&")}`,await r());for(let g of m.messages)n.onMessage(g);i=m.cursor,n.onHealthy?.()}catch(m){n.onError?.(k(m))}d||(u=setTimeout(c,b))},p=()=>{d=!0,u&&clearTimeout(u)};return a?.signal?.addEventListener("abort",p),u=setTimeout(c,0),p},requestHuman:async()=>{await fetch(`${t}${E}/chat/request-human${s("?")}`,{method:"POST",headers:await r(),body:"{}"})}}};var $=require("react"),A=(e,t)=>{let[o,s]=(0,$.useState)("");return(0,$.useEffect)(()=>{if(!e){s("");return}let r=Uint8Array.from(atob(e),n=>n.charCodeAt(0)),l=URL.createObjectURL(new Blob([r],{type:t}));return s(l),()=>URL.revokeObjectURL(l)},[e,t]),o};var U=require("react");var M=require("react"),X=require("react/jsx-runtime"),Y=(0,M.createContext)(null),Q=({client:e,children:t})=>(0,X.jsx)(Y.Provider,{value:e,children:t}),W=()=>{let e=(0,M.useContext)(Y);if(!e)throw new Error("useHolaClient must be used within <HolaProvider>");return e};var x=require("react"),D=e=>{let[t,o]=(0,x.useState)([]),[s,r]=(0,x.useState)(""),[l,n]=(0,x.useState)(!1),[a,i]=(0,x.useState)(null),d=(0,x.useRef)(0),u=(0,x.useCallback)(()=>{let c=d.current;return d.current+=1,c},[]);(0,x.useEffect)(()=>{let c=!0;return e.getInfo().then(p=>{c&&p.greeting&&o([{id:u(),role:"assistant",text:p.greeting}])}).catch(()=>{}),()=>{c=!1}},[e,u]);let b=(0,x.useCallback)(()=>{let c=s.trim();if(!c||l)return;r(""),i(null),n(!0);let p=u(),m=u();o(f=>[...f,{id:p,role:"user",text:c},{id:m,role:"assistant",text:"",streaming:!0}]);let g=f=>{o(T=>T.map(O=>O.id===m?f(O):O))};e.streamMessage(c,{onText:f=>g(T=>({...T,text:T.text+f})),onComplete:f=>{g(T=>({...T,text:f.reply||T.text,artifacts:f.artifacts,streaming:!1})),n(!1)},onError:f=>{g(T=>({...T,streaming:!1})),i(f.error),n(!1)}}).catch(f=>{g(T=>({...T,streaming:!1})),i(f instanceof Error?f.message:"stream_failed"),n(!1)})},[s,l,e,u]);return{messages:t,input:s,setInput:r,send:b,sending:l,error:a}};var y=require("react/jsx-runtime"),P={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"}},xe=({artifact:e})=>{let t=A(e.dataBase64??"",e.mimeType),o=e.url??t;return o?e.mimeType.startsWith("image/")?(0,y.jsx)("a",{href:o,rel:"noopener noreferrer",target:"_blank",children:(0,y.jsx)("img",{alt:e.filename,src:o,style:P.image})}):(0,y.jsx)("a",{download:e.filename,href:o,style:P.link,children:e.filename}):null},Z=()=>{let e=W(),{messages:t,input:o,setInput:s,send:r,sending:l,error:n}=D(e),a=(0,U.useRef)(null);(0,U.useEffect)(()=>{let d=a.current;d&&(d.scrollTop=d.scrollHeight)},[t]);let i=d=>{d.preventDefault(),r()};return(0,y.jsxs)("div",{style:P.root,children:[(0,y.jsx)("div",{ref:a,style:P.log,children:t.map(d=>(0,y.jsxs)("div",{style:d.role==="user"?P.user:P.assistant,children:[d.text||(d.streaming?"\u2026":""),d.artifacts&&d.artifacts.length>0?(0,y.jsx)("div",{style:P.artifacts,children:d.artifacts.map(u=>(0,y.jsx)(xe,{artifact:u},u.filename))}):null]},d.id))}),n?(0,y.jsx)("div",{style:P.error,children:n}):null,(0,y.jsxs)("form",{onSubmit:i,style:P.form,children:[(0,y.jsx)("input",{"aria-label":"Message",onChange:d=>s(d.target.value),placeholder:"Type a message\u2026",style:P.input,value:o}),(0,y.jsx)("button",{disabled:l||o.trim().length===0,style:P.button,type:"submit",children:"Send"})]})]})};var we=/\/+$/,F=e=>{let t=e.sessionId,o=e.baseUrl.replace(we,""),s=n=>`${o}/endpoint/${encodeURIComponent(e.token)}${n}`,r={"content-type":"application/json"},l=(n,a)=>({url:s(n),headers:r,body:JSON.stringify({message:a,...t?{sessionId:t}:{},...e.identity?{externalUserId:e.identity.externalUserId,userHmac:e.identity.userHmac}:{}})});return{sessionId:()=>t,getInfo:()=>h(s("/config"),{}),sendMessage:async n=>{let a=await J(l("/message",n));return t=a.sessionId,a},streamMessage:(n,a,i)=>q(l("/message/stream",n),a,d=>{t=d},i),subscribe:(n,a)=>{let i=a?.since??"0",d=!1,u,b=a?.intervalMs??3e3,c=async()=>{let m=t;if(m)try{let g=await h(s(`/messages?session=${encodeURIComponent(m)}&since=${encodeURIComponent(i)}`),{});for(let f of g.messages)n.onMessage(f);i=g.cursor,n.onHealthy?.()}catch(g){n.onError?.(k(g))}d||(u=setTimeout(c,b))},p=()=>{d=!0,u&&clearTimeout(u)};return a?.signal?.addEventListener("abort",p),u=setTimeout(c,0),p},requestHuman:async()=>{t&&await fetch(s("/request-human"),{method:"POST",headers:r,body:JSON.stringify({sessionId:t})})}}};var K=e=>"transport"in e?e.transport:F(e);var Te=/^https?:\/\//i,Pe=/^\d{4}-\d{2}-\d{2}(?:[T ]|$)/,He=e=>e.replace(/_/g," ").replace(/\b\w/g,t=>t.toUpperCase());function ke(e){if(typeof e=="number")return"number";if(typeof e=="boolean")return"boolean";if(typeof e=="string"){if(Te.test(e))return"url";if(Pe.test(e))return"date"}return"text"}function N(e){let t=[],o=new Map;for(let s of e)for(let[r,l]of Object.entries(s.data??{})){if(l==null)continue;let n=o.get(r);n||(n=new Map,o.set(r,n),t.push(r));let a=ke(l);n.set(a,(n.get(a)??0)+1)}return t.map(s=>{let r=o.get(s)??new Map,l="text",n=-1;for(let[a,i]of r)i>n&&(n=i,l=a);return{key:s,label:He(s),type:l}})}var Ce=e=>typeof e=="number"?e:Number(e)||0,ee=e=>/rate|position|rank|score|percent|avg/i.test(e),Se=/posted|published|sent|completed|shipped|launched|_at|date/i,ve=new Set(["service","order","end_user_id"]);function L(e,t){let o=e.filter(i=>!ve.has(i.key)),s=o.filter(i=>i.type==="number").slice(0,3),r=o.find(i=>i.key==="status")??o.find(i=>i.type==="select"),l=o.find(i=>i.type==="date"&&Se.test(i.key))??o.find(i=>i.type==="date"),n=o.filter(i=>i.type==="number"&&!ee(i.key)).map(i=>({field:i,total:t.reduce((d,u)=>d+Ce(u.data[i.key]),0)})).sort((i,d)=>d.total-i.total).find(i=>i.total>0)?.field??null,a=[{type:"stat",label:"Items",agg:"count"}];for(let i of s){let d=ee(i.key);a.push({type:"stat",metric:i.key,agg:d?"avg":"sum",label:d?`Avg ${i.label.toLowerCase()}`:i.label})}return l&&a.push({type:"line",x:l.key,y:n?.key,agg:"sum",title:n?`${n.label} by day`:"Items by day"}),r&&a.push({type:"donut",groupBy:r.key,title:r.label}),a.push({type:"table",columns:o.map(i=>i.key)}),{version:1,widgets:a}}var te=new Set(["service","order","end_user_id"]),re=e=>typeof e=="number"?e:Number(e)||0,ne=e=>e==null?"":String(e);function oe(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((s,r)=>s+r,0);return e==="avg"?Math.round(o/t.length):o}function Re(e,t,o,s){let r=new Map;for(let l of e){let n=new Date(ne(l.data[t]));if(Number.isNaN(n.getTime()))continue;let a=n.toISOString().slice(0,10),i=r.get(a)??[];i.push(o?re(l.data[o]):1),r.set(a,i)}return[...r.entries()].sort((l,n)=>l[0]<n[0]?-1:1).map(([l,n])=>({label:new Date(`${l}T00:00:00`).toLocaleDateString(void 0,{month:"short",day:"numeric"}),value:o?oe(s,n):n.length}))}function Ie(e,t){let o=new Map;for(let s of e){let r=ne(s.data[t]).trim();r&&o.set(r,(o.get(r)??0)+1)}return[...o.entries()].sort((s,r)=>r[1]-s[1]).map(([s,r])=>({label:s,value:r}))}function Ee(e,t,o,s){switch(e.type){case"stat":{let r=e.metric?t.get(e.metric):void 0;if(e.metric&&!r)return null;if(!r)return{kind:"stat",label:e.label??"Items",value:s.length};let l=s.map(n=>re(n.data[r.key]));return{kind:"stat",label:e.label??r.label,value:oe(e.agg??"sum",l)}}case"line":case"bar":{if(!t.has(e.x)||e.y&&!t.has(e.y))return null;let r=Re(s,e.x,e.y,e.agg??"sum");return r.length<2?null:{kind:"series",draw:e.type,title:e.title??"By day",points:r}}case"donut":{if(!t.has(e.groupBy))return null;let r=Ie(s,e.groupBy);return r.length===0?null:{kind:"donut",title:e.title??t.get(e.groupBy)?.label??"Breakdown",points:r}}case"table":{let r=e.columns?e.columns.map(l=>t.get(l)).filter(l=>l!==void 0&&!te.has(l.key)):o;return r.length===0?null:{kind:"table",title:e.title,columns:r,rows:s}}case"text":return{kind:"text",title:e.title,body:e.body};default:return null}}function j(e,t,o){let s=t.filter(n=>!te.has(n.key)),r=new Map(t.map(n=>[n.key,n])),l=[];for(let n of e.widgets){let a=Ee(n,r,s,o);a&&l.push(a)}return l}var $e=new Set(["sum","avg","count","min","max","last"]),se=e=>typeof e=="string"&&$e.has(e)?e:void 0,H=e=>typeof e=="string"&&e!==""?e:void 0;function Ae(e){if(typeof e!="object"||e===null)return null;let t=e;switch(t.type){case"stat":return{type:"stat",label:H(t.label),metric:H(t.metric),agg:se(t.agg)};case"line":case"bar":{let o=H(t.x);return o?{type:t.type,title:H(t.title),x:o,y:H(t.y),agg:se(t.agg)}:null}case"donut":{let o=H(t.groupBy);return o?{type:"donut",title:H(t.title),groupBy:o}:null}case"table":{let o=Array.isArray(t.columns)?t.columns.filter(s=>typeof s=="string"):void 0;return{type:"table",title:H(t.title),columns:o}}case"text":{let o=H(t.body);return o?{type:"text",title:H(t.title),body:o}:null}default:return null}}function B(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 s=o.map(Ae).filter(l=>l!==null);if(s.length===0)return null;let r=t.version;return{version:typeof r=="number"?r:1,title:H(t.title),widgets:s}}var Me=/\/+$/,C="/api/v1/end-user",S=class extends Error{constructor(t){super(t),this.name="PortalConflict"}};function We(e){let t="";for(let s=0;s<e.length;s+=32768)t+=String.fromCharCode(...e.subarray(s,s+32768));return btoa(t)}var ae=e=>{let t=e.baseUrl.replace(Me,""),o=()=>typeof e.token=="function"?e.token():e.token,s=async()=>({"content-type":"application/json",authorization:`Bearer ${await o()}`}),r=async(n,a)=>{try{let i=await fetch(`${t}${C}${n}`,{method:a.method,headers:await s(),...a.body===void 0?{}:{body:JSON.stringify(a.body)}});if(i.status===409){let d=await i.json().catch(()=>({}));throw new S(d.message??"Someone else saved this first.")}if(!i.ok){let d=await i.text().catch(()=>""),u=`${a.method} ${n} \u2192 ${String(i.status)}`;try{let b=JSON.parse(d);b.message&&(u=b.message)}catch{u=d?`${u}: ${d}`:u}throw k(new Error(u))}return await i.json()}catch(i){throw k(i)}},l=n=>`/tables/${encodeURIComponent(n)}`;return{listTables:async()=>(await h(`${t}${C}/tables`,await s())).tables,listRows:async(n,a)=>await h(`${t}${C}${l(n)}/rows?limit=${String(a??100)}`,await s()),insertRow:async(n,a)=>{let{rowIds:i}=await r(`${l(n)}/rows`,{method:"POST",body:{rows:[a]}}),d=i[0];if(!d)throw k(new Error("The row was not created."));return d},patchRow:async(n,a,i)=>(await r(`${l(n)}/rows/${encodeURIComponent(a)}`,{method:"PATCH",body:i})).updated,deleteRow:async(n,a)=>(await r(`/${encodeURIComponent(n)}/${encodeURIComponent(a)}`,{method:"DELETE"})).deleted,listFiles:async()=>(await h(`${t}${C}/tables/files/rows?limit=200`,await s())).rows.map(a=>({id:a.rowId,filename:String(a.data.filename??""),source:String(a.data.source??"client"),campaign:String(a.data.campaign??""),size:typeof a.data.size=="number"?a.data.size:0,createdAt:a.createdAt})),uploadFile:async(n,a)=>{let i=new Uint8Array(await n.arrayBuffer());return await r("/files",{method:"POST",body:{filename:n.name,mime:n.type||"application/octet-stream",data:We(i),...a===void 0?{}:{message:a}}})},fileLink:async n=>await h(`${t}${C}/files/${encodeURIComponent(n)}/url`,await s()),deleteFile:async n=>(await r(`/files/${encodeURIComponent(n)}`,{method:"DELETE"})).deleted,listDocuments:async()=>(await h(`${t}${C}/documents`,await s())).documents,readDocument:async n=>(await h(`${t}${C}/documents/${encodeURIComponent(n)}`,await s())).document,saveDocument:async(n,a)=>await r(`/documents/${encodeURIComponent(n)}`,{method:"PATCH",body:a})}};var w=require("react"),ie="greeting";function z(e,t){if(e.some(r=>r.id===t.id))return e;let o=e.filter(r=>r.id!==ie);return[...t.author==="client"?o.filter(r=>!(r.pending&&r.author==="client"&&r.text===t.text)):o,t]}var le=(e,t)=>{let[o,s]=(0,w.useState)([]),[r,l]=(0,w.useState)(""),[n,a]=(0,w.useState)(!1),[i,d]=(0,w.useState)(null),u=(0,w.useRef)(0),b=t?.pollMs??2e3;(0,w.useEffect)(()=>{let p=!0;return e.getInfo().then(m=>{p&&m.greeting&&s(g=>g.length===0?[{id:ie,cursor:"",author:"agent",text:m.greeting}]:g)}).catch(()=>{}),()=>{p=!1}},[e]),(0,w.useEffect)(()=>e.subscribe?.({onMessage:p=>s(m=>z(m,p)),onError:p=>d(p.error),onHealthy:()=>d(null)},{intervalMs:b}),[e,b]);let c=(0,w.useCallback)(()=>{let p=r.trim();if(!p||n)return;l(""),d(null),a(!0),u.current+=1;let m={id:`pending-${u.current}`,cursor:"",author:"client",text:p,pending:!0};s(g=>[...g,m]),e.sendMessage(p).then(()=>a(!1)).catch(g=>{d(g instanceof Error?g.message:"send_failed"),a(!1)})},[r,n,e]);return{messages:o,input:r,setInput:l,send:c,sending:n,error:i}};0&&(module.exports={Chat,HolaProvider,PortalConflict,createApiTransport,createHolaClient,createPortalData,createWidgetTransport,deriveFields,inferSpec,mergeMessage,parseDashboardSpec,renderModel,textDeltaOf,thinkingDeltaOf,toolEventOf,useArtifactUrl,useChat,useHolaClient,useThread});
8
+ `)}},d=async()=>{let u=await l.read();if(!u.done)return a+=o.decode(u.value,{stream:!0}),i(),d()};await d()};var Te=/\/+$/,M="/api/v1/end-user",X=e=>{let t=e.baseUrl.replace(Te,""),r=()=>typeof e.token=="function"?e.token():e.token,s=o=>e.project?`${o}project=${encodeURIComponent(e.project)}`:"",n=async()=>({"content-type":"application/json",authorization:`Bearer ${await r()}`}),l=async o=>{let a=await fetch(`${t}${M}/chat${s("?")}`,{method:"POST",headers:await n(),body:JSON.stringify({message:o})});if(!a.ok)throw new Error(`hola: message failed (${a.status})`);return{reply:(await a.json()).reply??"",sessionId:"",artifacts:[]}};return{sessionId:()=>"",getInfo:async()=>h(`${t}${M}/chat/info${s("?")}`,await n()),sendMessage:l,streamMessage:async(o,a)=>{try{let i=await l(o);a.onText?.(i.reply),a.onComplete?.(i)}catch(i){a.onError?.(H(i))}},subscribe:(o,a)=>{let i=a?.since??"0",d=!1,u,b=a?.intervalMs??3e3,c=async()=>{try{let m=await h(`${t}${M}/chat/thread?since=${encodeURIComponent(i)}${s("&")}`,await n());for(let g of m.messages)o.onMessage(g);i=m.cursor,o.onHealthy?.()}catch(m){o.onError?.(H(m))}d||(u=setTimeout(c,b))},p=()=>{d=!0,u&&clearTimeout(u)};return a?.signal?.addEventListener("abort",p),u=setTimeout(c,0),p},requestHuman:async()=>{await fetch(`${t}${M}/chat/request-human${s("?")}`,{method:"POST",headers:await n(),body:"{}"})}}};var $=require("react"),A=(e,t)=>{let[r,s]=(0,$.useState)("");return(0,$.useEffect)(()=>{if(!e){s("");return}let n=Uint8Array.from(atob(e),o=>o.charCodeAt(0)),l=URL.createObjectURL(new Blob([n],{type:t}));return s(l),()=>URL.revokeObjectURL(l)},[e,t]),r};var F=require("react");var W=require("react"),ee=require("react/jsx-runtime"),Z=(0,W.createContext)(null),K=({client:e,children:t})=>(0,ee.jsx)(Z.Provider,{value:e,children:t}),D=()=>{let e=(0,W.useContext)(Z);if(!e)throw new Error("useHolaClient must be used within <HolaProvider>");return e};var w=require("react"),U=e=>{let[t,r]=(0,w.useState)([]),[s,n]=(0,w.useState)(""),[l,o]=(0,w.useState)(!1),[a,i]=(0,w.useState)(null),d=(0,w.useRef)(0),u=(0,w.useCallback)(()=>{let c=d.current;return d.current+=1,c},[]);(0,w.useEffect)(()=>{let c=!0;return e.getInfo().then(p=>{c&&p.greeting&&r([{id:u(),role:"assistant",text:p.greeting}])}).catch(()=>{}),()=>{c=!1}},[e,u]);let b=(0,w.useCallback)(()=>{let c=s.trim();if(!c||l)return;n(""),i(null),o(!0);let p=u(),m=u();r(f=>[...f,{id:p,role:"user",text:c},{id:m,role:"assistant",text:"",streaming:!0}]);let g=f=>{r(T=>T.map(_=>_.id===m?f(_):_))};e.streamMessage(c,{onText:f=>g(T=>({...T,text:T.text+f})),onComplete:f=>{g(T=>({...T,text:f.reply||T.text,artifacts:f.artifacts,streaming:!1})),o(!1)},onError:f=>{g(T=>({...T,streaming:!1})),i(f.error),o(!1)}}).catch(f=>{g(T=>({...T,streaming:!1})),i(f instanceof Error?f.message:"stream_failed"),o(!1)})},[s,l,e,u]);return{messages:t,input:s,setInput:n,send:b,sending:l,error:a}};var y=require("react/jsx-runtime"),P={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"}},Pe=({artifact:e})=>{let t=A(e.dataBase64??"",e.mimeType),r=e.url??t;return r?e.mimeType.startsWith("image/")?(0,y.jsx)("a",{href:r,rel:"noopener noreferrer",target:"_blank",children:(0,y.jsx)("img",{alt:e.filename,src:r,style:P.image})}):(0,y.jsx)("a",{download:e.filename,href:r,style:P.link,children:e.filename}):null},te=()=>{let e=D(),{messages:t,input:r,setInput:s,send:n,sending:l,error:o}=U(e),a=(0,F.useRef)(null);(0,F.useEffect)(()=>{let d=a.current;d&&(d.scrollTop=d.scrollHeight)},[t]);let i=d=>{d.preventDefault(),n()};return(0,y.jsxs)("div",{style:P.root,children:[(0,y.jsx)("div",{ref:a,style:P.log,children:t.map(d=>(0,y.jsxs)("div",{style:d.role==="user"?P.user:P.assistant,children:[d.text||(d.streaming?"\u2026":""),d.artifacts&&d.artifacts.length>0?(0,y.jsx)("div",{style:P.artifacts,children:d.artifacts.map(u=>(0,y.jsx)(Pe,{artifact:u},u.filename))}):null]},d.id))}),o?(0,y.jsx)("div",{style:P.error,children:o}):null,(0,y.jsxs)("form",{onSubmit:i,style:P.form,children:[(0,y.jsx)("input",{"aria-label":"Message",onChange:d=>s(d.target.value),placeholder:"Type a message\u2026",style:P.input,value:r}),(0,y.jsx)("button",{disabled:l||r.trim().length===0,style:P.button,type:"submit",children:"Send"})]})]})};var ke=/\/+$/,O=e=>{let t=e.sessionId,r=e.baseUrl.replace(ke,""),s=o=>`${r}/endpoint/${encodeURIComponent(e.token)}${o}`,n={"content-type":"application/json"},l=(o,a)=>({url:s(o),headers:n,body:JSON.stringify({message:a,...t?{sessionId:t}:{},...e.identity?{externalUserId:e.identity.externalUserId,userHmac:e.identity.userHmac}:{}})});return{sessionId:()=>t,getInfo:()=>h(s("/config"),{}),sendMessage:async o=>{let a=await Y(l("/message",o));return t=a.sessionId,a},streamMessage:(o,a,i)=>Q(l("/message/stream",o),a,d=>{t=d},i),subscribe:(o,a)=>{let i=a?.since??"0",d=!1,u,b=a?.intervalMs??3e3,c=async()=>{let m=t;if(m)try{let g=await h(s(`/messages?session=${encodeURIComponent(m)}&since=${encodeURIComponent(i)}`),{});for(let f of g.messages)o.onMessage(f);i=g.cursor,o.onHealthy?.()}catch(g){o.onError?.(H(g))}d||(u=setTimeout(c,b))},p=()=>{d=!0,u&&clearTimeout(u)};return a?.signal?.addEventListener("abort",p),u=setTimeout(c,0),p},requestHuman:async()=>{t&&await fetch(s("/request-human"),{method:"POST",headers:n,body:JSON.stringify({sessionId:t})})}}};var re=e=>"transport"in e?e.transport:O(e);var He=/^https?:\/\//i,Se=/^\d{4}-\d{2}-\d{2}(?:[T ]|$)/,Ce=e=>e.replace(/_/g," ").replace(/\b\w/g,t=>t.toUpperCase());function ve(e){if(typeof e=="number")return"number";if(typeof e=="boolean")return"boolean";if(typeof e=="string"){if(He.test(e))return"url";if(Se.test(e))return"date"}return"text"}function N(e){let t=[],r=new Map;for(let s of e)for(let[n,l]of Object.entries(s.data??{})){if(l==null)continue;let o=r.get(n);o||(o=new Map,r.set(n,o),t.push(n));let a=ve(l);o.set(a,(o.get(a)??0)+1)}return t.map(s=>{let n=r.get(s)??new Map,l="text",o=-1;for(let[a,i]of n)i>o&&(o=i,l=a);return{key:s,label:Ce(s),type:l}})}var Re=e=>typeof e=="number"?e:Number(e)||0,ne=e=>/rate|position|rank|score|percent|avg/i.test(e),Ie=/posted|published|sent|completed|shipped|launched|_at|date/i,Ee=new Set(["service","order","end_user_id"]);function j(e,t){let r=e.filter(i=>!Ee.has(i.key)),s=r.filter(i=>i.type==="number").slice(0,3),n=r.find(i=>i.key==="status")??r.find(i=>i.type==="select"),l=r.find(i=>i.type==="date"&&Ie.test(i.key))??r.find(i=>i.type==="date"),o=r.filter(i=>i.type==="number"&&!ne(i.key)).map(i=>({field:i,total:t.reduce((d,u)=>d+Re(u.data[i.key]),0)})).sort((i,d)=>d.total-i.total).find(i=>i.total>0)?.field??null,a=[{type:"stat",label:"Items",agg:"count"}];for(let i of s){let d=ne(i.key);a.push({type:"stat",metric:i.key,agg:d?"avg":"sum",label:d?`Avg ${i.label.toLowerCase()}`:i.label})}return l&&a.push({type:"line",x:l.key,y:o?.key,agg:"sum",title:o?`${o.label} by day`:"Items by day"}),n&&a.push({type:"donut",groupBy:n.key,title:n.label}),a.push({type:"table",columns:r.map(i=>i.key)}),{version:1,widgets:a}}function G(e){let t=[];for(let r of e){let s=t.length>0?t[t.length-1]:void 0;r.kind==="stat"?s?.kind==="stats"?s.items.push(r):t.push({kind:"stats",items:[r]}):r.kind==="series"||r.kind==="donut"?s?.kind==="charts"?s.items.push(r):t.push({kind:"charts",items:[r]}):t.push({kind:"block",item:r})}return t}var oe=new Set(["service","order","end_user_id"]),se=e=>typeof e=="number"?e:Number(e)||0,ae=e=>e==null?"":String(e);function ie(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((s,n)=>s+n,0);return e==="avg"?Math.round(r/t.length):r}function Me(e,t,r,s){let n=new Map;for(let l of e){let o=new Date(ae(l.data[t]));if(Number.isNaN(o.getTime()))continue;let a=o.toISOString().slice(0,10),i=n.get(a)??[];i.push(r?se(l.data[r]):1),n.set(a,i)}return[...n.entries()].sort((l,o)=>l[0]<o[0]?-1:1).map(([l,o])=>({label:new Date(`${l}T00:00:00`).toLocaleDateString(void 0,{month:"short",day:"numeric"}),value:r?ie(s,o):o.length}))}function $e(e,t){let r=new Map;for(let s of e){let n=ae(s.data[t]).trim();n&&r.set(n,(r.get(n)??0)+1)}return[...r.entries()].sort((s,n)=>n[1]-s[1]).map(([s,n])=>({label:s,value:n}))}function Ae(e,t,r,s){switch(e.type){case"stat":{let n=e.metric?t.get(e.metric):void 0;if(e.metric&&!n)return null;if(!n)return{kind:"stat",label:e.label??"Items",value:s.length};let l=s.map(o=>se(o.data[n.key]));return{kind:"stat",label:e.label??n.label,value:ie(e.agg??"sum",l)}}case"line":case"bar":{if(!t.has(e.x)||e.y&&!t.has(e.y))return null;let n=Me(s,e.x,e.y,e.agg??"sum");return n.length<2?null:{kind:"series",draw:e.type,title:e.title??"By day",points:n}}case"donut":{if(!t.has(e.groupBy))return null;let n=$e(s,e.groupBy);return n.length===0?null:{kind:"donut",title:e.title??t.get(e.groupBy)?.label??"Breakdown",points:n}}case"table":{let n=e.columns?e.columns.map(l=>t.get(l)).filter(l=>l!==void 0&&!oe.has(l.key)):r;return n.length===0?null:{kind:"table",title:e.title,columns:n,rows:s}}case"text":return{kind:"text",title:e.title,body:e.body};default:return null}}function B(e,t,r){let s=t.filter(o=>!oe.has(o.key)),n=new Map(t.map(o=>[o.key,o])),l=[];for(let o of e.widgets){let a=Ae(o,n,s,r);a&&l.push({...a,w:o.w})}return l}function z(e,t,r){return e&&e>=1?Math.min(4,Math.round(e)):t==="stat"?1:t==="chart"?r?4:2:4}var We=new Set(["sum","avg","count","min","max","last"]),le=e=>typeof e=="string"&&We.has(e)?e:void 0,k=e=>typeof e=="string"&&e!==""?e:void 0,C=e=>typeof e=="number"&&e>=1?Math.min(4,Math.round(e)):void 0;function De(e){if(typeof e!="object"||e===null)return null;let t=e;switch(t.type){case"stat":return{type:"stat",label:k(t.label),metric:k(t.metric),agg:le(t.agg),w:C(t.w)};case"line":case"bar":{let r=k(t.x);return r?{type:t.type,title:k(t.title),x:r,y:k(t.y),agg:le(t.agg),w:C(t.w)}:null}case"donut":{let r=k(t.groupBy);return r?{type:"donut",title:k(t.title),groupBy:r,w:C(t.w)}:null}case"table":{let r=Array.isArray(t.columns)?t.columns.filter(s=>typeof s=="string"):void 0;return{type:"table",title:k(t.title),columns:r,w:C(t.w)}}case"text":{let r=k(t.body);return r?{type:"text",title:k(t.title),body:r,w:C(t.w)}:null}default:return null}}function J(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 s=r.map(De).filter(l=>l!==null);if(s.length===0)return null;let n=t.version;return{version:typeof n=="number"?n:1,title:k(t.title),widgets:s}}var Ue=/\/+$/,S="/api/v1/end-user",v=class extends Error{constructor(t){super(t),this.name="PortalConflict"}};function Fe(e){let t="";for(let s=0;s<e.length;s+=32768)t+=String.fromCharCode(...e.subarray(s,s+32768));return btoa(t)}var de=e=>{let t=e.baseUrl.replace(Ue,""),r=()=>typeof e.token=="function"?e.token():e.token,s=async()=>({"content-type":"application/json",authorization:`Bearer ${await r()}`}),n=async(o,a)=>{try{let i=await fetch(`${t}${S}${o}`,{method:a.method,headers:await s(),...a.body===void 0?{}:{body:JSON.stringify(a.body)}});if(i.status===409){let d=await i.json().catch(()=>({}));throw new v(d.message??"Someone else saved this first.")}if(!i.ok){let d=await i.text().catch(()=>""),u=`${a.method} ${o} \u2192 ${String(i.status)}`;try{let b=JSON.parse(d);b.message&&(u=b.message)}catch{u=d?`${u}: ${d}`:u}throw H(new Error(u))}return await i.json()}catch(i){throw H(i)}},l=o=>`/tables/${encodeURIComponent(o)}`;return{listTables:async()=>(await h(`${t}${S}/tables`,await s())).tables,listRows:async(o,a)=>await h(`${t}${S}${l(o)}/rows?limit=${String(a??100)}`,await s()),insertRow:async(o,a)=>{let{rowIds:i}=await n(`${l(o)}/rows`,{method:"POST",body:{rows:[a]}}),d=i[0];if(!d)throw H(new Error("The row was not created."));return d},patchRow:async(o,a,i)=>(await n(`${l(o)}/rows/${encodeURIComponent(a)}`,{method:"PATCH",body:i})).updated,deleteRow:async(o,a)=>(await n(`/${encodeURIComponent(o)}/${encodeURIComponent(a)}`,{method:"DELETE"})).deleted,listFiles:async()=>(await h(`${t}${S}/tables/files/rows?limit=200`,await s())).rows.map(a=>({id:a.rowId,filename:String(a.data.filename??""),source:String(a.data.source??"client"),campaign:String(a.data.campaign??""),size:typeof a.data.size=="number"?a.data.size:0,createdAt:a.createdAt})),uploadFile:async(o,a)=>{let i=new Uint8Array(await o.arrayBuffer());return await n("/files",{method:"POST",body:{filename:o.name,mime:o.type||"application/octet-stream",data:Fe(i),...a===void 0?{}:{message:a}}})},fileLink:async o=>await h(`${t}${S}/files/${encodeURIComponent(o)}/url`,await s()),deleteFile:async o=>(await n(`/files/${encodeURIComponent(o)}`,{method:"DELETE"})).deleted,listDocuments:async()=>(await h(`${t}${S}/documents`,await s())).documents,readDocument:async o=>(await h(`${t}${S}/documents/${encodeURIComponent(o)}`,await s())).document,saveDocument:async(o,a)=>await n(`/documents/${encodeURIComponent(o)}`,{method:"PATCH",body:a})}};var x=require("react"),ue="greeting";function V(e,t){if(e.some(n=>n.id===t.id))return e;let r=e.filter(n=>n.id!==ue);return[...t.author==="client"?r.filter(n=>!(n.pending&&n.author==="client"&&n.text===t.text)):r,t]}var pe=(e,t)=>{let[r,s]=(0,x.useState)([]),[n,l]=(0,x.useState)(""),[o,a]=(0,x.useState)(!1),[i,d]=(0,x.useState)(null),u=(0,x.useRef)(0),b=t?.pollMs??2e3;(0,x.useEffect)(()=>{let p=!0;return e.getInfo().then(m=>{p&&m.greeting&&s(g=>g.length===0?[{id:ue,cursor:"",author:"agent",text:m.greeting}]:g)}).catch(()=>{}),()=>{p=!1}},[e]),(0,x.useEffect)(()=>e.subscribe?.({onMessage:p=>s(m=>V(m,p)),onError:p=>d(p.error),onHealthy:()=>d(null)},{intervalMs:b}),[e,b]);let c=(0,x.useCallback)(()=>{let p=n.trim();if(!p||o)return;l(""),d(null),a(!0),u.current+=1;let m={id:`pending-${u.current}`,cursor:"",author:"client",text:p,pending:!0};s(g=>[...g,m]),e.sendMessage(p).then(()=>a(!1)).catch(g=>{d(g instanceof Error?g.message:"send_failed"),a(!1)})},[n,o,e]);return{messages:r,input:n,setInput:l,send:c,sending:o,error:i}};0&&(module.exports={Chat,HolaProvider,PortalConflict,createApiTransport,createHolaClient,createPortalData,createWidgetTransport,deriveFields,inferSpec,layoutGroups,mergeMessage,parseDashboardSpec,renderModel,textDeltaOf,thinkingDeltaOf,toolEventOf,useArtifactUrl,useChat,useHolaClient,useThread,widgetSpan});
package/dist/index.d.cts CHANGED
@@ -306,6 +306,7 @@ interface StatWidget {
306
306
  label?: string | undefined;
307
307
  metric?: string | undefined;
308
308
  agg?: Agg | undefined;
309
+ w?: number | undefined;
309
310
  }
310
311
  /** A time series: `y` (a numeric column) aggregated per day of `x` (a date column); omit `y` to count
311
312
  * rows per day. `line` and `bar` differ only in how the renderer draws the same points. */
@@ -315,24 +316,28 @@ interface SeriesWidget {
315
316
  x: string;
316
317
  y?: string | undefined;
317
318
  agg?: Agg | undefined;
319
+ w?: number | undefined;
318
320
  }
319
321
  /** A breakdown: the count of rows per distinct value of `groupBy`. */
320
322
  interface DonutWidget {
321
323
  type: "donut";
322
324
  title?: string | undefined;
323
325
  groupBy: string;
326
+ w?: number | undefined;
324
327
  }
325
328
  /** A row table: `columns` (by key, in order) or every non-plumbing column when omitted. */
326
329
  interface TableWidget {
327
330
  type: "table";
328
331
  title?: string | undefined;
329
332
  columns?: string[] | undefined;
333
+ w?: number | undefined;
330
334
  }
331
335
  /** Static prose — a note above or between the data widgets. */
332
336
  interface TextWidget {
333
337
  type: "text";
334
338
  title?: string | undefined;
335
339
  body: string;
340
+ w?: number | undefined;
336
341
  }
337
342
  type Widget = StatWidget | SeriesWidget | DonutWidget | TableWidget | TextWidget;
338
343
  interface DashboardSpec {
@@ -357,28 +362,58 @@ type ResolvedWidget = {
357
362
  kind: "stat";
358
363
  label: string;
359
364
  value: number;
365
+ w?: number | undefined;
360
366
  } | {
361
367
  kind: "series";
362
368
  draw: "line" | "bar";
363
369
  title: string;
364
370
  points: Point[];
371
+ w?: number | undefined;
365
372
  } | {
366
373
  kind: "donut";
367
374
  title: string;
368
375
  points: Point[];
376
+ w?: number | undefined;
369
377
  } | {
370
378
  kind: "table";
371
379
  title?: string | undefined;
372
380
  columns: PortalField[];
373
381
  rows: PortalRow[];
382
+ w?: number | undefined;
374
383
  } | {
375
384
  kind: "text";
376
385
  title?: string | undefined;
377
386
  body: string;
387
+ w?: number | undefined;
378
388
  };
379
389
  /** Resolve a whole spec against the data. The result is render-ready and free of widgets that would
380
390
  * draw nothing. */
381
391
  declare function renderModel(spec: DashboardSpec, fields: PortalField[], rows: PortalRow[]): ResolvedWidget[];
392
+ /** The column span (1–4, in a 4-col grid) a widget occupies: its explicit `w` clamped, else a sensible
393
+ * default by its layout run — a stat is a quarter (1); a chart is full (4) on its own row or a half
394
+ * (2) when it shares one; a table or note is full (4). Apps map the number to their own grid classes,
395
+ * so the operator console and the customer portal lay a dashboard out identically. */
396
+ declare function widgetSpan(explicit: number | undefined, run: "stat" | "chart" | "block", alone: boolean): number;
397
+
398
+ type StatView = Extract<ResolvedWidget, {
399
+ kind: "stat";
400
+ }>;
401
+ type ChartView = Extract<ResolvedWidget, {
402
+ kind: "series" | "donut";
403
+ }>;
404
+ type LayoutGroup = {
405
+ kind: "stats";
406
+ items: StatView[];
407
+ } | {
408
+ kind: "charts";
409
+ items: ChartView[];
410
+ } | {
411
+ kind: "block";
412
+ item: ResolvedWidget;
413
+ };
414
+ /** Fold resolved widgets into layout groups: a run of adjacent stat tiles becomes one tile row, a run
415
+ * of adjacent charts becomes one chart row, and a table or note stands alone. Order is preserved. */
416
+ declare function layoutGroups(resolved: ResolvedWidget[]): LayoutGroup[];
382
417
 
383
418
  /** Extract a streamed text delta from a raw pi turn event, or null. */
384
419
  declare const textDeltaOf: (event: unknown) => string | null;
@@ -436,4 +471,4 @@ declare const useThread: (client: HolaClient, options?: {
436
471
  pollMs?: number;
437
472
  }) => UseThread;
438
473
 
439
- export { type Agg, type ApiTransportConfig, Chat, type ChatMessage, type CreateHolaClientOptions, type DashboardSpec, type DonutWidget, 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 Point, PortalConflict, type PortalData, type PortalDocument, type PortalDocumentSummary, type PortalField, type PortalFile, type PortalRow, type PortalRowPage, type PortalTable, type ResolvedWidget, type SeriesWidget, type StatWidget, type TableWidget, type TextWidget, type ThreadMessage, type UseChat, type UseThread, type Widget, type WidgetTransportConfig, type WidgetType, createApiTransport, createHolaClient, createPortalData, createWidgetTransport, deriveFields, inferSpec, mergeMessage, parseDashboardSpec, renderModel, textDeltaOf, thinkingDeltaOf, toolEventOf, useArtifactUrl, useChat, useHolaClient, useThread };
474
+ export { type Agg, type ApiTransportConfig, type ChartView, Chat, type ChatMessage, type CreateHolaClientOptions, type DashboardSpec, type DonutWidget, 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 LayoutGroup, type Point, PortalConflict, type PortalData, type PortalDocument, type PortalDocumentSummary, type PortalField, type PortalFile, type PortalRow, type PortalRowPage, type PortalTable, type ResolvedWidget, type SeriesWidget, type StatView, type StatWidget, type TableWidget, type TextWidget, type ThreadMessage, type UseChat, type UseThread, type Widget, type WidgetTransportConfig, type WidgetType, createApiTransport, createHolaClient, createPortalData, createWidgetTransport, deriveFields, inferSpec, layoutGroups, mergeMessage, parseDashboardSpec, renderModel, textDeltaOf, thinkingDeltaOf, toolEventOf, useArtifactUrl, useChat, useHolaClient, useThread, widgetSpan };
package/dist/index.d.ts CHANGED
@@ -306,6 +306,7 @@ interface StatWidget {
306
306
  label?: string | undefined;
307
307
  metric?: string | undefined;
308
308
  agg?: Agg | undefined;
309
+ w?: number | undefined;
309
310
  }
310
311
  /** A time series: `y` (a numeric column) aggregated per day of `x` (a date column); omit `y` to count
311
312
  * rows per day. `line` and `bar` differ only in how the renderer draws the same points. */
@@ -315,24 +316,28 @@ interface SeriesWidget {
315
316
  x: string;
316
317
  y?: string | undefined;
317
318
  agg?: Agg | undefined;
319
+ w?: number | undefined;
318
320
  }
319
321
  /** A breakdown: the count of rows per distinct value of `groupBy`. */
320
322
  interface DonutWidget {
321
323
  type: "donut";
322
324
  title?: string | undefined;
323
325
  groupBy: string;
326
+ w?: number | undefined;
324
327
  }
325
328
  /** A row table: `columns` (by key, in order) or every non-plumbing column when omitted. */
326
329
  interface TableWidget {
327
330
  type: "table";
328
331
  title?: string | undefined;
329
332
  columns?: string[] | undefined;
333
+ w?: number | undefined;
330
334
  }
331
335
  /** Static prose — a note above or between the data widgets. */
332
336
  interface TextWidget {
333
337
  type: "text";
334
338
  title?: string | undefined;
335
339
  body: string;
340
+ w?: number | undefined;
336
341
  }
337
342
  type Widget = StatWidget | SeriesWidget | DonutWidget | TableWidget | TextWidget;
338
343
  interface DashboardSpec {
@@ -357,28 +362,58 @@ type ResolvedWidget = {
357
362
  kind: "stat";
358
363
  label: string;
359
364
  value: number;
365
+ w?: number | undefined;
360
366
  } | {
361
367
  kind: "series";
362
368
  draw: "line" | "bar";
363
369
  title: string;
364
370
  points: Point[];
371
+ w?: number | undefined;
365
372
  } | {
366
373
  kind: "donut";
367
374
  title: string;
368
375
  points: Point[];
376
+ w?: number | undefined;
369
377
  } | {
370
378
  kind: "table";
371
379
  title?: string | undefined;
372
380
  columns: PortalField[];
373
381
  rows: PortalRow[];
382
+ w?: number | undefined;
374
383
  } | {
375
384
  kind: "text";
376
385
  title?: string | undefined;
377
386
  body: string;
387
+ w?: number | undefined;
378
388
  };
379
389
  /** Resolve a whole spec against the data. The result is render-ready and free of widgets that would
380
390
  * draw nothing. */
381
391
  declare function renderModel(spec: DashboardSpec, fields: PortalField[], rows: PortalRow[]): ResolvedWidget[];
392
+ /** The column span (1–4, in a 4-col grid) a widget occupies: its explicit `w` clamped, else a sensible
393
+ * default by its layout run — a stat is a quarter (1); a chart is full (4) on its own row or a half
394
+ * (2) when it shares one; a table or note is full (4). Apps map the number to their own grid classes,
395
+ * so the operator console and the customer portal lay a dashboard out identically. */
396
+ declare function widgetSpan(explicit: number | undefined, run: "stat" | "chart" | "block", alone: boolean): number;
397
+
398
+ type StatView = Extract<ResolvedWidget, {
399
+ kind: "stat";
400
+ }>;
401
+ type ChartView = Extract<ResolvedWidget, {
402
+ kind: "series" | "donut";
403
+ }>;
404
+ type LayoutGroup = {
405
+ kind: "stats";
406
+ items: StatView[];
407
+ } | {
408
+ kind: "charts";
409
+ items: ChartView[];
410
+ } | {
411
+ kind: "block";
412
+ item: ResolvedWidget;
413
+ };
414
+ /** Fold resolved widgets into layout groups: a run of adjacent stat tiles becomes one tile row, a run
415
+ * of adjacent charts becomes one chart row, and a table or note stands alone. Order is preserved. */
416
+ declare function layoutGroups(resolved: ResolvedWidget[]): LayoutGroup[];
382
417
 
383
418
  /** Extract a streamed text delta from a raw pi turn event, or null. */
384
419
  declare const textDeltaOf: (event: unknown) => string | null;
@@ -436,4 +471,4 @@ declare const useThread: (client: HolaClient, options?: {
436
471
  pollMs?: number;
437
472
  }) => UseThread;
438
473
 
439
- export { type Agg, type ApiTransportConfig, Chat, type ChatMessage, type CreateHolaClientOptions, type DashboardSpec, type DonutWidget, 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 Point, PortalConflict, type PortalData, type PortalDocument, type PortalDocumentSummary, type PortalField, type PortalFile, type PortalRow, type PortalRowPage, type PortalTable, type ResolvedWidget, type SeriesWidget, type StatWidget, type TableWidget, type TextWidget, type ThreadMessage, type UseChat, type UseThread, type Widget, type WidgetTransportConfig, type WidgetType, createApiTransport, createHolaClient, createPortalData, createWidgetTransport, deriveFields, inferSpec, mergeMessage, parseDashboardSpec, renderModel, textDeltaOf, thinkingDeltaOf, toolEventOf, useArtifactUrl, useChat, useHolaClient, useThread };
474
+ export { type Agg, type ApiTransportConfig, type ChartView, Chat, type ChatMessage, type CreateHolaClientOptions, type DashboardSpec, type DonutWidget, 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 LayoutGroup, type Point, PortalConflict, type PortalData, type PortalDocument, type PortalDocumentSummary, type PortalField, type PortalFile, type PortalRow, type PortalRowPage, type PortalTable, type ResolvedWidget, type SeriesWidget, type StatView, type StatWidget, type TableWidget, type TextWidget, type ThreadMessage, type UseChat, type UseThread, type Widget, type WidgetTransportConfig, type WidgetType, createApiTransport, createHolaClient, createPortalData, createWidgetTransport, deriveFields, inferSpec, layoutGroups, mergeMessage, parseDashboardSpec, renderModel, textDeltaOf, thinkingDeltaOf, toolEventOf, useArtifactUrl, useChat, useHolaClient, useThread, widgetSpan };
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  'use client'
2
- var F=e=>{if(!e||typeof e!="object")return null;let t=e;return t.type==="message_update"?t.assistantMessageEvent??null:null},I=e=>{let t=F(e);return t?.type==="text_delta"&&typeof t.delta=="string"?t.delta:null},E=e=>{let t=F(e);return t?.type==="thinking_delta"&&typeof t.delta=="string"?t.delta:null},$=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 te=/^ /,T=e=>{if(e&&typeof e=="object"){let t=e,s=typeof t.error=="string"?t.error:"request_failed";return typeof t.retryable=="boolean"?{error:s,retryable:t.retryable}:{error:s}}return{error:"request_failed"}},re=e=>{let t="message",s=[];for(let o of e.split(`
3
- `))o.startsWith(":")||(o.startsWith("event:")?t=o.slice(6).trim():o.startsWith("data:")&&s.push(o.slice(5).replace(te,"")));return s.length>0?{event:t,data:s.join(`
4
- `)}:null},ne=(e,t,s)=>{let o;try{o=JSON.parse(e.data)}catch{return}if(e.event==="session"){let n=o.sessionId;n&&(s(n),t.onSession?.(n));return}if(e.event==="turn_event"){t.onEvent?.(o);let n=I(o);n&&t.onText?.(n);let l=E(o);l&&t.onThinking?.(l);let r=$(o);r&&t.onTool?.(r);return}if(e.event==="chat_completed"){let n=o;s(n.sessionId),t.onComplete?.(n);return}e.event==="chat_error"&&t.onError?.(T(o))},b=async(e,t)=>{let s=await fetch(e,{headers:t});if(!s.ok)throw new Error(`hola: request failed (${s.status})`);return await s.json()},O=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()},_=async(e,t,s,o)=>{let n=await fetch(e.url,{method:"POST",headers:e.headers,body:e.body,signal:o});if(!(n.ok&&n.body)){t.onError?.({error:`stream_failed_${n.status}`});return}let l=n.body.getReader(),r=new TextDecoder,a="",i=()=>{let u=a.indexOf(`
2
+ var O=e=>{if(!e||typeof e!="object")return null;let t=e;return t.type==="message_update"?t.assistantMessageEvent??null:null},E=e=>{let t=O(e);return t?.type==="text_delta"&&typeof t.delta=="string"?t.delta:null},M=e=>{let t=O(e);return t?.type==="thinking_delta"&&typeof t.delta=="string"?t.delta:null},$=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 oe=/^ /,T=e=>{if(e&&typeof e=="object"){let t=e,n=typeof t.error=="string"?t.error:"request_failed";return typeof t.retryable=="boolean"?{error:n,retryable:t.retryable}:{error:n}}return{error:"request_failed"}},se=e=>{let t="message",n=[];for(let s of e.split(`
3
+ `))s.startsWith(":")||(s.startsWith("event:")?t=s.slice(6).trim():s.startsWith("data:")&&n.push(s.slice(5).replace(oe,"")));return n.length>0?{event:t,data:n.join(`
4
+ `)}:null},ae=(e,t,n)=>{let s;try{s=JSON.parse(e.data)}catch{return}if(e.event==="session"){let o=s.sessionId;o&&(n(o),t.onSession?.(o));return}if(e.event==="turn_event"){t.onEvent?.(s);let o=E(s);o&&t.onText?.(o);let l=M(s);l&&t.onThinking?.(l);let r=$(s);r&&t.onTool?.(r);return}if(e.event==="chat_completed"){let o=s;n(o.sessionId),t.onComplete?.(o);return}e.event==="chat_error"&&t.onError?.(T(s))},b=async(e,t)=>{let n=await fetch(e,{headers:t});if(!n.ok)throw new Error(`hola: request failed (${n.status})`);return await n.json()},_=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()},L=async(e,t,n,s)=>{let o=await fetch(e.url,{method:"POST",headers:e.headers,body:e.body,signal:s});if(!(o.ok&&o.body)){t.onError?.({error:`stream_failed_${o.status}`});return}let l=o.body.getReader(),r=new TextDecoder,a="",i=()=>{let u=a.indexOf(`
5
5
 
6
- `);for(;u!==-1;){let y=a.slice(0,u);a=a.slice(u+2);let c=re(y);c&&ne(c,t,s),u=a.indexOf(`
6
+ `);for(;u!==-1;){let y=a.slice(0,u);a=a.slice(u+2);let c=se(y);c&&ae(c,t,n),u=a.indexOf(`
7
7
 
8
- `)}},d=async()=>{let u=await l.read();if(!u.done)return a+=r.decode(u.value,{stream:!0}),i(),d()};await d()};var oe=/\/+$/,k="/api/v1/end-user",se=e=>{let t=e.baseUrl.replace(oe,""),s=()=>typeof e.token=="function"?e.token():e.token,o=r=>e.project?`${r}project=${encodeURIComponent(e.project)}`:"",n=async()=>({"content-type":"application/json",authorization:`Bearer ${await s()}`}),l=async r=>{let a=await fetch(`${t}${k}/chat${o("?")}`,{method:"POST",headers:await n(),body:JSON.stringify({message:r})});if(!a.ok)throw new Error(`hola: message failed (${a.status})`);return{reply:(await a.json()).reply??"",sessionId:"",artifacts:[]}};return{sessionId:()=>"",getInfo:async()=>b(`${t}${k}/chat/info${o("?")}`,await n()),sendMessage:l,streamMessage:async(r,a)=>{try{let i=await l(r);a.onText?.(i.reply),a.onComplete?.(i)}catch(i){a.onError?.(T(i))}},subscribe:(r,a)=>{let i=a?.since??"0",d=!1,u,y=a?.intervalMs??3e3,c=async()=>{try{let m=await b(`${t}${k}/chat/thread?since=${encodeURIComponent(i)}${o("&")}`,await n());for(let g of m.messages)r.onMessage(g);i=m.cursor,r.onHealthy?.()}catch(m){r.onError?.(T(m))}d||(u=setTimeout(c,y))},p=()=>{d=!0,u&&clearTimeout(u)};return a?.signal?.addEventListener("abort",p),u=setTimeout(c,0),p},requestHuman:async()=>{await fetch(`${t}${k}/chat/request-human${o("?")}`,{method:"POST",headers:await n(),body:"{}"})}}};import{useEffect as ae,useState as ie}from"react";var A=(e,t)=>{let[s,o]=ie("");return ae(()=>{if(!e){o("");return}let n=Uint8Array.from(atob(e),r=>r.charCodeAt(0)),l=URL.createObjectURL(new Blob([n],{type:t}));return o(l),()=>URL.revokeObjectURL(l)},[e,t]),s};import{useEffect as me,useRef as fe}from"react";import{createContext as le,useContext as de}from"react";import{jsx as pe}from"react/jsx-runtime";var N=le(null),ue=({client:e,children:t})=>pe(N.Provider,{value:e,children:t}),M=()=>{let e=de(N);if(!e)throw new Error("useHolaClient must be used within <HolaProvider>");return e};import{useCallback as L,useEffect as ce,useRef as ge,useState as C}from"react";var W=e=>{let[t,s]=C([]),[o,n]=C(""),[l,r]=C(!1),[a,i]=C(null),d=ge(0),u=L(()=>{let c=d.current;return d.current+=1,c},[]);ce(()=>{let c=!0;return e.getInfo().then(p=>{c&&p.greeting&&s([{id:u(),role:"assistant",text:p.greeting}])}).catch(()=>{}),()=>{c=!1}},[e,u]);let y=L(()=>{let c=o.trim();if(!c||l)return;n(""),i(null),r(!0);let p=u(),m=u();s(f=>[...f,{id:p,role:"user",text:c},{id:m,role:"assistant",text:"",streaming:!0}]);let g=f=>{s(h=>h.map(R=>R.id===m?f(R):R))};e.streamMessage(c,{onText:f=>g(h=>({...h,text:h.text+f})),onComplete:f=>{g(h=>({...h,text:f.reply||h.text,artifacts:f.artifacts,streaming:!1})),r(!1)},onError:f=>{g(h=>({...h,streaming:!1})),i(f.error),r(!1)}}).catch(f=>{g(h=>({...h,streaming:!1})),i(f instanceof Error?f.message:"stream_failed"),r(!1)})},[o,l,e,u]);return{messages:t,input:o,setInput:n,send:y,sending:l,error:a}};import{jsx as P,jsxs as D}from"react/jsx-runtime";var x={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=A(e.dataBase64??"",e.mimeType),s=e.url??t;return s?e.mimeType.startsWith("image/")?P("a",{href:s,rel:"noopener noreferrer",target:"_blank",children:P("img",{alt:e.filename,src:s,style:x.image})}):P("a",{download:e.filename,href:s,style:x.link,children:e.filename}):null},be=()=>{let e=M(),{messages:t,input:s,setInput:o,send:n,sending:l,error:r}=W(e),a=fe(null);me(()=>{let d=a.current;d&&(d.scrollTop=d.scrollHeight)},[t]);let i=d=>{d.preventDefault(),n()};return D("div",{style:x.root,children:[P("div",{ref:a,style:x.log,children:t.map(d=>D("div",{style:d.role==="user"?x.user:x.assistant,children:[d.text||(d.streaming?"\u2026":""),d.artifacts&&d.artifacts.length>0?P("div",{style:x.artifacts,children:d.artifacts.map(u=>P(ye,{artifact:u},u.filename))}):null]},d.id))}),r?P("div",{style:x.error,children:r}):null,D("form",{onSubmit:i,style:x.form,children:[P("input",{"aria-label":"Message",onChange:d=>o(d.target.value),placeholder:"Type a message\u2026",style:x.input,value:s}),P("button",{disabled:l||s.trim().length===0,style:x.button,type:"submit",children:"Send"})]})]})};var he=/\/+$/,U=e=>{let t=e.sessionId,s=e.baseUrl.replace(he,""),o=r=>`${s}/endpoint/${encodeURIComponent(e.token)}${r}`,n={"content-type":"application/json"},l=(r,a)=>({url:o(r),headers:n,body:JSON.stringify({message:a,...t?{sessionId:t}:{},...e.identity?{externalUserId:e.identity.externalUserId,userHmac:e.identity.userHmac}:{}})});return{sessionId:()=>t,getInfo:()=>b(o("/config"),{}),sendMessage:async r=>{let a=await O(l("/message",r));return t=a.sessionId,a},streamMessage:(r,a,i)=>_(l("/message/stream",r),a,d=>{t=d},i),subscribe:(r,a)=>{let i=a?.since??"0",d=!1,u,y=a?.intervalMs??3e3,c=async()=>{let m=t;if(m)try{let g=await b(o(`/messages?session=${encodeURIComponent(m)}&since=${encodeURIComponent(i)}`),{});for(let f of g.messages)r.onMessage(f);i=g.cursor,r.onHealthy?.()}catch(g){r.onError?.(T(g))}d||(u=setTimeout(c,y))},p=()=>{d=!0,u&&clearTimeout(u)};return a?.signal?.addEventListener("abort",p),u=setTimeout(c,0),p},requestHuman:async()=>{t&&await fetch(o("/request-human"),{method:"POST",headers:n,body:JSON.stringify({sessionId:t})})}}};var xe=e=>"transport"in e?e.transport:U(e);var we=/^https?:\/\//i,Te=/^\d{4}-\d{2}-\d{2}(?:[T ]|$)/,Pe=e=>e.replace(/_/g," ").replace(/\b\w/g,t=>t.toUpperCase());function He(e){if(typeof e=="number")return"number";if(typeof e=="boolean")return"boolean";if(typeof e=="string"){if(we.test(e))return"url";if(Te.test(e))return"date"}return"text"}function j(e){let t=[],s=new Map;for(let o of e)for(let[n,l]of Object.entries(o.data??{})){if(l==null)continue;let r=s.get(n);r||(r=new Map,s.set(n,r),t.push(n));let a=He(l);r.set(a,(r.get(a)??0)+1)}return t.map(o=>{let n=s.get(o)??new Map,l="text",r=-1;for(let[a,i]of n)i>r&&(r=i,l=a);return{key:o,label:Pe(o),type:l}})}var ke=e=>typeof e=="number"?e:Number(e)||0,B=e=>/rate|position|rank|score|percent|avg/i.test(e),Ce=/posted|published|sent|completed|shipped|launched|_at|date/i,Se=new Set(["service","order","end_user_id"]);function z(e,t){let s=e.filter(i=>!Se.has(i.key)),o=s.filter(i=>i.type==="number").slice(0,3),n=s.find(i=>i.key==="status")??s.find(i=>i.type==="select"),l=s.find(i=>i.type==="date"&&Ce.test(i.key))??s.find(i=>i.type==="date"),r=s.filter(i=>i.type==="number"&&!B(i.key)).map(i=>({field:i,total:t.reduce((d,u)=>d+ke(u.data[i.key]),0)})).sort((i,d)=>d.total-i.total).find(i=>i.total>0)?.field??null,a=[{type:"stat",label:"Items",agg:"count"}];for(let i of o){let d=B(i.key);a.push({type:"stat",metric:i.key,agg:d?"avg":"sum",label:d?`Avg ${i.label.toLowerCase()}`:i.label})}return l&&a.push({type:"line",x:l.key,y:r?.key,agg:"sum",title:r?`${r.label} by day`:"Items by day"}),n&&a.push({type:"donut",groupBy:n.key,title:n.label}),a.push({type:"table",columns:s.map(i=>i.key)}),{version:1,widgets:a}}var G=new Set(["service","order","end_user_id"]),J=e=>typeof e=="number"?e:Number(e)||0,q=e=>e==null?"":String(e);function V(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 s=t.reduce((o,n)=>o+n,0);return e==="avg"?Math.round(s/t.length):s}function ve(e,t,s,o){let n=new Map;for(let l of e){let r=new Date(q(l.data[t]));if(Number.isNaN(r.getTime()))continue;let a=r.toISOString().slice(0,10),i=n.get(a)??[];i.push(s?J(l.data[s]):1),n.set(a,i)}return[...n.entries()].sort((l,r)=>l[0]<r[0]?-1:1).map(([l,r])=>({label:new Date(`${l}T00:00:00`).toLocaleDateString(void 0,{month:"short",day:"numeric"}),value:s?V(o,r):r.length}))}function Re(e,t){let s=new Map;for(let o of e){let n=q(o.data[t]).trim();n&&s.set(n,(s.get(n)??0)+1)}return[...s.entries()].sort((o,n)=>n[1]-o[1]).map(([o,n])=>({label:o,value:n}))}function Ie(e,t,s,o){switch(e.type){case"stat":{let n=e.metric?t.get(e.metric):void 0;if(e.metric&&!n)return null;if(!n)return{kind:"stat",label:e.label??"Items",value:o.length};let l=o.map(r=>J(r.data[n.key]));return{kind:"stat",label:e.label??n.label,value:V(e.agg??"sum",l)}}case"line":case"bar":{if(!t.has(e.x)||e.y&&!t.has(e.y))return null;let n=ve(o,e.x,e.y,e.agg??"sum");return n.length<2?null:{kind:"series",draw:e.type,title:e.title??"By day",points:n}}case"donut":{if(!t.has(e.groupBy))return null;let n=Re(o,e.groupBy);return n.length===0?null:{kind:"donut",title:e.title??t.get(e.groupBy)?.label??"Breakdown",points:n}}case"table":{let n=e.columns?e.columns.map(l=>t.get(l)).filter(l=>l!==void 0&&!G.has(l.key)):s;return n.length===0?null:{kind:"table",title:e.title,columns:n,rows:o}}case"text":return{kind:"text",title:e.title,body:e.body};default:return null}}function Y(e,t,s){let o=t.filter(r=>!G.has(r.key)),n=new Map(t.map(r=>[r.key,r])),l=[];for(let r of e.widgets){let a=Ie(r,n,o,s);a&&l.push(a)}return l}var Ee=new Set(["sum","avg","count","min","max","last"]),Q=e=>typeof e=="string"&&Ee.has(e)?e:void 0,w=e=>typeof e=="string"&&e!==""?e:void 0;function $e(e){if(typeof e!="object"||e===null)return null;let t=e;switch(t.type){case"stat":return{type:"stat",label:w(t.label),metric:w(t.metric),agg:Q(t.agg)};case"line":case"bar":{let s=w(t.x);return s?{type:t.type,title:w(t.title),x:s,y:w(t.y),agg:Q(t.agg)}:null}case"donut":{let s=w(t.groupBy);return s?{type:"donut",title:w(t.title),groupBy:s}:null}case"table":{let s=Array.isArray(t.columns)?t.columns.filter(o=>typeof o=="string"):void 0;return{type:"table",title:w(t.title),columns:s}}case"text":{let s=w(t.body);return s?{type:"text",title:w(t.title),body:s}:null}default:return null}}function X(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 s=t.widgets;if(!Array.isArray(s))return null;let o=s.map($e).filter(l=>l!==null);if(o.length===0)return null;let n=t.version;return{version:typeof n=="number"?n:1,title:w(t.title),widgets:o}}var Ae=/\/+$/,H="/api/v1/end-user",S=class extends Error{constructor(t){super(t),this.name="PortalConflict"}};function Me(e){let t="";for(let o=0;o<e.length;o+=32768)t+=String.fromCharCode(...e.subarray(o,o+32768));return btoa(t)}var We=e=>{let t=e.baseUrl.replace(Ae,""),s=()=>typeof e.token=="function"?e.token():e.token,o=async()=>({"content-type":"application/json",authorization:`Bearer ${await s()}`}),n=async(r,a)=>{try{let i=await fetch(`${t}${H}${r}`,{method:a.method,headers:await o(),...a.body===void 0?{}:{body:JSON.stringify(a.body)}});if(i.status===409){let d=await i.json().catch(()=>({}));throw new S(d.message??"Someone else saved this first.")}if(!i.ok){let d=await i.text().catch(()=>""),u=`${a.method} ${r} \u2192 ${String(i.status)}`;try{let y=JSON.parse(d);y.message&&(u=y.message)}catch{u=d?`${u}: ${d}`:u}throw T(new Error(u))}return await i.json()}catch(i){throw T(i)}},l=r=>`/tables/${encodeURIComponent(r)}`;return{listTables:async()=>(await b(`${t}${H}/tables`,await o())).tables,listRows:async(r,a)=>await b(`${t}${H}${l(r)}/rows?limit=${String(a??100)}`,await o()),insertRow:async(r,a)=>{let{rowIds:i}=await n(`${l(r)}/rows`,{method:"POST",body:{rows:[a]}}),d=i[0];if(!d)throw T(new Error("The row was not created."));return d},patchRow:async(r,a,i)=>(await n(`${l(r)}/rows/${encodeURIComponent(a)}`,{method:"PATCH",body:i})).updated,deleteRow:async(r,a)=>(await n(`/${encodeURIComponent(r)}/${encodeURIComponent(a)}`,{method:"DELETE"})).deleted,listFiles:async()=>(await b(`${t}${H}/tables/files/rows?limit=200`,await o())).rows.map(a=>({id:a.rowId,filename:String(a.data.filename??""),source:String(a.data.source??"client"),campaign:String(a.data.campaign??""),size:typeof a.data.size=="number"?a.data.size:0,createdAt:a.createdAt})),uploadFile:async(r,a)=>{let i=new Uint8Array(await r.arrayBuffer());return await n("/files",{method:"POST",body:{filename:r.name,mime:r.type||"application/octet-stream",data:Me(i),...a===void 0?{}:{message:a}}})},fileLink:async r=>await b(`${t}${H}/files/${encodeURIComponent(r)}/url`,await o()),deleteFile:async r=>(await n(`/files/${encodeURIComponent(r)}`,{method:"DELETE"})).deleted,listDocuments:async()=>(await b(`${t}${H}/documents`,await o())).documents,readDocument:async r=>(await b(`${t}${H}/documents/${encodeURIComponent(r)}`,await o())).document,saveDocument:async(r,a)=>await n(`/documents/${encodeURIComponent(r)}`,{method:"PATCH",body:a})}};import{useCallback as De,useEffect as Z,useRef as Ue,useState as v}from"react";var K="greeting";function ee(e,t){if(e.some(n=>n.id===t.id))return e;let s=e.filter(n=>n.id!==K);return[...t.author==="client"?s.filter(n=>!(n.pending&&n.author==="client"&&n.text===t.text)):s,t]}var Fe=(e,t)=>{let[s,o]=v([]),[n,l]=v(""),[r,a]=v(!1),[i,d]=v(null),u=Ue(0),y=t?.pollMs??2e3;Z(()=>{let p=!0;return e.getInfo().then(m=>{p&&m.greeting&&o(g=>g.length===0?[{id:K,cursor:"",author:"agent",text:m.greeting}]:g)}).catch(()=>{}),()=>{p=!1}},[e]),Z(()=>e.subscribe?.({onMessage:p=>o(m=>ee(m,p)),onError:p=>d(p.error),onHealthy:()=>d(null)},{intervalMs:y}),[e,y]);let c=De(()=>{let p=n.trim();if(!p||r)return;l(""),d(null),a(!0),u.current+=1;let m={id:`pending-${u.current}`,cursor:"",author:"client",text:p,pending:!0};o(g=>[...g,m]),e.sendMessage(p).then(()=>a(!1)).catch(g=>{d(g instanceof Error?g.message:"send_failed"),a(!1)})},[n,r,e]);return{messages:s,input:n,setInput:l,send:c,sending:r,error:i}};export{be as Chat,ue as HolaProvider,S as PortalConflict,se as createApiTransport,xe as createHolaClient,We as createPortalData,U as createWidgetTransport,j as deriveFields,z as inferSpec,ee as mergeMessage,X as parseDashboardSpec,Y as renderModel,I as textDeltaOf,E as thinkingDeltaOf,$ as toolEventOf,A as useArtifactUrl,W as useChat,M as useHolaClient,Fe as useThread};
8
+ `)}},d=async()=>{let u=await l.read();if(!u.done)return a+=r.decode(u.value,{stream:!0}),i(),d()};await d()};var ie=/\/+$/,S="/api/v1/end-user",le=e=>{let t=e.baseUrl.replace(ie,""),n=()=>typeof e.token=="function"?e.token():e.token,s=r=>e.project?`${r}project=${encodeURIComponent(e.project)}`:"",o=async()=>({"content-type":"application/json",authorization:`Bearer ${await n()}`}),l=async r=>{let a=await fetch(`${t}${S}/chat${s("?")}`,{method:"POST",headers:await o(),body:JSON.stringify({message:r})});if(!a.ok)throw new Error(`hola: message failed (${a.status})`);return{reply:(await a.json()).reply??"",sessionId:"",artifacts:[]}};return{sessionId:()=>"",getInfo:async()=>b(`${t}${S}/chat/info${s("?")}`,await o()),sendMessage:l,streamMessage:async(r,a)=>{try{let i=await l(r);a.onText?.(i.reply),a.onComplete?.(i)}catch(i){a.onError?.(T(i))}},subscribe:(r,a)=>{let i=a?.since??"0",d=!1,u,y=a?.intervalMs??3e3,c=async()=>{try{let m=await b(`${t}${S}/chat/thread?since=${encodeURIComponent(i)}${s("&")}`,await o());for(let g of m.messages)r.onMessage(g);i=m.cursor,r.onHealthy?.()}catch(m){r.onError?.(T(m))}d||(u=setTimeout(c,y))},p=()=>{d=!0,u&&clearTimeout(u)};return a?.signal?.addEventListener("abort",p),u=setTimeout(c,0),p},requestHuman:async()=>{await fetch(`${t}${S}/chat/request-human${s("?")}`,{method:"POST",headers:await o(),body:"{}"})}}};import{useEffect as de,useState as ue}from"react";var A=(e,t)=>{let[n,s]=ue("");return de(()=>{if(!e){s("");return}let o=Uint8Array.from(atob(e),r=>r.charCodeAt(0)),l=URL.createObjectURL(new Blob([o],{type:t}));return s(l),()=>URL.revokeObjectURL(l)},[e,t]),n};import{useEffect as be,useRef as he}from"react";import{createContext as pe,useContext as ce}from"react";import{jsx as me}from"react/jsx-runtime";var N=pe(null),ge=({client:e,children:t})=>me(N.Provider,{value:e,children:t}),W=()=>{let e=ce(N);if(!e)throw new Error("useHolaClient must be used within <HolaProvider>");return e};import{useCallback as j,useEffect as fe,useRef as ye,useState as C}from"react";var D=e=>{let[t,n]=C([]),[s,o]=C(""),[l,r]=C(!1),[a,i]=C(null),d=ye(0),u=j(()=>{let c=d.current;return d.current+=1,c},[]);fe(()=>{let c=!0;return e.getInfo().then(p=>{c&&p.greeting&&n([{id:u(),role:"assistant",text:p.greeting}])}).catch(()=>{}),()=>{c=!1}},[e,u]);let y=j(()=>{let c=s.trim();if(!c||l)return;o(""),i(null),r(!0);let p=u(),m=u();n(f=>[...f,{id:p,role:"user",text:c},{id:m,role:"assistant",text:"",streaming:!0}]);let g=f=>{n(h=>h.map(I=>I.id===m?f(I):I))};e.streamMessage(c,{onText:f=>g(h=>({...h,text:h.text+f})),onComplete:f=>{g(h=>({...h,text:f.reply||h.text,artifacts:f.artifacts,streaming:!1})),r(!1)},onError:f=>{g(h=>({...h,streaming:!1})),i(f.error),r(!1)}}).catch(f=>{g(h=>({...h,streaming:!1})),i(f instanceof Error?f.message:"stream_failed"),r(!1)})},[s,l,e,u]);return{messages:t,input:s,setInput:o,send:y,sending:l,error:a}};import{jsx as P,jsxs as U}from"react/jsx-runtime";var w={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"}},we=({artifact:e})=>{let t=A(e.dataBase64??"",e.mimeType),n=e.url??t;return n?e.mimeType.startsWith("image/")?P("a",{href:n,rel:"noopener noreferrer",target:"_blank",children:P("img",{alt:e.filename,src:n,style:w.image})}):P("a",{download:e.filename,href:n,style:w.link,children:e.filename}):null},xe=()=>{let e=W(),{messages:t,input:n,setInput:s,send:o,sending:l,error:r}=D(e),a=he(null);be(()=>{let d=a.current;d&&(d.scrollTop=d.scrollHeight)},[t]);let i=d=>{d.preventDefault(),o()};return U("div",{style:w.root,children:[P("div",{ref:a,style:w.log,children:t.map(d=>U("div",{style:d.role==="user"?w.user:w.assistant,children:[d.text||(d.streaming?"\u2026":""),d.artifacts&&d.artifacts.length>0?P("div",{style:w.artifacts,children:d.artifacts.map(u=>P(we,{artifact:u},u.filename))}):null]},d.id))}),r?P("div",{style:w.error,children:r}):null,U("form",{onSubmit:i,style:w.form,children:[P("input",{"aria-label":"Message",onChange:d=>s(d.target.value),placeholder:"Type a message\u2026",style:w.input,value:n}),P("button",{disabled:l||n.trim().length===0,style:w.button,type:"submit",children:"Send"})]})]})};var Te=/\/+$/,F=e=>{let t=e.sessionId,n=e.baseUrl.replace(Te,""),s=r=>`${n}/endpoint/${encodeURIComponent(e.token)}${r}`,o={"content-type":"application/json"},l=(r,a)=>({url:s(r),headers:o,body:JSON.stringify({message:a,...t?{sessionId:t}:{},...e.identity?{externalUserId:e.identity.externalUserId,userHmac:e.identity.userHmac}:{}})});return{sessionId:()=>t,getInfo:()=>b(s("/config"),{}),sendMessage:async r=>{let a=await _(l("/message",r));return t=a.sessionId,a},streamMessage:(r,a,i)=>L(l("/message/stream",r),a,d=>{t=d},i),subscribe:(r,a)=>{let i=a?.since??"0",d=!1,u,y=a?.intervalMs??3e3,c=async()=>{let m=t;if(m)try{let g=await b(s(`/messages?session=${encodeURIComponent(m)}&since=${encodeURIComponent(i)}`),{});for(let f of g.messages)r.onMessage(f);i=g.cursor,r.onHealthy?.()}catch(g){r.onError?.(T(g))}d||(u=setTimeout(c,y))},p=()=>{d=!0,u&&clearTimeout(u)};return a?.signal?.addEventListener("abort",p),u=setTimeout(c,0),p},requestHuman:async()=>{t&&await fetch(s("/request-human"),{method:"POST",headers:o,body:JSON.stringify({sessionId:t})})}}};var Pe=e=>"transport"in e?e.transport:F(e);var ke=/^https?:\/\//i,He=/^\d{4}-\d{2}-\d{2}(?:[T ]|$)/,Se=e=>e.replace(/_/g," ").replace(/\b\w/g,t=>t.toUpperCase());function Ce(e){if(typeof e=="number")return"number";if(typeof e=="boolean")return"boolean";if(typeof e=="string"){if(ke.test(e))return"url";if(He.test(e))return"date"}return"text"}function G(e){let t=[],n=new Map;for(let s of e)for(let[o,l]of Object.entries(s.data??{})){if(l==null)continue;let r=n.get(o);r||(r=new Map,n.set(o,r),t.push(o));let a=Ce(l);r.set(a,(r.get(a)??0)+1)}return t.map(s=>{let o=n.get(s)??new Map,l="text",r=-1;for(let[a,i]of o)i>r&&(r=i,l=a);return{key:s,label:Se(s),type:l}})}var ve=e=>typeof e=="number"?e:Number(e)||0,B=e=>/rate|position|rank|score|percent|avg/i.test(e),Re=/posted|published|sent|completed|shipped|launched|_at|date/i,Ie=new Set(["service","order","end_user_id"]);function z(e,t){let n=e.filter(i=>!Ie.has(i.key)),s=n.filter(i=>i.type==="number").slice(0,3),o=n.find(i=>i.key==="status")??n.find(i=>i.type==="select"),l=n.find(i=>i.type==="date"&&Re.test(i.key))??n.find(i=>i.type==="date"),r=n.filter(i=>i.type==="number"&&!B(i.key)).map(i=>({field:i,total:t.reduce((d,u)=>d+ve(u.data[i.key]),0)})).sort((i,d)=>d.total-i.total).find(i=>i.total>0)?.field??null,a=[{type:"stat",label:"Items",agg:"count"}];for(let i of s){let d=B(i.key);a.push({type:"stat",metric:i.key,agg:d?"avg":"sum",label:d?`Avg ${i.label.toLowerCase()}`:i.label})}return l&&a.push({type:"line",x:l.key,y:r?.key,agg:"sum",title:r?`${r.label} by day`:"Items by day"}),o&&a.push({type:"donut",groupBy:o.key,title:o.label}),a.push({type:"table",columns:n.map(i=>i.key)}),{version:1,widgets:a}}function J(e){let t=[];for(let n of e){let s=t.length>0?t[t.length-1]:void 0;n.kind==="stat"?s?.kind==="stats"?s.items.push(n):t.push({kind:"stats",items:[n]}):n.kind==="series"||n.kind==="donut"?s?.kind==="charts"?s.items.push(n):t.push({kind:"charts",items:[n]}):t.push({kind:"block",item:n})}return t}var V=new Set(["service","order","end_user_id"]),q=e=>typeof e=="number"?e:Number(e)||0,Y=e=>e==null?"":String(e);function Q(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 n=t.reduce((s,o)=>s+o,0);return e==="avg"?Math.round(n/t.length):n}function Ee(e,t,n,s){let o=new Map;for(let l of e){let r=new Date(Y(l.data[t]));if(Number.isNaN(r.getTime()))continue;let a=r.toISOString().slice(0,10),i=o.get(a)??[];i.push(n?q(l.data[n]):1),o.set(a,i)}return[...o.entries()].sort((l,r)=>l[0]<r[0]?-1:1).map(([l,r])=>({label:new Date(`${l}T00:00:00`).toLocaleDateString(void 0,{month:"short",day:"numeric"}),value:n?Q(s,r):r.length}))}function Me(e,t){let n=new Map;for(let s of e){let o=Y(s.data[t]).trim();o&&n.set(o,(n.get(o)??0)+1)}return[...n.entries()].sort((s,o)=>o[1]-s[1]).map(([s,o])=>({label:s,value:o}))}function $e(e,t,n,s){switch(e.type){case"stat":{let o=e.metric?t.get(e.metric):void 0;if(e.metric&&!o)return null;if(!o)return{kind:"stat",label:e.label??"Items",value:s.length};let l=s.map(r=>q(r.data[o.key]));return{kind:"stat",label:e.label??o.label,value:Q(e.agg??"sum",l)}}case"line":case"bar":{if(!t.has(e.x)||e.y&&!t.has(e.y))return null;let o=Ee(s,e.x,e.y,e.agg??"sum");return o.length<2?null:{kind:"series",draw:e.type,title:e.title??"By day",points:o}}case"donut":{if(!t.has(e.groupBy))return null;let o=Me(s,e.groupBy);return o.length===0?null:{kind:"donut",title:e.title??t.get(e.groupBy)?.label??"Breakdown",points:o}}case"table":{let o=e.columns?e.columns.map(l=>t.get(l)).filter(l=>l!==void 0&&!V.has(l.key)):n;return o.length===0?null:{kind:"table",title:e.title,columns:o,rows:s}}case"text":return{kind:"text",title:e.title,body:e.body};default:return null}}function X(e,t,n){let s=t.filter(r=>!V.has(r.key)),o=new Map(t.map(r=>[r.key,r])),l=[];for(let r of e.widgets){let a=$e(r,o,s,n);a&&l.push({...a,w:r.w})}return l}function Z(e,t,n){return e&&e>=1?Math.min(4,Math.round(e)):t==="stat"?1:t==="chart"?n?4:2:4}var Ae=new Set(["sum","avg","count","min","max","last"]),K=e=>typeof e=="string"&&Ae.has(e)?e:void 0,x=e=>typeof e=="string"&&e!==""?e:void 0,H=e=>typeof e=="number"&&e>=1?Math.min(4,Math.round(e)):void 0;function We(e){if(typeof e!="object"||e===null)return null;let t=e;switch(t.type){case"stat":return{type:"stat",label:x(t.label),metric:x(t.metric),agg:K(t.agg),w:H(t.w)};case"line":case"bar":{let n=x(t.x);return n?{type:t.type,title:x(t.title),x:n,y:x(t.y),agg:K(t.agg),w:H(t.w)}:null}case"donut":{let n=x(t.groupBy);return n?{type:"donut",title:x(t.title),groupBy:n,w:H(t.w)}:null}case"table":{let n=Array.isArray(t.columns)?t.columns.filter(s=>typeof s=="string"):void 0;return{type:"table",title:x(t.title),columns:n,w:H(t.w)}}case"text":{let n=x(t.body);return n?{type:"text",title:x(t.title),body:n,w:H(t.w)}:null}default:return null}}function ee(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 n=t.widgets;if(!Array.isArray(n))return null;let s=n.map(We).filter(l=>l!==null);if(s.length===0)return null;let o=t.version;return{version:typeof o=="number"?o:1,title:x(t.title),widgets:s}}var De=/\/+$/,k="/api/v1/end-user",v=class extends Error{constructor(t){super(t),this.name="PortalConflict"}};function Ue(e){let t="";for(let s=0;s<e.length;s+=32768)t+=String.fromCharCode(...e.subarray(s,s+32768));return btoa(t)}var Fe=e=>{let t=e.baseUrl.replace(De,""),n=()=>typeof e.token=="function"?e.token():e.token,s=async()=>({"content-type":"application/json",authorization:`Bearer ${await n()}`}),o=async(r,a)=>{try{let i=await fetch(`${t}${k}${r}`,{method:a.method,headers:await s(),...a.body===void 0?{}:{body:JSON.stringify(a.body)}});if(i.status===409){let d=await i.json().catch(()=>({}));throw new v(d.message??"Someone else saved this first.")}if(!i.ok){let d=await i.text().catch(()=>""),u=`${a.method} ${r} \u2192 ${String(i.status)}`;try{let y=JSON.parse(d);y.message&&(u=y.message)}catch{u=d?`${u}: ${d}`:u}throw T(new Error(u))}return await i.json()}catch(i){throw T(i)}},l=r=>`/tables/${encodeURIComponent(r)}`;return{listTables:async()=>(await b(`${t}${k}/tables`,await s())).tables,listRows:async(r,a)=>await b(`${t}${k}${l(r)}/rows?limit=${String(a??100)}`,await s()),insertRow:async(r,a)=>{let{rowIds:i}=await o(`${l(r)}/rows`,{method:"POST",body:{rows:[a]}}),d=i[0];if(!d)throw T(new Error("The row was not created."));return d},patchRow:async(r,a,i)=>(await o(`${l(r)}/rows/${encodeURIComponent(a)}`,{method:"PATCH",body:i})).updated,deleteRow:async(r,a)=>(await o(`/${encodeURIComponent(r)}/${encodeURIComponent(a)}`,{method:"DELETE"})).deleted,listFiles:async()=>(await b(`${t}${k}/tables/files/rows?limit=200`,await s())).rows.map(a=>({id:a.rowId,filename:String(a.data.filename??""),source:String(a.data.source??"client"),campaign:String(a.data.campaign??""),size:typeof a.data.size=="number"?a.data.size:0,createdAt:a.createdAt})),uploadFile:async(r,a)=>{let i=new Uint8Array(await r.arrayBuffer());return await o("/files",{method:"POST",body:{filename:r.name,mime:r.type||"application/octet-stream",data:Ue(i),...a===void 0?{}:{message:a}}})},fileLink:async r=>await b(`${t}${k}/files/${encodeURIComponent(r)}/url`,await s()),deleteFile:async r=>(await o(`/files/${encodeURIComponent(r)}`,{method:"DELETE"})).deleted,listDocuments:async()=>(await b(`${t}${k}/documents`,await s())).documents,readDocument:async r=>(await b(`${t}${k}/documents/${encodeURIComponent(r)}`,await s())).document,saveDocument:async(r,a)=>await o(`/documents/${encodeURIComponent(r)}`,{method:"PATCH",body:a})}};import{useCallback as Oe,useEffect as te,useRef as _e,useState as R}from"react";var re="greeting";function ne(e,t){if(e.some(o=>o.id===t.id))return e;let n=e.filter(o=>o.id!==re);return[...t.author==="client"?n.filter(o=>!(o.pending&&o.author==="client"&&o.text===t.text)):n,t]}var Le=(e,t)=>{let[n,s]=R([]),[o,l]=R(""),[r,a]=R(!1),[i,d]=R(null),u=_e(0),y=t?.pollMs??2e3;te(()=>{let p=!0;return e.getInfo().then(m=>{p&&m.greeting&&s(g=>g.length===0?[{id:re,cursor:"",author:"agent",text:m.greeting}]:g)}).catch(()=>{}),()=>{p=!1}},[e]),te(()=>e.subscribe?.({onMessage:p=>s(m=>ne(m,p)),onError:p=>d(p.error),onHealthy:()=>d(null)},{intervalMs:y}),[e,y]);let c=Oe(()=>{let p=o.trim();if(!p||r)return;l(""),d(null),a(!0),u.current+=1;let m={id:`pending-${u.current}`,cursor:"",author:"client",text:p,pending:!0};s(g=>[...g,m]),e.sendMessage(p).then(()=>a(!1)).catch(g=>{d(g instanceof Error?g.message:"send_failed"),a(!1)})},[o,r,e]);return{messages:n,input:o,setInput:l,send:c,sending:r,error:i}};export{xe as Chat,ge as HolaProvider,v as PortalConflict,le as createApiTransport,Pe as createHolaClient,Fe as createPortalData,F as createWidgetTransport,G as deriveFields,z as inferSpec,J as layoutGroups,ne as mergeMessage,ee as parseDashboardSpec,X as renderModel,E as textDeltaOf,M as thinkingDeltaOf,$ as toolEventOf,A as useArtifactUrl,D as useChat,W as useHolaClient,Le as useThread,Z as widgetSpan};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@holaboss/client",
3
- "version": "0.2.0-beta.6",
3
+ "version": "0.2.0-beta.7",
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",