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