@holaboss/client 0.2.0-beta.0 → 0.2.0-beta.2

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 F=Object.defineProperty;var Y=Object.getOwnPropertyDescriptor;var Q=Object.getOwnPropertyNames;var X=Object.prototype.hasOwnProperty;var Z=(e,t)=>{for(var n in t)F(e,n,{get:t[n],enumerable:!0})},ee=(e,t,n,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of Q(t))!X.call(e,a)&&a!==n&&F(e,a,{get:()=>t[a],enumerable:!(s=Y(t,a))||s.enumerable});return e};var te=e=>ee(F({},"__esModule",{value:!0}),e);var de={};Z(de,{Chat:()=>B,HolaProvider:()=>J,createApiTransport:()=>j,createHolaClient:()=>G,createPortalData:()=>K,createWidgetTransport:()=>O,mergeMessage:()=>D,textDeltaOf:()=>P,thinkingDeltaOf:()=>I,toolEventOf:()=>R,useArtifactUrl:()=>k,useChat:()=>A,useHolaClient:()=>M,useThread:()=>V});module.exports=te(de);var L=e=>{if(!e||typeof e!="object")return null;let t=e;return t.type==="message_update"?t.assistantMessageEvent??null:null},P=e=>{let t=L(e);return t?.type==="text_delta"&&typeof t.delta=="string"?t.delta:null},I=e=>{let t=L(e);return t?.type==="thinking_delta"&&typeof t.delta=="string"?t.delta:null},R=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 re=/^ /,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"}},oe=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(re,"")));return n.length>0?{event:t,data:n.join(`
4
- `)}:null},se=(e,t,n)=>{let s;try{s=JSON.parse(e.data)}catch{return}if(e.event==="session"){let a=s.sessionId;a&&(n(a),t.onSession?.(a));return}if(e.event==="turn_event"){t.onEvent?.(s);let a=P(s);a&&t.onText?.(a);let p=I(s);p&&t.onThinking?.(p);let r=R(s);r&&t.onTool?.(r);return}if(e.event==="chat_completed"){let a=s;n(a.sessionId),t.onComplete?.(a);return}e.event==="chat_error"&&t.onError?.(T(s))},C=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()},W=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()},N=async(e,t,n,s)=>{let a=await fetch(e.url,{method:"POST",headers:e.headers,body:e.body,signal:s});if(!(a.ok&&a.body)){t.onError?.({error:`stream_failed_${a.status}`});return}let p=a.body.getReader(),r=new TextDecoder,o="",d=()=>{let l=o.indexOf(`
2
+ var F=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var X=Object.getOwnPropertyNames;var Z=Object.prototype.hasOwnProperty;var ee=(e,t)=>{for(var n in t)F(e,n,{get:t[n],enumerable:!0})},te=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of X(t))!Z.call(e,a)&&a!==n&&F(e,a,{get:()=>t[a],enumerable:!(o=Q(t,a))||o.enumerable});return e};var re=e=>te(F({},"__esModule",{value:!0}),e);var pe={};ee(pe,{Chat:()=>G,HolaProvider:()=>q,PortalConflict:()=>v,createApiTransport:()=>z,createHolaClient:()=>K,createPortalData:()=>V,createWidgetTransport:()=>O,mergeMessage:()=>L,textDeltaOf:()=>I,thinkingDeltaOf:()=>R,toolEventOf:()=>E,useArtifactUrl:()=>k,useChat:()=>U,useHolaClient:()=>A,useThread:()=>Y});module.exports=re(pe);var W=e=>{if(!e||typeof e!="object")return null;let t=e;return t.type==="message_update"?t.assistantMessageEvent??null:null},I=e=>{let t=W(e);return t?.type==="text_delta"&&typeof t.delta=="string"?t.delta:null},R=e=>{let t=W(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 oe=/^ /,C=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 o of e.split(`
3
+ `))o.startsWith(":")||(o.startsWith("event:")?t=o.slice(6).trim():o.startsWith("data:")&&n.push(o.slice(5).replace(oe,"")));return n.length>0?{event:t,data:n.join(`
4
+ `)}:null},ne=(e,t,n)=>{let o;try{o=JSON.parse(e.data)}catch{return}if(e.event==="session"){let a=o.sessionId;a&&(n(a),t.onSession?.(a));return}if(e.event==="turn_event"){t.onEvent?.(o);let a=I(o);a&&t.onText?.(a);let d=R(o);d&&t.onThinking?.(d);let r=E(o);r&&t.onTool?.(r);return}if(e.event==="chat_completed"){let a=o;n(a.sessionId),t.onComplete?.(a);return}e.event==="chat_error"&&t.onError?.(C(o))},h=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()},N=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()},j=async(e,t,n,o)=>{let a=await fetch(e.url,{method:"POST",headers:e.headers,body:e.body,signal:o});if(!(a.ok&&a.body)){t.onError?.({error:`stream_failed_${a.status}`});return}let d=a.body.getReader(),r=new TextDecoder,s="",l=()=>{let c=s.indexOf(`
5
5
 
6
- `);for(;l!==-1;){let f=o.slice(0,l);o=o.slice(l+2);let u=oe(f);u&&se(u,t,n),l=o.indexOf(`
6
+ `);for(;c!==-1;){let f=s.slice(0,c);s=s.slice(c+2);let u=se(f);u&&ne(u,t,n),c=s.indexOf(`
7
7
 
8
- `)}},i=async()=>{let l=await p.read();if(!l.done)return o+=r.decode(l.value,{stream:!0}),d(),i()};await i()};var ne=/\/+$/,E="/api/v1/end-user",j=e=>{let t=e.baseUrl.replace(ne,""),n=()=>typeof e.token=="function"?e.token():e.token,s=async()=>({"content-type":"application/json",authorization:`Bearer ${await n()}`}),a=async p=>{let r=await fetch(`${t}${E}/chat`,{method:"POST",headers:await s(),body:JSON.stringify({message:p})});if(!r.ok)throw new Error(`hola: message failed (${r.status})`);return{reply:(await r.json()).reply??"",sessionId:"",artifacts:[]}};return{sessionId:()=>"",getInfo:async()=>C(`${t}${E}/chat/info`,await s()),sendMessage:a,streamMessage:async(p,r)=>{try{let o=await a(p);r.onText?.(o.reply),r.onComplete?.(o)}catch(o){r.onError?.(T(o))}},subscribe:(p,r)=>{let o=r?.since??"0",d=!1,i,l=r?.intervalMs??3e3,f=async()=>{try{let c=await C(`${t}${E}/chat/thread?since=${encodeURIComponent(o)}`,await s());for(let y of c.messages)p.onMessage(y);o=c.cursor}catch(c){p.onError?.(T(c))}d||(i=setTimeout(f,l))},u=()=>{d=!0,i&&clearTimeout(i)};return r?.signal?.addEventListener("abort",u),i=setTimeout(f,0),u},requestHuman:async()=>{await fetch(`${t}${E}/chat/request-human`,{method:"POST",headers:await s(),body:"{}"})}}};var S=require("react"),k=(e,t)=>{let[n,s]=(0,S.useState)("");return(0,S.useEffect)(()=>{if(!e){s("");return}let a=Uint8Array.from(atob(e),r=>r.charCodeAt(0)),p=URL.createObjectURL(new Blob([a],{type:t}));return s(p),()=>URL.revokeObjectURL(p)},[e,t]),n};var U=require("react");var $=require("react"),q=require("react/jsx-runtime"),z=(0,$.createContext)(null),J=({client:e,children:t})=>(0,q.jsx)(z.Provider,{value:e,children:t}),M=()=>{let e=(0,$.useContext)(z);if(!e)throw new Error("useHolaClient must be used within <HolaProvider>");return e};var b=require("react"),A=e=>{let[t,n]=(0,b.useState)([]),[s,a]=(0,b.useState)(""),[p,r]=(0,b.useState)(!1),[o,d]=(0,b.useState)(null),i=(0,b.useRef)(0),l=(0,b.useCallback)(()=>{let u=i.current;return i.current+=1,u},[]);(0,b.useEffect)(()=>{let u=!0;return e.getInfo().then(c=>{u&&c.greeting&&n([{id:l(),role:"assistant",text:c.greeting}])}).catch(()=>{}),()=>{u=!1}},[e,l]);let f=(0,b.useCallback)(()=>{let u=s.trim();if(!u||p)return;a(""),d(null),r(!0);let c=l(),y=l();n(m=>[...m,{id:c,role:"user",text:u},{id:y,role:"assistant",text:"",streaming:!0}]);let g=m=>{n(x=>x.map(_=>_.id===y?m(_):_))};e.streamMessage(u,{onText:m=>g(x=>({...x,text:x.text+m})),onComplete:m=>{g(x=>({...x,text:m.reply||x.text,artifacts:m.artifacts,streaming:!1})),r(!1)},onError:m=>{g(x=>({...x,streaming:!1})),d(m.error),r(!1)}}).catch(m=>{g(x=>({...x,streaming:!1})),d(m instanceof Error?m.message:"stream_failed"),r(!1)})},[s,p,e,l]);return{messages:t,input:s,setInput:a,send:f,sending:p,error:o}};var h=require("react/jsx-runtime"),H={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"}},ae=({artifact:e})=>{let t=k(e.dataBase64??"",e.mimeType),n=e.url??t;return n?e.mimeType.startsWith("image/")?(0,h.jsx)("a",{href:n,rel:"noopener noreferrer",target:"_blank",children:(0,h.jsx)("img",{alt:e.filename,src:n,style:H.image})}):(0,h.jsx)("a",{download:e.filename,href:n,style:H.link,children:e.filename}):null},B=()=>{let e=M(),{messages:t,input:n,setInput:s,send:a,sending:p,error:r}=A(e),o=(0,U.useRef)(null);(0,U.useEffect)(()=>{let i=o.current;i&&(i.scrollTop=i.scrollHeight)},[t]);let d=i=>{i.preventDefault(),a()};return(0,h.jsxs)("div",{style:H.root,children:[(0,h.jsx)("div",{ref:o,style:H.log,children:t.map(i=>(0,h.jsxs)("div",{style:i.role==="user"?H.user:H.assistant,children:[i.text||(i.streaming?"\u2026":""),i.artifacts&&i.artifacts.length>0?(0,h.jsx)("div",{style:H.artifacts,children:i.artifacts.map(l=>(0,h.jsx)(ae,{artifact:l},l.filename))}):null]},i.id))}),r?(0,h.jsx)("div",{style:H.error,children:r}):null,(0,h.jsxs)("form",{onSubmit:d,style:H.form,children:[(0,h.jsx)("input",{"aria-label":"Message",onChange:i=>s(i.target.value),placeholder:"Type a message\u2026",style:H.input,value:n}),(0,h.jsx)("button",{disabled:p||n.trim().length===0,style:H.button,type:"submit",children:"Send"})]})]})};var ie=/\/+$/,O=e=>{let t=e.sessionId,n=e.baseUrl.replace(ie,""),s=r=>`${n}/endpoint/${encodeURIComponent(e.token)}${r}`,a={"content-type":"application/json"},p=(r,o)=>({url:s(r),headers:a,body:JSON.stringify({message:o,...t?{sessionId:t}:{},...e.identity?{externalUserId:e.identity.externalUserId,userHmac:e.identity.userHmac}:{}})});return{sessionId:()=>t,getInfo:()=>C(s("/config"),{}),sendMessage:async r=>{let o=await W(p("/message",r));return t=o.sessionId,o},streamMessage:(r,o,d)=>N(p("/message/stream",r),o,i=>{t=i},d),subscribe:(r,o)=>{let d=o?.since??"0",i=!1,l,f=o?.intervalMs??3e3,u=async()=>{let y=t;if(y)try{let g=await C(s(`/messages?session=${encodeURIComponent(y)}&since=${encodeURIComponent(d)}`),{});for(let m of g.messages)r.onMessage(m);d=g.cursor}catch(g){r.onError?.(T(g))}i||(l=setTimeout(u,f))},c=()=>{i=!0,l&&clearTimeout(l)};return o?.signal?.addEventListener("abort",c),l=setTimeout(u,0),c},requestHuman:async()=>{t&&await fetch(s("/request-human"),{method:"POST",headers:a,body:JSON.stringify({sessionId:t})})}}};var G=e=>"transport"in e?e.transport:O(e);var le=/\/+$/,v="/api/v1/end-user";function pe(e){let t="";for(let s=0;s<e.length;s+=32768)t+=String.fromCharCode(...e.subarray(s,s+32768));return btoa(t)}var K=e=>{let t=e.baseUrl.replace(le,""),n=()=>typeof e.token=="function"?e.token():e.token,s=async()=>({"content-type":"application/json",authorization:`Bearer ${await n()}`}),a=async(r,o)=>{try{let d=await fetch(`${t}${v}${r}`,{method:o.method,headers:await s(),...o.body===void 0?{}:{body:JSON.stringify(o.body)}});if(!d.ok){let i=await d.text().catch(()=>""),l=`${o.method} ${r} \u2192 ${String(d.status)}`;try{let f=JSON.parse(i);f.message&&(l=f.message)}catch{l=i?`${l}: ${i}`:l}throw T(new Error(l))}return await d.json()}catch(d){throw T(d)}},p=r=>`/tables/${encodeURIComponent(r)}`;return{listTables:async()=>(await C(`${t}${v}/tables`,await s())).tables,listRows:async(r,o)=>await C(`${t}${v}${p(r)}/rows?limit=${String(o??100)}`,await s()),insertRow:async(r,o)=>{let{rowIds:d}=await a(`${p(r)}/rows`,{method:"POST",body:{rows:[o]}}),i=d[0];if(!i)throw T(new Error("The row was not created."));return i},patchRow:async(r,o,d)=>(await a(`${p(r)}/rows/${encodeURIComponent(o)}`,{method:"PATCH",body:d})).updated,deleteRow:async(r,o)=>(await a(`/${encodeURIComponent(r)}/${encodeURIComponent(o)}`,{method:"DELETE"})).deleted,listFiles:async()=>(await C(`${t}${v}/tables/files/rows?limit=200`,await s())).rows.map(o=>({id:o.rowId,filename:String(o.data.filename??""),source:String(o.data.source??"client"),campaign:String(o.data.campaign??""),size:typeof o.data.size=="number"?o.data.size:0,createdAt:o.createdAt})),uploadFile:async(r,o)=>{let d=new Uint8Array(await r.arrayBuffer());return await a("/files",{method:"POST",body:{filename:r.name,mime:r.type||"application/octet-stream",data:pe(d),...o===void 0?{}:{message:o}}})},fileUrl:r=>`${t}${v}/files/${encodeURIComponent(r)}/raw`,deleteFile:async r=>(await a(`/files/${encodeURIComponent(r)}`,{method:"DELETE"})).deleted}};var w=require("react");function D(e,t){return e.some(s=>s.id===t.id)?e:[...t.author==="client"?e.filter(s=>!(s.pending&&s.author==="client"&&s.text===t.text)):e,t]}var V=(e,t)=>{let[n,s]=(0,w.useState)([]),[a,p]=(0,w.useState)(""),[r,o]=(0,w.useState)(!1),[d,i]=(0,w.useState)(null),l=(0,w.useRef)(0),f=t?.pollMs??2e3;(0,w.useEffect)(()=>{let c=!0;return e.getInfo().then(y=>{c&&y.greeting&&s(g=>g.length===0?[{id:"greeting",cursor:"",author:"agent",text:y.greeting}]:g)}).catch(()=>{}),()=>{c=!1}},[e]),(0,w.useEffect)(()=>e.subscribe?.({onMessage:c=>s(y=>D(y,c)),onError:c=>i(c.error)},{intervalMs:f}),[e,f]);let u=(0,w.useCallback)(()=>{let c=a.trim();if(!c||r)return;p(""),i(null),o(!0),l.current+=1;let y={id:`pending-${l.current}`,cursor:"",author:"client",text:c,pending:!0};s(g=>[...g,y]),e.sendMessage(c).then(()=>o(!1)).catch(g=>{i(g instanceof Error?g.message:"send_failed"),o(!1)})},[a,r,e]);return{messages:n,input:a,setInput:p,send:u,sending:r,error:d}};0&&(module.exports={Chat,HolaProvider,createApiTransport,createHolaClient,createPortalData,createWidgetTransport,mergeMessage,textDeltaOf,thinkingDeltaOf,toolEventOf,useArtifactUrl,useChat,useHolaClient,useThread});
8
+ `)}},i=async()=>{let c=await d.read();if(!c.done)return s+=r.decode(c.value,{stream:!0}),l(),i()};await i()};var ae=/\/+$/,S="/api/v1/end-user",z=e=>{let t=e.baseUrl.replace(ae,""),n=()=>typeof e.token=="function"?e.token():e.token,o=async()=>({"content-type":"application/json",authorization:`Bearer ${await n()}`}),a=async d=>{let r=await fetch(`${t}${S}/chat`,{method:"POST",headers:await o(),body:JSON.stringify({message:d})});if(!r.ok)throw new Error(`hola: message failed (${r.status})`);return{reply:(await r.json()).reply??"",sessionId:"",artifacts:[]}};return{sessionId:()=>"",getInfo:async()=>h(`${t}${S}/chat/info`,await o()),sendMessage:a,streamMessage:async(d,r)=>{try{let s=await a(d);r.onText?.(s.reply),r.onComplete?.(s)}catch(s){r.onError?.(C(s))}},subscribe:(d,r)=>{let s=r?.since??"0",l=!1,i,c=r?.intervalMs??3e3,f=async()=>{try{let p=await h(`${t}${S}/chat/thread?since=${encodeURIComponent(s)}`,await o());for(let y of p.messages)d.onMessage(y);s=p.cursor}catch(p){d.onError?.(C(p))}l||(i=setTimeout(f,c))},u=()=>{l=!0,i&&clearTimeout(i)};return r?.signal?.addEventListener("abort",u),i=setTimeout(f,0),u},requestHuman:async()=>{await fetch(`${t}${S}/chat/request-human`,{method:"POST",headers:await o(),body:"{}"})}}};var $=require("react"),k=(e,t)=>{let[n,o]=(0,$.useState)("");return(0,$.useEffect)(()=>{if(!e){o("");return}let a=Uint8Array.from(atob(e),r=>r.charCodeAt(0)),d=URL.createObjectURL(new Blob([a],{type:t}));return o(d),()=>URL.revokeObjectURL(d)},[e,t]),n};var D=require("react");var M=require("react"),B=require("react/jsx-runtime"),J=(0,M.createContext)(null),q=({client:e,children:t})=>(0,B.jsx)(J.Provider,{value:e,children:t}),A=()=>{let e=(0,M.useContext)(J);if(!e)throw new Error("useHolaClient must be used within <HolaProvider>");return e};var w=require("react"),U=e=>{let[t,n]=(0,w.useState)([]),[o,a]=(0,w.useState)(""),[d,r]=(0,w.useState)(!1),[s,l]=(0,w.useState)(null),i=(0,w.useRef)(0),c=(0,w.useCallback)(()=>{let u=i.current;return i.current+=1,u},[]);(0,w.useEffect)(()=>{let u=!0;return e.getInfo().then(p=>{u&&p.greeting&&n([{id:c(),role:"assistant",text:p.greeting}])}).catch(()=>{}),()=>{u=!1}},[e,c]);let f=(0,w.useCallback)(()=>{let u=o.trim();if(!u||d)return;a(""),l(null),r(!0);let p=c(),y=c();n(g=>[...g,{id:p,role:"user",text:u},{id:y,role:"assistant",text:"",streaming:!0}]);let m=g=>{n(H=>H.map(_=>_.id===y?g(_):_))};e.streamMessage(u,{onText:g=>m(H=>({...H,text:H.text+g})),onComplete:g=>{m(H=>({...H,text:g.reply||H.text,artifacts:g.artifacts,streaming:!1})),r(!1)},onError:g=>{m(H=>({...H,streaming:!1})),l(g.error),r(!1)}}).catch(g=>{m(H=>({...H,streaming:!1})),l(g instanceof Error?g.message:"stream_failed"),r(!1)})},[o,d,e,c]);return{messages:t,input:o,setInput:a,send:f,sending:d,error:s}};var b=require("react/jsx-runtime"),T={root:{display:"flex",flexDirection:"column",height:"100%",fontFamily:"system-ui, -apple-system, sans-serif",fontSize:14,color:"#111827"},log:{flex:1,overflowY:"auto",padding:12,display:"flex",flexDirection:"column",gap:8},user:{alignSelf:"flex-end",background:"#111827",color:"#ffffff",borderRadius:12,padding:"8px 12px",maxWidth:"80%",whiteSpace:"pre-wrap"},assistant:{alignSelf:"flex-start",background:"#f1f1f4",color:"#111827",borderRadius:12,padding:"8px 12px",maxWidth:"80%",whiteSpace:"pre-wrap"},artifacts:{display:"flex",flexDirection:"column",gap:6,marginTop:6},image:{maxHeight:220,borderRadius:8,border:"1px solid #e5e7eb"},link:{color:"#2563eb",textDecoration:"underline",wordBreak:"break-all"},error:{color:"#b91c1c",padding:"4px 12px",fontSize:13},form:{display:"flex",gap:8,borderTop:"1px solid #e5e7eb",padding:8},input:{flex:1,border:"1px solid #d1d5db",borderRadius:8,padding:"8px 10px",fontSize:14,outline:"none"},button:{border:"none",background:"#111827",color:"#ffffff",borderRadius:8,padding:"8px 14px",fontSize:14,cursor:"pointer"}},ie=({artifact:e})=>{let t=k(e.dataBase64??"",e.mimeType),n=e.url??t;return n?e.mimeType.startsWith("image/")?(0,b.jsx)("a",{href:n,rel:"noopener noreferrer",target:"_blank",children:(0,b.jsx)("img",{alt:e.filename,src:n,style:T.image})}):(0,b.jsx)("a",{download:e.filename,href:n,style:T.link,children:e.filename}):null},G=()=>{let e=A(),{messages:t,input:n,setInput:o,send:a,sending:d,error:r}=U(e),s=(0,D.useRef)(null);(0,D.useEffect)(()=>{let i=s.current;i&&(i.scrollTop=i.scrollHeight)},[t]);let l=i=>{i.preventDefault(),a()};return(0,b.jsxs)("div",{style:T.root,children:[(0,b.jsx)("div",{ref:s,style:T.log,children:t.map(i=>(0,b.jsxs)("div",{style:i.role==="user"?T.user:T.assistant,children:[i.text||(i.streaming?"\u2026":""),i.artifacts&&i.artifacts.length>0?(0,b.jsx)("div",{style:T.artifacts,children:i.artifacts.map(c=>(0,b.jsx)(ie,{artifact:c},c.filename))}):null]},i.id))}),r?(0,b.jsx)("div",{style:T.error,children:r}):null,(0,b.jsxs)("form",{onSubmit:l,style:T.form,children:[(0,b.jsx)("input",{"aria-label":"Message",onChange:i=>o(i.target.value),placeholder:"Type a message\u2026",style:T.input,value:n}),(0,b.jsx)("button",{disabled:d||n.trim().length===0,style:T.button,type:"submit",children:"Send"})]})]})};var le=/\/+$/,O=e=>{let t=e.sessionId,n=e.baseUrl.replace(le,""),o=r=>`${n}/endpoint/${encodeURIComponent(e.token)}${r}`,a={"content-type":"application/json"},d=(r,s)=>({url:o(r),headers:a,body:JSON.stringify({message:s,...t?{sessionId:t}:{},...e.identity?{externalUserId:e.identity.externalUserId,userHmac:e.identity.userHmac}:{}})});return{sessionId:()=>t,getInfo:()=>h(o("/config"),{}),sendMessage:async r=>{let s=await N(d("/message",r));return t=s.sessionId,s},streamMessage:(r,s,l)=>j(d("/message/stream",r),s,i=>{t=i},l),subscribe:(r,s)=>{let l=s?.since??"0",i=!1,c,f=s?.intervalMs??3e3,u=async()=>{let y=t;if(y)try{let m=await h(o(`/messages?session=${encodeURIComponent(y)}&since=${encodeURIComponent(l)}`),{});for(let g of m.messages)r.onMessage(g);l=m.cursor}catch(m){r.onError?.(C(m))}i||(c=setTimeout(u,f))},p=()=>{i=!0,c&&clearTimeout(c)};return s?.signal?.addEventListener("abort",p),c=setTimeout(u,0),p},requestHuman:async()=>{t&&await fetch(o("/request-human"),{method:"POST",headers:a,body:JSON.stringify({sessionId:t})})}}};var K=e=>"transport"in e?e.transport:O(e);var ce=/\/+$/,P="/api/v1/end-user",v=class extends Error{constructor(t){super(t),this.name="PortalConflict"}};function de(e){let t="";for(let o=0;o<e.length;o+=32768)t+=String.fromCharCode(...e.subarray(o,o+32768));return btoa(t)}var V=e=>{let t=e.baseUrl.replace(ce,""),n=()=>typeof e.token=="function"?e.token():e.token,o=async()=>({"content-type":"application/json",authorization:`Bearer ${await n()}`}),a=async(r,s)=>{try{let l=await fetch(`${t}${P}${r}`,{method:s.method,headers:await o(),...s.body===void 0?{}:{body:JSON.stringify(s.body)}});if(l.status===409){let i=await l.json().catch(()=>({}));throw new v(i.message??"Someone else saved this first.")}if(!l.ok){let i=await l.text().catch(()=>""),c=`${s.method} ${r} \u2192 ${String(l.status)}`;try{let f=JSON.parse(i);f.message&&(c=f.message)}catch{c=i?`${c}: ${i}`:c}throw C(new Error(c))}return await l.json()}catch(l){throw C(l)}},d=r=>`/tables/${encodeURIComponent(r)}`;return{listTables:async()=>(await h(`${t}${P}/tables`,await o())).tables,listRows:async(r,s)=>await h(`${t}${P}${d(r)}/rows?limit=${String(s??100)}`,await o()),insertRow:async(r,s)=>{let{rowIds:l}=await a(`${d(r)}/rows`,{method:"POST",body:{rows:[s]}}),i=l[0];if(!i)throw C(new Error("The row was not created."));return i},patchRow:async(r,s,l)=>(await a(`${d(r)}/rows/${encodeURIComponent(s)}`,{method:"PATCH",body:l})).updated,deleteRow:async(r,s)=>(await a(`/${encodeURIComponent(r)}/${encodeURIComponent(s)}`,{method:"DELETE"})).deleted,listFiles:async()=>(await h(`${t}${P}/tables/files/rows?limit=200`,await o())).rows.map(s=>({id:s.rowId,filename:String(s.data.filename??""),source:String(s.data.source??"client"),campaign:String(s.data.campaign??""),size:typeof s.data.size=="number"?s.data.size:0,createdAt:s.createdAt})),uploadFile:async(r,s)=>{let l=new Uint8Array(await r.arrayBuffer());return await a("/files",{method:"POST",body:{filename:r.name,mime:r.type||"application/octet-stream",data:de(l),...s===void 0?{}:{message:s}}})},fileLink:async r=>await h(`${t}${P}/files/${encodeURIComponent(r)}/url`,await o()),deleteFile:async r=>(await a(`/files/${encodeURIComponent(r)}`,{method:"DELETE"})).deleted,listDocuments:async()=>(await h(`${t}${P}/documents`,await o())).documents,readDocument:async r=>(await h(`${t}${P}/documents/${encodeURIComponent(r)}`,await o())).document,saveDocument:async(r,s)=>await a(`/documents/${encodeURIComponent(r)}`,{method:"PATCH",body:s})}};var x=require("react");function L(e,t){return e.some(o=>o.id===t.id)?e:[...t.author==="client"?e.filter(o=>!(o.pending&&o.author==="client"&&o.text===t.text)):e,t]}var Y=(e,t)=>{let[n,o]=(0,x.useState)([]),[a,d]=(0,x.useState)(""),[r,s]=(0,x.useState)(!1),[l,i]=(0,x.useState)(null),c=(0,x.useRef)(0),f=t?.pollMs??2e3;(0,x.useEffect)(()=>{let p=!0;return e.getInfo().then(y=>{p&&y.greeting&&o(m=>m.length===0?[{id:"greeting",cursor:"",author:"agent",text:y.greeting}]:m)}).catch(()=>{}),()=>{p=!1}},[e]),(0,x.useEffect)(()=>e.subscribe?.({onMessage:p=>o(y=>L(y,p)),onError:p=>i(p.error)},{intervalMs:f}),[e,f]);let u=(0,x.useCallback)(()=>{let p=a.trim();if(!p||r)return;d(""),i(null),s(!0),c.current+=1;let y={id:`pending-${c.current}`,cursor:"",author:"client",text:p,pending:!0};o(m=>[...m,y]),e.sendMessage(p).then(()=>s(!1)).catch(m=>{i(m instanceof Error?m.message:"send_failed"),s(!1)})},[a,r,e]);return{messages:n,input:a,setInput:d,send:u,sending:r,error:l}};0&&(module.exports={Chat,HolaProvider,PortalConflict,createApiTransport,createHolaClient,createPortalData,createWidgetTransport,mergeMessage,textDeltaOf,thinkingDeltaOf,toolEventOf,useArtifactUrl,useChat,useHolaClient,useThread});
package/dist/index.d.cts CHANGED
@@ -197,6 +197,29 @@ type PortalFile = {
197
197
  size: number;
198
198
  createdAt: string;
199
199
  };
200
+ /** A document shared with this customer. The body arrives only on a read. */
201
+ type PortalDocumentSummary = {
202
+ documentId: string;
203
+ title: string;
204
+ version: number;
205
+ /** Whether the company opened this one for editing, not merely for reading. */
206
+ editable: boolean;
207
+ updatedAt: string;
208
+ };
209
+ type PortalDocument = PortalDocumentSummary & {
210
+ body: string;
211
+ };
212
+ /**
213
+ * A save that lost a race.
214
+ *
215
+ * Thrown rather than returned so it cannot be mistaken for success, and separate
216
+ * from a plain error because the caller should do something different: re-read,
217
+ * reapply, save again — never retry the same bytes, which would overwrite whoever
218
+ * got there first.
219
+ */
220
+ declare class PortalConflict extends Error {
221
+ constructor(message: string);
222
+ }
200
223
  type PortalData = {
201
224
  /** The tables this customer can see. A table the company has not shared is
202
225
  * absent, not empty — it answers as if it did not exist. */
@@ -222,10 +245,37 @@ type PortalData = {
222
245
  uploadFile(file: File, message?: string): Promise<{
223
246
  rowId: string;
224
247
  }>;
225
- /** A URL to open or download. It redirects to a signed one. */
226
- fileUrl(rowId: string): string;
248
+ /**
249
+ * A link the browser can actually follow.
250
+ *
251
+ * Not a plain URL string: the download route needs the customer's token, and
252
+ * navigation from an `<a href>` carries no Authorization header — so a direct
253
+ * link is a guaranteed 401. This fetches the signed URL with the token, and
254
+ * what comes back needs no header of its own.
255
+ */
256
+ fileLink(rowId: string): Promise<{
257
+ url: string;
258
+ filename: string;
259
+ }>;
227
260
  /** Only files this customer sent, and only before they are filed. */
228
261
  deleteFile(rowId: string): Promise<number>;
262
+ /** Documents the company shared with this customer. */
263
+ listDocuments(): Promise<PortalDocumentSummary[]>;
264
+ readDocument(documentId: string): Promise<PortalDocument>;
265
+ /**
266
+ * Save new text.
267
+ *
268
+ * `baseVersion` is the version that was open. Rejects with a PortalConflict if
269
+ * it has moved — do not retry with the same text: read again, put the change
270
+ * back on top of theirs, and save that.
271
+ */
272
+ saveDocument(documentId: string, edit: {
273
+ body: string;
274
+ baseVersion: number;
275
+ note?: string;
276
+ }): Promise<{
277
+ version: number;
278
+ }>;
229
279
  };
230
280
  declare const createPortalData: (config: ApiTransportConfig) => PortalData;
231
281
 
@@ -281,4 +331,4 @@ declare const useThread: (client: HolaClient, options?: {
281
331
  pollMs?: number;
282
332
  }) => UseThread;
283
333
 
284
- export { type ApiTransportConfig, Chat, type ChatMessage, type CreateHolaClientOptions, 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 PortalData, type PortalField, type PortalFile, type PortalRow, type PortalRowPage, type PortalTable, type ThreadMessage, type UseChat, type UseThread, type WidgetTransportConfig, createApiTransport, createHolaClient, createPortalData, createWidgetTransport, mergeMessage, textDeltaOf, thinkingDeltaOf, toolEventOf, useArtifactUrl, useChat, useHolaClient, useThread };
334
+ export { type ApiTransportConfig, Chat, type ChatMessage, type CreateHolaClientOptions, 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, PortalConflict, type PortalData, type PortalDocument, type PortalDocumentSummary, type PortalField, type PortalFile, type PortalRow, type PortalRowPage, type PortalTable, type ThreadMessage, type UseChat, type UseThread, type WidgetTransportConfig, createApiTransport, createHolaClient, createPortalData, createWidgetTransport, mergeMessage, textDeltaOf, thinkingDeltaOf, toolEventOf, useArtifactUrl, useChat, useHolaClient, useThread };
package/dist/index.d.ts CHANGED
@@ -197,6 +197,29 @@ type PortalFile = {
197
197
  size: number;
198
198
  createdAt: string;
199
199
  };
200
+ /** A document shared with this customer. The body arrives only on a read. */
201
+ type PortalDocumentSummary = {
202
+ documentId: string;
203
+ title: string;
204
+ version: number;
205
+ /** Whether the company opened this one for editing, not merely for reading. */
206
+ editable: boolean;
207
+ updatedAt: string;
208
+ };
209
+ type PortalDocument = PortalDocumentSummary & {
210
+ body: string;
211
+ };
212
+ /**
213
+ * A save that lost a race.
214
+ *
215
+ * Thrown rather than returned so it cannot be mistaken for success, and separate
216
+ * from a plain error because the caller should do something different: re-read,
217
+ * reapply, save again — never retry the same bytes, which would overwrite whoever
218
+ * got there first.
219
+ */
220
+ declare class PortalConflict extends Error {
221
+ constructor(message: string);
222
+ }
200
223
  type PortalData = {
201
224
  /** The tables this customer can see. A table the company has not shared is
202
225
  * absent, not empty — it answers as if it did not exist. */
@@ -222,10 +245,37 @@ type PortalData = {
222
245
  uploadFile(file: File, message?: string): Promise<{
223
246
  rowId: string;
224
247
  }>;
225
- /** A URL to open or download. It redirects to a signed one. */
226
- fileUrl(rowId: string): string;
248
+ /**
249
+ * A link the browser can actually follow.
250
+ *
251
+ * Not a plain URL string: the download route needs the customer's token, and
252
+ * navigation from an `<a href>` carries no Authorization header — so a direct
253
+ * link is a guaranteed 401. This fetches the signed URL with the token, and
254
+ * what comes back needs no header of its own.
255
+ */
256
+ fileLink(rowId: string): Promise<{
257
+ url: string;
258
+ filename: string;
259
+ }>;
227
260
  /** Only files this customer sent, and only before they are filed. */
228
261
  deleteFile(rowId: string): Promise<number>;
262
+ /** Documents the company shared with this customer. */
263
+ listDocuments(): Promise<PortalDocumentSummary[]>;
264
+ readDocument(documentId: string): Promise<PortalDocument>;
265
+ /**
266
+ * Save new text.
267
+ *
268
+ * `baseVersion` is the version that was open. Rejects with a PortalConflict if
269
+ * it has moved — do not retry with the same text: read again, put the change
270
+ * back on top of theirs, and save that.
271
+ */
272
+ saveDocument(documentId: string, edit: {
273
+ body: string;
274
+ baseVersion: number;
275
+ note?: string;
276
+ }): Promise<{
277
+ version: number;
278
+ }>;
229
279
  };
230
280
  declare const createPortalData: (config: ApiTransportConfig) => PortalData;
231
281
 
@@ -281,4 +331,4 @@ declare const useThread: (client: HolaClient, options?: {
281
331
  pollMs?: number;
282
332
  }) => UseThread;
283
333
 
284
- export { type ApiTransportConfig, Chat, type ChatMessage, type CreateHolaClientOptions, 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 PortalData, type PortalField, type PortalFile, type PortalRow, type PortalRowPage, type PortalTable, type ThreadMessage, type UseChat, type UseThread, type WidgetTransportConfig, createApiTransport, createHolaClient, createPortalData, createWidgetTransport, mergeMessage, textDeltaOf, thinkingDeltaOf, toolEventOf, useArtifactUrl, useChat, useHolaClient, useThread };
334
+ export { type ApiTransportConfig, Chat, type ChatMessage, type CreateHolaClientOptions, 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, PortalConflict, type PortalData, type PortalDocument, type PortalDocumentSummary, type PortalField, type PortalFile, type PortalRow, type PortalRowPage, type PortalTable, type ThreadMessage, type UseChat, type UseThread, type WidgetTransportConfig, createApiTransport, createHolaClient, createPortalData, createWidgetTransport, mergeMessage, textDeltaOf, thinkingDeltaOf, toolEventOf, useArtifactUrl, useChat, useHolaClient, useThread };
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},R=e=>{let t=O(e);return t?.type==="text_delta"&&typeof t.delta=="string"?t.delta:null},E=e=>{let t=O(e);return t?.type==="thinking_delta"&&typeof t.delta=="string"?t.delta:null},S=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 j=/^ /,w=e=>{if(e&&typeof e=="object"){let t=e,a=typeof t.error=="string"?t.error:"request_failed";return typeof t.retryable=="boolean"?{error:a,retryable:t.retryable}:{error:a}}return{error:"request_failed"}},z=e=>{let t="message",a=[];for(let s of e.split(`
3
- `))s.startsWith(":")||(s.startsWith("event:")?t=s.slice(6).trim():s.startsWith("data:")&&a.push(s.slice(5).replace(j,"")));return a.length>0?{event:t,data:a.join(`
4
- `)}:null},J=(e,t,a)=>{let s;try{s=JSON.parse(e.data)}catch{return}if(e.event==="session"){let i=s.sessionId;i&&(a(i),t.onSession?.(i));return}if(e.event==="turn_event"){t.onEvent?.(s);let i=R(s);i&&t.onText?.(i);let p=E(s);p&&t.onThinking?.(p);let r=S(s);r&&t.onTool?.(r);return}if(e.event==="chat_completed"){let i=s;a(i.sessionId),t.onComplete?.(i);return}e.event==="chat_error"&&t.onError?.(w(s))},x=async(e,t)=>{let a=await fetch(e,{headers:t});if(!a.ok)throw new Error(`hola: request failed (${a.status})`);return await a.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()},F=async(e,t,a,s)=>{let i=await fetch(e.url,{method:"POST",headers:e.headers,body:e.body,signal:s});if(!(i.ok&&i.body)){t.onError?.({error:`stream_failed_${i.status}`});return}let p=i.body.getReader(),r=new TextDecoder,o="",d=()=>{let l=o.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},S=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 z=/^ /,x=e=>{if(e&&typeof e=="object"){let t=e,a=typeof t.error=="string"?t.error:"request_failed";return typeof t.retryable=="boolean"?{error:a,retryable:t.retryable}:{error:a}}return{error:"request_failed"}},J=e=>{let t="message",a=[];for(let s of e.split(`
3
+ `))s.startsWith(":")||(s.startsWith("event:")?t=s.slice(6).trim():s.startsWith("data:")&&a.push(s.slice(5).replace(z,"")));return a.length>0?{event:t,data:a.join(`
4
+ `)}:null},q=(e,t,a)=>{let s;try{s=JSON.parse(e.data)}catch{return}if(e.event==="session"){let i=s.sessionId;i&&(a(i),t.onSession?.(i));return}if(e.event==="turn_event"){t.onEvent?.(s);let i=E(s);i&&t.onText?.(i);let d=S(s);d&&t.onThinking?.(d);let r=$(s);r&&t.onTool?.(r);return}if(e.event==="chat_completed"){let i=s;a(i.sessionId),t.onComplete?.(i);return}e.event==="chat_error"&&t.onError?.(x(s))},b=async(e,t)=>{let a=await fetch(e,{headers:t});if(!a.ok)throw new Error(`hola: request failed (${a.status})`);return await a.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()},F=async(e,t,a,s)=>{let i=await fetch(e.url,{method:"POST",headers:e.headers,body:e.body,signal:s});if(!(i.ok&&i.body)){t.onError?.({error:`stream_failed_${i.status}`});return}let d=i.body.getReader(),r=new TextDecoder,o="",l=()=>{let c=o.indexOf(`
5
5
 
6
- `);for(;l!==-1;){let f=o.slice(0,l);o=o.slice(l+2);let u=z(f);u&&J(u,t,a),l=o.indexOf(`
6
+ `);for(;c!==-1;){let f=o.slice(0,c);o=o.slice(c+2);let u=J(f);u&&q(u,t,a),c=o.indexOf(`
7
7
 
8
- `)}},n=async()=>{let l=await p.read();if(!l.done)return o+=r.decode(l.value,{stream:!0}),d(),n()};await n()};var q=/\/+$/,C="/api/v1/end-user",B=e=>{let t=e.baseUrl.replace(q,""),a=()=>typeof e.token=="function"?e.token():e.token,s=async()=>({"content-type":"application/json",authorization:`Bearer ${await a()}`}),i=async p=>{let r=await fetch(`${t}${C}/chat`,{method:"POST",headers:await s(),body:JSON.stringify({message:p})});if(!r.ok)throw new Error(`hola: message failed (${r.status})`);return{reply:(await r.json()).reply??"",sessionId:"",artifacts:[]}};return{sessionId:()=>"",getInfo:async()=>x(`${t}${C}/chat/info`,await s()),sendMessage:i,streamMessage:async(p,r)=>{try{let o=await i(p);r.onText?.(o.reply),r.onComplete?.(o)}catch(o){r.onError?.(w(o))}},subscribe:(p,r)=>{let o=r?.since??"0",d=!1,n,l=r?.intervalMs??3e3,f=async()=>{try{let c=await x(`${t}${C}/chat/thread?since=${encodeURIComponent(o)}`,await s());for(let y of c.messages)p.onMessage(y);o=c.cursor}catch(c){p.onError?.(w(c))}d||(n=setTimeout(f,l))},u=()=>{d=!0,n&&clearTimeout(n)};return r?.signal?.addEventListener("abort",u),n=setTimeout(f,0),u},requestHuman:async()=>{await fetch(`${t}${C}/chat/request-human`,{method:"POST",headers:await s(),body:"{}"})}}};import{useEffect as G,useState as K}from"react";var k=(e,t)=>{let[a,s]=K("");return G(()=>{if(!e){s("");return}let i=Uint8Array.from(atob(e),r=>r.charCodeAt(0)),p=URL.createObjectURL(new Blob([i],{type:t}));return s(p),()=>URL.revokeObjectURL(p)},[e,t]),a};import{useEffect as te,useRef as re}from"react";import{createContext as V,useContext as Y}from"react";import{jsx as X}from"react/jsx-runtime";var D=V(null),Q=({client:e,children:t})=>X(D.Provider,{value:e,children:t}),$=()=>{let e=Y(D);if(!e)throw new Error("useHolaClient must be used within <HolaProvider>");return e};import{useCallback as L,useEffect as Z,useRef as ee,useState as v}from"react";var M=e=>{let[t,a]=v([]),[s,i]=v(""),[p,r]=v(!1),[o,d]=v(null),n=ee(0),l=L(()=>{let u=n.current;return n.current+=1,u},[]);Z(()=>{let u=!0;return e.getInfo().then(c=>{u&&c.greeting&&a([{id:l(),role:"assistant",text:c.greeting}])}).catch(()=>{}),()=>{u=!1}},[e,l]);let f=L(()=>{let u=s.trim();if(!u||p)return;i(""),d(null),r(!0);let c=l(),y=l();a(m=>[...m,{id:c,role:"user",text:u},{id:y,role:"assistant",text:"",streaming:!0}]);let g=m=>{a(h=>h.map(I=>I.id===y?m(I):I))};e.streamMessage(u,{onText:m=>g(h=>({...h,text:h.text+m})),onComplete:m=>{g(h=>({...h,text:m.reply||h.text,artifacts:m.artifacts,streaming:!1})),r(!1)},onError:m=>{g(h=>({...h,streaming:!1})),d(m.error),r(!1)}}).catch(m=>{g(h=>({...h,streaming:!1})),d(m instanceof Error?m.message:"stream_failed"),r(!1)})},[s,p,e,l]);return{messages:t,input:s,setInput:i,send:f,sending:p,error:o}};import{jsx as H,jsxs as A}from"react/jsx-runtime";var b={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"}},oe=({artifact:e})=>{let t=k(e.dataBase64??"",e.mimeType),a=e.url??t;return a?e.mimeType.startsWith("image/")?H("a",{href:a,rel:"noopener noreferrer",target:"_blank",children:H("img",{alt:e.filename,src:a,style:b.image})}):H("a",{download:e.filename,href:a,style:b.link,children:e.filename}):null},se=()=>{let e=$(),{messages:t,input:a,setInput:s,send:i,sending:p,error:r}=M(e),o=re(null);te(()=>{let n=o.current;n&&(n.scrollTop=n.scrollHeight)},[t]);let d=n=>{n.preventDefault(),i()};return A("div",{style:b.root,children:[H("div",{ref:o,style:b.log,children:t.map(n=>A("div",{style:n.role==="user"?b.user:b.assistant,children:[n.text||(n.streaming?"\u2026":""),n.artifacts&&n.artifacts.length>0?H("div",{style:b.artifacts,children:n.artifacts.map(l=>H(oe,{artifact:l},l.filename))}):null]},n.id))}),r?H("div",{style:b.error,children:r}):null,A("form",{onSubmit:d,style:b.form,children:[H("input",{"aria-label":"Message",onChange:n=>s(n.target.value),placeholder:"Type a message\u2026",style:b.input,value:a}),H("button",{disabled:p||a.trim().length===0,style:b.button,type:"submit",children:"Send"})]})]})};var ne=/\/+$/,U=e=>{let t=e.sessionId,a=e.baseUrl.replace(ne,""),s=r=>`${a}/endpoint/${encodeURIComponent(e.token)}${r}`,i={"content-type":"application/json"},p=(r,o)=>({url:s(r),headers:i,body:JSON.stringify({message:o,...t?{sessionId:t}:{},...e.identity?{externalUserId:e.identity.externalUserId,userHmac:e.identity.userHmac}:{}})});return{sessionId:()=>t,getInfo:()=>x(s("/config"),{}),sendMessage:async r=>{let o=await _(p("/message",r));return t=o.sessionId,o},streamMessage:(r,o,d)=>F(p("/message/stream",r),o,n=>{t=n},d),subscribe:(r,o)=>{let d=o?.since??"0",n=!1,l,f=o?.intervalMs??3e3,u=async()=>{let y=t;if(y)try{let g=await x(s(`/messages?session=${encodeURIComponent(y)}&since=${encodeURIComponent(d)}`),{});for(let m of g.messages)r.onMessage(m);d=g.cursor}catch(g){r.onError?.(w(g))}n||(l=setTimeout(u,f))},c=()=>{n=!0,l&&clearTimeout(l)};return o?.signal?.addEventListener("abort",c),l=setTimeout(u,0),c},requestHuman:async()=>{t&&await fetch(s("/request-human"),{method:"POST",headers:i,body:JSON.stringify({sessionId:t})})}}};var ae=e=>"transport"in e?e.transport:U(e);var ie=/\/+$/,T="/api/v1/end-user";function le(e){let t="";for(let s=0;s<e.length;s+=32768)t+=String.fromCharCode(...e.subarray(s,s+32768));return btoa(t)}var pe=e=>{let t=e.baseUrl.replace(ie,""),a=()=>typeof e.token=="function"?e.token():e.token,s=async()=>({"content-type":"application/json",authorization:`Bearer ${await a()}`}),i=async(r,o)=>{try{let d=await fetch(`${t}${T}${r}`,{method:o.method,headers:await s(),...o.body===void 0?{}:{body:JSON.stringify(o.body)}});if(!d.ok){let n=await d.text().catch(()=>""),l=`${o.method} ${r} \u2192 ${String(d.status)}`;try{let f=JSON.parse(n);f.message&&(l=f.message)}catch{l=n?`${l}: ${n}`:l}throw w(new Error(l))}return await d.json()}catch(d){throw w(d)}},p=r=>`/tables/${encodeURIComponent(r)}`;return{listTables:async()=>(await x(`${t}${T}/tables`,await s())).tables,listRows:async(r,o)=>await x(`${t}${T}${p(r)}/rows?limit=${String(o??100)}`,await s()),insertRow:async(r,o)=>{let{rowIds:d}=await i(`${p(r)}/rows`,{method:"POST",body:{rows:[o]}}),n=d[0];if(!n)throw w(new Error("The row was not created."));return n},patchRow:async(r,o,d)=>(await i(`${p(r)}/rows/${encodeURIComponent(o)}`,{method:"PATCH",body:d})).updated,deleteRow:async(r,o)=>(await i(`/${encodeURIComponent(r)}/${encodeURIComponent(o)}`,{method:"DELETE"})).deleted,listFiles:async()=>(await x(`${t}${T}/tables/files/rows?limit=200`,await s())).rows.map(o=>({id:o.rowId,filename:String(o.data.filename??""),source:String(o.data.source??"client"),campaign:String(o.data.campaign??""),size:typeof o.data.size=="number"?o.data.size:0,createdAt:o.createdAt})),uploadFile:async(r,o)=>{let d=new Uint8Array(await r.arrayBuffer());return await i("/files",{method:"POST",body:{filename:r.name,mime:r.type||"application/octet-stream",data:le(d),...o===void 0?{}:{message:o}}})},fileUrl:r=>`${t}${T}/files/${encodeURIComponent(r)}/raw`,deleteFile:async r=>(await i(`/files/${encodeURIComponent(r)}`,{method:"DELETE"})).deleted}};import{useCallback as de,useEffect as W,useRef as ce,useState as P}from"react";function N(e,t){return e.some(s=>s.id===t.id)?e:[...t.author==="client"?e.filter(s=>!(s.pending&&s.author==="client"&&s.text===t.text)):e,t]}var ue=(e,t)=>{let[a,s]=P([]),[i,p]=P(""),[r,o]=P(!1),[d,n]=P(null),l=ce(0),f=t?.pollMs??2e3;W(()=>{let c=!0;return e.getInfo().then(y=>{c&&y.greeting&&s(g=>g.length===0?[{id:"greeting",cursor:"",author:"agent",text:y.greeting}]:g)}).catch(()=>{}),()=>{c=!1}},[e]),W(()=>e.subscribe?.({onMessage:c=>s(y=>N(y,c)),onError:c=>n(c.error)},{intervalMs:f}),[e,f]);let u=de(()=>{let c=i.trim();if(!c||r)return;p(""),n(null),o(!0),l.current+=1;let y={id:`pending-${l.current}`,cursor:"",author:"client",text:c,pending:!0};s(g=>[...g,y]),e.sendMessage(c).then(()=>o(!1)).catch(g=>{n(g instanceof Error?g.message:"send_failed"),o(!1)})},[i,r,e]);return{messages:a,input:i,setInput:p,send:u,sending:r,error:d}};export{se as Chat,Q as HolaProvider,B as createApiTransport,ae as createHolaClient,pe as createPortalData,U as createWidgetTransport,N as mergeMessage,R as textDeltaOf,E as thinkingDeltaOf,S as toolEventOf,k as useArtifactUrl,M as useChat,$ as useHolaClient,ue as useThread};
8
+ `)}},n=async()=>{let c=await d.read();if(!c.done)return o+=r.decode(c.value,{stream:!0}),l(),n()};await n()};var B=/\/+$/,C="/api/v1/end-user",G=e=>{let t=e.baseUrl.replace(B,""),a=()=>typeof e.token=="function"?e.token():e.token,s=async()=>({"content-type":"application/json",authorization:`Bearer ${await a()}`}),i=async d=>{let r=await fetch(`${t}${C}/chat`,{method:"POST",headers:await s(),body:JSON.stringify({message:d})});if(!r.ok)throw new Error(`hola: message failed (${r.status})`);return{reply:(await r.json()).reply??"",sessionId:"",artifacts:[]}};return{sessionId:()=>"",getInfo:async()=>b(`${t}${C}/chat/info`,await s()),sendMessage:i,streamMessage:async(d,r)=>{try{let o=await i(d);r.onText?.(o.reply),r.onComplete?.(o)}catch(o){r.onError?.(x(o))}},subscribe:(d,r)=>{let o=r?.since??"0",l=!1,n,c=r?.intervalMs??3e3,f=async()=>{try{let p=await b(`${t}${C}/chat/thread?since=${encodeURIComponent(o)}`,await s());for(let y of p.messages)d.onMessage(y);o=p.cursor}catch(p){d.onError?.(x(p))}l||(n=setTimeout(f,c))},u=()=>{l=!0,n&&clearTimeout(n)};return r?.signal?.addEventListener("abort",u),n=setTimeout(f,0),u},requestHuman:async()=>{await fetch(`${t}${C}/chat/request-human`,{method:"POST",headers:await s(),body:"{}"})}}};import{useEffect as K,useState as V}from"react";var k=(e,t)=>{let[a,s]=V("");return K(()=>{if(!e){s("");return}let i=Uint8Array.from(atob(e),r=>r.charCodeAt(0)),d=URL.createObjectURL(new Blob([i],{type:t}));return s(d),()=>URL.revokeObjectURL(d)},[e,t]),a};import{useEffect as re,useRef as oe}from"react";import{createContext as Y,useContext as Q}from"react";import{jsx as Z}from"react/jsx-runtime";var L=Y(null),X=({client:e,children:t})=>Z(L.Provider,{value:e,children:t}),M=()=>{let e=Q(L);if(!e)throw new Error("useHolaClient must be used within <HolaProvider>");return e};import{useCallback as W,useEffect as ee,useRef as te,useState as P}from"react";var A=e=>{let[t,a]=P([]),[s,i]=P(""),[d,r]=P(!1),[o,l]=P(null),n=te(0),c=W(()=>{let u=n.current;return n.current+=1,u},[]);ee(()=>{let u=!0;return e.getInfo().then(p=>{u&&p.greeting&&a([{id:c(),role:"assistant",text:p.greeting}])}).catch(()=>{}),()=>{u=!1}},[e,c]);let f=W(()=>{let u=s.trim();if(!u||d)return;i(""),l(null),r(!0);let p=c(),y=c();a(g=>[...g,{id:p,role:"user",text:u},{id:y,role:"assistant",text:"",streaming:!0}]);let m=g=>{a(h=>h.map(R=>R.id===y?g(R):R))};e.streamMessage(u,{onText:g=>m(h=>({...h,text:h.text+g})),onComplete:g=>{m(h=>({...h,text:g.reply||h.text,artifacts:g.artifacts,streaming:!1})),r(!1)},onError:g=>{m(h=>({...h,streaming:!1})),l(g.error),r(!1)}}).catch(g=>{m(h=>({...h,streaming:!1})),l(g instanceof Error?g.message:"stream_failed"),r(!1)})},[s,d,e,c]);return{messages:t,input:s,setInput:i,send:f,sending:d,error:o}};import{jsx as H,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"}},se=({artifact:e})=>{let t=k(e.dataBase64??"",e.mimeType),a=e.url??t;return a?e.mimeType.startsWith("image/")?H("a",{href:a,rel:"noopener noreferrer",target:"_blank",children:H("img",{alt:e.filename,src:a,style:w.image})}):H("a",{download:e.filename,href:a,style:w.link,children:e.filename}):null},ne=()=>{let e=M(),{messages:t,input:a,setInput:s,send:i,sending:d,error:r}=A(e),o=oe(null);re(()=>{let n=o.current;n&&(n.scrollTop=n.scrollHeight)},[t]);let l=n=>{n.preventDefault(),i()};return U("div",{style:w.root,children:[H("div",{ref:o,style:w.log,children:t.map(n=>U("div",{style:n.role==="user"?w.user:w.assistant,children:[n.text||(n.streaming?"\u2026":""),n.artifacts&&n.artifacts.length>0?H("div",{style:w.artifacts,children:n.artifacts.map(c=>H(se,{artifact:c},c.filename))}):null]},n.id))}),r?H("div",{style:w.error,children:r}):null,U("form",{onSubmit:l,style:w.form,children:[H("input",{"aria-label":"Message",onChange:n=>s(n.target.value),placeholder:"Type a message\u2026",style:w.input,value:a}),H("button",{disabled:d||a.trim().length===0,style:w.button,type:"submit",children:"Send"})]})]})};var ae=/\/+$/,D=e=>{let t=e.sessionId,a=e.baseUrl.replace(ae,""),s=r=>`${a}/endpoint/${encodeURIComponent(e.token)}${r}`,i={"content-type":"application/json"},d=(r,o)=>({url:s(r),headers:i,body:JSON.stringify({message:o,...t?{sessionId:t}:{},...e.identity?{externalUserId:e.identity.externalUserId,userHmac:e.identity.userHmac}:{}})});return{sessionId:()=>t,getInfo:()=>b(s("/config"),{}),sendMessage:async r=>{let o=await _(d("/message",r));return t=o.sessionId,o},streamMessage:(r,o,l)=>F(d("/message/stream",r),o,n=>{t=n},l),subscribe:(r,o)=>{let l=o?.since??"0",n=!1,c,f=o?.intervalMs??3e3,u=async()=>{let y=t;if(y)try{let m=await b(s(`/messages?session=${encodeURIComponent(y)}&since=${encodeURIComponent(l)}`),{});for(let g of m.messages)r.onMessage(g);l=m.cursor}catch(m){r.onError?.(x(m))}n||(c=setTimeout(u,f))},p=()=>{n=!0,c&&clearTimeout(c)};return o?.signal?.addEventListener("abort",p),c=setTimeout(u,0),p},requestHuman:async()=>{t&&await fetch(s("/request-human"),{method:"POST",headers:i,body:JSON.stringify({sessionId:t})})}}};var ie=e=>"transport"in e?e.transport:D(e);var le=/\/+$/,T="/api/v1/end-user",v=class extends Error{constructor(t){super(t),this.name="PortalConflict"}};function ce(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(le,""),a=()=>typeof e.token=="function"?e.token():e.token,s=async()=>({"content-type":"application/json",authorization:`Bearer ${await a()}`}),i=async(r,o)=>{try{let l=await fetch(`${t}${T}${r}`,{method:o.method,headers:await s(),...o.body===void 0?{}:{body:JSON.stringify(o.body)}});if(l.status===409){let n=await l.json().catch(()=>({}));throw new v(n.message??"Someone else saved this first.")}if(!l.ok){let n=await l.text().catch(()=>""),c=`${o.method} ${r} \u2192 ${String(l.status)}`;try{let f=JSON.parse(n);f.message&&(c=f.message)}catch{c=n?`${c}: ${n}`:c}throw x(new Error(c))}return await l.json()}catch(l){throw x(l)}},d=r=>`/tables/${encodeURIComponent(r)}`;return{listTables:async()=>(await b(`${t}${T}/tables`,await s())).tables,listRows:async(r,o)=>await b(`${t}${T}${d(r)}/rows?limit=${String(o??100)}`,await s()),insertRow:async(r,o)=>{let{rowIds:l}=await i(`${d(r)}/rows`,{method:"POST",body:{rows:[o]}}),n=l[0];if(!n)throw x(new Error("The row was not created."));return n},patchRow:async(r,o,l)=>(await i(`${d(r)}/rows/${encodeURIComponent(o)}`,{method:"PATCH",body:l})).updated,deleteRow:async(r,o)=>(await i(`/${encodeURIComponent(r)}/${encodeURIComponent(o)}`,{method:"DELETE"})).deleted,listFiles:async()=>(await b(`${t}${T}/tables/files/rows?limit=200`,await s())).rows.map(o=>({id:o.rowId,filename:String(o.data.filename??""),source:String(o.data.source??"client"),campaign:String(o.data.campaign??""),size:typeof o.data.size=="number"?o.data.size:0,createdAt:o.createdAt})),uploadFile:async(r,o)=>{let l=new Uint8Array(await r.arrayBuffer());return await i("/files",{method:"POST",body:{filename:r.name,mime:r.type||"application/octet-stream",data:ce(l),...o===void 0?{}:{message:o}}})},fileLink:async r=>await b(`${t}${T}/files/${encodeURIComponent(r)}/url`,await s()),deleteFile:async r=>(await i(`/files/${encodeURIComponent(r)}`,{method:"DELETE"})).deleted,listDocuments:async()=>(await b(`${t}${T}/documents`,await s())).documents,readDocument:async r=>(await b(`${t}${T}/documents/${encodeURIComponent(r)}`,await s())).document,saveDocument:async(r,o)=>await i(`/documents/${encodeURIComponent(r)}`,{method:"PATCH",body:o})}};import{useCallback as pe,useEffect as N,useRef as ue,useState as I}from"react";function j(e,t){return e.some(s=>s.id===t.id)?e:[...t.author==="client"?e.filter(s=>!(s.pending&&s.author==="client"&&s.text===t.text)):e,t]}var me=(e,t)=>{let[a,s]=I([]),[i,d]=I(""),[r,o]=I(!1),[l,n]=I(null),c=ue(0),f=t?.pollMs??2e3;N(()=>{let p=!0;return e.getInfo().then(y=>{p&&y.greeting&&s(m=>m.length===0?[{id:"greeting",cursor:"",author:"agent",text:y.greeting}]:m)}).catch(()=>{}),()=>{p=!1}},[e]),N(()=>e.subscribe?.({onMessage:p=>s(y=>j(y,p)),onError:p=>n(p.error)},{intervalMs:f}),[e,f]);let u=pe(()=>{let p=i.trim();if(!p||r)return;d(""),n(null),o(!0),c.current+=1;let y={id:`pending-${c.current}`,cursor:"",author:"client",text:p,pending:!0};s(m=>[...m,y]),e.sendMessage(p).then(()=>o(!1)).catch(m=>{n(m instanceof Error?m.message:"send_failed"),o(!1)})},[i,r,e]);return{messages:a,input:i,setInput:d,send:u,sending:r,error:l}};export{ne as Chat,X as HolaProvider,v as PortalConflict,G as createApiTransport,ie as createHolaClient,de as createPortalData,D as createWidgetTransport,j as mergeMessage,E as textDeltaOf,S as thinkingDeltaOf,$ as toolEventOf,k as useArtifactUrl,A as useChat,M as useHolaClient,me as useThread};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@holaboss/client",
3
- "version": "0.2.0-beta.0",
3
+ "version": "0.2.0-beta.2",
4
4
  "description": "Injectable client SDK for embedding a Holaboss AI employee (chat today; dashboard + artifacts next) into your own web app.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",