@holaboss/client 0.2.0-beta.5 → 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 +5 -5
- package/dist/index.d.cts +43 -1
- package/dist/index.d.ts +43 -1
- package/dist/index.js +5 -5
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client'
|
|
2
|
-
var
|
|
3
|
-
`))s.startsWith(":")||(s.startsWith("event:")?t=s.slice(6).trim():s.startsWith("data:")&&
|
|
4
|
-
`)}:null},
|
|
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
|
|
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
|
-
`)}},l=async()=>{let u=await d.read();if(!u.done)return a+=n.decode(u.value,{stream:!0}),i(),l()};await l()};var be=/\/+$/,E="/api/v1/end-user",q=e=>{let t=e.baseUrl.replace(be,""),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()}`}),d=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:d,streamMessage:async(n,a)=>{try{let i=await d(n);a.onText?.(i.reply),a.onComplete?.(i)}catch(i){a.onError?.(k(i))}},subscribe:(n,a)=>{let i=a?.since??"0",l=!1,u,b=a?.intervalMs??3e3,p=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))}l||(u=setTimeout(p,b))},c=()=>{l=!0,u&&clearTimeout(u)};return a?.signal?.addEventListener("abort",c),u=setTimeout(p,0),c},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)),d=URL.createObjectURL(new Blob([r],{type:t}));return s(d),()=>URL.revokeObjectURL(d)},[e,t]),o};var U=require("react");var W=require("react"),Q=require("react/jsx-runtime"),V=(0,W.createContext)(null),Y=({client:e,children:t})=>(0,Q.jsx)(V.Provider,{value:e,children:t}),M=()=>{let e=(0,W.useContext)(V);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)(""),[d,n]=(0,x.useState)(!1),[a,i]=(0,x.useState)(null),l=(0,x.useRef)(0),u=(0,x.useCallback)(()=>{let p=l.current;return l.current+=1,p},[]);(0,x.useEffect)(()=>{let p=!0;return e.getInfo().then(c=>{p&&c.greeting&&o([{id:u(),role:"assistant",text:c.greeting}])}).catch(()=>{}),()=>{p=!1}},[e,u]);let b=(0,x.useCallback)(()=>{let p=s.trim();if(!p||d)return;r(""),i(null),n(!0);let c=u(),m=u();o(f=>[...f,{id:c,role:"user",text:p},{id:m,role:"assistant",text:"",streaming:!0}]);let g=f=>{o(T=>T.map(F=>F.id===m?f(F):F))};e.streamMessage(p,{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,d,e,u]);return{messages:t,input:s,setInput:r,send:b,sending:d,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"}},he=({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},X=()=>{let e=M(),{messages:t,input:o,setInput:s,send:r,sending:d,error:n}=D(e),a=(0,U.useRef)(null);(0,U.useEffect)(()=>{let l=a.current;l&&(l.scrollTop=l.scrollHeight)},[t]);let i=l=>{l.preventDefault(),r()};return(0,y.jsxs)("div",{style:P.root,children:[(0,y.jsx)("div",{ref:a,style:P.log,children:t.map(l=>(0,y.jsxs)("div",{style:l.role==="user"?P.user:P.assistant,children:[l.text||(l.streaming?"\u2026":""),l.artifacts&&l.artifacts.length>0?(0,y.jsx)("div",{style:P.artifacts,children:l.artifacts.map(u=>(0,y.jsx)(he,{artifact:u},u.filename))}):null]},l.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:l=>s(l.target.value),placeholder:"Type a message\u2026",style:P.input,value:o}),(0,y.jsx)("button",{disabled:d||o.trim().length===0,style:P.button,type:"submit",children:"Send"})]})]})};var xe=/\/+$/,O=e=>{let t=e.sessionId,o=e.baseUrl.replace(xe,""),s=n=>`${o}/endpoint/${encodeURIComponent(e.token)}${n}`,r={"content-type":"application/json"},d=(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(d("/message",n));return t=a.sessionId,a},streamMessage:(n,a,i)=>z(d("/message/stream",n),a,l=>{t=l},i),subscribe:(n,a)=>{let i=a?.since??"0",l=!1,u,b=a?.intervalMs??3e3,p=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))}l||(u=setTimeout(p,b))},c=()=>{l=!0,u&&clearTimeout(u)};return a?.signal?.addEventListener("abort",c),u=setTimeout(p,0),c},requestHuman:async()=>{t&&await fetch(s("/request-human"),{method:"POST",headers:r,body:JSON.stringify({sessionId:t})})}}};var Z=e=>"transport"in e?e.transport:O(e);var we=e=>typeof e=="number"?e:Number(e)||0,K=e=>/rate|position|rank|score|percent|avg/i.test(e),Te=/posted|published|sent|completed|shipped|launched|_at|date/i,Pe=new Set(["service","order","end_user_id"]);function N(e,t){let o=e.filter(i=>!Pe.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"),d=o.find(i=>i.type==="date"&&Te.test(i.key))??o.find(i=>i.type==="date"),n=o.filter(i=>i.type==="number"&&!K(i.key)).map(i=>({field:i,total:t.reduce((l,u)=>l+we(u.data[i.key]),0)})).sort((i,l)=>l.total-i.total).find(i=>i.total>0)?.field??null,a=[{type:"stat",label:"Items",agg:"count"}];for(let i of s){let l=K(i.key);a.push({type:"stat",metric:i.key,agg:l?"avg":"sum",label:l?`Avg ${i.label.toLowerCase()}`:i.label})}return d&&a.push({type:"line",x:d.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 ee=new Set(["service","order","end_user_id"]),te=e=>typeof e=="number"?e:Number(e)||0,re=e=>e==null?"":String(e);function ne(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 He(e,t,o,s){let r=new Map;for(let d of e){let n=new Date(re(d.data[t]));if(Number.isNaN(n.getTime()))continue;let a=n.toISOString().slice(0,10),i=r.get(a)??[];i.push(o?te(d.data[o]):1),r.set(a,i)}return[...r.entries()].sort((d,n)=>d[0]<n[0]?-1:1).map(([d,n])=>({label:new Date(`${d}T00:00:00`).toLocaleDateString(void 0,{month:"short",day:"numeric"}),value:o?ne(s,n):n.length}))}function ke(e,t){let o=new Map;for(let s of e){let r=re(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 Ce(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 d=s.map(n=>te(n.data[r.key]));return{kind:"stat",label:e.label??r.label,value:ne(e.agg??"sum",d)}}case"line":case"bar":{if(!t.has(e.x)||e.y&&!t.has(e.y))return null;let r=He(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=ke(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(d=>t.get(d)).filter(d=>d!==void 0&&!ee.has(d.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 L(e,t,o){let s=t.filter(n=>!ee.has(n.key)),r=new Map(t.map(n=>[n.key,n])),d=[];for(let n of e.widgets){let a=Ce(n,r,s,o);a&&d.push(a)}return d}var Se=new Set(["sum","avg","count","min","max","last"]),oe=e=>typeof e=="string"&&Se.has(e)?e:void 0,H=e=>typeof e=="string"&&e!==""?e:void 0;function ve(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:oe(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:oe(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 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 o=t.widgets;if(!Array.isArray(o))return null;let s=o.map(ve).filter(d=>d!==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 Re=/\/+$/,C="/api/v1/end-user",S=class extends Error{constructor(t){super(t),this.name="PortalConflict"}};function Ie(e){let t="";for(let s=0;s<e.length;s+=32768)t+=String.fromCharCode(...e.subarray(s,s+32768));return btoa(t)}var se=e=>{let t=e.baseUrl.replace(Re,""),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 l=await i.json().catch(()=>({}));throw new S(l.message??"Someone else saved this first.")}if(!i.ok){let l=await i.text().catch(()=>""),u=`${a.method} ${n} \u2192 ${String(i.status)}`;try{let b=JSON.parse(l);b.message&&(u=b.message)}catch{u=l?`${u}: ${l}`:u}throw k(new Error(u))}return await i.json()}catch(i){throw k(i)}},d=n=>`/tables/${encodeURIComponent(n)}`;return{listTables:async()=>(await h(`${t}${C}/tables`,await s())).tables,listRows:async(n,a)=>await h(`${t}${C}${d(n)}/rows?limit=${String(a??100)}`,await s()),insertRow:async(n,a)=>{let{rowIds:i}=await r(`${d(n)}/rows`,{method:"POST",body:{rows:[a]}}),l=i[0];if(!l)throw k(new Error("The row was not created."));return l},patchRow:async(n,a,i)=>(await r(`${d(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:Ie(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"),ae="greeting";function B(e,t){if(e.some(r=>r.id===t.id))return e;let o=e.filter(r=>r.id!==ae);return[...t.author==="client"?o.filter(r=>!(r.pending&&r.author==="client"&&r.text===t.text)):o,t]}var ie=(e,t)=>{let[o,s]=(0,w.useState)([]),[r,d]=(0,w.useState)(""),[n,a]=(0,w.useState)(!1),[i,l]=(0,w.useState)(null),u=(0,w.useRef)(0),b=t?.pollMs??2e3;(0,w.useEffect)(()=>{let c=!0;return e.getInfo().then(m=>{c&&m.greeting&&s(g=>g.length===0?[{id:ae,cursor:"",author:"agent",text:m.greeting}]:g)}).catch(()=>{}),()=>{c=!1}},[e]),(0,w.useEffect)(()=>e.subscribe?.({onMessage:c=>s(m=>B(m,c)),onError:c=>l(c.error),onHealthy:()=>l(null)},{intervalMs:b}),[e,b]);let p=(0,w.useCallback)(()=>{let c=r.trim();if(!c||n)return;d(""),l(null),a(!0),u.current+=1;let m={id:`pending-${u.current}`,cursor:"",author:"client",text:c,pending:!0};s(g=>[...g,m]),e.sendMessage(c).then(()=>a(!1)).catch(g=>{l(g instanceof Error?g.message:"send_failed"),a(!1)})},[r,n,e]);return{messages:o,input:r,setInput:d,send:p,sending:n,error:i}};0&&(module.exports={Chat,HolaProvider,PortalConflict,createApiTransport,createHolaClient,createPortalData,createWidgetTransport,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
|
@@ -290,6 +290,13 @@ type PortalData = {
|
|
|
290
290
|
};
|
|
291
291
|
declare const createPortalData: (config: ApiTransportConfig) => PortalData;
|
|
292
292
|
|
|
293
|
+
/** Build a `PortalField[]` from a slice's rows, typed by the dominant JSON value type per key.
|
|
294
|
+
* `select` is never inferred (it needs an option set only a template carries) — such columns fall
|
|
295
|
+
* back to `text`. Returns [] for an empty slice. */
|
|
296
|
+
declare function deriveFields(rows: readonly {
|
|
297
|
+
data: Record<string, unknown>;
|
|
298
|
+
}[]): PortalField[];
|
|
299
|
+
|
|
293
300
|
/** How a metric column is reduced to a single number. */
|
|
294
301
|
type Agg = "sum" | "avg" | "count" | "min" | "max" | "last";
|
|
295
302
|
type WidgetType = "stat" | "line" | "bar" | "donut" | "table" | "text";
|
|
@@ -299,6 +306,7 @@ interface StatWidget {
|
|
|
299
306
|
label?: string | undefined;
|
|
300
307
|
metric?: string | undefined;
|
|
301
308
|
agg?: Agg | undefined;
|
|
309
|
+
w?: number | undefined;
|
|
302
310
|
}
|
|
303
311
|
/** A time series: `y` (a numeric column) aggregated per day of `x` (a date column); omit `y` to count
|
|
304
312
|
* rows per day. `line` and `bar` differ only in how the renderer draws the same points. */
|
|
@@ -308,24 +316,28 @@ interface SeriesWidget {
|
|
|
308
316
|
x: string;
|
|
309
317
|
y?: string | undefined;
|
|
310
318
|
agg?: Agg | undefined;
|
|
319
|
+
w?: number | undefined;
|
|
311
320
|
}
|
|
312
321
|
/** A breakdown: the count of rows per distinct value of `groupBy`. */
|
|
313
322
|
interface DonutWidget {
|
|
314
323
|
type: "donut";
|
|
315
324
|
title?: string | undefined;
|
|
316
325
|
groupBy: string;
|
|
326
|
+
w?: number | undefined;
|
|
317
327
|
}
|
|
318
328
|
/** A row table: `columns` (by key, in order) or every non-plumbing column when omitted. */
|
|
319
329
|
interface TableWidget {
|
|
320
330
|
type: "table";
|
|
321
331
|
title?: string | undefined;
|
|
322
332
|
columns?: string[] | undefined;
|
|
333
|
+
w?: number | undefined;
|
|
323
334
|
}
|
|
324
335
|
/** Static prose — a note above or between the data widgets. */
|
|
325
336
|
interface TextWidget {
|
|
326
337
|
type: "text";
|
|
327
338
|
title?: string | undefined;
|
|
328
339
|
body: string;
|
|
340
|
+
w?: number | undefined;
|
|
329
341
|
}
|
|
330
342
|
type Widget = StatWidget | SeriesWidget | DonutWidget | TableWidget | TextWidget;
|
|
331
343
|
interface DashboardSpec {
|
|
@@ -350,28 +362,58 @@ type ResolvedWidget = {
|
|
|
350
362
|
kind: "stat";
|
|
351
363
|
label: string;
|
|
352
364
|
value: number;
|
|
365
|
+
w?: number | undefined;
|
|
353
366
|
} | {
|
|
354
367
|
kind: "series";
|
|
355
368
|
draw: "line" | "bar";
|
|
356
369
|
title: string;
|
|
357
370
|
points: Point[];
|
|
371
|
+
w?: number | undefined;
|
|
358
372
|
} | {
|
|
359
373
|
kind: "donut";
|
|
360
374
|
title: string;
|
|
361
375
|
points: Point[];
|
|
376
|
+
w?: number | undefined;
|
|
362
377
|
} | {
|
|
363
378
|
kind: "table";
|
|
364
379
|
title?: string | undefined;
|
|
365
380
|
columns: PortalField[];
|
|
366
381
|
rows: PortalRow[];
|
|
382
|
+
w?: number | undefined;
|
|
367
383
|
} | {
|
|
368
384
|
kind: "text";
|
|
369
385
|
title?: string | undefined;
|
|
370
386
|
body: string;
|
|
387
|
+
w?: number | undefined;
|
|
371
388
|
};
|
|
372
389
|
/** Resolve a whole spec against the data. The result is render-ready and free of widgets that would
|
|
373
390
|
* draw nothing. */
|
|
374
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[];
|
|
375
417
|
|
|
376
418
|
/** Extract a streamed text delta from a raw pi turn event, or null. */
|
|
377
419
|
declare const textDeltaOf: (event: unknown) => string | null;
|
|
@@ -429,4 +471,4 @@ declare const useThread: (client: HolaClient, options?: {
|
|
|
429
471
|
pollMs?: number;
|
|
430
472
|
}) => UseThread;
|
|
431
473
|
|
|
432
|
-
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, 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
|
@@ -290,6 +290,13 @@ type PortalData = {
|
|
|
290
290
|
};
|
|
291
291
|
declare const createPortalData: (config: ApiTransportConfig) => PortalData;
|
|
292
292
|
|
|
293
|
+
/** Build a `PortalField[]` from a slice's rows, typed by the dominant JSON value type per key.
|
|
294
|
+
* `select` is never inferred (it needs an option set only a template carries) — such columns fall
|
|
295
|
+
* back to `text`. Returns [] for an empty slice. */
|
|
296
|
+
declare function deriveFields(rows: readonly {
|
|
297
|
+
data: Record<string, unknown>;
|
|
298
|
+
}[]): PortalField[];
|
|
299
|
+
|
|
293
300
|
/** How a metric column is reduced to a single number. */
|
|
294
301
|
type Agg = "sum" | "avg" | "count" | "min" | "max" | "last";
|
|
295
302
|
type WidgetType = "stat" | "line" | "bar" | "donut" | "table" | "text";
|
|
@@ -299,6 +306,7 @@ interface StatWidget {
|
|
|
299
306
|
label?: string | undefined;
|
|
300
307
|
metric?: string | undefined;
|
|
301
308
|
agg?: Agg | undefined;
|
|
309
|
+
w?: number | undefined;
|
|
302
310
|
}
|
|
303
311
|
/** A time series: `y` (a numeric column) aggregated per day of `x` (a date column); omit `y` to count
|
|
304
312
|
* rows per day. `line` and `bar` differ only in how the renderer draws the same points. */
|
|
@@ -308,24 +316,28 @@ interface SeriesWidget {
|
|
|
308
316
|
x: string;
|
|
309
317
|
y?: string | undefined;
|
|
310
318
|
agg?: Agg | undefined;
|
|
319
|
+
w?: number | undefined;
|
|
311
320
|
}
|
|
312
321
|
/** A breakdown: the count of rows per distinct value of `groupBy`. */
|
|
313
322
|
interface DonutWidget {
|
|
314
323
|
type: "donut";
|
|
315
324
|
title?: string | undefined;
|
|
316
325
|
groupBy: string;
|
|
326
|
+
w?: number | undefined;
|
|
317
327
|
}
|
|
318
328
|
/** A row table: `columns` (by key, in order) or every non-plumbing column when omitted. */
|
|
319
329
|
interface TableWidget {
|
|
320
330
|
type: "table";
|
|
321
331
|
title?: string | undefined;
|
|
322
332
|
columns?: string[] | undefined;
|
|
333
|
+
w?: number | undefined;
|
|
323
334
|
}
|
|
324
335
|
/** Static prose — a note above or between the data widgets. */
|
|
325
336
|
interface TextWidget {
|
|
326
337
|
type: "text";
|
|
327
338
|
title?: string | undefined;
|
|
328
339
|
body: string;
|
|
340
|
+
w?: number | undefined;
|
|
329
341
|
}
|
|
330
342
|
type Widget = StatWidget | SeriesWidget | DonutWidget | TableWidget | TextWidget;
|
|
331
343
|
interface DashboardSpec {
|
|
@@ -350,28 +362,58 @@ type ResolvedWidget = {
|
|
|
350
362
|
kind: "stat";
|
|
351
363
|
label: string;
|
|
352
364
|
value: number;
|
|
365
|
+
w?: number | undefined;
|
|
353
366
|
} | {
|
|
354
367
|
kind: "series";
|
|
355
368
|
draw: "line" | "bar";
|
|
356
369
|
title: string;
|
|
357
370
|
points: Point[];
|
|
371
|
+
w?: number | undefined;
|
|
358
372
|
} | {
|
|
359
373
|
kind: "donut";
|
|
360
374
|
title: string;
|
|
361
375
|
points: Point[];
|
|
376
|
+
w?: number | undefined;
|
|
362
377
|
} | {
|
|
363
378
|
kind: "table";
|
|
364
379
|
title?: string | undefined;
|
|
365
380
|
columns: PortalField[];
|
|
366
381
|
rows: PortalRow[];
|
|
382
|
+
w?: number | undefined;
|
|
367
383
|
} | {
|
|
368
384
|
kind: "text";
|
|
369
385
|
title?: string | undefined;
|
|
370
386
|
body: string;
|
|
387
|
+
w?: number | undefined;
|
|
371
388
|
};
|
|
372
389
|
/** Resolve a whole spec against the data. The result is render-ready and free of widgets that would
|
|
373
390
|
* draw nothing. */
|
|
374
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[];
|
|
375
417
|
|
|
376
418
|
/** Extract a streamed text delta from a raw pi turn event, or null. */
|
|
377
419
|
declare const textDeltaOf: (event: unknown) => string | null;
|
|
@@ -429,4 +471,4 @@ declare const useThread: (client: HolaClient, options?: {
|
|
|
429
471
|
pollMs?: number;
|
|
430
472
|
}) => UseThread;
|
|
431
473
|
|
|
432
|
-
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, 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 O=e=>{if(!e||typeof e!="object")return null;let t=e;return t.type==="message_update"?t.assistantMessageEvent??null:null},
|
|
3
|
-
`))s.startsWith(":")||(s.startsWith("event:")?t=s.slice(6).trim():s.startsWith("data:")&&
|
|
4
|
-
`)}:null},
|
|
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
|
|
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
|
-
`)}},l=async()=>{let u=await d.read();if(!u.done)return a+=r.decode(u.value,{stream:!0}),i(),l()};await l()};var ne=/\/+$/,k="/api/v1/end-user",oe=e=>{let t=e.baseUrl.replace(ne,""),o=()=>typeof e.token=="function"?e.token():e.token,s=r=>e.project?`${r}project=${encodeURIComponent(e.project)}`:"",n=async()=>({"content-type":"application/json",authorization:`Bearer ${await o()}`}),d=async r=>{let a=await fetch(`${t}${k}/chat${s("?")}`,{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${s("?")}`,await n()),sendMessage:d,streamMessage:async(r,a)=>{try{let i=await d(r);a.onText?.(i.reply),a.onComplete?.(i)}catch(i){a.onError?.(T(i))}},subscribe:(r,a)=>{let i=a?.since??"0",l=!1,u,y=a?.intervalMs??3e3,p=async()=>{try{let m=await b(`${t}${k}/chat/thread?since=${encodeURIComponent(i)}${s("&")}`,await n());for(let g of m.messages)r.onMessage(g);i=m.cursor,r.onHealthy?.()}catch(m){r.onError?.(T(m))}l||(u=setTimeout(p,y))},c=()=>{l=!0,u&&clearTimeout(u)};return a?.signal?.addEventListener("abort",c),u=setTimeout(p,0),c},requestHuman:async()=>{await fetch(`${t}${k}/chat/request-human${s("?")}`,{method:"POST",headers:await n(),body:"{}"})}}};import{useEffect as se,useState as ae}from"react";var A=(e,t)=>{let[o,s]=ae("");return se(()=>{if(!e){s("");return}let n=Uint8Array.from(atob(e),r=>r.charCodeAt(0)),d=URL.createObjectURL(new Blob([n],{type:t}));return s(d),()=>URL.revokeObjectURL(d)},[e,t]),o};import{useEffect as ge,useRef as me}from"react";import{createContext as ie,useContext as le}from"react";import{jsx as ue}from"react/jsx-runtime";var N=ie(null),de=({client:e,children:t})=>ue(N.Provider,{value:e,children:t}),W=()=>{let e=le(N);if(!e)throw new Error("useHolaClient must be used within <HolaProvider>");return e};import{useCallback as L,useEffect as ce,useRef as pe,useState as C}from"react";var M=e=>{let[t,o]=C([]),[s,n]=C(""),[d,r]=C(!1),[a,i]=C(null),l=pe(0),u=L(()=>{let p=l.current;return l.current+=1,p},[]);ce(()=>{let p=!0;return e.getInfo().then(c=>{p&&c.greeting&&o([{id:u(),role:"assistant",text:c.greeting}])}).catch(()=>{}),()=>{p=!1}},[e,u]);let y=L(()=>{let p=s.trim();if(!p||d)return;n(""),i(null),r(!0);let c=u(),m=u();o(f=>[...f,{id:c,role:"user",text:p},{id:m,role:"assistant",text:"",streaming:!0}]);let g=f=>{o(h=>h.map(R=>R.id===m?f(R):R))};e.streamMessage(p,{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,d,e,u]);return{messages:t,input:s,setInput:n,send:y,sending:d,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"}},fe=({artifact:e})=>{let t=A(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:x.image})}):P("a",{download:e.filename,href:o,style:x.link,children:e.filename}):null},ye=()=>{let e=W(),{messages:t,input:o,setInput:s,send:n,sending:d,error:r}=M(e),a=me(null);ge(()=>{let l=a.current;l&&(l.scrollTop=l.scrollHeight)},[t]);let i=l=>{l.preventDefault(),n()};return D("div",{style:x.root,children:[P("div",{ref:a,style:x.log,children:t.map(l=>D("div",{style:l.role==="user"?x.user:x.assistant,children:[l.text||(l.streaming?"\u2026":""),l.artifacts&&l.artifacts.length>0?P("div",{style:x.artifacts,children:l.artifacts.map(u=>P(fe,{artifact:u},u.filename))}):null]},l.id))}),r?P("div",{style:x.error,children:r}):null,D("form",{onSubmit:i,style:x.form,children:[P("input",{"aria-label":"Message",onChange:l=>s(l.target.value),placeholder:"Type a message\u2026",style:x.input,value:o}),P("button",{disabled:d||o.trim().length===0,style:x.button,type:"submit",children:"Send"})]})]})};var be=/\/+$/,U=e=>{let t=e.sessionId,o=e.baseUrl.replace(be,""),s=r=>`${o}/endpoint/${encodeURIComponent(e.token)}${r}`,n={"content-type":"application/json"},d=(r,a)=>({url:s(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(s("/config"),{}),sendMessage:async r=>{let a=await F(d("/message",r));return t=a.sessionId,a},streamMessage:(r,a,i)=>_(d("/message/stream",r),a,l=>{t=l},i),subscribe:(r,a)=>{let i=a?.since??"0",l=!1,u,y=a?.intervalMs??3e3,p=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))}l||(u=setTimeout(p,y))},c=()=>{l=!0,u&&clearTimeout(u)};return a?.signal?.addEventListener("abort",c),u=setTimeout(p,0),c},requestHuman:async()=>{t&&await fetch(s("/request-human"),{method:"POST",headers:n,body:JSON.stringify({sessionId:t})})}}};var he=e=>"transport"in e?e.transport:U(e);var xe=e=>typeof e=="number"?e:Number(e)||0,j=e=>/rate|position|rank|score|percent|avg/i.test(e),we=/posted|published|sent|completed|shipped|launched|_at|date/i,Te=new Set(["service","order","end_user_id"]);function B(e,t){let o=e.filter(i=>!Te.has(i.key)),s=o.filter(i=>i.type==="number").slice(0,3),n=o.find(i=>i.key==="status")??o.find(i=>i.type==="select"),d=o.find(i=>i.type==="date"&&we.test(i.key))??o.find(i=>i.type==="date"),r=o.filter(i=>i.type==="number"&&!j(i.key)).map(i=>({field:i,total:t.reduce((l,u)=>l+xe(u.data[i.key]),0)})).sort((i,l)=>l.total-i.total).find(i=>i.total>0)?.field??null,a=[{type:"stat",label:"Items",agg:"count"}];for(let i of s){let l=j(i.key);a.push({type:"stat",metric:i.key,agg:l?"avg":"sum",label:l?`Avg ${i.label.toLowerCase()}`:i.label})}return d&&a.push({type:"line",x:d.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:o.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,z=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 o=t.reduce((s,n)=>s+n,0);return e==="avg"?Math.round(o/t.length):o}function Pe(e,t,o,s){let n=new Map;for(let d of e){let r=new Date(z(d.data[t]));if(Number.isNaN(r.getTime()))continue;let a=r.toISOString().slice(0,10),i=n.get(a)??[];i.push(o?J(d.data[o]):1),n.set(a,i)}return[...n.entries()].sort((d,r)=>d[0]<r[0]?-1:1).map(([d,r])=>({label:new Date(`${d}T00:00:00`).toLocaleDateString(void 0,{month:"short",day:"numeric"}),value:o?q(s,r):r.length}))}function He(e,t){let o=new Map;for(let s of e){let n=z(s.data[t]).trim();n&&o.set(n,(o.get(n)??0)+1)}return[...o.entries()].sort((s,n)=>n[1]-s[1]).map(([s,n])=>({label:s,value:n}))}function ke(e,t,o,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 d=s.map(r=>J(r.data[n.key]));return{kind:"stat",label:e.label??n.label,value:q(e.agg??"sum",d)}}case"line":case"bar":{if(!t.has(e.x)||e.y&&!t.has(e.y))return null;let n=Pe(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=He(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(d=>t.get(d)).filter(d=>d!==void 0&&!G.has(d.key)):o;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 V(e,t,o){let s=t.filter(r=>!G.has(r.key)),n=new Map(t.map(r=>[r.key,r])),d=[];for(let r of e.widgets){let a=ke(r,n,s,o);a&&d.push(a)}return d}var Ce=new Set(["sum","avg","count","min","max","last"]),Y=e=>typeof e=="string"&&Ce.has(e)?e:void 0,w=e=>typeof e=="string"&&e!==""?e:void 0;function Se(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:Y(t.agg)};case"line":case"bar":{let o=w(t.x);return o?{type:t.type,title:w(t.title),x:o,y:w(t.y),agg:Y(t.agg)}:null}case"donut":{let o=w(t.groupBy);return o?{type:"donut",title:w(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:w(t.title),columns:o}}case"text":{let o=w(t.body);return o?{type:"text",title:w(t.title),body:o}:null}default:return null}}function Q(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(Se).filter(d=>d!==null);if(s.length===0)return null;let n=t.version;return{version:typeof n=="number"?n:1,title:w(t.title),widgets:s}}var ve=/\/+$/,H="/api/v1/end-user",S=class extends Error{constructor(t){super(t),this.name="PortalConflict"}};function Re(e){let t="";for(let s=0;s<e.length;s+=32768)t+=String.fromCharCode(...e.subarray(s,s+32768));return btoa(t)}var Ie=e=>{let t=e.baseUrl.replace(ve,""),o=()=>typeof e.token=="function"?e.token():e.token,s=async()=>({"content-type":"application/json",authorization:`Bearer ${await o()}`}),n=async(r,a)=>{try{let i=await fetch(`${t}${H}${r}`,{method:a.method,headers:await s(),...a.body===void 0?{}:{body:JSON.stringify(a.body)}});if(i.status===409){let l=await i.json().catch(()=>({}));throw new S(l.message??"Someone else saved this first.")}if(!i.ok){let l=await i.text().catch(()=>""),u=`${a.method} ${r} \u2192 ${String(i.status)}`;try{let y=JSON.parse(l);y.message&&(u=y.message)}catch{u=l?`${u}: ${l}`:u}throw T(new Error(u))}return await i.json()}catch(i){throw T(i)}},d=r=>`/tables/${encodeURIComponent(r)}`;return{listTables:async()=>(await b(`${t}${H}/tables`,await s())).tables,listRows:async(r,a)=>await b(`${t}${H}${d(r)}/rows?limit=${String(a??100)}`,await s()),insertRow:async(r,a)=>{let{rowIds:i}=await n(`${d(r)}/rows`,{method:"POST",body:{rows:[a]}}),l=i[0];if(!l)throw T(new Error("The row was not created."));return l},patchRow:async(r,a,i)=>(await n(`${d(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 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 n("/files",{method:"POST",body:{filename:r.name,mime:r.type||"application/octet-stream",data:Re(i),...a===void 0?{}:{message:a}}})},fileLink:async r=>await b(`${t}${H}/files/${encodeURIComponent(r)}/url`,await s()),deleteFile:async r=>(await n(`/files/${encodeURIComponent(r)}`,{method:"DELETE"})).deleted,listDocuments:async()=>(await b(`${t}${H}/documents`,await s())).documents,readDocument:async r=>(await b(`${t}${H}/documents/${encodeURIComponent(r)}`,await s())).document,saveDocument:async(r,a)=>await n(`/documents/${encodeURIComponent(r)}`,{method:"PATCH",body:a})}};import{useCallback as Ee,useEffect as X,useRef as $e,useState as v}from"react";var Z="greeting";function K(e,t){if(e.some(n=>n.id===t.id))return e;let o=e.filter(n=>n.id!==Z);return[...t.author==="client"?o.filter(n=>!(n.pending&&n.author==="client"&&n.text===t.text)):o,t]}var Ae=(e,t)=>{let[o,s]=v([]),[n,d]=v(""),[r,a]=v(!1),[i,l]=v(null),u=$e(0),y=t?.pollMs??2e3;X(()=>{let c=!0;return e.getInfo().then(m=>{c&&m.greeting&&s(g=>g.length===0?[{id:Z,cursor:"",author:"agent",text:m.greeting}]:g)}).catch(()=>{}),()=>{c=!1}},[e]),X(()=>e.subscribe?.({onMessage:c=>s(m=>K(m,c)),onError:c=>l(c.error),onHealthy:()=>l(null)},{intervalMs:y}),[e,y]);let p=Ee(()=>{let c=n.trim();if(!c||r)return;d(""),l(null),a(!0),u.current+=1;let m={id:`pending-${u.current}`,cursor:"",author:"client",text:c,pending:!0};s(g=>[...g,m]),e.sendMessage(c).then(()=>a(!1)).catch(g=>{l(g instanceof Error?g.message:"send_failed"),a(!1)})},[n,r,e]);return{messages:o,input:n,setInput:d,send:p,sending:r,error:i}};export{ye as Chat,de as HolaProvider,S as PortalConflict,oe as createApiTransport,he as createHolaClient,Ie as createPortalData,U as createWidgetTransport,B as inferSpec,K as mergeMessage,Q as parseDashboardSpec,V as renderModel,I as textDeltaOf,E as thinkingDeltaOf,$ as toolEventOf,A as useArtifactUrl,M as useChat,W as useHolaClient,Ae 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.
|
|
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",
|