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

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 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(`
2
+ var F=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var X=Object.getOwnPropertyNames;var Z=Object.prototype.hasOwnProperty;var ee=(e,t)=>{for(var a in t)F(e,a,{get:t[a],enumerable:!0})},te=(e,t,a,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of X(t))!Z.call(e,n)&&n!==a&&F(e,n,{get:()=>t[n],enumerable:!(s=Q(t,n))||s.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,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"}},se=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(oe,"")));return a.length>0?{event:t,data:a.join(`
4
+ `)}:null},ne=(e,t,a)=>{let s;try{s=JSON.parse(e.data)}catch{return}if(e.event==="session"){let n=s.sessionId;n&&(a(n),t.onSession?.(n));return}if(e.event==="turn_event"){t.onEvent?.(s);let n=I(s);n&&t.onText?.(n);let d=R(s);d&&t.onThinking?.(d);let r=E(s);r&&t.onTool?.(r);return}if(e.event==="chat_completed"){let n=s;a(n.sessionId),t.onComplete?.(n);return}e.event==="chat_error"&&t.onError?.(C(s))},h=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()},j=async e=>{let t=await fetch(e.url,{method:"POST",headers:e.headers,body:e.body});if(!t.ok)throw new Error(`hola: message failed (${t.status})`);return await t.json()},N=async(e,t,a,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 d=n.body.getReader(),r=new TextDecoder,o="",l=()=>{let c=o.indexOf(`
5
5
 
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(`
6
+ `);for(;c!==-1;){let b=o.slice(0,c);o=o.slice(c+2);let u=se(b);u&&ne(u,t,a),c=o.indexOf(`
7
7
 
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});
8
+ `)}},i=async()=>{let c=await d.read();if(!c.done)return o+=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,""),a=()=>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 a()}`}),d=async r=>{let o=await fetch(`${t}${S}/chat${s("?")}`,{method:"POST",headers:await n(),body:JSON.stringify({message:r})});if(!o.ok)throw new Error(`hola: message failed (${o.status})`);return{reply:(await o.json()).reply??"",sessionId:"",artifacts:[]}};return{sessionId:()=>"",getInfo:async()=>h(`${t}${S}/chat/info${s("?")}`,await n()),sendMessage:d,streamMessage:async(r,o)=>{try{let l=await d(r);o.onText?.(l.reply),o.onComplete?.(l)}catch(l){o.onError?.(C(l))}},subscribe:(r,o)=>{let l=o?.since??"0",i=!1,c,b=o?.intervalMs??3e3,u=async()=>{try{let g=await h(`${t}${S}/chat/thread?since=${encodeURIComponent(l)}${s("&")}`,await n());for(let m of g.messages)r.onMessage(m);l=g.cursor}catch(g){r.onError?.(C(g))}i||(c=setTimeout(u,b))},p=()=>{i=!0,c&&clearTimeout(c)};return o?.signal?.addEventListener("abort",p),c=setTimeout(u,0),p},requestHuman:async()=>{await fetch(`${t}${S}/chat/request-human${s("?")}`,{method:"POST",headers:await n(),body:"{}"})}}};var $=require("react"),k=(e,t)=>{let[a,s]=(0,$.useState)("");return(0,$.useEffect)(()=>{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]),a};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,a]=(0,w.useState)([]),[s,n]=(0,w.useState)(""),[d,r]=(0,w.useState)(!1),[o,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&&a([{id:c(),role:"assistant",text:p.greeting}])}).catch(()=>{}),()=>{u=!1}},[e,c]);let b=(0,w.useCallback)(()=>{let u=s.trim();if(!u||d)return;n(""),l(null),r(!0);let p=c(),g=c();a(f=>[...f,{id:p,role:"user",text:u},{id:g,role:"assistant",text:"",streaming:!0}]);let m=f=>{a(H=>H.map(_=>_.id===g?f(_):_))};e.streamMessage(u,{onText:f=>m(H=>({...H,text:H.text+f})),onComplete:f=>{m(H=>({...H,text:f.reply||H.text,artifacts:f.artifacts,streaming:!1})),r(!1)},onError:f=>{m(H=>({...H,streaming:!1})),l(f.error),r(!1)}}).catch(f=>{m(H=>({...H,streaming:!1})),l(f instanceof Error?f.message:"stream_failed"),r(!1)})},[s,d,e,c]);return{messages:t,input:s,setInput:n,send:b,sending:d,error:o}};var y=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),a=e.url??t;return a?e.mimeType.startsWith("image/")?(0,y.jsx)("a",{href:a,rel:"noopener noreferrer",target:"_blank",children:(0,y.jsx)("img",{alt:e.filename,src:a,style:T.image})}):(0,y.jsx)("a",{download:e.filename,href:a,style:T.link,children:e.filename}):null},G=()=>{let e=A(),{messages:t,input:a,setInput:s,send:n,sending:d,error:r}=U(e),o=(0,D.useRef)(null);(0,D.useEffect)(()=>{let i=o.current;i&&(i.scrollTop=i.scrollHeight)},[t]);let l=i=>{i.preventDefault(),n()};return(0,y.jsxs)("div",{style:T.root,children:[(0,y.jsx)("div",{ref:o,style:T.log,children:t.map(i=>(0,y.jsxs)("div",{style:i.role==="user"?T.user:T.assistant,children:[i.text||(i.streaming?"\u2026":""),i.artifacts&&i.artifacts.length>0?(0,y.jsx)("div",{style:T.artifacts,children:i.artifacts.map(c=>(0,y.jsx)(ie,{artifact:c},c.filename))}):null]},i.id))}),r?(0,y.jsx)("div",{style:T.error,children:r}):null,(0,y.jsxs)("form",{onSubmit:l,style:T.form,children:[(0,y.jsx)("input",{"aria-label":"Message",onChange:i=>s(i.target.value),placeholder:"Type a message\u2026",style:T.input,value:a}),(0,y.jsx)("button",{disabled:d||a.trim().length===0,style:T.button,type:"submit",children:"Send"})]})]})};var le=/\/+$/,O=e=>{let t=e.sessionId,a=e.baseUrl.replace(le,""),s=r=>`${a}/endpoint/${encodeURIComponent(e.token)}${r}`,n={"content-type":"application/json"},d=(r,o)=>({url:s(r),headers:n,body:JSON.stringify({message:o,...t?{sessionId:t}:{},...e.identity?{externalUserId:e.identity.externalUserId,userHmac:e.identity.userHmac}:{}})});return{sessionId:()=>t,getInfo:()=>h(s("/config"),{}),sendMessage:async r=>{let o=await j(d("/message",r));return t=o.sessionId,o},streamMessage:(r,o,l)=>N(d("/message/stream",r),o,i=>{t=i},l),subscribe:(r,o)=>{let l=o?.since??"0",i=!1,c,b=o?.intervalMs??3e3,u=async()=>{let g=t;if(g)try{let m=await h(s(`/messages?session=${encodeURIComponent(g)}&since=${encodeURIComponent(l)}`),{});for(let f of m.messages)r.onMessage(f);l=m.cursor}catch(m){r.onError?.(C(m))}i||(c=setTimeout(u,b))},p=()=>{i=!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:n,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 s=0;s<e.length;s+=32768)t+=String.fromCharCode(...e.subarray(s,s+32768));return btoa(t)}var V=e=>{let t=e.baseUrl.replace(ce,""),a=()=>typeof e.token=="function"?e.token():e.token,s=async()=>({"content-type":"application/json",authorization:`Bearer ${await a()}`}),n=async(r,o)=>{try{let l=await fetch(`${t}${P}${r}`,{method:o.method,headers:await s(),...o.body===void 0?{}:{body:JSON.stringify(o.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=`${o.method} ${r} \u2192 ${String(l.status)}`;try{let b=JSON.parse(i);b.message&&(c=b.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 s())).tables,listRows:async(r,o)=>await h(`${t}${P}${d(r)}/rows?limit=${String(o??100)}`,await s()),insertRow:async(r,o)=>{let{rowIds:l}=await n(`${d(r)}/rows`,{method:"POST",body:{rows:[o]}}),i=l[0];if(!i)throw C(new Error("The row was not created."));return i},patchRow:async(r,o,l)=>(await n(`${d(r)}/rows/${encodeURIComponent(o)}`,{method:"PATCH",body:l})).updated,deleteRow:async(r,o)=>(await n(`/${encodeURIComponent(r)}/${encodeURIComponent(o)}`,{method:"DELETE"})).deleted,listFiles:async()=>(await h(`${t}${P}/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 n("/files",{method:"POST",body:{filename:r.name,mime:r.type||"application/octet-stream",data:de(l),...o===void 0?{}:{message:o}}})},fileLink:async r=>await h(`${t}${P}/files/${encodeURIComponent(r)}/url`,await s()),deleteFile:async r=>(await n(`/files/${encodeURIComponent(r)}`,{method:"DELETE"})).deleted,listDocuments:async()=>(await h(`${t}${P}/documents`,await s())).documents,readDocument:async r=>(await h(`${t}${P}/documents/${encodeURIComponent(r)}`,await s())).document,saveDocument:async(r,o)=>await n(`/documents/${encodeURIComponent(r)}`,{method:"PATCH",body:o})}};var x=require("react");function L(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 Y=(e,t)=>{let[a,s]=(0,x.useState)([]),[n,d]=(0,x.useState)(""),[r,o]=(0,x.useState)(!1),[l,i]=(0,x.useState)(null),c=(0,x.useRef)(0),b=t?.pollMs??2e3;(0,x.useEffect)(()=>{let p=!0;return e.getInfo().then(g=>{p&&g.greeting&&s(m=>m.length===0?[{id:"greeting",cursor:"",author:"agent",text:g.greeting}]:m)}).catch(()=>{}),()=>{p=!1}},[e]),(0,x.useEffect)(()=>e.subscribe?.({onMessage:p=>s(g=>L(g,p)),onError:p=>i(p.error)},{intervalMs:b}),[e,b]);let u=(0,x.useCallback)(()=>{let p=n.trim();if(!p||r)return;d(""),i(null),o(!0),c.current+=1;let g={id:`pending-${c.current}`,cursor:"",author:"client",text:p,pending:!0};s(m=>[...m,g]),e.sendMessage(p).then(()=>o(!1)).catch(m=>{i(m instanceof Error?m.message:"send_failed"),o(!1)})},[n,r,e]);return{messages:a,input:n,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
@@ -108,10 +108,19 @@ type ApiTransportConfig = {
108
108
  /** End-user access token for the Authorization header. A string, or a getter so a
109
109
  * refreshed token is used per request. */
110
110
  token: string | (() => string | Promise<string>);
111
+ /**
112
+ * Which of the customer's projects this conversation is about.
113
+ *
114
+ * Omit for the general thread — the one running conversation with the company,
115
+ * and where everything that predates per-project threads still lives. The
116
+ * server checks the project belongs to this customer before it trusts it, so
117
+ * naming someone else's is a 404 rather than a way into their thread.
118
+ */
119
+ project?: string;
111
120
  };
112
121
  /** The Bearer-authed transport for the signed-in end-user PORTAL (`/api/v1/end-user/*`). Same
113
122
  * client surface as the anonymous widget transport — the token (not a path param) resolves the
114
- * customer and their one lifelong thread. The portal is buffered (no SSE) and one-thread-per-user,
123
+ * customer; an optional `project` picks which of their threads. The portal is buffered (no SSE) and one-thread-per-user,
115
124
  * so `sendMessage` returns just the reply and everything out-of-turn — the AI's turns, a human's
116
125
  * reply, an async artifact (video) — arrives via `subscribe`. */
117
126
  declare const createApiTransport: (config: ApiTransportConfig) => HolaTransport;
package/dist/index.d.ts CHANGED
@@ -108,10 +108,19 @@ type ApiTransportConfig = {
108
108
  /** End-user access token for the Authorization header. A string, or a getter so a
109
109
  * refreshed token is used per request. */
110
110
  token: string | (() => string | Promise<string>);
111
+ /**
112
+ * Which of the customer's projects this conversation is about.
113
+ *
114
+ * Omit for the general thread — the one running conversation with the company,
115
+ * and where everything that predates per-project threads still lives. The
116
+ * server checks the project belongs to this customer before it trusts it, so
117
+ * naming someone else's is a 404 rather than a way into their thread.
118
+ */
119
+ project?: string;
111
120
  };
112
121
  /** The Bearer-authed transport for the signed-in end-user PORTAL (`/api/v1/end-user/*`). Same
113
122
  * client surface as the anonymous widget transport — the token (not a path param) resolves the
114
- * customer and their one lifelong thread. The portal is buffered (no SSE) and one-thread-per-user,
123
+ * customer; an optional `project` picks which of their threads. The portal is buffered (no SSE) and one-thread-per-user,
115
124
  * so `sendMessage` returns just the reply and everything out-of-turn — the AI's turns, a human's
116
125
  * reply, an async artifact (video) — arrives via `subscribe`. */
117
126
  declare const createApiTransport: (config: ApiTransportConfig) => HolaTransport;
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},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(`
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,i=typeof t.error=="string"?t.error:"request_failed";return typeof t.retryable=="boolean"?{error:i,retryable:t.retryable}:{error:i}}return{error:"request_failed"}},J=e=>{let t="message",i=[];for(let s of e.split(`
3
+ `))s.startsWith(":")||(s.startsWith("event:")?t=s.slice(6).trim():s.startsWith("data:")&&i.push(s.slice(5).replace(z,"")));return i.length>0?{event:t,data:i.join(`
4
+ `)}:null},q=(e,t,i)=>{let s;try{s=JSON.parse(e.data)}catch{return}if(e.event==="session"){let a=s.sessionId;a&&(i(a),t.onSession?.(a));return}if(e.event==="turn_event"){t.onEvent?.(s);let a=E(s);a&&t.onText?.(a);let d=S(s);d&&t.onThinking?.(d);let r=$(s);r&&t.onTool?.(r);return}if(e.event==="chat_completed"){let a=s;i(a.sessionId),t.onComplete?.(a);return}e.event==="chat_error"&&t.onError?.(x(s))},b=async(e,t)=>{let i=await fetch(e,{headers:t});if(!i.ok)throw new Error(`hola: request failed (${i.status})`);return await i.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,i,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 d=a.body.getReader(),r=new TextDecoder,o="",l=()=>{let c=o.indexOf(`
5
5
 
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(`
6
+ `);for(;c!==-1;){let y=o.slice(0,c);o=o.slice(c+2);let u=J(y);u&&q(u,t,i),c=o.indexOf(`
7
7
 
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};
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,""),i=()=>typeof e.token=="function"?e.token():e.token,s=r=>e.project?`${r}project=${encodeURIComponent(e.project)}`:"",a=async()=>({"content-type":"application/json",authorization:`Bearer ${await i()}`}),d=async r=>{let o=await fetch(`${t}${C}/chat${s("?")}`,{method:"POST",headers:await a(),body:JSON.stringify({message:r})});if(!o.ok)throw new Error(`hola: message failed (${o.status})`);return{reply:(await o.json()).reply??"",sessionId:"",artifacts:[]}};return{sessionId:()=>"",getInfo:async()=>b(`${t}${C}/chat/info${s("?")}`,await a()),sendMessage:d,streamMessage:async(r,o)=>{try{let l=await d(r);o.onText?.(l.reply),o.onComplete?.(l)}catch(l){o.onError?.(x(l))}},subscribe:(r,o)=>{let l=o?.since??"0",n=!1,c,y=o?.intervalMs??3e3,u=async()=>{try{let g=await b(`${t}${C}/chat/thread?since=${encodeURIComponent(l)}${s("&")}`,await a());for(let m of g.messages)r.onMessage(m);l=g.cursor}catch(g){r.onError?.(x(g))}n||(c=setTimeout(u,y))},p=()=>{n=!0,c&&clearTimeout(c)};return o?.signal?.addEventListener("abort",p),c=setTimeout(u,0),p},requestHuman:async()=>{await fetch(`${t}${C}/chat/request-human${s("?")}`,{method:"POST",headers:await a(),body:"{}"})}}};import{useEffect as K,useState as V}from"react";var k=(e,t)=>{let[i,s]=V("");return K(()=>{if(!e){s("");return}let a=Uint8Array.from(atob(e),r=>r.charCodeAt(0)),d=URL.createObjectURL(new Blob([a],{type:t}));return s(d),()=>URL.revokeObjectURL(d)},[e,t]),i};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,i]=P([]),[s,a]=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&&i([{id:c(),role:"assistant",text:p.greeting}])}).catch(()=>{}),()=>{u=!1}},[e,c]);let y=W(()=>{let u=s.trim();if(!u||d)return;a(""),l(null),r(!0);let p=c(),g=c();i(f=>[...f,{id:p,role:"user",text:u},{id:g,role:"assistant",text:"",streaming:!0}]);let m=f=>{i(h=>h.map(R=>R.id===g?f(R):R))};e.streamMessage(u,{onText:f=>m(h=>({...h,text:h.text+f})),onComplete:f=>{m(h=>({...h,text:f.reply||h.text,artifacts:f.artifacts,streaming:!1})),r(!1)},onError:f=>{m(h=>({...h,streaming:!1})),l(f.error),r(!1)}}).catch(f=>{m(h=>({...h,streaming:!1})),l(f instanceof Error?f.message:"stream_failed"),r(!1)})},[s,d,e,c]);return{messages:t,input:s,setInput:a,send:y,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),i=e.url??t;return i?e.mimeType.startsWith("image/")?H("a",{href:i,rel:"noopener noreferrer",target:"_blank",children:H("img",{alt:e.filename,src:i,style:w.image})}):H("a",{download:e.filename,href:i,style:w.link,children:e.filename}):null},ne=()=>{let e=M(),{messages:t,input:i,setInput:s,send:a,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(),a()};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:i}),H("button",{disabled:d||i.trim().length===0,style:w.button,type:"submit",children:"Send"})]})]})};var ae=/\/+$/,D=e=>{let t=e.sessionId,i=e.baseUrl.replace(ae,""),s=r=>`${i}/endpoint/${encodeURIComponent(e.token)}${r}`,a={"content-type":"application/json"},d=(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:()=>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,y=o?.intervalMs??3e3,u=async()=>{let g=t;if(g)try{let m=await b(s(`/messages?session=${encodeURIComponent(g)}&since=${encodeURIComponent(l)}`),{});for(let f of m.messages)r.onMessage(f);l=m.cursor}catch(m){r.onError?.(x(m))}n||(c=setTimeout(u,y))},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:a,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,""),i=()=>typeof e.token=="function"?e.token():e.token,s=async()=>({"content-type":"application/json",authorization:`Bearer ${await i()}`}),a=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 y=JSON.parse(n);y.message&&(c=y.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 a(`${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 a(`${d(r)}/rows/${encodeURIComponent(o)}`,{method:"PATCH",body:l})).updated,deleteRow:async(r,o)=>(await a(`/${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 a("/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 a(`/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 a(`/documents/${encodeURIComponent(r)}`,{method:"PATCH",body:o})}};import{useCallback as pe,useEffect as j,useRef as ue,useState as I}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 me=(e,t)=>{let[i,s]=I([]),[a,d]=I(""),[r,o]=I(!1),[l,n]=I(null),c=ue(0),y=t?.pollMs??2e3;j(()=>{let p=!0;return e.getInfo().then(g=>{p&&g.greeting&&s(m=>m.length===0?[{id:"greeting",cursor:"",author:"agent",text:g.greeting}]:m)}).catch(()=>{}),()=>{p=!1}},[e]),j(()=>e.subscribe?.({onMessage:p=>s(g=>N(g,p)),onError:p=>n(p.error)},{intervalMs:y}),[e,y]);let u=pe(()=>{let p=a.trim();if(!p||r)return;d(""),n(null),o(!0),c.current+=1;let g={id:`pending-${c.current}`,cursor:"",author:"client",text:p,pending:!0};s(m=>[...m,g]),e.sendMessage(p).then(()=>o(!1)).catch(m=>{n(m instanceof Error?m.message:"send_failed"),o(!1)})},[a,r,e]);return{messages:i,input:a,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,N 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.2",
3
+ "version": "0.2.0-beta.3",
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",