eve
Version:
Filesystem-first framework for durable backend AI agents that run anywhere.
5 lines • 13.6 kB
JavaScript
import{At as e,It as t,Nt as n,X as r,Y as i,at as a,q as o,wt as s,zt as c}from"../../_chunks/node/dist-DYDVZ-FS.js";import{a as ee,d as l,f as te,i as u,p as ne}from"../../_chunks/node/dist-iEFkK9qw.js";import{n as re,r as ie,t as d}from"../../_chunks/node/chunk-PFJ2G64A-B79fSABi.js";import{c as f,i as p,l as m,o as ae,r as oe,s as h,u as g}from"../../_chunks/node/chunk-KBOOTKHF-DJqFk2r1.js";import{a as _,c as v,d as y,f as b,i as x,l as S,n as C,o as w,r as T,s as E}from"../../_chunks/node/chunk-TREVQR3E-CLsTAn-O.js";import{createHash as se}from"crypto";var ce=`https://content.twilio.com`,le=50,ue=20,de=200,fe=/^twilio\//,D=new Map;function pe(e,t,n){return`${e}:${t}:${A(n)}`}function O(e,t){if(D.delete(e),D.set(e,t),D.size>de){let e=D.keys().next().value;e!==void 0&&D.delete(e)}}function k(e){return e.contentApiUrl??e.apiUrl??e.apiBaseUrl??ce}function A(e){let{language:t,types:n,variables:r}=e;return se(`sha256`).update(JSON.stringify({language:t,types:n,variables:r??null})).digest(`hex`)}function j(e){return`chat_sdk_${Object.keys(e.types).find(e=>e.startsWith(`twilio/`))?.replace(fe,``)??`text`}_${A(e).slice(0,16)}`}async function M(e){let t=pe(await m(e.credentials?.accountSid,`TWILIO_ACCOUNT_SID`),k(e),e.contentBody),n=D.get(t);if(n)return{friendly_name:j(e.contentBody),sid:n};let r=j(e.contentBody),i=await I(e,r);if(i?.sid)return O(t,i.sid),i;let a={...e.contentBody,friendly_name:r};try{let n=await N({...e,contentBody:a});return O(t,n.sid),n}catch(n){if(!F(n))throw n;let i=await I(e,r);if(!i?.sid)throw n;return O(t,i.sid),i}}async function N(e){let t=await m(e.credentials?.accountSid,`TWILIO_ACCOUNT_SID`),n=await m(e.credentials?.authToken,`TWILIO_AUTH_TOKEN`),r=new URL(`/v1/Content`,k(e)),i=await(e.fetch??fetch)(r,{body:JSON.stringify(e.contentBody),headers:{authorization:`Basic ${p(`${t}:${n}`)}`,"content-type":`application/json`},method:`POST`}),a=await i.text(),o;try{o=JSON.parse(a)}catch{o=a}if(!i.ok)throw new P(`Content API returned HTTP ${i.status}: ${typeof o==`string`?o:JSON.stringify(o)}`,i.status,o);return o}var P=class extends Error{status;body;constructor(e,t,n){super(e),this.name=`TwilioContentApiError`,this.status=t,this.body=n}};function F(e){if(!(e instanceof P))return!1;if(e.status===409)return!0;let t=typeof e.body==`object`&&e.body!==null&&`message`in e.body&&typeof e.body.message==`string`?e.body.message.toLowerCase():e.message.toLowerCase();return t.includes(`friendly`)&&t.includes(`exist`)}async function I(e,t){let n=await m(e.credentials?.accountSid,`TWILIO_ACCOUNT_SID`),r=await m(e.credentials?.authToken,`TWILIO_AUTH_TOKEN`),i=new URL(`/v1/Content`,k(e));i.searchParams.set(`PageSize`,String(le));let a=e.fetch??fetch,o=`Basic ${p(`${n}:${r}`)}`,s=0;for(;i&&s<ue;){s+=1;let e=await a(i,{headers:{authorization:o},method:`GET`}),n=await e.text(),r;try{r=JSON.parse(n)}catch{return null}if(!e.ok)return null;let c=r.contents?.find(e=>e.friendly_name===t);if(c)return c;i=r.meta?.next_page_url??null}return null}var L=11,R=25,z=200,B=2,V=`Message from bot`;function H(e){return ee(e).replace(/\*/g,``)}function U(e){let t=G(e.children);if(!t)return{text:H(e),type:`text`};let n=_e(t),r=ve(t);return n.length>0?e.imageUrl||e.title||r.length>0?he(e,n,r):me(e,n):r.length>0?ge(e,r):{text:H(e),type:`text`}}function me(e,t){return{type:`content`,contentBody:{language:`en`,types:{"twilio/quick-reply":{body:K(e)||e.title||`Choose an option`,actions:t.slice(0,L).map(e=>({id:_(e.id,e.value),title:J(e.label,R),type:`quick_reply`}))},"twilio/text":{body:W(e)}}}}}function he(e,t,n){let r=[...t.map(e=>({id:_(e.id,e.value),title:J(e.label,R),type:`quick_reply`})),...n.map(e=>({title:J(e.label,R),type:`URL`,url:e.url}))].slice(0,L),i={title:J(e.title??`Menu`,z),body:K(e)||e.subtitle||` `,actions:r};return e.imageUrl&&(i.media=[e.imageUrl]),{type:`content`,contentBody:{language:`en`,types:{"twilio/card":i,"twilio/text":{body:W(e)}}}}}function ge(e,t){let n=t.slice(0,B),r=t.slice(B);return{type:`content`,contentBody:{language:`en`,types:{"twilio/call-to-action":{body:[K(e)||e.title||`See link`,...r.map(e=>`${e.label}: ${e.url}`)].join(`
`),actions:n.map(e=>({title:J(e.label,R),type:`URL`,url:e.url}))},"twilio/text":{body:W(e)}}}}}function W(e){return H(e)||V}function G(e){for(let t of e){if(t.type===`actions`)return t;if(t.type===`section`){let e=G(t.children);if(e)return e}}return null}function _e(e){let t=[];for(let n of e.children)n.type===`button`&&n.id&&t.push(n);return t.slice(0,L)}function ve(e){let t=[];for(let n of e.children)n.type===`link-button`&&t.push(n);return t}function K(e){let t=[];e.subtitle&&t.push(e.subtitle);for(let n of e.children){if(n.type===`actions`)continue;let e=q(n);e&&t.push(e)}return t.join(`
`)}function q(e){switch(e.type){case`text`:return e.content;case`fields`:return e.children.map(e=>`${e.label}: ${e.value}`).join(`
`);case`actions`:return null;case`section`:return e.children.map(q).filter(Boolean).join(`
`);default:return null}}function J(e,t){return e.length<=t?e:`${e.slice(0,t-1)}\u2026`}var Y=class extends a{toAst(t){return e(t)}fromAst(e){let r=c(structuredClone(e),e=>s(e)?{type:`code`,value:t(e)}:e);return n(r).trim()}renderPostable(e){return typeof e==`string`?e:`raw`in e?e.raw:`markdown`in e?this.fromMarkdown(e.markdown):`ast`in e?this.fromAst(e.ast):super.renderPostable(e)}};function ye(e){return`twilio:${encodeURIComponent(e.sender)}:${encodeURIComponent(e.recipient)}`}function X(e){let[t,n,r]=e.split(`:`);if(t!==`twilio`||!n||!r)throw new u(`twilio`,`Invalid Twilio thread ID: ${e}`);return{recipient:decodeURIComponent(r),sender:decodeURIComponent(n)}}function be(e){return X(e),e}function Z(){return new Response(`<Response></Response>`,{headers:{"content-type":`application/xml`},status:200})}function Q(e){return e.startsWith(`MG`)?{messagingServiceSid:e}:{from:e}}function xe(e){return e?.startsWith(`image/`)?`image`:e?.startsWith(`video/`)?`video`:e?.startsWith(`audio/`)?`audio`:`file`}var $=class{name=`twilio`;lockScope=`thread`;persistThreadHistory=!0;userName;chat=null;accountSid;apiUrl;authToken;contentApiUrl;fetch;formatConverter=new Y;logger;messagingServiceSid;phoneNumber;rcsSenderId;statusCallbackUrl;webhookUrl;webhookVerifier;constructor(e={}){this.accountSid=e.accountSid,this.apiUrl=e.apiUrl,this.authToken=e.authToken,this.contentApiUrl=e.contentApiUrl,this.fetch=e.fetch,this.logger=e.logger??new o(`info`).child(`twilio`),this.messagingServiceSid=e.messagingServiceSid??process.env.TWILIO_MESSAGING_SERVICE_SID,this.phoneNumber=e.phoneNumber??process.env.TWILIO_PHONE_NUMBER,this.rcsSenderId=e.rcsSenderId??process.env.TWILIO_RCS_SENDER_ID,this.statusCallbackUrl=e.statusCallbackUrl,this.userName=e.userName??`bot`,this.webhookUrl=e.webhookUrl,this.webhookVerifier=e.webhookVerifier}async initialize(e){this.chat=e,this.logger.info(`Twilio adapter initialized`,{messagingServiceSid:this.messagingServiceSid,phoneNumber:this.phoneNumber})}async handleWebhook(e,t){let n;try{n=await y(e,{authToken:this.authToken,webhookUrl:this.webhookUrl,webhookVerifier:this.webhookVerifier})}catch(e){if(e instanceof T)return new Response(`Invalid signature`,{status:401});if(e instanceof C)return new Response(`Invalid webhook`,{status:400});throw e}if(!this.chat)return Z();if(n.kind===`action`)return this.handleButtonAction(n,t),Z();if(n.kind===`text`){let e=this.encodeThreadId({recipient:n.from,sender:this.inboundThreadSender(n)}),r=this.parseTwilioTextPayload(n,e);return this.chat.processMessage(this,e,r,t),Z()}return n.kind===`status`&&n.eventType&&this.logger.debug(`Twilio status event`,{eventType:n.eventType,messageSid:n.messageSid,channelPrefix:n.channelPrefix}),Z()}handleButtonAction(e,t){if(!this.chat)return;let n=this.encodeThreadId({recipient:e.from,sender:this.inboundThreadSender(e)}),{actionId:r,value:i}=x(e.buttonPayload);this.chat.processAction({adapter:this,actionId:r,value:i??e.buttonText,messageId:e.messageSid??`action:${Date.now()}`,threadId:n,user:{userId:e.from,userName:e.from,fullName:e.from,isBot:!1,isMe:!1},raw:e},t)}async postMessage(e,t){let n=this.decodeThreadId(e),r=l(t);if(r&&v(n.sender)){let e=U(r);if(e.type===`content`){let t;try{t=(await M({...this.apiOptions(),contentApiUrl:this.contentApiUrl,contentBody:e.contentBody})).sid}catch(e){this.logger.warn(`RCS content template resolution failed, falling back to text`,{error:String(e)})}if(t){let e=await g({...this.apiOptions(),contentSid:t,statusCallbackUrl:this.statusCallbackUrl,to:n.recipient,...Q(n.sender)});return{id:e.sid,raw:e,threadId:this.threadIdForResource(e,n)}}}}let i=this.renderPostableText(t),a=this.mediaUrls(t);if(!i&&a.length===0)throw new u(`twilio`,`Message text cannot be empty`);let o=await g({...this.apiOptions(),body:i||a.length===0?ie(i):void 0,mediaUrl:a,statusCallbackUrl:this.statusCallbackUrl,to:n.recipient,...Q(n.sender)});return{id:o.sid,raw:o,threadId:this.threadIdForResource(o,n)}}async editMessage(){throw new r(`Twilio does not support editing sent messages`,`editMessage`)}async deleteMessage(e,t){await oe({...this.apiOptions(),messageSid:t})}async addReaction(){throw new r(`Twilio does not support message reactions`,`addReaction`)}async removeReaction(){throw new r(`Twilio does not support message reactions`,`removeReaction`)}async startTyping(){}parseMessage(e){if(we(e)){if(e.kind===`action`)throw new u(`twilio`,`Cannot parse action webhook as message`);if(e.kind!==`text`)throw new u(`twilio`,`Cannot parse unsupported webhook`);return this.parseTwilioTextPayload(e,this.encodeThreadId({recipient:e.from,sender:this.inboundThreadSender(e)}))}return this.parseTwilioResource(e,void 0)}async fetchMessage(e,t){let n=this.decodeThreadId(e);try{let e=await h({...this.apiOptions(),messageSid:t});return this.parseTwilioResource(e,n)}catch{return null}}async fetchMessages(e,t={}){let n=this.decodeThreadId(e),r=t.limit??50,[i,a]=await Promise.all([f({...this.apiOptions(),from:n.sender,limit:r,to:n.recipient}),f({...this.apiOptions(),from:n.recipient,limit:r,to:n.sender})]);return{messages:[...i,...a].map(e=>this.parseTwilioResource(e,n)).sort((e,t)=>e.metadata.dateSent.getTime()-t.metadata.dateSent.getTime()).slice(-r)}}async fetchThread(e){let t=this.decodeThreadId(e);return{channelId:this.channelIdFromThreadId(e),channelName:t.sender,id:e,isDM:!0,metadata:{...t}}}async getUser(e){return{fullName:e,isBot:!1,userId:e,userName:e}}async openDM(e){return this.encodeThreadId({recipient:e,sender:this.defaultSender()})}isDM(e){return e.startsWith(`twilio:`)}channelIdFromThreadId(e){return be(e)}encodeThreadId(e){return ye(e)}decodeThreadId(e){return X(e)}renderFormatted(e){return this.formatConverter.fromAst(e)}rehydrateAttachment(e){let t=e.fetchMetadata?.twilioMediaUrl??e.url;return t&&Ce.test(t)?this.twilioAttachment({contentType:e.mimeType,url:t}):e}parseTwilioTextPayload(e,t){let n=e.media.map(e=>this.twilioAttachment(e));if(e.latitude&&e.longitude){let t={latitude:e.latitude,longitude:e.longitude};e.address&&(t.address=e.address),e.label&&(t.label=e.label),n.push({fetchMetadata:t,type:`file`,url:`geo:${e.latitude},${e.longitude}`})}return new i({attachments:n,author:this.author(e.from,!1),formatted:this.formatConverter.toAst(e.body),id:e.messageSid??`twilio:${Date.now()}`,metadata:{dateSent:new Date,edited:!1},raw:e,text:e.body,threadId:t})}parseTwilioResource(e,t){let n=e.direction?.startsWith(`outbound`)??!1,r=e.from??e.messaging_service_sid??(n?t?.sender:t?.recipient),a=e.to??(n?t?.recipient:t?.sender);if(!(r&&a))throw new u(`twilio`,`Twilio message is missing routing`);let o=e.body??``,s=n?{recipient:t?.recipient??a,sender:t?.sender??r}:{recipient:r,sender:a};return new i({attachments:[],author:this.author(n?s.sender:r,n),formatted:this.formatConverter.toAst(o),id:e.sid,metadata:{dateSent:Te(e.date_sent??e.date_created),edited:!1},raw:e,text:o,threadId:this.encodeThreadId(s)})}renderPostableText(e){let t=l(e),n=t?H(t)||V:this.formatConverter.renderPostable(e);return re(n,{limit:d}).text}mediaUrls(e){if(te(e).length>0)throw new u(`twilio`,`Twilio adapter supports media attachments by public URL only`);let t=ne(e),n=[];for(let e of t){if(typeof e.url!=`string`||e.url.length===0)throw new u(`twilio`,`Twilio adapter supports media attachments by public URL only`);n.push(e.url)}return n}twilioAttachment(e){return{fetchData:async()=>Buffer.from(await ae({...this.apiOptions(),url:e.url})),fetchMetadata:{twilioMediaUrl:e.url},mimeType:e.contentType,type:xe(e.contentType),url:e.url}}apiOptions(){return{apiUrl:this.apiUrl,credentials:{accountSid:this.accountSid,authToken:this.authToken},fetch:this.fetch}}defaultSender(){let e=this.phoneNumber??this.messagingServiceSid??(this.rcsSenderId?S(this.rcsSenderId):void 0);if(!e)throw new u(`twilio`,`phoneNumber, messagingServiceSid, or rcsSenderId is required`);return e}inboundThreadSender(e){return b({channelMetadata:e.channelMetadata,messagingServiceSid:e.messagingServiceSid,messagingServiceSidConfig:this.messagingServiceSid,rcsSenderIdConfig:this.rcsSenderId,to:e.to})}author(e,t){return{fullName:e,isBot:t,isMe:t,userId:e,userName:e}}threadIdForResource(e,t){return this.parseTwilioResource(e,t).threadId}};function Se(e={}){return new $(e)}var Ce=/^https?:\/\//;function we(e){return`kind`in e}function Te(e){let t=e?new Date(e):new Date;return Number.isNaN(t.getTime())?new Date:t}export{$ as TwilioAdapter,Y as TwilioFormatConverter,U as cardToTwilioRcs,H as cardToTwilioText,Se as createTwilioAdapter,x as decodeTwilioCallbackData,_ as encodeTwilioCallbackData,w as inferTwilioChannel,E as isRcsAddress,v as isRcsCapableSender,S as normalizeRcsSenderId,b as resolveInboundThreadSender};