birdcash-chat-sdk-alpha 1.0.4 → 1.0.8

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/main.cjs.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});const e="https://chat-api2-3rnt.onrender.com",t="web_link",s="ai_choice_prompt",r="official_account_tweet";async function a(t){var s;const{clientId:r,clientSecret:a}=t;if(!r||!a)throw new Error("getAccessToken: clientId and clientSecret are required");const i=e.replace(/\/$/,""),o=null!==(s=t.scope)&&void 0!==s?s:"chat:write uploads:write";if("undefined"==typeof fetch)throw new Error("getAccessToken: global fetch is not available");const n=await fetch(`${i}/v1/oauth/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"client_credentials",client_id:r,client_secret:a,scope:o})});if(!n.ok)throw new Error(`Token request failed: ${n.status} ${n.statusText}`);return await n.json()}var i;function o(e){return{elemType:exports.ElemType.Text,priority:0,textElem:{text:e.trim()}}}function n(e){return{elemType:exports.ElemType.Image,priority:0,imageElem:{upload_ids:e}}}function l(e){return{elemType:exports.ElemType.File,priority:0,fileElem:{upload_ids:e}}}function u(e,t=0){return{elemType:exports.ElemType.Sound,priority:0,soundElem:{uploadID:e,duration:t}}}function c(e,t){return{elemType:exports.ElemType.Sticker,priority:0,stickerElem:{packID:e,stickerID:t}}}function d(e){return{elemType:exports.ElemType.Custom,priority:0,customElem:{data:e}}}function h(e){return{elemType:exports.ElemType.MiniApp,priority:0,miniAppElem:e}}function g(e){const t=new Uint8Array(e.byteLength);return t.set(e),t}function p(e){const t=(new TextEncoder).encode(e);let s="";for(const e of t)s+=String.fromCharCode(e);return btoa(s)}function m(e,t=10){if(e.length<=t)return[e];const s=[];let r="";for(const a of e.split(" "))r.length+a.length+1>t&&r.length>0?(s.push(r.trim()+" "),r=a):r+=(r?" ":"")+a;return r&&s.push(r.trim()),s.length>0?s:[e]}exports.ElemType=void 0,(i=exports.ElemType||(exports.ElemType={}))[i.None=0]="None",i[i.Text=1]="Text",i[i.Image=2]="Image",i[i.Sound=3]="Sound",i[i.Video=4]="Video",i[i.File=5]="File",i[i.Sticker=6]="Sticker",i[i.GroupTips=7]="GroupTips",i[i.Merger=8]="Merger",i[i.Custom=9]="Custom",i[i.Location=10]="Location",i[i.GroupAnnouncement=11]="GroupAnnouncement",i[i.Quote=12]="Quote",i[i.InputStatus=14]="InputStatus",i[i.TypingStatus=15]="TypingStatus",i[i.MiniApp=16]="MiniApp",i[i.Order=17]="Order",i[i.Transfer=18]="Transfer";class f{constructor(t){var s,r;if(!(null==t?void 0:t.token))throw new Error("ChatClient: token is required");this.token=t.token,this.baseUrl=(null!==(s=t.baseUrl)&&void 0!==s?s:e).replace(/\/$/,""),this.logger=t.logger;const a=null!==(r=t.fetch)&&void 0!==r?r:"undefined"!=typeof fetch?fetch:void 0;if(!a)throw new Error("ChatClient: no fetch implementation available; pass `fetch` in options");this.fetchImpl=a.bind(globalThis)}static async fromCredentials(e){const{access_token:t}=await a({clientId:e.clientId,clientSecret:e.clientSecret,scope:e.scope});return new f({token:t,baseUrl:e.baseUrl,logger:e.logger,fetch:e.fetch})}get authHeaders(){return{"Content-Type":"application/json",Authorization:`Bearer ${this.token}`}}replyUrl(e){return`${this.baseUrl}/v1/chat/message/${e}/reply`}newMsgID(){return globalThis.crypto.randomUUID()}async postElements(e,t,s="POST"){return await this.fetchImpl(this.replyUrl(e),{method:s,headers:this.authHeaders,body:JSON.stringify(t)})}async uploadImage(e,t,s="image/png"){var r;const a=new FormData;a.append("file",new Blob([g(e)],{type:s}),t);const i=await this.fetchImpl(`${this.baseUrl}/v1/upload/image`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`},body:a}),o=await i.json();if(!i.ok)throw new Error(`uploadImage failed: ${i.status} ${JSON.stringify(o)}`);if(!o.upload_id)throw new Error(`uploadImage: missing upload_id: ${JSON.stringify(o)}`);return{upload_id:o.upload_id,url:null!==(r=o.url)&&void 0!==r?r:""}}async uploadFile(e,t,s="application/octet-stream"){var r;const a=new FormData;a.append("file",new Blob([g(e)],{type:s}),t);const i=await this.fetchImpl(`${this.baseUrl}/v1/upload/file`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`},body:a}),o=await i.json();if(!i.ok)throw new Error(`uploadFile failed: ${i.status} ${JSON.stringify(o)}`);if(!o.upload_id)throw new Error(`uploadFile: missing upload_id: ${JSON.stringify(o)}`);return{upload_id:o.upload_id,url:null!==(r=o.url)&&void 0!==r?r:""}}async sendMessage(e,t,s){var r;let a=Array.isArray(t)?t.map((e=>e.trim())).filter(Boolean).map(o):[o(t)];if(0===a.length)return;s&&(a=a.map((e=>({...e,msgID:s}))));const i=await this.postElements(e,a),n=await i.text();if(null===(r=this.logger)||void 0===r||r.log("[chat-sdk] message sent",{status:i.status,elements:a.length}),!i.ok)throw new Error(`sendMessage failed: ${i.status} ${n}`)}async sendImageMessage(e,t){var s;if(!(null==t?void 0:t.length))return;const r=await this.postElements(e,[n(t)]),a=await r.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] image message sent",{status:r.status}),!r.ok)throw new Error(`sendImageMessage failed: ${r.status} ${a}`)}async sendFileMessage(e,t){var s;if(!(null==t?void 0:t.length))return;const r=await this.postElements(e,[l(t)]),a=await r.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] file message sent",{status:r.status}),!r.ok)throw new Error(`sendFileMessage failed: ${r.status} ${a}`)}async sendSoundMessage(e,t,s=0){var r;if(!(null==t?void 0:t.trim()))return;const a=await this.postElements(e,[u(t,s)]),i=await a.text();if(null===(r=this.logger)||void 0===r||r.log("[chat-sdk] sound message sent",{status:a.status}),!a.ok)throw new Error(`sendSoundMessage failed: ${a.status} ${i.slice(0,500)}`)}async sendStickerMessage(e,t,s,r){var a;if(!(null==t?void 0:t.trim())||!(null==s?void 0:s.trim()))return;const i=c(t,s),o=await this.postElements(e,[r?{...i,msgID:r}:i]),n=await o.text();if(null===(a=this.logger)||void 0===a||a.log("[chat-sdk] sticker message sent",{status:o.status}),!o.ok)throw new Error(`sendStickerMessage failed: ${o.status} ${n}`)}async editTextMessage(e,t){var s;const r=await this.postElements(e,[{msgID:e,...o(t)}]),a=await r.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] text message edited",{status:r.status}),!r.ok)throw new Error(`editTextMessage failed: ${r.status} ${a.slice(0,500)}`)}async editStickerMessage(e,t,s){var r;const a=await this.postElements(e,[{msgID:e,...c(t,s)}]),i=await a.text();if(null===(r=this.logger)||void 0===r||r.log("[chat-sdk] sticker message edited",{status:a.status}),!a.ok)throw new Error(`editStickerMessage failed: ${a.status} ${i.slice(0,500)}`)}async editImageMessage(e,t){var s;const r=await this.postElements(e,[{msgID:e,...n(t)}]),a=await r.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] image message edited",{status:r.status}),!r.ok)throw new Error(`editImageMessage failed: ${r.status} ${a.slice(0,500)}`)}async deleteMessage(e){var t;const s=await this.fetchImpl(`${this.baseUrl}/v1/chat/message/${e}`,{method:"DELETE",headers:this.authHeaders});if(null===(t=this.logger)||void 0===t||t.log("[chat-sdk] message deleted",{status:s.status}),!s.ok){const e=await s.text();throw new Error(`deleteMessage failed: ${s.status} ${e.slice(0,500)}`)}}async sendTypingStatus(e,t){var s,r;const a={businessID:"user_typing_status",typingStatus:t?1:0,version:1,userAction:14,actionParam:t?"EIMAMSG_InputStatus_Ing":"EIMAMSG_InputStatus_End"};try{await this.postElements(e,[d(p(JSON.stringify(a)))])}catch(e){null===(s=this.logger)||void 0===s||s.error("[chat-sdk] typing status failed",null!==(r=null==e?void 0:e.message)&&void 0!==r?r:String(e))}}async sendStreamingChunk(e,t,s,r){const a={businessID:"chatbotPlugin",src:0,chunks:t,isFinished:s,TMessageCell_Name:"ChatbotMessageCell_Minimalist",TMessageCell_Data_Name:"ChatbotMessageCellData"},i={msgID:e,...d(p(JSON.stringify(a)))},o=await this.postElements(e,[i],r?"POST":"PATCH");if(!o.ok)throw new Error(`sendStreamingChunk failed: ${o.statusText}`);await o.text()}async sendMiniAppMessage(e,t){var s;const r=await this.postElements(e,[h(t)]),a=await r.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] miniapp card sent",{status:r.status}),!r.ok)throw new Error(`sendMiniAppMessage failed: ${r.status} ${a}`)}async sendWebLinkMessage(e,s){var r;const a={businessID:t,url:s},i=await this.postElements(e,[d(p(JSON.stringify(a)))]),o=await i.text();if(null===(r=this.logger)||void 0===r||r.log("[chat-sdk] web link sent",{status:i.status}),!i.ok)throw new Error(`sendWebLinkMessage failed: ${i.status} ${o.slice(0,500)}`)}async sendChoicesMessage(e,t){var r,a,i;const o=this.newMsgID(),n={businessID:s,promptId:null!==(r=t.promptId)&&void 0!==r?r:this.newMsgID(),prompt:t.prompt,selectionMode:null!==(a=t.selectionMode)&&void 0!==a?a:"single",choices:t.choices},l=await this.postElements(e,[{msgID:o,...d(p(JSON.stringify(n)))}]),u=await l.text();if(null===(i=this.logger)||void 0===i||i.log("[chat-sdk] choices message sent",{status:l.status}),!l.ok)throw new Error(`sendChoicesMessage failed: ${l.status} ${u.slice(0,500)}`);return o}async sendOfficialAccountTweetMessage(e,t){var s;const a=this.newMsgID(),i={businessID:r,...t},o=await this.postElements(e,[{msgID:a,...d(p(JSON.stringify(i)))}]),n=await o.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] official account tweet sent",{status:o.status}),!o.ok)throw new Error(`sendOfficialAccountTweetMessage failed: ${o.status} ${n.slice(0,500)}`);return a}async streamMessage(e,t,s=10){const r=m(t,s),a=[];for(let t=0;t<r.length;t++)a.push(r[t]),await this.sendStreamingChunk(e,a,t===r.length-1,0===t)}}f.ElemType=exports.ElemType,exports.AI_CHOICE_PROMPT_BUSINESS_ID=s,exports.ChatClient=f,exports.DEFAULT_BASE_URL=e,exports.OFFICIAL_ACCOUNT_TWEET_BUSINESS_ID=r,exports.WEB_LINK_BUSINESS_ID=t,exports.arrayBufferToBase64=function(e){let t="";const s=new Uint8Array(e),r=s.byteLength;for(let e=0;e<r;e++)t+=String.fromCharCode(s[e]);return btoa(t)},exports.base64ToArrayBuffer=function(e){const t=atob(e),s=t.length,r=new Uint8Array(s);for(let e=0;e<s;e++)r[e]=t.charCodeAt(e);return r.buffer},exports.customElem=d,exports.fileElem=l,exports.getAccessToken=a,exports.imageElem=n,exports.miniAppElem=h,exports.soundElem=u,exports.splitIntoChunks=m,exports.stickerElem=c,exports.textElem=o,exports.toBase64=p,exports.verifyWebhookSignature=async function(e,t,s,r={}){const{toleranceSec:a=300,logger:i}=r,o=e.headers.get("X-Webhook-Signature");if(!o)return null==i||i.error("[chat-sdk] webhook missing X-Webhook-Signature header"),{valid:!1,error:"Missing X-Webhook-Signature header"};const n=e.headers.get("X-Webhook-Timestamp");if(!n)return null==i||i.error("[chat-sdk] webhook missing X-Webhook-Timestamp header"),{valid:!1,error:"Missing X-Webhook-Timestamp header"};const l=o.startsWith("sha256=")?o.slice(7):o,u=await async function(e,t){const s=new TextEncoder,r=await crypto.subtle.importKey("raw",s.encode(e),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),a=await crypto.subtle.sign("HMAC",r,s.encode(t));return[...new Uint8Array(a)].map((e=>e.toString(16).padStart(2,"0"))).join("")}(t,`${n}.${s}`);if(!function(e,t){if(e.length!==t.length)return!1;let s=0;for(let r=0;r<e.length;r++)s|=e.charCodeAt(r)^t.charCodeAt(r);return 0===s}(l,u))return null==i||i.error("[chat-sdk] webhook invalid signature"),{valid:!1,error:"Invalid signature"};const c=parseInt(n,10),d=Math.floor(Date.now()/1e3);return!Number.isFinite(c)||Math.abs(d-c)>a?(null==i||i.error("[chat-sdk] webhook timestamp out of range"),{valid:!1,error:"Request timestamp too old or too far in future"}):(null==i||i.log("[chat-sdk] webhook signature valid"),{valid:!0})};
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});const e="https://chat-api2-3rnt.onrender.com",t="web_link",s="ai_choice_prompt",a="official_account_tweet";async function r(t){var s;const{clientId:a,clientSecret:r}=t;if(!a||!r)throw new Error("getAccessToken: clientId and clientSecret are required");const o=e.replace(/\/$/,""),n=null!==(s=t.scope)&&void 0!==s?s:"chat:write uploads:write";if("undefined"==typeof fetch)throw new Error("getAccessToken: global fetch is not available");const i=await fetch(`${o}/v1/oauth/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"client_credentials",client_id:a,client_secret:r,scope:n})});if(!i.ok)throw new Error(`Token request failed: ${i.status} ${i.statusText}`);return await i.json()}var o;function n(e){return{elemType:exports.ElemType.Text,priority:0,textElem:{text:e.trim()}}}function i(e){return{elemType:exports.ElemType.Image,priority:0,imageElem:{upload_ids:e}}}function l(e){return{elemType:exports.ElemType.File,priority:0,fileElem:{upload_ids:e}}}function u(e,t=0){return{elemType:exports.ElemType.Sound,priority:0,soundElem:{uploadID:e,duration:t}}}function c(e,t){return{elemType:exports.ElemType.Sticker,priority:0,stickerElem:{packID:e,stickerID:t}}}function d(e,t,s){const a={...n(e),cloudCustomData:{messageReply:t}};return s?{msgID:s,...a}:a}function g(e){return{elemType:exports.ElemType.Custom,priority:0,customElem:{data:e}}}function h(e){return{elemType:exports.ElemType.MiniApp,priority:0,miniAppElem:e}}function p(e){const t=new Uint8Array(e.byteLength);return t.set(e),t}function m(e){const t=(new TextEncoder).encode(e);let s="";for(const e of t)s+=String.fromCharCode(e);return btoa(s)}function f(e,t=10){if(e.length<=t)return[e];const s=[];let a="";for(const r of e.split(" "))a.length+r.length+1>t&&a.length>0?(s.push(a.trim()+" "),a=r):a+=(a?" ":"")+r;return a&&s.push(a.trim()),s.length>0?s:[e]}exports.ElemType=void 0,(o=exports.ElemType||(exports.ElemType={}))[o.None=0]="None",o[o.Text=1]="Text",o[o.Image=2]="Image",o[o.Sound=3]="Sound",o[o.Video=4]="Video",o[o.File=5]="File",o[o.Sticker=6]="Sticker",o[o.GroupTips=7]="GroupTips",o[o.Merger=8]="Merger",o[o.Custom=9]="Custom",o[o.Location=10]="Location",o[o.GroupAnnouncement=11]="GroupAnnouncement",o[o.Quote=12]="Quote",o[o.InputStatus=14]="InputStatus",o[o.TypingStatus=15]="TypingStatus",o[o.MiniApp=16]="MiniApp",o[o.Order=17]="Order",o[o.Transfer=18]="Transfer";class w{constructor(t){var s,a;if(!(null==t?void 0:t.token))throw new Error("ChatClient: token is required");this.token=t.token,this.baseUrl=(null!==(s=t.baseUrl)&&void 0!==s?s:e).replace(/\/$/,""),this.logger=t.logger;const r=null!==(a=t.fetch)&&void 0!==a?a:"undefined"!=typeof fetch?fetch:void 0;if(!r)throw new Error("ChatClient: no fetch implementation available; pass `fetch` in options");this.fetchImpl=r.bind(globalThis)}static async fromCredentials(e){const{access_token:t}=await r({clientId:e.clientId,clientSecret:e.clientSecret,scope:e.scope});return new w({token:t,baseUrl:e.baseUrl,logger:e.logger,fetch:e.fetch})}get authHeaders(){return{"Content-Type":"application/json",Authorization:`Bearer ${this.token}`}}replyUrl(e){return`${this.baseUrl}/v1/chat/message/${e}/reply`}newMsgID(){return globalThis.crypto.randomUUID()}async postElements(e,t,s="POST"){return await this.fetchImpl(this.replyUrl(e),{method:s,headers:this.authHeaders,body:JSON.stringify(t)})}async uploadImage(e,t,s="image/png"){var a;const r=new FormData;r.append("file",new Blob([p(e)],{type:s}),t);const o=await this.fetchImpl(`${this.baseUrl}/v1/upload/image`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`},body:r}),n=await o.json();if(!o.ok)throw new Error(`uploadImage failed: ${o.status} ${JSON.stringify(n)}`);if(!n.upload_id)throw new Error(`uploadImage: missing upload_id: ${JSON.stringify(n)}`);return{upload_id:n.upload_id,url:null!==(a=n.url)&&void 0!==a?a:""}}async uploadFile(e,t,s="application/octet-stream"){var a;const r=new FormData;r.append("file",new Blob([p(e)],{type:s}),t);const o=await this.fetchImpl(`${this.baseUrl}/v1/upload/file`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`},body:r}),n=await o.json();if(!o.ok)throw new Error(`uploadFile failed: ${o.status} ${JSON.stringify(n)}`);if(!n.upload_id)throw new Error(`uploadFile: missing upload_id: ${JSON.stringify(n)}`);return{upload_id:n.upload_id,url:null!==(a=n.url)&&void 0!==a?a:""}}async sendMessage(e,t,s){var a;let r=Array.isArray(t)?t.map((e=>e.trim())).filter(Boolean).map(n):[n(t)];if(0===r.length)return;s&&(r=r.map((e=>({...e,msgID:s}))));const o=await this.postElements(e,r),i=await o.text();if(null===(a=this.logger)||void 0===a||a.log("[chat-sdk] message sent",{status:o.status,elements:r.length}),!o.ok)throw new Error(`sendMessage failed: ${o.status} ${i}`)}async sendQuoteMessage(e,t,s){var a,r,o,n;const i=null!==(a=s.replyMsgID)&&void 0!==a?a:this.newMsgID(),l=d(t,{messageID:s.quotedMessageID,messageAbstract:s.messageAbstract,messageSender:s.messageSender,messageType:null!==(r=s.messageType)&&void 0!==r?r:1,version:null!==(o=s.version)&&void 0!==o?o:1},i),u=await this.postElements(e,[l]),c=await u.text();if(null===(n=this.logger)||void 0===n||n.log("[chat-sdk] quote message sent",{status:u.status}),!u.ok)throw new Error(`sendQuoteMessage failed: ${u.status} ${c}`);return i}async sendImageMessage(e,t){var s;if(!(null==t?void 0:t.length))return;const a=await this.postElements(e,[i(t)]),r=await a.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] image message sent",{status:a.status}),!a.ok)throw new Error(`sendImageMessage failed: ${a.status} ${r}`)}async sendFileMessage(e,t){var s;if(!(null==t?void 0:t.length))return;const a=await this.postElements(e,[l(t)]),r=await a.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] file message sent",{status:a.status}),!a.ok)throw new Error(`sendFileMessage failed: ${a.status} ${r}`)}async sendSoundMessage(e,t,s=0){var a;if(!(null==t?void 0:t.trim()))return;const r=await this.postElements(e,[u(t,s)]),o=await r.text();if(null===(a=this.logger)||void 0===a||a.log("[chat-sdk] sound message sent",{status:r.status}),!r.ok)throw new Error(`sendSoundMessage failed: ${r.status} ${o.slice(0,500)}`)}async sendStickerMessage(e,t,s,a){var r;if(!(null==t?void 0:t.trim())||!(null==s?void 0:s.trim()))return;const o=c(t,s),n=await this.postElements(e,[a?{...o,msgID:a}:o]),i=await n.text();if(null===(r=this.logger)||void 0===r||r.log("[chat-sdk] sticker message sent",{status:n.status}),!n.ok)throw new Error(`sendStickerMessage failed: ${n.status} ${i}`)}async editTextMessage(e,t){var s;const a=await this.postElements(e,[{msgID:e,...n(t)}]),r=await a.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] text message edited",{status:a.status}),!a.ok)throw new Error(`editTextMessage failed: ${a.status} ${r.slice(0,500)}`)}async editStickerMessage(e,t,s){var a;const r=await this.postElements(e,[{msgID:e,...c(t,s)}]),o=await r.text();if(null===(a=this.logger)||void 0===a||a.log("[chat-sdk] sticker message edited",{status:r.status}),!r.ok)throw new Error(`editStickerMessage failed: ${r.status} ${o.slice(0,500)}`)}async editImageMessage(e,t){var s;const a=await this.postElements(e,[{msgID:e,...i(t)}]),r=await a.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] image message edited",{status:a.status}),!a.ok)throw new Error(`editImageMessage failed: ${a.status} ${r.slice(0,500)}`)}async deleteMessage(e){var t;const s=await this.fetchImpl(`${this.baseUrl}/v1/chat/message/${e}`,{method:"DELETE",headers:this.authHeaders});if(null===(t=this.logger)||void 0===t||t.log("[chat-sdk] message deleted",{status:s.status}),!s.ok){const e=await s.text();throw new Error(`deleteMessage failed: ${s.status} ${e.slice(0,500)}`)}}async sendTypingStatus(e,t){var s,a;const r={businessID:"user_typing_status",typingStatus:t?1:0,version:1,userAction:14,actionParam:t?"EIMAMSG_InputStatus_Ing":"EIMAMSG_InputStatus_End"};try{await this.postElements(e,[g(m(JSON.stringify(r)))])}catch(e){null===(s=this.logger)||void 0===s||s.error("[chat-sdk] typing status failed",null!==(a=null==e?void 0:e.message)&&void 0!==a?a:String(e))}}async sendStreamingChunk(e,t,s,a){const r={businessID:"chatbotPlugin",src:0,chunks:t,isFinished:s,TMessageCell_Name:"ChatbotMessageCell_Minimalist",TMessageCell_Data_Name:"ChatbotMessageCellData"},o={msgID:e,...g(m(JSON.stringify(r)))},n=await this.postElements(e,[o],a?"POST":"PATCH");if(!n.ok)throw new Error(`sendStreamingChunk failed: ${n.statusText}`);await n.text()}async sendMiniAppMessage(e,t){var s;const a=await this.postElements(e,[h(t)]),r=await a.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] miniapp card sent",{status:a.status}),!a.ok)throw new Error(`sendMiniAppMessage failed: ${a.status} ${r}`)}async sendWebLinkMessage(e,s){var a;const r={businessID:t,url:s},o=await this.postElements(e,[g(m(JSON.stringify(r)))]),n=await o.text();if(null===(a=this.logger)||void 0===a||a.log("[chat-sdk] web link sent",{status:o.status}),!o.ok)throw new Error(`sendWebLinkMessage failed: ${o.status} ${n.slice(0,500)}`)}async sendChoicesMessage(e,t){var a,r,o;const n=this.newMsgID(),i={businessID:s,promptId:null!==(a=t.promptId)&&void 0!==a?a:this.newMsgID(),prompt:t.prompt,selectionMode:null!==(r=t.selectionMode)&&void 0!==r?r:"single",choices:t.choices},l=await this.postElements(e,[{msgID:n,...g(m(JSON.stringify(i)))}]),u=await l.text();if(null===(o=this.logger)||void 0===o||o.log("[chat-sdk] choices message sent",{status:l.status}),!l.ok)throw new Error(`sendChoicesMessage failed: ${l.status} ${u.slice(0,500)}`);return n}async sendOfficialAccountTweetMessage(e,t){var s;const r=this.newMsgID(),o={businessID:a,...t},n=await this.postElements(e,[{msgID:r,...g(m(JSON.stringify(o)))}]),i=await n.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] official account tweet sent",{status:n.status}),!n.ok)throw new Error(`sendOfficialAccountTweetMessage failed: ${n.status} ${i.slice(0,500)}`);return r}async streamMessage(e,t,s=10){const a=f(t,s),r=[];for(let t=0;t<a.length;t++)r.push(a[t]),await this.sendStreamingChunk(e,r,t===a.length-1,0===t)}}w.ElemType=exports.ElemType,exports.AI_CHOICE_PROMPT_BUSINESS_ID=s,exports.DEFAULT_BASE_URL=e,exports.OFFICIAL_ACCOUNT_TWEET_BUSINESS_ID=a,exports.WEB_LINK_BUSINESS_ID=t,exports.arrayBufferToBase64=function(e){let t="";const s=new Uint8Array(e),a=s.byteLength;for(let e=0;e<a;e++)t+=String.fromCharCode(s[e]);return btoa(t)},exports.base64ToArrayBuffer=function(e){const t=atob(e),s=t.length,a=new Uint8Array(s);for(let e=0;e<s;e++)a[e]=t.charCodeAt(e);return a.buffer},exports.chatClient=function(e){return new w({token:e})},exports.customElem=g,exports.fileElem=l,exports.getAccessToken=r,exports.imageElem=i,exports.miniAppElem=h,exports.quoteTextElem=d,exports.soundElem=u,exports.splitIntoChunks=f,exports.stickerElem=c,exports.textElem=n,exports.toBase64=m,exports.verifyWebhookSignature=async function(e,t,s,a={}){const{toleranceSec:r=300,logger:o}=a,n=e.headers.get("X-Webhook-Signature");if(!n)return null==o||o.error("[chat-sdk] webhook missing X-Webhook-Signature header"),{valid:!1,error:"Missing X-Webhook-Signature header"};const i=e.headers.get("X-Webhook-Timestamp");if(!i)return null==o||o.error("[chat-sdk] webhook missing X-Webhook-Timestamp header"),{valid:!1,error:"Missing X-Webhook-Timestamp header"};const l=n.startsWith("sha256=")?n.slice(7):n,u=await async function(e,t){const s=new TextEncoder,a=await crypto.subtle.importKey("raw",s.encode(e),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),r=await crypto.subtle.sign("HMAC",a,s.encode(t));return[...new Uint8Array(r)].map((e=>e.toString(16).padStart(2,"0"))).join("")}(t,`${i}.${s}`);if(!function(e,t){if(e.length!==t.length)return!1;let s=0;for(let a=0;a<e.length;a++)s|=e.charCodeAt(a)^t.charCodeAt(a);return 0===s}(l,u))return null==o||o.error("[chat-sdk] webhook invalid signature"),{valid:!1,error:"Invalid signature"};const c=parseInt(i,10),d=Math.floor(Date.now()/1e3);return!Number.isFinite(c)||Math.abs(d-c)>r?(null==o||o.error("[chat-sdk] webhook timestamp out of range"),{valid:!1,error:"Request timestamp too old or too far in future"}):(null==o||o.log("[chat-sdk] webhook signature valid"),{valid:!0})};
2
2
  //# sourceMappingURL=main.cjs.js.map
package/dist/main.esm.js CHANGED
@@ -1,2 +1,2 @@
1
- const t="https://chat-api2-3rnt.onrender.com",e="web_link",s="ai_choice_prompt",a="official_account_tweet";async function i(e){var s;const{clientId:a,clientSecret:i}=e;if(!a||!i)throw new Error("getAccessToken: clientId and clientSecret are required");const n=t.replace(/\/$/,""),r=null!==(s=e.scope)&&void 0!==s?s:"chat:write uploads:write";if("undefined"==typeof fetch)throw new Error("getAccessToken: global fetch is not available");const o=await fetch(`${n}/v1/oauth/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"client_credentials",client_id:a,client_secret:i,scope:r})});if(!o.ok)throw new Error(`Token request failed: ${o.status} ${o.statusText}`);return await o.json()}var n;function r(t){return{elemType:n.Text,priority:0,textElem:{text:t.trim()}}}function o(t){return{elemType:n.Image,priority:0,imageElem:{upload_ids:t}}}function l(t){return{elemType:n.File,priority:0,fileElem:{upload_ids:t}}}function u(t,e=0){return{elemType:n.Sound,priority:0,soundElem:{uploadID:t,duration:e}}}function c(t,e){return{elemType:n.Sticker,priority:0,stickerElem:{packID:t,stickerID:e}}}function d(t){return{elemType:n.Custom,priority:0,customElem:{data:t}}}function h(t){return{elemType:n.MiniApp,priority:0,miniAppElem:t}}function g(t){const e=new Uint8Array(t.byteLength);return e.set(t),e}function p(t){let e="";const s=new Uint8Array(t),a=s.byteLength;for(let t=0;t<a;t++)e+=String.fromCharCode(s[t]);return btoa(e)}function m(t){const e=atob(t),s=e.length,a=new Uint8Array(s);for(let t=0;t<s;t++)a[t]=e.charCodeAt(t);return a.buffer}function f(t){const e=(new TextEncoder).encode(t);let s="";for(const t of e)s+=String.fromCharCode(t);return btoa(s)}function w(t,e=10){if(t.length<=e)return[t];const s=[];let a="";for(const i of t.split(" "))a.length+i.length+1>e&&a.length>0?(s.push(a.trim()+" "),a=i):a+=(a?" ":"")+i;return a&&s.push(a.trim()),s.length>0?s:[t]}!function(t){t[t.None=0]="None",t[t.Text=1]="Text",t[t.Image=2]="Image",t[t.Sound=3]="Sound",t[t.Video=4]="Video",t[t.File=5]="File",t[t.Sticker=6]="Sticker",t[t.GroupTips=7]="GroupTips",t[t.Merger=8]="Merger",t[t.Custom=9]="Custom",t[t.Location=10]="Location",t[t.GroupAnnouncement=11]="GroupAnnouncement",t[t.Quote=12]="Quote",t[t.InputStatus=14]="InputStatus",t[t.TypingStatus=15]="TypingStatus",t[t.MiniApp=16]="MiniApp",t[t.Order=17]="Order",t[t.Transfer=18]="Transfer"}(n||(n={}));class y{constructor(e){var s,a;if(!(null==e?void 0:e.token))throw new Error("ChatClient: token is required");this.token=e.token,this.baseUrl=(null!==(s=e.baseUrl)&&void 0!==s?s:t).replace(/\/$/,""),this.logger=e.logger;const i=null!==(a=e.fetch)&&void 0!==a?a:"undefined"!=typeof fetch?fetch:void 0;if(!i)throw new Error("ChatClient: no fetch implementation available; pass `fetch` in options");this.fetchImpl=i.bind(globalThis)}static async fromCredentials(t){const{access_token:e}=await i({clientId:t.clientId,clientSecret:t.clientSecret,scope:t.scope});return new y({token:e,baseUrl:t.baseUrl,logger:t.logger,fetch:t.fetch})}get authHeaders(){return{"Content-Type":"application/json",Authorization:`Bearer ${this.token}`}}replyUrl(t){return`${this.baseUrl}/v1/chat/message/${t}/reply`}newMsgID(){return globalThis.crypto.randomUUID()}async postElements(t,e,s="POST"){return await this.fetchImpl(this.replyUrl(t),{method:s,headers:this.authHeaders,body:JSON.stringify(e)})}async uploadImage(t,e,s="image/png"){var a;const i=new FormData;i.append("file",new Blob([g(t)],{type:s}),e);const n=await this.fetchImpl(`${this.baseUrl}/v1/upload/image`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`},body:i}),r=await n.json();if(!n.ok)throw new Error(`uploadImage failed: ${n.status} ${JSON.stringify(r)}`);if(!r.upload_id)throw new Error(`uploadImage: missing upload_id: ${JSON.stringify(r)}`);return{upload_id:r.upload_id,url:null!==(a=r.url)&&void 0!==a?a:""}}async uploadFile(t,e,s="application/octet-stream"){var a;const i=new FormData;i.append("file",new Blob([g(t)],{type:s}),e);const n=await this.fetchImpl(`${this.baseUrl}/v1/upload/file`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`},body:i}),r=await n.json();if(!n.ok)throw new Error(`uploadFile failed: ${n.status} ${JSON.stringify(r)}`);if(!r.upload_id)throw new Error(`uploadFile: missing upload_id: ${JSON.stringify(r)}`);return{upload_id:r.upload_id,url:null!==(a=r.url)&&void 0!==a?a:""}}async sendMessage(t,e,s){var a;let i=Array.isArray(e)?e.map((t=>t.trim())).filter(Boolean).map(r):[r(e)];if(0===i.length)return;s&&(i=i.map((t=>({...t,msgID:s}))));const n=await this.postElements(t,i),o=await n.text();if(null===(a=this.logger)||void 0===a||a.log("[chat-sdk] message sent",{status:n.status,elements:i.length}),!n.ok)throw new Error(`sendMessage failed: ${n.status} ${o}`)}async sendImageMessage(t,e){var s;if(!(null==e?void 0:e.length))return;const a=await this.postElements(t,[o(e)]),i=await a.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] image message sent",{status:a.status}),!a.ok)throw new Error(`sendImageMessage failed: ${a.status} ${i}`)}async sendFileMessage(t,e){var s;if(!(null==e?void 0:e.length))return;const a=await this.postElements(t,[l(e)]),i=await a.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] file message sent",{status:a.status}),!a.ok)throw new Error(`sendFileMessage failed: ${a.status} ${i}`)}async sendSoundMessage(t,e,s=0){var a;if(!(null==e?void 0:e.trim()))return;const i=await this.postElements(t,[u(e,s)]),n=await i.text();if(null===(a=this.logger)||void 0===a||a.log("[chat-sdk] sound message sent",{status:i.status}),!i.ok)throw new Error(`sendSoundMessage failed: ${i.status} ${n.slice(0,500)}`)}async sendStickerMessage(t,e,s,a){var i;if(!(null==e?void 0:e.trim())||!(null==s?void 0:s.trim()))return;const n=c(e,s),r=await this.postElements(t,[a?{...n,msgID:a}:n]),o=await r.text();if(null===(i=this.logger)||void 0===i||i.log("[chat-sdk] sticker message sent",{status:r.status}),!r.ok)throw new Error(`sendStickerMessage failed: ${r.status} ${o}`)}async editTextMessage(t,e){var s;const a=await this.postElements(t,[{msgID:t,...r(e)}]),i=await a.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] text message edited",{status:a.status}),!a.ok)throw new Error(`editTextMessage failed: ${a.status} ${i.slice(0,500)}`)}async editStickerMessage(t,e,s){var a;const i=await this.postElements(t,[{msgID:t,...c(e,s)}]),n=await i.text();if(null===(a=this.logger)||void 0===a||a.log("[chat-sdk] sticker message edited",{status:i.status}),!i.ok)throw new Error(`editStickerMessage failed: ${i.status} ${n.slice(0,500)}`)}async editImageMessage(t,e){var s;const a=await this.postElements(t,[{msgID:t,...o(e)}]),i=await a.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] image message edited",{status:a.status}),!a.ok)throw new Error(`editImageMessage failed: ${a.status} ${i.slice(0,500)}`)}async deleteMessage(t){var e;const s=await this.fetchImpl(`${this.baseUrl}/v1/chat/message/${t}`,{method:"DELETE",headers:this.authHeaders});if(null===(e=this.logger)||void 0===e||e.log("[chat-sdk] message deleted",{status:s.status}),!s.ok){const t=await s.text();throw new Error(`deleteMessage failed: ${s.status} ${t.slice(0,500)}`)}}async sendTypingStatus(t,e){var s,a;const i={businessID:"user_typing_status",typingStatus:e?1:0,version:1,userAction:14,actionParam:e?"EIMAMSG_InputStatus_Ing":"EIMAMSG_InputStatus_End"};try{await this.postElements(t,[d(f(JSON.stringify(i)))])}catch(t){null===(s=this.logger)||void 0===s||s.error("[chat-sdk] typing status failed",null!==(a=null==t?void 0:t.message)&&void 0!==a?a:String(t))}}async sendStreamingChunk(t,e,s,a){const i={businessID:"chatbotPlugin",src:0,chunks:e,isFinished:s,TMessageCell_Name:"ChatbotMessageCell_Minimalist",TMessageCell_Data_Name:"ChatbotMessageCellData"},n={msgID:t,...d(f(JSON.stringify(i)))},r=await this.postElements(t,[n],a?"POST":"PATCH");if(!r.ok)throw new Error(`sendStreamingChunk failed: ${r.statusText}`);await r.text()}async sendMiniAppMessage(t,e){var s;const a=await this.postElements(t,[h(e)]),i=await a.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] miniapp card sent",{status:a.status}),!a.ok)throw new Error(`sendMiniAppMessage failed: ${a.status} ${i}`)}async sendWebLinkMessage(t,s){var a;const i={businessID:e,url:s},n=await this.postElements(t,[d(f(JSON.stringify(i)))]),r=await n.text();if(null===(a=this.logger)||void 0===a||a.log("[chat-sdk] web link sent",{status:n.status}),!n.ok)throw new Error(`sendWebLinkMessage failed: ${n.status} ${r.slice(0,500)}`)}async sendChoicesMessage(t,e){var a,i,n;const r=this.newMsgID(),o={businessID:s,promptId:null!==(a=e.promptId)&&void 0!==a?a:this.newMsgID(),prompt:e.prompt,selectionMode:null!==(i=e.selectionMode)&&void 0!==i?i:"single",choices:e.choices},l=await this.postElements(t,[{msgID:r,...d(f(JSON.stringify(o)))}]),u=await l.text();if(null===(n=this.logger)||void 0===n||n.log("[chat-sdk] choices message sent",{status:l.status}),!l.ok)throw new Error(`sendChoicesMessage failed: ${l.status} ${u.slice(0,500)}`);return r}async sendOfficialAccountTweetMessage(t,e){var s;const i=this.newMsgID(),n={businessID:a,...e},r=await this.postElements(t,[{msgID:i,...d(f(JSON.stringify(n)))}]),o=await r.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] official account tweet sent",{status:r.status}),!r.ok)throw new Error(`sendOfficialAccountTweetMessage failed: ${r.status} ${o.slice(0,500)}`);return i}async streamMessage(t,e,s=10){const a=w(e,s),i=[];for(let e=0;e<a.length;e++)i.push(a[e]),await this.sendStreamingChunk(t,i,e===a.length-1,0===e)}}async function k(t,e,s,a={}){const{toleranceSec:i=300,logger:n}=a,r=t.headers.get("X-Webhook-Signature");if(!r)return null==n||n.error("[chat-sdk] webhook missing X-Webhook-Signature header"),{valid:!1,error:"Missing X-Webhook-Signature header"};const o=t.headers.get("X-Webhook-Timestamp");if(!o)return null==n||n.error("[chat-sdk] webhook missing X-Webhook-Timestamp header"),{valid:!1,error:"Missing X-Webhook-Timestamp header"};const l=r.startsWith("sha256=")?r.slice(7):r,u=await async function(t,e){const s=new TextEncoder,a=await crypto.subtle.importKey("raw",s.encode(t),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),i=await crypto.subtle.sign("HMAC",a,s.encode(e));return[...new Uint8Array(i)].map((t=>t.toString(16).padStart(2,"0"))).join("")}(e,`${o}.${s}`);if(!function(t,e){if(t.length!==e.length)return!1;let s=0;for(let a=0;a<t.length;a++)s|=t.charCodeAt(a)^e.charCodeAt(a);return 0===s}(l,u))return null==n||n.error("[chat-sdk] webhook invalid signature"),{valid:!1,error:"Invalid signature"};const c=parseInt(o,10),d=Math.floor(Date.now()/1e3);return!Number.isFinite(c)||Math.abs(d-c)>i?(null==n||n.error("[chat-sdk] webhook timestamp out of range"),{valid:!1,error:"Request timestamp too old or too far in future"}):(null==n||n.log("[chat-sdk] webhook signature valid"),{valid:!0})}y.ElemType=n;export{s as AI_CHOICE_PROMPT_BUSINESS_ID,y as ChatClient,t as DEFAULT_BASE_URL,n as ElemType,a as OFFICIAL_ACCOUNT_TWEET_BUSINESS_ID,e as WEB_LINK_BUSINESS_ID,p as arrayBufferToBase64,m as base64ToArrayBuffer,d as customElem,l as fileElem,i as getAccessToken,o as imageElem,h as miniAppElem,u as soundElem,w as splitIntoChunks,c as stickerElem,r as textElem,f as toBase64,k as verifyWebhookSignature};
1
+ const e="https://chat-api2-3rnt.onrender.com",t="web_link",s="ai_choice_prompt",a="official_account_tweet";async function n(t){var s;const{clientId:a,clientSecret:n}=t;if(!a||!n)throw new Error("getAccessToken: clientId and clientSecret are required");const i=e.replace(/\/$/,""),r=null!==(s=t.scope)&&void 0!==s?s:"chat:write uploads:write";if("undefined"==typeof fetch)throw new Error("getAccessToken: global fetch is not available");const o=await fetch(`${i}/v1/oauth/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"client_credentials",client_id:a,client_secret:n,scope:r})});if(!o.ok)throw new Error(`Token request failed: ${o.status} ${o.statusText}`);return await o.json()}var i;function r(e){return{elemType:i.Text,priority:0,textElem:{text:e.trim()}}}function o(e){return{elemType:i.Image,priority:0,imageElem:{upload_ids:e}}}function l(e){return{elemType:i.File,priority:0,fileElem:{upload_ids:e}}}function u(e,t=0){return{elemType:i.Sound,priority:0,soundElem:{uploadID:e,duration:t}}}function c(e,t){return{elemType:i.Sticker,priority:0,stickerElem:{packID:e,stickerID:t}}}function d(e,t,s){const a={...r(e),cloudCustomData:{messageReply:t}};return s?{msgID:s,...a}:a}function g(e){return{elemType:i.Custom,priority:0,customElem:{data:e}}}function h(e){return{elemType:i.MiniApp,priority:0,miniAppElem:e}}function p(e){const t=new Uint8Array(e.byteLength);return t.set(e),t}function m(e){let t="";const s=new Uint8Array(e),a=s.byteLength;for(let e=0;e<a;e++)t+=String.fromCharCode(s[e]);return btoa(t)}function f(e){const t=atob(e),s=t.length,a=new Uint8Array(s);for(let e=0;e<s;e++)a[e]=t.charCodeAt(e);return a.buffer}function w(e){const t=(new TextEncoder).encode(e);let s="";for(const e of t)s+=String.fromCharCode(e);return btoa(s)}function y(e,t=10){if(e.length<=t)return[e];const s=[];let a="";for(const n of e.split(" "))a.length+n.length+1>t&&a.length>0?(s.push(a.trim()+" "),a=n):a+=(a?" ":"")+n;return a&&s.push(a.trim()),s.length>0?s:[e]}function k(e){return new v({token:e})}!function(e){e[e.None=0]="None",e[e.Text=1]="Text",e[e.Image=2]="Image",e[e.Sound=3]="Sound",e[e.Video=4]="Video",e[e.File=5]="File",e[e.Sticker=6]="Sticker",e[e.GroupTips=7]="GroupTips",e[e.Merger=8]="Merger",e[e.Custom=9]="Custom",e[e.Location=10]="Location",e[e.GroupAnnouncement=11]="GroupAnnouncement",e[e.Quote=12]="Quote",e[e.InputStatus=14]="InputStatus",e[e.TypingStatus=15]="TypingStatus",e[e.MiniApp=16]="MiniApp",e[e.Order=17]="Order",e[e.Transfer=18]="Transfer"}(i||(i={}));class v{constructor(t){var s,a;if(!(null==t?void 0:t.token))throw new Error("ChatClient: token is required");this.token=t.token,this.baseUrl=(null!==(s=t.baseUrl)&&void 0!==s?s:e).replace(/\/$/,""),this.logger=t.logger;const n=null!==(a=t.fetch)&&void 0!==a?a:"undefined"!=typeof fetch?fetch:void 0;if(!n)throw new Error("ChatClient: no fetch implementation available; pass `fetch` in options");this.fetchImpl=n.bind(globalThis)}static async fromCredentials(e){const{access_token:t}=await n({clientId:e.clientId,clientSecret:e.clientSecret,scope:e.scope});return new v({token:t,baseUrl:e.baseUrl,logger:e.logger,fetch:e.fetch})}get authHeaders(){return{"Content-Type":"application/json",Authorization:`Bearer ${this.token}`}}replyUrl(e){return`${this.baseUrl}/v1/chat/message/${e}/reply`}newMsgID(){return globalThis.crypto.randomUUID()}async postElements(e,t,s="POST"){return await this.fetchImpl(this.replyUrl(e),{method:s,headers:this.authHeaders,body:JSON.stringify(t)})}async uploadImage(e,t,s="image/png"){var a;const n=new FormData;n.append("file",new Blob([p(e)],{type:s}),t);const i=await this.fetchImpl(`${this.baseUrl}/v1/upload/image`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`},body:n}),r=await i.json();if(!i.ok)throw new Error(`uploadImage failed: ${i.status} ${JSON.stringify(r)}`);if(!r.upload_id)throw new Error(`uploadImage: missing upload_id: ${JSON.stringify(r)}`);return{upload_id:r.upload_id,url:null!==(a=r.url)&&void 0!==a?a:""}}async uploadFile(e,t,s="application/octet-stream"){var a;const n=new FormData;n.append("file",new Blob([p(e)],{type:s}),t);const i=await this.fetchImpl(`${this.baseUrl}/v1/upload/file`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`},body:n}),r=await i.json();if(!i.ok)throw new Error(`uploadFile failed: ${i.status} ${JSON.stringify(r)}`);if(!r.upload_id)throw new Error(`uploadFile: missing upload_id: ${JSON.stringify(r)}`);return{upload_id:r.upload_id,url:null!==(a=r.url)&&void 0!==a?a:""}}async sendMessage(e,t,s){var a;let n=Array.isArray(t)?t.map((e=>e.trim())).filter(Boolean).map(r):[r(t)];if(0===n.length)return;s&&(n=n.map((e=>({...e,msgID:s}))));const i=await this.postElements(e,n),o=await i.text();if(null===(a=this.logger)||void 0===a||a.log("[chat-sdk] message sent",{status:i.status,elements:n.length}),!i.ok)throw new Error(`sendMessage failed: ${i.status} ${o}`)}async sendQuoteMessage(e,t,s){var a,n,i,r;const o=null!==(a=s.replyMsgID)&&void 0!==a?a:this.newMsgID(),l=d(t,{messageID:s.quotedMessageID,messageAbstract:s.messageAbstract,messageSender:s.messageSender,messageType:null!==(n=s.messageType)&&void 0!==n?n:1,version:null!==(i=s.version)&&void 0!==i?i:1},o),u=await this.postElements(e,[l]),c=await u.text();if(null===(r=this.logger)||void 0===r||r.log("[chat-sdk] quote message sent",{status:u.status}),!u.ok)throw new Error(`sendQuoteMessage failed: ${u.status} ${c}`);return o}async sendImageMessage(e,t){var s;if(!(null==t?void 0:t.length))return;const a=await this.postElements(e,[o(t)]),n=await a.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] image message sent",{status:a.status}),!a.ok)throw new Error(`sendImageMessage failed: ${a.status} ${n}`)}async sendFileMessage(e,t){var s;if(!(null==t?void 0:t.length))return;const a=await this.postElements(e,[l(t)]),n=await a.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] file message sent",{status:a.status}),!a.ok)throw new Error(`sendFileMessage failed: ${a.status} ${n}`)}async sendSoundMessage(e,t,s=0){var a;if(!(null==t?void 0:t.trim()))return;const n=await this.postElements(e,[u(t,s)]),i=await n.text();if(null===(a=this.logger)||void 0===a||a.log("[chat-sdk] sound message sent",{status:n.status}),!n.ok)throw new Error(`sendSoundMessage failed: ${n.status} ${i.slice(0,500)}`)}async sendStickerMessage(e,t,s,a){var n;if(!(null==t?void 0:t.trim())||!(null==s?void 0:s.trim()))return;const i=c(t,s),r=await this.postElements(e,[a?{...i,msgID:a}:i]),o=await r.text();if(null===(n=this.logger)||void 0===n||n.log("[chat-sdk] sticker message sent",{status:r.status}),!r.ok)throw new Error(`sendStickerMessage failed: ${r.status} ${o}`)}async editTextMessage(e,t){var s;const a=await this.postElements(e,[{msgID:e,...r(t)}]),n=await a.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] text message edited",{status:a.status}),!a.ok)throw new Error(`editTextMessage failed: ${a.status} ${n.slice(0,500)}`)}async editStickerMessage(e,t,s){var a;const n=await this.postElements(e,[{msgID:e,...c(t,s)}]),i=await n.text();if(null===(a=this.logger)||void 0===a||a.log("[chat-sdk] sticker message edited",{status:n.status}),!n.ok)throw new Error(`editStickerMessage failed: ${n.status} ${i.slice(0,500)}`)}async editImageMessage(e,t){var s;const a=await this.postElements(e,[{msgID:e,...o(t)}]),n=await a.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] image message edited",{status:a.status}),!a.ok)throw new Error(`editImageMessage failed: ${a.status} ${n.slice(0,500)}`)}async deleteMessage(e){var t;const s=await this.fetchImpl(`${this.baseUrl}/v1/chat/message/${e}`,{method:"DELETE",headers:this.authHeaders});if(null===(t=this.logger)||void 0===t||t.log("[chat-sdk] message deleted",{status:s.status}),!s.ok){const e=await s.text();throw new Error(`deleteMessage failed: ${s.status} ${e.slice(0,500)}`)}}async sendTypingStatus(e,t){var s,a;const n={businessID:"user_typing_status",typingStatus:t?1:0,version:1,userAction:14,actionParam:t?"EIMAMSG_InputStatus_Ing":"EIMAMSG_InputStatus_End"};try{await this.postElements(e,[g(w(JSON.stringify(n)))])}catch(e){null===(s=this.logger)||void 0===s||s.error("[chat-sdk] typing status failed",null!==(a=null==e?void 0:e.message)&&void 0!==a?a:String(e))}}async sendStreamingChunk(e,t,s,a){const n={businessID:"chatbotPlugin",src:0,chunks:t,isFinished:s,TMessageCell_Name:"ChatbotMessageCell_Minimalist",TMessageCell_Data_Name:"ChatbotMessageCellData"},i={msgID:e,...g(w(JSON.stringify(n)))},r=await this.postElements(e,[i],a?"POST":"PATCH");if(!r.ok)throw new Error(`sendStreamingChunk failed: ${r.statusText}`);await r.text()}async sendMiniAppMessage(e,t){var s;const a=await this.postElements(e,[h(t)]),n=await a.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] miniapp card sent",{status:a.status}),!a.ok)throw new Error(`sendMiniAppMessage failed: ${a.status} ${n}`)}async sendWebLinkMessage(e,s){var a;const n={businessID:t,url:s},i=await this.postElements(e,[g(w(JSON.stringify(n)))]),r=await i.text();if(null===(a=this.logger)||void 0===a||a.log("[chat-sdk] web link sent",{status:i.status}),!i.ok)throw new Error(`sendWebLinkMessage failed: ${i.status} ${r.slice(0,500)}`)}async sendChoicesMessage(e,t){var a,n,i;const r=this.newMsgID(),o={businessID:s,promptId:null!==(a=t.promptId)&&void 0!==a?a:this.newMsgID(),prompt:t.prompt,selectionMode:null!==(n=t.selectionMode)&&void 0!==n?n:"single",choices:t.choices},l=await this.postElements(e,[{msgID:r,...g(w(JSON.stringify(o)))}]),u=await l.text();if(null===(i=this.logger)||void 0===i||i.log("[chat-sdk] choices message sent",{status:l.status}),!l.ok)throw new Error(`sendChoicesMessage failed: ${l.status} ${u.slice(0,500)}`);return r}async sendOfficialAccountTweetMessage(e,t){var s;const n=this.newMsgID(),i={businessID:a,...t},r=await this.postElements(e,[{msgID:n,...g(w(JSON.stringify(i)))}]),o=await r.text();if(null===(s=this.logger)||void 0===s||s.log("[chat-sdk] official account tweet sent",{status:r.status}),!r.ok)throw new Error(`sendOfficialAccountTweetMessage failed: ${r.status} ${o.slice(0,500)}`);return n}async streamMessage(e,t,s=10){const a=y(t,s),n=[];for(let t=0;t<a.length;t++)n.push(a[t]),await this.sendStreamingChunk(e,n,t===a.length-1,0===t)}}async function M(e,t,s,a={}){const{toleranceSec:n=300,logger:i}=a,r=e.headers.get("X-Webhook-Signature");if(!r)return null==i||i.error("[chat-sdk] webhook missing X-Webhook-Signature header"),{valid:!1,error:"Missing X-Webhook-Signature header"};const o=e.headers.get("X-Webhook-Timestamp");if(!o)return null==i||i.error("[chat-sdk] webhook missing X-Webhook-Timestamp header"),{valid:!1,error:"Missing X-Webhook-Timestamp header"};const l=r.startsWith("sha256=")?r.slice(7):r,u=await async function(e,t){const s=new TextEncoder,a=await crypto.subtle.importKey("raw",s.encode(e),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),n=await crypto.subtle.sign("HMAC",a,s.encode(t));return[...new Uint8Array(n)].map((e=>e.toString(16).padStart(2,"0"))).join("")}(t,`${o}.${s}`);if(!function(e,t){if(e.length!==t.length)return!1;let s=0;for(let a=0;a<e.length;a++)s|=e.charCodeAt(a)^t.charCodeAt(a);return 0===s}(l,u))return null==i||i.error("[chat-sdk] webhook invalid signature"),{valid:!1,error:"Invalid signature"};const c=parseInt(o,10),d=Math.floor(Date.now()/1e3);return!Number.isFinite(c)||Math.abs(d-c)>n?(null==i||i.error("[chat-sdk] webhook timestamp out of range"),{valid:!1,error:"Request timestamp too old or too far in future"}):(null==i||i.log("[chat-sdk] webhook signature valid"),{valid:!0})}v.ElemType=i;export{s as AI_CHOICE_PROMPT_BUSINESS_ID,e as DEFAULT_BASE_URL,i as ElemType,a as OFFICIAL_ACCOUNT_TWEET_BUSINESS_ID,t as WEB_LINK_BUSINESS_ID,m as arrayBufferToBase64,f as base64ToArrayBuffer,k as chatClient,g as customElem,l as fileElem,n as getAccessToken,o as imageElem,h as miniAppElem,d as quoteTextElem,u as soundElem,y as splitIntoChunks,c as stickerElem,r as textElem,w as toBase64,M as verifyWebhookSignature};
2
2
  //# sourceMappingURL=main.esm.js.map
@@ -1,4 +1,6 @@
1
- import { ChatClientOptions, ChoicesPrompt, ElemType, Logger, MiniAppElem, OfficialAccountTweet, UploadV1FileResponse, UploadV1ImageResponse } from "./types";
1
+ import { ChatClientOptions, ChoicesPrompt, ElemType, Logger, MiniAppElem, OfficialAccountTweet, QuoteReply, UploadV1FileResponse, UploadV1ImageResponse } from "./types";
2
+ /** Build a one-off ChatClient bound to a bearer token (shorthand for `new ChatClient({ token })`). */
3
+ export declare function chatClient(token: string): ChatClient;
2
4
  /**
3
5
  * ChatClient wraps the chat API reply/upload endpoints. Construct once with a
4
6
  * token (and optionally a baseUrl / logger), then call the message helpers.
@@ -8,7 +10,7 @@ import { ChatClientOptions, ChoicesPrompt, ElemType, Logger, MiniAppElem, Offici
8
10
  * await chat.sendMessage(msgID, 'Hello!')
9
11
  * ```
10
12
  */
11
- export declare class ChatClient {
13
+ declare class ChatClient {
12
14
  private readonly token;
13
15
  private readonly baseUrl;
14
16
  private readonly logger?;
@@ -47,6 +49,13 @@ export declare class ChatClient {
47
49
  * be edited via {@link editTextMessage}); it is applied to every element sent.
48
50
  */
49
51
  sendMessage(msgID: string, message: string | string[], replyMsgID?: string): Promise<void>;
52
+ /**
53
+ * Send a text reply that quotes another message (persists
54
+ * `cloudCustomData.messageReply` so the quoted preview renders). `parentMsgID`
55
+ * is the message being replied to — usually the same as `quote.quotedMessageID`
56
+ * when quoting that message. Returns the new reply's id.
57
+ */
58
+ sendQuoteMessage(parentMsgID: string, text: string, quote: QuoteReply): Promise<string>;
50
59
  /** Send an image message by upload_id(s) (use uploadImage first). */
51
60
  sendImageMessage(msgID: string, uploadIDs: string[]): Promise<void>;
52
61
  /** Send a file message by upload_id(s) (use uploadFile first). */
@@ -95,5 +104,4 @@ export declare class ChatClient {
95
104
  /** Re-export of the element types for convenience. */
96
105
  static ElemType: typeof ElemType;
97
106
  }
98
- /** Build a one-off SDK client bound to a bearer token. */
99
- export declare function chatClient(token: string): ChatClient;
107
+ export {};
@@ -1,4 +1,4 @@
1
- import { MessageElem, MiniAppElem } from './types';
1
+ import { MessageElem, MessageReplyCloudCustom, MiniAppElem } from './types';
2
2
  /** Single text message element for the chat API body. */
3
3
  export declare function textElem(text: string): MessageElem;
4
4
  /** Single image message element (requires upload_ids from uploadImage). */
@@ -9,6 +9,11 @@ export declare function fileElem(uploadIDs: string[]): MessageElem;
9
9
  export declare function soundElem(uploadID: string, durationSec?: number): MessageElem;
10
10
  /** Single sticker message element (pack + sticker identifiers). */
11
11
  export declare function stickerElem(packID: string, stickerID: string): MessageElem;
12
+ /**
13
+ * Text element that quotes another message (persists cloudCustomData.messageReply
14
+ * so the quoted preview renders). Pass `msgID` to assign the reply a known id.
15
+ */
16
+ export declare function quoteTextElem(text: string, reply: MessageReplyCloudCustom, msgID?: string): MessageElem;
12
17
  /** Single custom message element carrying a base64-encoded payload. */
13
18
  export declare function customElem(dataBase64: string): MessageElem;
14
19
  /** Single miniapp card message element. */
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Inbound webhook event payload shapes (the `message.new` / `order.*` events the
3
+ * server delivers to your endpoint). These describe data you *receive*; the
4
+ * element builders in `elements.ts` describe data you *send*.
5
+ */
6
+ import { ElemType } from './types';
7
+ /** V2 E2EE wire shape (webhook / WS); keyEnvelopes only on full stored payloads. */
8
+ export interface EncryptedTextPayload {
9
+ aad: string;
10
+ combinedCiphertext: string;
11
+ ephemeralPublicKey: string;
12
+ encryptedSessionKey?: string;
13
+ protocolVersion: number;
14
+ senderPublicKey: string;
15
+ senderSigningPublicKey: string;
16
+ signature: string;
17
+ keyEnvelopes?: Array<{
18
+ userID: string;
19
+ deviceID: string;
20
+ encryptedSessionKey: string;
21
+ }>;
22
+ }
23
+ export interface SendTextElem {
24
+ text?: string | null;
25
+ encryptedPayload?: EncryptedTextPayload;
26
+ }
27
+ export interface ImageItem {
28
+ uuid: string;
29
+ type: 1 | 2 | 3;
30
+ width: number;
31
+ height: number;
32
+ size: number;
33
+ url: string;
34
+ }
35
+ export interface ImageElem {
36
+ imageList: ImageItem[];
37
+ }
38
+ export interface FileElem {
39
+ uuid: string;
40
+ fileName?: string;
41
+ fileSize: number;
42
+ }
43
+ export interface SendVideoSnapshot {
44
+ snapshotUUID: string;
45
+ width: number;
46
+ height: number;
47
+ size: number;
48
+ url?: string;
49
+ }
50
+ export interface SendVideoElem {
51
+ videoUUID: string;
52
+ videoType?: string;
53
+ videoSize: number;
54
+ durationSec: number;
55
+ snapshot?: SendVideoSnapshot;
56
+ }
57
+ export interface SendSoundElem {
58
+ uuid: string;
59
+ dataSize: number;
60
+ duration: number;
61
+ /** Public URL to download the audio asset. */
62
+ url?: string;
63
+ /** Same as url in webhook payloads from GraphQL. */
64
+ path?: string;
65
+ }
66
+ export interface SendFaceElem {
67
+ index: number;
68
+ data: string;
69
+ path?: string;
70
+ }
71
+ export interface SendCustomElem {
72
+ data: string;
73
+ desc?: string;
74
+ ext?: string;
75
+ sound?: string;
76
+ }
77
+ export interface SendMiniAppElem {
78
+ appID: string;
79
+ title?: string;
80
+ path?: string;
81
+ imageURL?: string;
82
+ }
83
+ export interface SendTransferElem {
84
+ transferID?: string;
85
+ status: number;
86
+ amount?: string;
87
+ note?: string;
88
+ currency?: string;
89
+ senderID?: string;
90
+ receiverID?: string;
91
+ }
92
+ /** Payload of a `message.new` webhook event. */
93
+ export interface MessageNewPayload {
94
+ msgID: string;
95
+ conversationID: string;
96
+ updatedAt: string;
97
+ createdAt: string;
98
+ seq: number;
99
+ direction: number;
100
+ elemType: ElemType;
101
+ status: number;
102
+ priority: number;
103
+ faceURL: string;
104
+ nickName: string;
105
+ nameCard: string | null;
106
+ senderID: string;
107
+ userID: string;
108
+ atUserList?: string[];
109
+ textElem?: SendTextElem;
110
+ imageElem?: ImageElem;
111
+ fileElem?: FileElem;
112
+ videoElem?: SendVideoElem;
113
+ soundElem?: SendSoundElem;
114
+ faceElem?: SendFaceElem;
115
+ customElem?: SendCustomElem;
116
+ miniAppElem?: SendMiniAppElem;
117
+ transferElem?: SendTransferElem;
118
+ }
119
+ export type OrderType = 'standard' | 'subscription' | string;
120
+ export type OrderStatus = 'pending' | 'approved' | 'captured' | 'cancelled' | string;
121
+ export type Currency = 'USD' | 'EUR' | 'GBP' | string;
122
+ export type LineItemType = 'physical' | 'digital' | 'service' | string;
123
+ export type LineItemStatus = 'final' | 'pending' | string;
124
+ export interface Link {
125
+ rel: string;
126
+ href: string;
127
+ method: 'GET' | 'POST' | 'PUT' | 'DELETE' | string;
128
+ }
129
+ export interface Total {
130
+ /** Always a string for precision (e.g. "10.00"). */
131
+ value: string;
132
+ currency: Currency;
133
+ }
134
+ export interface LineItem {
135
+ label: string;
136
+ type: LineItemType;
137
+ value: string;
138
+ status: LineItemStatus;
139
+ sku_id?: string;
140
+ thumbnail_url?: string;
141
+ }
142
+ /** Payload of an `order.*` webhook event. */
143
+ export interface OrderPayload {
144
+ order_id: string;
145
+ }
146
+ /** Discriminated union of webhook event bodies delivered to your endpoint. */
147
+ export type MessageNewBody = {
148
+ type: 'message.new';
149
+ id: string;
150
+ payload: MessageNewPayload;
151
+ targets: any;
152
+ } | {
153
+ type: 'order.captured' | 'order.approved' | 'order.expired';
154
+ id: string;
155
+ payload: OrderPayload;
156
+ targets?: any;
157
+ } | {
158
+ type: 'event.football.live';
159
+ id: string;
160
+ payload: any;
161
+ targets: any;
162
+ };
@@ -1,9 +1,10 @@
1
- export { ChatClient } from './client';
2
- export { getAccessToken } from './auth';
3
- export type { GetAccessTokenOptions } from './auth';
4
- export { verifyWebhookSignature } from './webhook';
5
- export type { VerifyWebhookOptions, WebhookVerificationResult } from './webhook';
6
- export * from './types';
7
- export * from './elements';
8
- export * from './constants';
9
- export { toBase64, splitIntoChunks, arrayBufferToBase64, base64ToArrayBuffer, } from './utils';
1
+ export { chatClient } from "./client";
2
+ export { getAccessToken } from "./auth";
3
+ export type { GetAccessTokenOptions } from "./auth";
4
+ export { verifyWebhookSignature } from "./webhook";
5
+ export type { VerifyWebhookOptions, WebhookVerificationResult, } from "./webhook";
6
+ export * from "./types";
7
+ export * from "./elements";
8
+ export * from "./events";
9
+ export * from "./constants";
10
+ export { toBase64, splitIntoChunks, arrayBufferToBase64, base64ToArrayBuffer, } from "./utils";
@@ -41,6 +41,32 @@ export type StickerElem = {
41
41
  packID: string;
42
42
  stickerID: string;
43
43
  };
44
+ /**
45
+ * cloudCustomData.messageReply — the quoted-message preview persisted on a
46
+ * reply (POST /v1/chat/message/{parentMsgID}/reply).
47
+ */
48
+ export type MessageReplyCloudCustom = {
49
+ messageID: string;
50
+ messageAbstract: string;
51
+ messageSender: string;
52
+ messageType: number;
53
+ version: number;
54
+ };
55
+ /** Describes the message being quoted in a quote reply. */
56
+ export type QuoteReply = {
57
+ /** The id of the message being quoted. */
58
+ quotedMessageID: string;
59
+ /** Short preview text shown for the quoted message. */
60
+ messageAbstract: string;
61
+ /** Display name of the quoted message's sender. */
62
+ messageSender: string;
63
+ /** ElemType of the quoted message. Defaults to 1 (text). */
64
+ messageType?: number;
65
+ /** cloudCustomData schema version. Defaults to 1. */
66
+ version?: number;
67
+ /** Optional id to assign the outgoing reply (so it can be edited later). */
68
+ replyMsgID?: string;
69
+ };
44
70
  /** A single choice in an `ai_choice_prompt` message. */
45
71
  export type Choice = {
46
72
  id: string;
@@ -76,6 +102,49 @@ export type TokenResponse = {
76
102
  scope: string;
77
103
  token_type: string;
78
104
  };
105
+ /**
106
+ * OpenID Connect UserInfo response (GET /v1/oauth/userinfo). Fields are present
107
+ * based on the scopes granted in the bearer token.
108
+ */
109
+ export interface OAuthUserInfo {
110
+ /** Unique identifier for the user (always present). */
111
+ sub: string;
112
+ name?: string;
113
+ preferred_username?: string;
114
+ picture?: string;
115
+ email?: string;
116
+ email_verified?: boolean;
117
+ ledger_id?: number;
118
+ currency?: string;
119
+ /** Formatted to 2 decimals, e.g. "1250.50". */
120
+ balance?: string;
121
+ /** First available crypto wallet address. */
122
+ address?: string;
123
+ external_accounts?: ExternalAccount[];
124
+ }
125
+ /** A linked financial account (crypto wallet or bank account). */
126
+ export interface ExternalAccount {
127
+ id: string;
128
+ type: 'crypto_wallet' | 'bank_account';
129
+ status: string;
130
+ created_at: number;
131
+ last_used_at: number;
132
+ verified_at?: number;
133
+ ledger_id?: number;
134
+ /** Present for crypto wallets. */
135
+ crypto?: {
136
+ address: string;
137
+ chain: string;
138
+ network: string;
139
+ };
140
+ /** Present for traditional bank accounts. */
141
+ bank?: {
142
+ bank_name: string;
143
+ last_four: string;
144
+ routing_number: string;
145
+ is_primary: boolean;
146
+ };
147
+ }
79
148
  /** A single message element as accepted by the chat API reply endpoint. */
80
149
  export type MessageElem = {
81
150
  elemType: ElemType;
@@ -96,6 +165,9 @@ export type MessageElem = {
96
165
  data: string;
97
166
  };
98
167
  miniAppElem?: MiniAppElem;
168
+ cloudCustomData?: {
169
+ messageReply: MessageReplyCloudCustom;
170
+ };
99
171
  };
100
172
  /** Minimal logger interface — pass `console` to enable logging, omit for silence. */
101
173
  export interface Logger {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "birdcash-chat-sdk-alpha",
3
- "version": "1.0.4",
3
+ "version": "1.0.8",
4
4
  "description": "TypeScript SDK for sending messages through the chat API (text, images, files, miniapp cards, streaming).",
5
5
  "main": "dist/main.cjs.js",
6
6
  "module": "dist/main.esm.js",