@stacksjs/chat 0.75.67 → 0.75.68
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.js +17 -6
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -38,15 +38,26 @@ var lt=Object.defineProperty;var ct=(e)=>e;function ut(e,t){this[e]=ct.bind(null
|
|
|
38
38
|
FROM ZABCDRECORD
|
|
39
39
|
`).all(),a=new Map,l=new Set;for(let c of i){let m=[c.first,c.last].filter(Boolean).join(" ").trim()||c.nick?.trim()||c.org?.trim();if(m)a.set(c.id,m);if(c.hasPhoto)l.add(c.id)}let o=t.query("SELECT ZOWNER AS owner, ZFULLNUMBER AS value FROM ZABCDPHONENUMBER").all(),d=t.query("SELECT ZOWNER AS owner, ZADDRESS AS value FROM ZABCDEMAILADDRESS").all();for(let c of[...o,...d]){let h=a.get(c.owner);if(!h||!c.value)continue;let m=x(c.value),b=l.has(c.owner)?{file:e,record:c.owner}:null,u=this.byHandle.get(m);if(!u)this.byHandle.set(m,{name:h,initials:tt(h),photo:b});else if(!u.photo&&b)u.photo=b}}finally{t.close()}}set(e,t){this.byHandle.set(x(e),{name:t,initials:tt(t)})}lookup(e){return this.byHandle.get(x(e))??null}nameFor(e){return this.lookup(e)?.name??null}hasPhoto(e){return!!this.lookup(e)?.photo}photo(e){let t=this.lookup(e)?.photo;if(!t)return null;try{let s=new Xe(t.file,{readonly:!0});try{let n=s.query("SELECT ZTHUMBNAILIMAGEDATA AS thumb, ZIMAGEDATA AS full FROM ZABCDRECORD WHERE Z_PK = ?").get(t.record);return et(t.file,n?.thumb??null)??et(t.file,n?.full??null)}finally{s.close()}}catch{return null}}}function Lt(e){if(e.style===H)return`group:${e.groupId||e.guid}`;return`direct:${e.identifier}`}function st(e){let t=new Map;for(let s of e){let n=Lt(s),r=t.get(n);if(!r){t.set(n,{key:n,kind:s.style===H?"group":"direct",chatGuids:[s.guid],displayName:s.displayName,groupId:s.groupId,groupPhotoGuid:s.style===H?s.groupPhotoGuid:null,participants:s.style===H?[...s.participants]:[s.identifier],messageCount:s.messageCount,recoverableCount:s.recoverableCount,unreadCount:s.unreadCount,lastMessageAt:s.lastMessageAt,lastMessageRowId:s.lastMessageRowId,lastMessageText:s.lastMessageText,lastMessageFromMe:s.lastMessageFromMe,services:[s.service]});continue}if(r.chatGuids.push(s.guid),r.kind==="group"&&!r.groupPhotoGuid)r.groupPhotoGuid=s.groupPhotoGuid;if(r.messageCount+=s.messageCount,r.recoverableCount+=s.recoverableCount,r.unreadCount+=s.unreadCount,!r.services.includes(s.service))r.services.push(s.service);for(let i of s.participants)if(r.kind==="group"&&!r.participants.includes(i))r.participants.push(i);if((s.lastMessageAt??0)>(r.lastMessageAt??0))r.lastMessageAt=s.lastMessageAt,r.lastMessageRowId=s.lastMessageRowId,r.lastMessageText=s.lastMessageText,r.lastMessageFromMe=s.lastMessageFromMe,r.displayName=s.displayName??r.displayName}return[...t.values()].sort((s,n)=>(n.lastMessageAt??0)-(s.lastMessageAt??0))}function ke(e){if(e.kind==="group")return e.groupId?`sms://open?groupid=${encodeURIComponent(e.groupId)}`:null;let t=e.participants[0];if(!t||!Je(t))return null;return`sms:${t}`}var Zt=`on run argv
|
|
40
40
|
set chatId to item 1 of argv
|
|
41
|
-
set
|
|
41
|
+
set theHandle to item 2 of argv
|
|
42
|
+
set serviceName to item 3 of argv
|
|
43
|
+
set theText to item 4 of argv
|
|
42
44
|
tell application "Messages"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
try
|
|
46
|
+
set target to chat id chatId
|
|
47
|
+
on error
|
|
48
|
+
if theHandle is "" then error "Messages has no chat " & chatId
|
|
49
|
+
if serviceName is "SMS" then
|
|
50
|
+
set target to participant theHandle of (1st account whose service type = SMS)
|
|
51
|
+
else
|
|
52
|
+
set target to participant theHandle of (1st account whose service type = iMessage)
|
|
53
|
+
end if
|
|
54
|
+
end try
|
|
55
|
+
if theText is not "" then send theText to target
|
|
56
|
+
repeat with i from 5 to (count of argv)
|
|
57
|
+
send (POSIX file (item i of argv)) to target
|
|
47
58
|
end repeat
|
|
48
59
|
end tell
|
|
49
|
-
end run`;async function Ht(e,t){let s=Bun.spawn(["/usr/bin/osascript","-e",e,...t],{stdout:"pipe",stderr:"pipe"}),[n,r,i]=await Promise.all([new Response(s.stdout).text(),new Response(s.stderr).text(),s.exited]);return{ok:i===0,output:(i===0?n:r).trim()}}var Gt={2000:"\u2764\uFE0F",2001:"\uD83D\uDC4D",2002:"\uD83D\uDC4E",2003:"\uD83D\uDE02",2004:"\u203C\uFE0F",2005:"\u2753",2006:"\uD83D\uDE00",2007:"\uD83D\uDD16"};function Jt(e){Bun.spawn(["/usr/bin/open",e],{stdio:["ignore","ignore","ignore"]})}class z{provider="imessage";label="iMessage";databasePath;addressBookDir;openUrl;controller;confirmDeletes;platform;runScript;contacts=null;contactsLoadedAt=0;constructor(e={}){this.databasePath=e.databasePath??_e,this.addressBookDir=e.addressBookDir??Me,this.openUrl=e.openUrl??Jt,this.controller=e.controller,this.confirmDeletes=e.confirmDeletes??!1,this.platform=e.platform??Bt.platform,this.runScript=e.runScript??Ht}capabilities(){return{send:!0,attachments:!0,replies:!1,reactions:!1,markRead:!1,live:!1}}async send(e,t){let s=t.text?.trim()??"",n=t.files??[];if(!s&&n.length===0)throw Error("Nothing to send.");let r=this.open((a)=>{let l=this.find(a,e);if(!l)return null;let[o]=a.messages(l.chatGuids,{newestFirst:!0,limit:1});return o?.chatGuid??l.chatGuids[0]??null});if(!r)throw Error("Messages has no chat for this conversation.");let i=await this.runScript(Zt,[r,s,...n.map((a)=>a.path)]);if(!i.ok)throw Error(`Messages did not send it: ${i.output||"no reason given"}`);return{id:null,sentAt:Date.now()}}rowNames(e){let t=[];if(e.kind==="group")t.push(e.displayName);else if(e.participants[0])t.push(this.names().nameFor(e.participants[0]),le(e.participants[0]),e.participants[0]);return[...new Set(t.filter((s)=>!!s))]}open(e){let t=new xe(this.databasePath);try{return e(t)}finally{t.close()}}names(){if(this.addressBookDir===!1)return this.contacts??=new J;if(!this.contacts||Date.now()-this.contactsLoadedAt>600000)this.contacts=J.load(this.addressBookDir),this.contactsLoadedAt=Date.now();return this.contacts}person(e){if(!e)return null;let t=this.names();return{id:e,name:t.nameFor(e),avatar:t.hasPhoto(e)?e:null}}async avatar(e){if(e.startsWith("group:")){let t=this.open((s)=>s.attachmentFile(e.slice(6)));return W(t&&de(t)?new Uint8Array($t(t)):null)}return W(this.names().photo(e))}grouped=null;chats(e){let t=[this.databasePath,`${this.databasePath}-wal`].map((s)=>{try{let n=Wt(s);return`${n.mtimeMs}:${n.size}`}catch{return"-"}}).join("|");if(this.grouped?.stamp!==t)this.grouped={stamp:t,chats:st(e.chats())};return this.grouped.chats}find(e,t){return this.chats(e).find((s)=>s.key===t)}async status(){if(this.platform!=="darwin")return{connected:!1,detail:"iMessage is only available on a Mac.",needs:"unsupported-platform"};try{return this.open(()=>{return}),{connected:!0,detail:"Reading Messages on this Mac."}}catch(e){if(e instanceof ue&&e.needsFullDiskAccess&&de(jt(this.databasePath)))return{connected:!1,detail:"Grant Full Disk Access in System Settings > Privacy & Security.",needs:"full-disk-access"};return{connected:!1,detail:"Sign in to Messages on this Mac.",needs:"messages-signed-out"}}}async conversations(){return this.open((e)=>this.chats(e).map((t)=>this.toConversation(t)))}toConversation(e){let t=ke(e);return{provider:"imessage",id:e.key,kind:e.kind,title:e.kind==="group"?e.displayName:null,participants:e.participants.map((s)=>this.person(s)),workspace:null,lastMessageAt:e.lastMessageAt,preview:e.messageCount>0?e.lastMessageText:null,previewFromMe:e.lastMessageFromMe,unread:e.unreadCount,cursor:String(e.lastMessageRowId),visible:e.messageCount>0,deleted:e.recoverableCount,archive:t?{mode:"confirm",detail:"Opens it in Messages at Delete Conversation for you to confirm. Messages keeps it in Recently Deleted for 30 days."}:{mode:"unsupported",detail:"Messages cannot open this conversation by address, so delete it there yourself."},url:t,avatar:e.kind==="group"&&e.groupPhotoGuid?`group:${e.groupPhotoGuid}`:null}}async messages(e,t={}){return this.open((s)=>{let n=this.find(s,e);if(!n)return[];let r=t.includeDeleted;return(t.after||!t.limit?s.messages(n.chatGuids,{afterRowId:Number(t.after)||0,byRowId:!0,limit:t.limit,includeDeleted:r}):s.messages(n.chatGuids,{newestFirst:!0,limit:t.limit,includeDeleted:r}).reverse()).map((a)=>this.toMessage(e,a))})}toMessage(e,t){let s=t.reactionType>=3000;return{id:t.guid,conversationId:e,kind:t.kind,text:t.kind==="event"&&t.groupTitle?`Named the conversation \u201C${t.groupTitle}\u201D`:t.text,fromMe:t.isFromMe,sentAt:t.sentAt,sender:t.isFromMe?null:this.person(t.sender),targetId:t.targetGuid,reaction:t.kind==="reaction"?Gt[s?t.reactionType-1000:t.reactionType]??"\u2022":null,reactionRemoved:s,replyToId:t.replyToGuid,service:t.service,editedAt:t.editedAt,unsent:t.unsent,attachments:t.attachments.map((n)=>({id:n.guid,name:n.name,mimeType:n.mimeType,bytes:n.bytes,path:n.path&&de(n.path)?n.path:null,url:null})),cursor:String(t.rowid)}}async archive(e){let t=this.open((r)=>this.find(r,e)),s=t?ke(t):null;if(!t||!s)return{mode:"unsupported",removed:!1,detail:"Messages cannot open this conversation by address, so delete it there yourself."};if(t.messageCount===0)return{mode:"confirm",removed:!0,detail:"Already gone from Messages."};let n=this.rowNames(t);if(this.controller&&n.length>0){let r=await this.controller.remove(n,s,this.confirmDeletes);return{mode:"confirm",removed:!1,detail:r.ok?this.confirmDeletes?"Deleted in Messages.":"Messages is asking you to confirm the delete.":r.detail}}return this.openUrl(s),{mode:"confirm",removed:!1,detail:"Messages is open on the conversation: choose Conversation > Delete Conversation to finish."}}async unarchive(e){if(!this.controller)return;let t=this.open((n)=>this.find(n,e));if(!t||t.messageCount>0)return;let s=this.rowNames(t);if(s.length>0)await this.controller.recover(s)}async attachment(e){if(!e.path||!de(e.path))return new Response("Not found",{status:404});return new Response(Bun.file(e.path),{headers:{"content-type":e.mimeType??"application/octet-stream"}})}}var zt="im,mpim,public_channel,private_channel",nt={"+1":"\uD83D\uDC4D",thumbsup:"\uD83D\uDC4D","-1":"\uD83D\uDC4E",heart:"\u2764\uFE0F",joy:"\uD83D\uDE02",laughing:"\uD83D\uDE06",tada:"\uD83C\uDF89",eyes:"\uD83D\uDC40",fire:"\uD83D\uDD25",white_check_mark:"\u2705",pray:"\uD83D\uDE4F",raised_hands:"\uD83D\uDE4C",rocket:"\uD83D\uDE80"},K=(e)=>Math.round(Number(e)*1000);function Kt(e){let t=Object.entries(nt).find(([,n])=>n===e);if(t)return t[0];let s=e.match(/^:([\w+-]+):$/);if(s)return s[1];throw Error(`Slack has no name for the reaction ${e}.`)}class V extends Error{method;code;constructor(e,t){super(`Slack ${e} failed: ${t}`);this.method=e;this.code=t;this.name="SlackApiError"}}class q{provider="slack";label="Slack";token;fetch;apiBase;concurrency;appToken;Socket;self=null;users=new Map;avatars=new Map;channels=new Map;constructor(e){this.token=e.token,this.fetch=e.fetch??((t,s)=>fetch(t,s)),this.apiBase=(e.apiBase??"https://slack.com/api").replace(/\/$/,""),this.concurrency=e.concurrency??4,this.appToken=e.appToken,this.Socket=e.WebSocket??globalThis.WebSocket}capabilities(){return{send:!0,attachments:!0,replies:!0,reactions:!0,markRead:!0,live:!!this.appToken}}async send(e,t){let s=t.text?.trim()??"",n=t.files??[];if(!s&&n.length===0)throw Error("Nothing to send.");let r=t.replyToId?await this.threadOf(e,t.replyToId):null;if(n.length===0){let a=await this.api("chat.postMessage",{channel:e,text:s,...r?{thread_ts:r}:{}},!0);return{id:a.ts,sentAt:K(a.ts)}}let i=[];for(let a of n){let l=await Bun.file(a.path).arrayBuffer(),o=a.name??a.path.split("/").pop()??"file",d=await this.api("files.getUploadURLExternal",{filename:o,length:l.byteLength},!0),c=await this.fetch(d.upload_url,{method:"POST",body:new Blob([l],{type:a.mimeType??"application/octet-stream"})});if(!c.ok)throw Error(`Slack did not take the upload of ${o}: ${c.status}`);i.push({id:d.file_id,title:o})}return await this.api("files.completeUploadExternal",{files:JSON.stringify(i),channel_id:e,...s?{initial_comment:s}:{},...r?{thread_ts:r}:{}},!0),{id:null,sentAt:Date.now()}}async threadOf(e,t){try{return(await this.api("conversations.history",{channel:e,latest:t,inclusive:!0,limit:1})).messages[0]?.thread_ts??t}catch{return t}}async react(e,t,s,n=!1){let r=Kt(s),i=t.split(":")[0];await this.api(n?"reactions.remove":"reactions.add",{channel:e,timestamp:i,name:r},!0)}async markRead(e){let s=(await this.api("conversations.history",{channel:e,limit:1})).messages[0];if(s)await this.api("conversations.mark",{channel:e,ts:s.ts},!0)}watch(e){let t=this.Socket;if(!this.appToken||!t)return()=>{};let s=!1,n=null,r=0,i=async()=>{if(s)return;try{let a=await this.fetch(`${this.apiBase}/apps.connections.open`,{method:"POST",headers:{authorization:`Bearer ${this.appToken}`}}),l=await a.json();if(!l.ok||!l.url)throw new V("apps.connections.open",l.error??`http_${a.status}`);let o=new t(l.url);n=o;let d=Promise.resolve();o.onmessage=(c)=>{r=0;let h;try{h=JSON.parse(String(c.data))}catch{return}if(h.envelope_id)o.send(JSON.stringify({envelope_id:h.envelope_id}));if(h.type==="disconnect"){o.close();return}d=d.then(()=>this.onEnvelope(h,e)).catch(()=>{})},o.onclose=()=>{if(n=null,!s)setTimeout(i,Math.min(60000,1000*2**Math.min(r++,6)))}}catch{if(!s)setTimeout(i,Math.min(60000,1000*2**Math.min(r++,6)))}};return i(),()=>{s=!0,n?.close()}}async onEnvelope(e,t){let s=e.payload?.event;if(e.type!=="events_api"||!s)return;if(s.type==="message"&&s.channel&&!s.subtype&&s.ts){let r=await this.toMessage(s.channel,s);t({type:"message",conversationId:s.channel,message:r});return}let n=s.channel??s.item?.channel??null;t({type:"changed",conversationId:n})}async api(e,t={},s=!1){for(let n=0;;n++){let r=new URLSearchParams(Object.entries(t).map(([l,o])=>[l,String(o)])),i=s?await this.fetch(`${this.apiBase}/${e}`,{method:"POST",headers:{authorization:`Bearer ${this.token}`,"content-type":"application/x-www-form-urlencoded"},body:r.toString()}):await this.fetch(`${this.apiBase}/${e}?${r}`,{headers:{authorization:`Bearer ${this.token}`}});if(i.status===429&&n<3){await Bun.sleep(Math.min(30,Number(i.headers.get("retry-after"))||1)*1000);continue}let a=await i.json();if(!a.ok)throw new V(e,a.error??`http_${i.status}`);return a}}async whoami(){if(!this.self){let e=await this.api("auth.test");this.self={userId:e.user_id,team:e.team,teamId:e.team_id}}return this.self}async userName(e){if(!e)return null;if(!this.users.has(e))try{let{user:t}=await this.api("users.info",{user:e});this.users.set(e,t.profile?.display_name||t.profile?.real_name||t.real_name||t.name||null),this.avatars.set(e,t.profile?.image_72??null)}catch{this.users.set(e,null)}return this.users.get(e)??null}async person(e){if(!e)return null;let t=await this.userName(e);return{id:e,name:t,avatar:this.avatars.get(e)??null}}async avatar(e){if(!oe(e,["slack-edge.com","slack.com","gravatar.com"]))return new Response("Not found",{status:404});return this.fetch(e)}async status(){if(!this.token)return{connected:!1,detail:"Add a Slack user token.",needs:"token"};try{return{connected:!0,detail:`Signed in to ${(await this.whoami()).team}.`}}catch(e){return{connected:!1,detail:e instanceof Error?e.message:String(e),needs:"token"}}}archiveSupport(e){if(e.is_im||e.is_mpim)return{mode:"native",detail:"Closes the conversation in Slack. Slack reopens it when someone writes."};if(!e.is_private)return{mode:"native",detail:"Leaves the channel in Slack, and rejoins it if you unarchive."};return{mode:"unsupported",detail:"Leaving a private channel would need someone to invite you back, so it stays in Slack."}}async list(){let e=[],t="";do{let s=await this.api("users.conversations",{types:zt,exclude_archived:!0,limit:200,...t?{cursor:t}:{}});e.push(...s.channels),t=s.response_metadata?.next_cursor??""}while(t);return e}async conversations(){let e=await this.whoami(),t=await this.list(),s=[];for(let n=0;n<t.length;n+=this.concurrency){let r=t.slice(n,n+this.concurrency);s.push(...await Promise.all(r.map((i)=>this.describe(i,e))))}return s.sort((n,r)=>(r.lastMessageAt??0)-(n.lastMessageAt??0))}async describe(e,t){let[{channel:s},n]=await Promise.all([this.api("conversations.info",{channel:e.id}).catch(()=>({channel:e})),this.api("conversations.history",{channel:e.id,limit:1}).catch(()=>({messages:[]}))]),r={...e,...s};this.channels.set(r.id,r);let i=n.messages[0],a=[];if(r.is_im)a=[await this.person(r.user)];else if(r.is_mpim){let l=await this.api("conversations.members",{channel:r.id,limit:50}).catch(()=>({members:[]}));a=await Promise.all(l.members.filter((o)=>o!==t.userId).map(async(o)=>await this.person(o)))}return{provider:"slack",id:r.id,kind:r.is_im?"direct":r.is_mpim?"group":"channel",title:r.is_im||r.is_mpim?null:`#${r.name}`,participants:a,workspace:t.team,lastMessageAt:i?K(i.ts):null,preview:i?.text||(i?.files?.length?"Attachment":null),previewFromMe:i?.user===t.userId,unread:r.unread_count_display??0,cursor:i?.ts??"0",visible:r.is_im||r.is_mpim?r.is_open!==!1:!0,archive:this.archiveSupport(r),url:`slack://channel?team=${t.teamId}&id=${r.id}`}}async messages(e,t={}){let s=await this.whoami(),n=[],r="",i=t.limit??1000;do{let l=await this.api("conversations.history",{channel:e,limit:Math.min(200,i),...t.after?{oldest:t.after,inclusive:!1}:{},...r?{cursor:r}:{}});n.push(...l.messages),r=l.has_more?l.response_metadata?.next_cursor??"":""}while(r&&n.length<i);n.sort((l,o)=>Number(l.ts)-Number(o.ts));let a=[];for(let l of n.slice(-i)){a.push(await this.toMessage(e,l));for(let o of l.reactions??[])for(let d of o.users??[])a.push({id:`${l.ts}:${o.name}:${d}`,conversationId:e,kind:"reaction",text:null,fromMe:d===s.userId,sentAt:K(l.ts),sender:d===s.userId?null:await this.person(d),targetId:l.ts,reaction:nt[o.name]??`:${o.name}:`,reactionRemoved:!1,replyToId:null,editedAt:null,unsent:!1,attachments:[],cursor:l.ts})}return a}async toMessage(e,t){let s=await this.whoami(),n=await this.person(t.user),r=!!t.subtype&&!["file_share","thread_broadcast","me_message"].includes(t.subtype);return{id:t.ts,conversationId:e,kind:r?"event":"message",text:t.text??null,fromMe:t.user===s.userId,sentAt:K(t.ts),sender:t.user===s.userId?null:n??(t.username?{id:t.bot_id??t.username,name:t.username}:null),targetId:null,reaction:null,reactionRemoved:!1,replyToId:t.thread_ts&&t.thread_ts!==t.ts?t.thread_ts:null,editedAt:t.edited?K(t.edited.ts):null,unsent:!1,attachments:(t.files??[]).map((i)=>({id:i.id,name:i.name??i.title??i.id,mimeType:i.mimetype??null,bytes:i.size??0,path:null,url:i.url_private??null})),cursor:t.ts}}async channel(e){let t=this.channels.get(e);if(t)return t;let{channel:s}=await this.api("conversations.info",{channel:e});return this.channels.set(e,s),s}async archive(e){let t=await this.channel(e),s=this.archiveSupport(t);if(s.mode!=="native")return{mode:s.mode,removed:!1,detail:s.detail};if(t.is_im||t.is_mpim)await this.api("conversations.close",{channel:e},!0);else await this.api("conversations.leave",{channel:e},!0);return this.channels.set(e,{...t,is_open:!1}),{mode:"native",removed:!0,detail:s.detail}}async unarchive(e){let t=await this.channel(e);if(t.is_im||t.is_mpim)await this.api("conversations.open",{channel:e},!0);else if(!t.is_private)await this.api("conversations.join",{channel:e},!0);this.channels.set(e,{...t,is_open:!0})}async attachment(e){if(!e.url)return new Response("Not found",{status:404});return this.fetch(e.url,{headers:{authorization:`Bearer ${this.token}`}})}}import{existsSync as he,readFileSync as ts}from"fs";import{basename as ss,dirname as Pe,extname as ns,join as Oe}from"path";import rs from"process";function Ee(e,t){let s=0n,n=0n;for(let r=t;r<e.length&&r<t+10;r++){let i=e[r];if(s|=BigInt(i&127)<<n,(i&128)===0)return{value:s,next:r+1};n+=7n}throw Error("Truncated varint")}function Vt(e){let t=[],s=0;while(s<e.length){let n=Ee(e,s);s=n.next;let r=Number(n.value>>3n),i=Number(n.value&7n);if(r===0)throw Error("Field number 0");if(i===0){let a=Ee(e,s);t.push({field:r,wire:i,value:a.value}),s=a.next}else if(i===1||i===5){let a=i===1?8:4;if(s+a>e.length)throw Error("Truncated fixed field");let l=0n;for(let o=a-1;o>=0;o--)l=l<<8n|BigInt(e[s+o]);t.push({field:r,wire:i,value:l}),s+=a}else if(i===2){let a=Ee(e,s),l=a.next,o=l+Number(a.value);if(o>e.length)throw Error("Truncated length-delimited field");t.push({field:r,wire:i,value:e.subarray(l,o)}),s=o}else throw Error(`Unsupported wire type ${i}`)}return t}function Y(e){if(!e||e.length===0)return null;try{return Vt(e)}catch{return null}}function qt(e,t){let s=e?.find((n)=>n.field===t&&n.wire===2);return s?s.value:null}function Ce(e,t){return(e??[]).filter((s)=>s.field===t&&s.wire===2).map((s)=>s.value)}function X(e,t){let s=qt(e,t);if(!s)return null;let n=new TextDecoder("utf-8",{fatal:!0});try{return n.decode(s)}catch{return null}}function Te(e,t){let s=e?.find((n)=>n.field===t&&n.wire!==2);return s?s.value:null}import{Database as Yt}from"bun:sqlite";import{homedir as Xt}from"os";import{join as Ie}from"path";var rt=Ie(Xt(),"Library","Group Containers","group.net.whatsapp.WhatsApp.shared"),Re=Ie(rt,"ChatStorage.sqlite"),it=Ie(rt,"Message"),Q=0,Qt=1,es=4,p={Text:0,Image:1,Video:2,Audio:3,Contact:4,Location:5,GroupEvent:6,Link:7,Document:8,Call:10,Gif:11,Deleted:14,Sticker:15};class pe extends Error{path;needsFullDiskAccess;constructor(e,t){let s=t instanceof Error?t.message:String(t);super(`Cannot read ${e}: ${s}`);this.path=e;this.name="WhatsAppAccessError",this.needsFullDiskAccess=/authorization denied|not permitted|unable to open/i.test(s)}}function f(e){let t=e?.replace(/\uFFFC/g,"").trim();return t?t:null}class De{path;db;constructor(e=Re){this.path=e;try{this.db=new Yt(e,{readonly:!0}),this.db.query("SELECT 1 FROM ZWACHATSESSION LIMIT 1").all()}catch(t){throw new pe(e,t)}}close(){this.db.close()}columns(e){try{return new Set(this.db.query(`PRAGMA table_info(${e})`).all().map((t)=>t.name))}catch{return new Set}}get hasMetadata(){return this.columns("ZWAMEDIAITEM").has("ZMETADATA")}get hasReceipts(){return this.columns("ZWAMESSAGE").has("ZMESSAGEINFO")&&this.columns("ZWAMESSAGEINFO").has("ZRECEIPTINFO")}sessions(e){return this.db.query(`
|
|
60
|
+
end run`;async function Ht(e,t){let s=Bun.spawn(["/usr/bin/osascript","-e",e,...t],{stdout:"pipe",stderr:"pipe"}),[n,r,i]=await Promise.all([new Response(s.stdout).text(),new Response(s.stderr).text(),s.exited]);return{ok:i===0,output:(i===0?n:r).trim()}}var Gt={2000:"\u2764\uFE0F",2001:"\uD83D\uDC4D",2002:"\uD83D\uDC4E",2003:"\uD83D\uDE02",2004:"\u203C\uFE0F",2005:"\u2753",2006:"\uD83D\uDE00",2007:"\uD83D\uDD16"};function Jt(e){Bun.spawn(["/usr/bin/open",e],{stdio:["ignore","ignore","ignore"]})}class z{provider="imessage";label="iMessage";databasePath;addressBookDir;openUrl;controller;confirmDeletes;platform;runScript;contacts=null;contactsLoadedAt=0;constructor(e={}){this.databasePath=e.databasePath??_e,this.addressBookDir=e.addressBookDir??Me,this.openUrl=e.openUrl??Jt,this.controller=e.controller,this.confirmDeletes=e.confirmDeletes??!1,this.platform=e.platform??Bt.platform,this.runScript=e.runScript??Ht}capabilities(){return{send:!0,attachments:!0,replies:!1,reactions:!1,markRead:!1,live:!1}}async send(e,t){let s=t.text?.trim()??"",n=t.files??[];if(!s&&n.length===0)throw Error("Nothing to send.");let r=this.open((a)=>{let l=this.find(a,e);if(!l)return null;let[o]=a.messages(l.chatGuids,{newestFirst:!0,limit:1});return{chatGuid:o?.chatGuid??l.chatGuids[0]??"",handle:l.kind==="direct"?l.participants[0]??"":"",service:o?.service==="SMS"?"SMS":"iMessage"}});if(!r||!r.chatGuid&&!r.handle)throw Error("Messages has no chat for this conversation.");let i=await this.runScript(Zt,[r.chatGuid,r.handle,r.service,s,...n.map((a)=>a.path)]);if(!i.ok)throw Error(`Messages did not send it: ${i.output||"no reason given"}`);return{id:null,sentAt:Date.now()}}rowNames(e){let t=[];if(e.kind==="group")t.push(e.displayName);else if(e.participants[0])t.push(this.names().nameFor(e.participants[0]),le(e.participants[0]),e.participants[0]);return[...new Set(t.filter((s)=>!!s))]}open(e){let t=new xe(this.databasePath);try{return e(t)}finally{t.close()}}names(){if(this.addressBookDir===!1)return this.contacts??=new J;if(!this.contacts||Date.now()-this.contactsLoadedAt>600000)this.contacts=J.load(this.addressBookDir),this.contactsLoadedAt=Date.now();return this.contacts}person(e){if(!e)return null;let t=this.names();return{id:e,name:t.nameFor(e),avatar:t.hasPhoto(e)?e:null}}async avatar(e){if(e.startsWith("group:")){let t=this.open((s)=>s.attachmentFile(e.slice(6)));return W(t&&de(t)?new Uint8Array($t(t)):null)}return W(this.names().photo(e))}grouped=null;chats(e){let t=[this.databasePath,`${this.databasePath}-wal`].map((s)=>{try{let n=Wt(s);return`${n.mtimeMs}:${n.size}`}catch{return"-"}}).join("|");if(this.grouped?.stamp!==t)this.grouped={stamp:t,chats:st(e.chats())};return this.grouped.chats}find(e,t){return this.chats(e).find((s)=>s.key===t)}async status(){if(this.platform!=="darwin")return{connected:!1,detail:"iMessage is only available on a Mac.",needs:"unsupported-platform"};try{return this.open(()=>{return}),{connected:!0,detail:"Reading Messages on this Mac."}}catch(e){if(e instanceof ue&&e.needsFullDiskAccess&&de(jt(this.databasePath)))return{connected:!1,detail:"Grant Full Disk Access in System Settings > Privacy & Security.",needs:"full-disk-access"};return{connected:!1,detail:"Sign in to Messages on this Mac.",needs:"messages-signed-out"}}}async conversations(){return this.open((e)=>this.chats(e).map((t)=>this.toConversation(t)))}toConversation(e){let t=ke(e);return{provider:"imessage",id:e.key,kind:e.kind,title:e.kind==="group"?e.displayName:null,participants:e.participants.map((s)=>this.person(s)),workspace:null,lastMessageAt:e.lastMessageAt,preview:e.messageCount>0?e.lastMessageText:null,previewFromMe:e.lastMessageFromMe,unread:e.unreadCount,cursor:String(e.lastMessageRowId),visible:e.messageCount>0,deleted:e.recoverableCount,archive:t?{mode:"confirm",detail:"Opens it in Messages at Delete Conversation for you to confirm. Messages keeps it in Recently Deleted for 30 days."}:{mode:"unsupported",detail:"Messages cannot open this conversation by address, so delete it there yourself."},url:t,avatar:e.kind==="group"&&e.groupPhotoGuid?`group:${e.groupPhotoGuid}`:null}}async messages(e,t={}){return this.open((s)=>{let n=this.find(s,e);if(!n)return[];let r=t.includeDeleted;return(t.after||!t.limit?s.messages(n.chatGuids,{afterRowId:Number(t.after)||0,byRowId:!0,limit:t.limit,includeDeleted:r}):s.messages(n.chatGuids,{newestFirst:!0,limit:t.limit,includeDeleted:r}).reverse()).map((a)=>this.toMessage(e,a))})}toMessage(e,t){let s=t.reactionType>=3000;return{id:t.guid,conversationId:e,kind:t.kind,text:t.kind==="event"&&t.groupTitle?`Named the conversation \u201C${t.groupTitle}\u201D`:t.text,fromMe:t.isFromMe,sentAt:t.sentAt,sender:t.isFromMe?null:this.person(t.sender),targetId:t.targetGuid,reaction:t.kind==="reaction"?Gt[s?t.reactionType-1000:t.reactionType]??"\u2022":null,reactionRemoved:s,replyToId:t.replyToGuid,service:t.service,editedAt:t.editedAt,unsent:t.unsent,attachments:t.attachments.map((n)=>({id:n.guid,name:n.name,mimeType:n.mimeType,bytes:n.bytes,path:n.path&&de(n.path)?n.path:null,url:null})),cursor:String(t.rowid)}}async archive(e){let t=this.open((r)=>this.find(r,e)),s=t?ke(t):null;if(!t||!s)return{mode:"unsupported",removed:!1,detail:"Messages cannot open this conversation by address, so delete it there yourself."};if(t.messageCount===0)return{mode:"confirm",removed:!0,detail:"Already gone from Messages."};let n=this.rowNames(t);if(this.controller&&n.length>0){let r=await this.controller.remove(n,s,this.confirmDeletes);return{mode:"confirm",removed:!1,detail:r.ok?this.confirmDeletes?"Deleted in Messages.":"Messages is asking you to confirm the delete.":r.detail}}return this.openUrl(s),{mode:"confirm",removed:!1,detail:"Messages is open on the conversation: choose Conversation > Delete Conversation to finish."}}async unarchive(e){if(!this.controller)return;let t=this.open((n)=>this.find(n,e));if(!t||t.messageCount>0)return;let s=this.rowNames(t);if(s.length>0)await this.controller.recover(s)}async attachment(e){if(!e.path||!de(e.path))return new Response("Not found",{status:404});return new Response(Bun.file(e.path),{headers:{"content-type":e.mimeType??"application/octet-stream"}})}}var zt="im,mpim,public_channel,private_channel",nt={"+1":"\uD83D\uDC4D",thumbsup:"\uD83D\uDC4D","-1":"\uD83D\uDC4E",heart:"\u2764\uFE0F",joy:"\uD83D\uDE02",laughing:"\uD83D\uDE06",tada:"\uD83C\uDF89",eyes:"\uD83D\uDC40",fire:"\uD83D\uDD25",white_check_mark:"\u2705",pray:"\uD83D\uDE4F",raised_hands:"\uD83D\uDE4C",rocket:"\uD83D\uDE80"},K=(e)=>Math.round(Number(e)*1000);function Kt(e){let t=Object.entries(nt).find(([,n])=>n===e);if(t)return t[0];let s=e.match(/^:([\w+-]+):$/);if(s)return s[1];throw Error(`Slack has no name for the reaction ${e}.`)}class V extends Error{method;code;constructor(e,t){super(`Slack ${e} failed: ${t}`);this.method=e;this.code=t;this.name="SlackApiError"}}class q{provider="slack";label="Slack";token;fetch;apiBase;concurrency;appToken;Socket;self=null;users=new Map;avatars=new Map;channels=new Map;constructor(e){this.token=e.token,this.fetch=e.fetch??((t,s)=>fetch(t,s)),this.apiBase=(e.apiBase??"https://slack.com/api").replace(/\/$/,""),this.concurrency=e.concurrency??4,this.appToken=e.appToken,this.Socket=e.WebSocket??globalThis.WebSocket}capabilities(){return{send:!0,attachments:!0,replies:!0,reactions:!0,markRead:!0,live:!!this.appToken}}async send(e,t){let s=t.text?.trim()??"",n=t.files??[];if(!s&&n.length===0)throw Error("Nothing to send.");let r=t.replyToId?await this.threadOf(e,t.replyToId):null;if(n.length===0){let a=await this.api("chat.postMessage",{channel:e,text:s,...r?{thread_ts:r}:{}},!0);return{id:a.ts,sentAt:K(a.ts)}}let i=[];for(let a of n){let l=await Bun.file(a.path).arrayBuffer(),o=a.name??a.path.split("/").pop()??"file",d=await this.api("files.getUploadURLExternal",{filename:o,length:l.byteLength},!0),c=await this.fetch(d.upload_url,{method:"POST",body:new Blob([l],{type:a.mimeType??"application/octet-stream"})});if(!c.ok)throw Error(`Slack did not take the upload of ${o}: ${c.status}`);i.push({id:d.file_id,title:o})}return await this.api("files.completeUploadExternal",{files:JSON.stringify(i),channel_id:e,...s?{initial_comment:s}:{},...r?{thread_ts:r}:{}},!0),{id:null,sentAt:Date.now()}}async threadOf(e,t){try{return(await this.api("conversations.history",{channel:e,latest:t,inclusive:!0,limit:1})).messages[0]?.thread_ts??t}catch{return t}}async react(e,t,s,n=!1){let r=Kt(s),i=t.split(":")[0];await this.api(n?"reactions.remove":"reactions.add",{channel:e,timestamp:i,name:r},!0)}async markRead(e){let s=(await this.api("conversations.history",{channel:e,limit:1})).messages[0];if(s)await this.api("conversations.mark",{channel:e,ts:s.ts},!0)}watch(e){let t=this.Socket;if(!this.appToken||!t)return()=>{};let s=!1,n=null,r=0,i=async()=>{if(s)return;try{let a=await this.fetch(`${this.apiBase}/apps.connections.open`,{method:"POST",headers:{authorization:`Bearer ${this.appToken}`}}),l=await a.json();if(!l.ok||!l.url)throw new V("apps.connections.open",l.error??`http_${a.status}`);let o=new t(l.url);n=o;let d=Promise.resolve();o.onmessage=(c)=>{r=0;let h;try{h=JSON.parse(String(c.data))}catch{return}if(h.envelope_id)o.send(JSON.stringify({envelope_id:h.envelope_id}));if(h.type==="disconnect"){o.close();return}d=d.then(()=>this.onEnvelope(h,e)).catch(()=>{})},o.onclose=()=>{if(n=null,!s)setTimeout(i,Math.min(60000,1000*2**Math.min(r++,6)))}}catch{if(!s)setTimeout(i,Math.min(60000,1000*2**Math.min(r++,6)))}};return i(),()=>{s=!0,n?.close()}}async onEnvelope(e,t){let s=e.payload?.event;if(e.type!=="events_api"||!s)return;if(s.type==="message"&&s.channel&&!s.subtype&&s.ts){let r=await this.toMessage(s.channel,s);t({type:"message",conversationId:s.channel,message:r});return}let n=s.channel??s.item?.channel??null;t({type:"changed",conversationId:n})}async api(e,t={},s=!1){for(let n=0;;n++){let r=new URLSearchParams(Object.entries(t).map(([l,o])=>[l,String(o)])),i=s?await this.fetch(`${this.apiBase}/${e}`,{method:"POST",headers:{authorization:`Bearer ${this.token}`,"content-type":"application/x-www-form-urlencoded"},body:r.toString()}):await this.fetch(`${this.apiBase}/${e}?${r}`,{headers:{authorization:`Bearer ${this.token}`}});if(i.status===429&&n<3){await Bun.sleep(Math.min(30,Number(i.headers.get("retry-after"))||1)*1000);continue}let a=await i.json();if(!a.ok)throw new V(e,a.error??`http_${i.status}`);return a}}async whoami(){if(!this.self){let e=await this.api("auth.test");this.self={userId:e.user_id,team:e.team,teamId:e.team_id}}return this.self}async userName(e){if(!e)return null;if(!this.users.has(e))try{let{user:t}=await this.api("users.info",{user:e});this.users.set(e,t.profile?.display_name||t.profile?.real_name||t.real_name||t.name||null),this.avatars.set(e,t.profile?.image_72??null)}catch{this.users.set(e,null)}return this.users.get(e)??null}async person(e){if(!e)return null;let t=await this.userName(e);return{id:e,name:t,avatar:this.avatars.get(e)??null}}async avatar(e){if(!oe(e,["slack-edge.com","slack.com","gravatar.com"]))return new Response("Not found",{status:404});return this.fetch(e)}async status(){if(!this.token)return{connected:!1,detail:"Add a Slack user token.",needs:"token"};try{return{connected:!0,detail:`Signed in to ${(await this.whoami()).team}.`}}catch(e){return{connected:!1,detail:e instanceof Error?e.message:String(e),needs:"token"}}}archiveSupport(e){if(e.is_im||e.is_mpim)return{mode:"native",detail:"Closes the conversation in Slack. Slack reopens it when someone writes."};if(!e.is_private)return{mode:"native",detail:"Leaves the channel in Slack, and rejoins it if you unarchive."};return{mode:"unsupported",detail:"Leaving a private channel would need someone to invite you back, so it stays in Slack."}}async list(){let e=[],t="";do{let s=await this.api("users.conversations",{types:zt,exclude_archived:!0,limit:200,...t?{cursor:t}:{}});e.push(...s.channels),t=s.response_metadata?.next_cursor??""}while(t);return e}async conversations(){let e=await this.whoami(),t=await this.list(),s=[];for(let n=0;n<t.length;n+=this.concurrency){let r=t.slice(n,n+this.concurrency);s.push(...await Promise.all(r.map((i)=>this.describe(i,e))))}return s.sort((n,r)=>(r.lastMessageAt??0)-(n.lastMessageAt??0))}async describe(e,t){let[{channel:s},n]=await Promise.all([this.api("conversations.info",{channel:e.id}).catch(()=>({channel:e})),this.api("conversations.history",{channel:e.id,limit:1}).catch(()=>({messages:[]}))]),r={...e,...s};this.channels.set(r.id,r);let i=n.messages[0],a=[];if(r.is_im)a=[await this.person(r.user)];else if(r.is_mpim){let l=await this.api("conversations.members",{channel:r.id,limit:50}).catch(()=>({members:[]}));a=await Promise.all(l.members.filter((o)=>o!==t.userId).map(async(o)=>await this.person(o)))}return{provider:"slack",id:r.id,kind:r.is_im?"direct":r.is_mpim?"group":"channel",title:r.is_im||r.is_mpim?null:`#${r.name}`,participants:a,workspace:t.team,lastMessageAt:i?K(i.ts):null,preview:i?.text||(i?.files?.length?"Attachment":null),previewFromMe:i?.user===t.userId,unread:r.unread_count_display??0,cursor:i?.ts??"0",visible:r.is_im||r.is_mpim?r.is_open!==!1:!0,archive:this.archiveSupport(r),url:`slack://channel?team=${t.teamId}&id=${r.id}`}}async messages(e,t={}){let s=await this.whoami(),n=[],r="",i=t.limit??1000;do{let l=await this.api("conversations.history",{channel:e,limit:Math.min(200,i),...t.after?{oldest:t.after,inclusive:!1}:{},...r?{cursor:r}:{}});n.push(...l.messages),r=l.has_more?l.response_metadata?.next_cursor??"":""}while(r&&n.length<i);n.sort((l,o)=>Number(l.ts)-Number(o.ts));let a=[];for(let l of n.slice(-i)){a.push(await this.toMessage(e,l));for(let o of l.reactions??[])for(let d of o.users??[])a.push({id:`${l.ts}:${o.name}:${d}`,conversationId:e,kind:"reaction",text:null,fromMe:d===s.userId,sentAt:K(l.ts),sender:d===s.userId?null:await this.person(d),targetId:l.ts,reaction:nt[o.name]??`:${o.name}:`,reactionRemoved:!1,replyToId:null,editedAt:null,unsent:!1,attachments:[],cursor:l.ts})}return a}async toMessage(e,t){let s=await this.whoami(),n=await this.person(t.user),r=!!t.subtype&&!["file_share","thread_broadcast","me_message"].includes(t.subtype);return{id:t.ts,conversationId:e,kind:r?"event":"message",text:t.text??null,fromMe:t.user===s.userId,sentAt:K(t.ts),sender:t.user===s.userId?null:n??(t.username?{id:t.bot_id??t.username,name:t.username}:null),targetId:null,reaction:null,reactionRemoved:!1,replyToId:t.thread_ts&&t.thread_ts!==t.ts?t.thread_ts:null,editedAt:t.edited?K(t.edited.ts):null,unsent:!1,attachments:(t.files??[]).map((i)=>({id:i.id,name:i.name??i.title??i.id,mimeType:i.mimetype??null,bytes:i.size??0,path:null,url:i.url_private??null})),cursor:t.ts}}async channel(e){let t=this.channels.get(e);if(t)return t;let{channel:s}=await this.api("conversations.info",{channel:e});return this.channels.set(e,s),s}async archive(e){let t=await this.channel(e),s=this.archiveSupport(t);if(s.mode!=="native")return{mode:s.mode,removed:!1,detail:s.detail};if(t.is_im||t.is_mpim)await this.api("conversations.close",{channel:e},!0);else await this.api("conversations.leave",{channel:e},!0);return this.channels.set(e,{...t,is_open:!1}),{mode:"native",removed:!0,detail:s.detail}}async unarchive(e){let t=await this.channel(e);if(t.is_im||t.is_mpim)await this.api("conversations.open",{channel:e},!0);else if(!t.is_private)await this.api("conversations.join",{channel:e},!0);this.channels.set(e,{...t,is_open:!0})}async attachment(e){if(!e.url)return new Response("Not found",{status:404});return this.fetch(e.url,{headers:{authorization:`Bearer ${this.token}`}})}}import{existsSync as he,readFileSync as ts}from"fs";import{basename as ss,dirname as Pe,extname as ns,join as Oe}from"path";import rs from"process";function Ee(e,t){let s=0n,n=0n;for(let r=t;r<e.length&&r<t+10;r++){let i=e[r];if(s|=BigInt(i&127)<<n,(i&128)===0)return{value:s,next:r+1};n+=7n}throw Error("Truncated varint")}function Vt(e){let t=[],s=0;while(s<e.length){let n=Ee(e,s);s=n.next;let r=Number(n.value>>3n),i=Number(n.value&7n);if(r===0)throw Error("Field number 0");if(i===0){let a=Ee(e,s);t.push({field:r,wire:i,value:a.value}),s=a.next}else if(i===1||i===5){let a=i===1?8:4;if(s+a>e.length)throw Error("Truncated fixed field");let l=0n;for(let o=a-1;o>=0;o--)l=l<<8n|BigInt(e[s+o]);t.push({field:r,wire:i,value:l}),s+=a}else if(i===2){let a=Ee(e,s),l=a.next,o=l+Number(a.value);if(o>e.length)throw Error("Truncated length-delimited field");t.push({field:r,wire:i,value:e.subarray(l,o)}),s=o}else throw Error(`Unsupported wire type ${i}`)}return t}function Y(e){if(!e||e.length===0)return null;try{return Vt(e)}catch{return null}}function qt(e,t){let s=e?.find((n)=>n.field===t&&n.wire===2);return s?s.value:null}function Ce(e,t){return(e??[]).filter((s)=>s.field===t&&s.wire===2).map((s)=>s.value)}function X(e,t){let s=qt(e,t);if(!s)return null;let n=new TextDecoder("utf-8",{fatal:!0});try{return n.decode(s)}catch{return null}}function Te(e,t){let s=e?.find((n)=>n.field===t&&n.wire!==2);return s?s.value:null}import{Database as Yt}from"bun:sqlite";import{homedir as Xt}from"os";import{join as Ie}from"path";var rt=Ie(Xt(),"Library","Group Containers","group.net.whatsapp.WhatsApp.shared"),Re=Ie(rt,"ChatStorage.sqlite"),it=Ie(rt,"Message"),Q=0,Qt=1,es=4,p={Text:0,Image:1,Video:2,Audio:3,Contact:4,Location:5,GroupEvent:6,Link:7,Document:8,Call:10,Gif:11,Deleted:14,Sticker:15};class pe extends Error{path;needsFullDiskAccess;constructor(e,t){let s=t instanceof Error?t.message:String(t);super(`Cannot read ${e}: ${s}`);this.path=e;this.name="WhatsAppAccessError",this.needsFullDiskAccess=/authorization denied|not permitted|unable to open/i.test(s)}}function f(e){let t=e?.replace(/\uFFFC/g,"").trim();return t?t:null}class De{path;db;constructor(e=Re){this.path=e;try{this.db=new Yt(e,{readonly:!0}),this.db.query("SELECT 1 FROM ZWACHATSESSION LIMIT 1").all()}catch(t){throw new pe(e,t)}}close(){this.db.close()}columns(e){try{return new Set(this.db.query(`PRAGMA table_info(${e})`).all().map((t)=>t.name))}catch{return new Set}}get hasMetadata(){return this.columns("ZWAMEDIAITEM").has("ZMETADATA")}get hasReceipts(){return this.columns("ZWAMESSAGE").has("ZMESSAGEINFO")&&this.columns("ZWAMESSAGEINFO").has("ZRECEIPTINFO")}sessions(e){return this.db.query(`
|
|
50
61
|
SELECT s.Z_PK AS pk, s.ZCONTACTJID AS jid, s.ZSESSIONTYPE AS type, s.ZPARTNERNAME AS name,
|
|
51
62
|
s.ZARCHIVED AS archived, s.ZUNREADCOUNT AS unread, s.ZLASTMESSAGEDATE AS lastDate,
|
|
52
63
|
s.ZLASTMESSAGETEXT AS lastText, COALESCE(last.ZISFROMME, 0) AS lastFromMe,
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/chat",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.68",
|
|
6
6
|
"description": "Easily interact with chat APIs.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -58,13 +58,13 @@
|
|
|
58
58
|
"prepublishOnly": "bun run build"
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@stacksjs/logging": "0.75.
|
|
61
|
+
"@stacksjs/logging": "0.75.68"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@stacksjs/cli": "0.75.
|
|
65
|
-
"@stacksjs/config": "0.75.
|
|
66
|
-
"@stacksjs/error-handling": "0.75.
|
|
67
|
-
"@stacksjs/types": "0.75.
|
|
64
|
+
"@stacksjs/cli": "0.75.68",
|
|
65
|
+
"@stacksjs/config": "0.75.68",
|
|
66
|
+
"@stacksjs/error-handling": "0.75.68",
|
|
67
|
+
"@stacksjs/types": "0.75.68",
|
|
68
68
|
"better-dx": "^0.2.24"
|
|
69
69
|
}
|
|
70
70
|
}
|