@softtynet/zplus-worker 1.0.37 → 1.0.38
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/cli.js +2 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -104,7 +104,7 @@ ${m}`,k="",T="",z=Math.min(y,a);hw(g)&&(k+=Kj(g,S,a),x=x.slice(g.length),z-=g.le
|
|
|
104
104
|
${m}${k}
|
|
105
105
|
${v}`),w.pop(),`{${k}}`}case"number":return isFinite(g)?String(g):t?t(g):"null";case"boolean":return g===!0?"true":"false";case"undefined":return;case"bigint":if(n)return String(g);default:return t?t(g):void 0}}function p(h,g,w){switch(typeof g){case"string":return bo(g);case"object":{if(g===null)return"null";if(typeof g.toJSON=="function"){if(g=g.toJSON(h),typeof g!="object")return p(h,g,w);if(g===null)return"null"}if(w.indexOf(g)!==-1)return r;let _="",m=g.length!==void 0;if(m&&Array.isArray(g)){if(g.length===0)return"[]";if(s<w.length+1)return'"[Array]"';w.push(g);let k=Math.min(g.length,a),T=0;for(;T<k-1;T++){let C=p(String(T),g[T],w);_+=C!==void 0?C:"null",_+=","}let z=p(String(T),g[T],w);if(_+=z!==void 0?z:"null",g.length-1>a){let C=g.length-a-1;_+=`,"... ${_s(C)} not stringified"`}return w.pop(),`[${_}]`}let v=Object.keys(g),x=v.length;if(x===0)return"{}";if(s<w.length+1)return'"[Object]"';let y="",S=Math.min(x,a);m&&hw(g)&&(_+=Kj(g,",",a),v=v.slice(g.length),S-=g.length,y=","),i&&(v=dw(v,o)),w.push(g);for(let k=0;k<S;k++){let T=v[k],z=p(T,g[T],w);z!==void 0&&(_+=`${y}${bo(T)}:${z}`,y=",")}if(x>a){let k=x-a;_+=`${y}"...":"${_s(k)} not stringified"`}return w.pop(),`{${_}}`}case"number":return isFinite(g)?String(g):t?t(g):"null";case"boolean":return g===!0?"true":"false";case"undefined":return;case"bigint":if(n)return String(g);default:return t?t(g):void 0}}function d(h,g,w){if(arguments.length>1){let _="";if(typeof w=="number"?_=" ".repeat(Math.min(w,10)):typeof w=="string"&&(_=w.slice(0,10)),g!=null){if(typeof g=="function")return c("",{"":h},[],g,_,"");if(Array.isArray(g))return u("",h,[],Qce(g),_,"")}if(_.length!==0)return l("",h,[],_,"")}return p("",h,[])}return d}});var n$=O((mPe,r$)=>{"use strict";var yw=Symbol.for("pino.metadata"),{DEFAULT_LEVELS:t$}=Kh(),tle=t$.info;function rle(e,t){e=e||[],t=t||{dedupe:!1};let r=Object.create(t$);r.silent=1/0,t.levels&&typeof t.levels=="object"&&Object.keys(t.levels).forEach(p=>{r[p]=t.levels[p]});let n={write:i,add:a,remove:c,emit:o,flushSync:s,end:u,minLevel:0,lastId:0,streams:[],clone:l,[yw]:!0,streamLevels:r};return Array.isArray(e)?e.forEach(a,n):a.call(n,e),e=null,n;function i(p){let d,h=this.lastLevel,{streams:g}=this,w=0,_;for(let m=nle(g.length,t.dedupe);ole(m,g.length,t.dedupe);m=ile(m,t.dedupe))if(d=g[m],d.level<=h){if(w!==0&&w!==d.level)break;if(_=d.stream,_[yw]){let{lastTime:v,lastMsg:x,lastObj:y,lastLogger:S}=this;_.lastLevel=h,_.lastTime=v,_.lastMsg=x,_.lastObj=y,_.lastLogger=S}_.write(p),t.dedupe&&(w=d.level)}else if(!t.dedupe)break}function o(...p){for(let{stream:d}of this.streams)typeof d.emit=="function"&&d.emit(...p)}function s(){for(let{stream:p}of this.streams)typeof p.flushSync=="function"&&p.flushSync()}function a(p){if(!p)return n;let d=typeof p.write=="function"||p.stream,h=p.write?p:p.stream;if(!d)throw Error("stream object needs to implement either StreamEntry or DestinationStream interface");let{streams:g,streamLevels:w}=this,_;typeof p.levelVal=="number"?_=p.levelVal:typeof p.level=="string"?_=w[p.level]:typeof p.level=="number"?_=p.level:_=tle;let m={stream:h,level:_,levelVal:void 0,id:++n.lastId};return g.unshift(m),g.sort(e$),this.minLevel=g[0].level,n}function c(p){let{streams:d}=this,h=d.findIndex(g=>g.id===p);return h>=0&&(d.splice(h,1),d.sort(e$),this.minLevel=d.length>0?d[0].level:-1),n}function u(){for(let{stream:p}of this.streams)typeof p.flushSync=="function"&&p.flushSync(),p.end()}function l(p){let d=new Array(this.streams.length);for(let h=0;h<d.length;h++)d[h]={level:p,stream:this.streams[h].stream};return{write:i,add:a,remove:c,minLevel:p,streams:d,clone:l,emit:o,flushSync:s,[yw]:!0}}}function e$(e,t){return e.level-t.level}function nle(e,t){return t?e-1:0}function ile(e,t){return t?e-1:e+1}function ole(e,t,r){return r?e>=0:e<t}r$.exports=rle});var y$=O((gPe,un)=>{"use strict";var sle=require("node:os"),p$=jv(),ale=$v(),cle=qv(),f$=K6(),lle=Zj(),d$=Ja(),{configure:ule}=Qj(),{assertDefaultLevelFound:ple,mappings:h$,genLsCache:fle,genLevelComparison:dle,assertLevelComparison:hle}=cw(),{DEFAULT_LEVELS:m$,SORTING_ORDER:mle}=Kh(),{createArgsNormalizer:gle,asChindings:yle,buildSafeSonicBoom:i$,buildFormatters:xle,stringify:xw,normalizeDestFileDescriptor:o$,noop:ble}=Zh(),{version:vle}=lw(),{chindingsSym:s$,redactFmtSym:wle,serializersSym:a$,timeSym:_le,timeSliceIndexSym:Sle,streamSym:kle,stringifySym:c$,stringifySafeSym:bw,stringifiersSym:l$,setLevelSym:Ele,endSym:Ale,formatOptsSym:Cle,messageKeySym:Rle,errorKeySym:Tle,nestedKeySym:Ile,mixinSym:Ple,levelCompSym:Ole,useOnlyCustomLevelsSym:Fle,formattersSym:u$,hooksSym:Dle,nestedKeyStrSym:Ble,mixinMergeStrategySym:Lle,msgPrefixSym:Nle}=d$,{epochTime:g$,nullTime:Ule}=f$,{pid:jle}=process,$le=sle.hostname(),zle=p$.err,Mle={level:"info",levelComparison:mle.ASC,levels:m$,messageKey:"msg",errorKey:"err",nestedKey:null,enabled:!0,base:{pid:jle,hostname:$le},serializers:Object.assign(Object.create(null),{err:zle}),formatters:Object.assign(Object.create(null),{bindings(e){return e},level(e,t){return{level:t}}}),hooks:{logMethod:void 0,streamWrite:void 0},timestamp:g$,name:void 0,redact:null,customLevels:null,useOnlyCustomLevels:!1,depthLimit:5,edgeLimit:100},qle=gle(Mle),Hle=Object.assign(Object.create(null),p$);function vw(...e){let t={},{opts:r,stream:n}=qle(t,ale(),...e);r.level&&typeof r.level=="string"&&m$[r.level.toLowerCase()]!==void 0&&(r.level=r.level.toLowerCase());let{redact:i,crlf:o,serializers:s,timestamp:a,messageKey:c,errorKey:u,nestedKey:l,base:p,name:d,level:h,customLevels:g,levelComparison:w,mixin:_,mixinMergeStrategy:m,useOnlyCustomLevels:v,formatters:x,hooks:y,depthLimit:S,edgeLimit:k,onChild:T,msgPrefix:z}=r,C=ule({maximumDepth:S,maximumBreadth:k}),N=xle(x.level,x.bindings,x.log),P=xw.bind({[bw]:C}),V=i?cle(i,P):{},Q=i?{stringify:V[wle]}:{stringify:P},J="}"+(o?`\r
|
|
106
106
|
`:`
|
|
107
|
-
`),fe=yle.bind(null,{[s$]:"",[a$]:s,[l$]:V,[c$]:xw,[bw]:C,[u$]:N}),de="";p!==null&&(d===void 0?de=fe(p):de=fe(Object.assign({},p,{name:d})));let be=a instanceof Function?a:a?g$:Ule,xe=be().indexOf(":")+1;if(v&&!g)throw Error("customLevels is required if useOnlyCustomLevels is set true");if(_&&typeof _!="function")throw Error(`Unknown mixin type "${typeof _}" - expected "function"`);if(z&&typeof z!="string")throw Error(`Unknown msgPrefix type "${typeof z}" - expected "string"`);ple(h,g,v);let K=h$(g,v);typeof n.emit=="function"&&n.emit("message",{code:"PINO_CONFIG",config:{levels:K,messageKey:c,errorKey:u}}),hle(w);let ie=dle(w);return Object.assign(t,{levels:K,[Ole]:ie,[Fle]:v,[kle]:n,[_le]:be,[Sle]:xe,[c$]:xw,[bw]:C,[l$]:V,[Ale]:J,[Cle]:Q,[Rle]:c,[Tle]:u,[Ile]:l,[Ble]:l?`,${JSON.stringify(l)}:{`:"",[a$]:s,[Ple]:_,[Lle]:m,[s$]:de,[u$]:N,[Dle]:y,silent:ble,onChild:T,[Nle]:z}),Object.setPrototypeOf(t,lle()),fle(t),t[Ele](h),t}un.exports=vw;un.exports.destination=(e=process.stdout.fd)=>typeof e=="object"?(e.dest=o$(e.dest||process.stdout.fd),i$(e)):i$({dest:o$(e),minLength:0});un.exports.transport=rw();un.exports.multistream=n$();un.exports.levels=h$();un.exports.stdSerializers=Hle;un.exports.stdTimeFunctions=Object.assign({},f$);un.exports.symbols=d$;un.exports.version=vle;un.exports.default=vw;un.exports.pino=vw});function em(e,t){let r=e.key,n=e.message,i=r.remoteJid||"",o="";r.fromMe?o=t:o=r.participant||r.remoteJid||"";let s="",a="text",c="";n?n.conversation?(s=n.conversation,a="text"):n.extendedTextMessage?(s=n.extendedTextMessage.text||"",a="text"):n.imageMessage?(s=n.imageMessage.caption||"",a="image",c=n.imageMessage.url||""):n.videoMessage?(s=n.videoMessage.caption||"",a="video",c=n.videoMessage.url||""):n.audioMessage?(a="audio",c=n.audioMessage.url||""):n.documentMessage?(s=n.documentMessage.title||n.documentMessage.fileName||"",a="file",c=n.documentMessage.url||""):n.stickerMessage?(a="sticker",c=n.stickerMessage.url||""):n.protocolMessage||n.senderKeyDistributionMessage?(a="system",s="System message"):(a="other",s="[Tin nh\u1EAFn kh\xF4ng \u0111\u01B0\u1EE3c h\u1ED7 tr\u1EE3]"):(a="other",s="");let u={rawMsg:Wle(e)};if(e.pushName&&(u.pushName=e.pushName),n?.extendedTextMessage?.contextInfo?.quotedMessage){let p=n.extendedTextMessage.contextInfo;u.quotedMessage={participant:p.participant,stanzaId:p.stanzaId,text:p.quotedMessage?.conversation||p.quotedMessage?.extendedTextMessage?.text||""}}let l=e.messageTimestamp?Number(e.messageTimestamp)*1e3:Date.now();return{id:r.id||"",conversationId:i,senderId:o,senderName:e.pushName||void 0,text:s,type:a,mediaUrl:c,timestamp:l,platform:"whatsapp",isFromMe:!!r.fromMe,metadata:u}}function Wle(e){if(!e||typeof e!="object")return e;let t={};if(e.key&&(t.key={remoteJid:e.key.remoteJid,fromMe:e.key.fromMe,id:e.key.id,participant:e.key.participant}),e.pushName&&(t.pushName=e.pushName),e.messageTimestamp&&(t.messageTimestamp=e.messageTimestamp),e.status&&(t.status=e.status),e.message){let r=e.message;t.message={},r.conversation&&(t.message.conversation=r.conversation),r.extendedTextMessage&&(t.message.extendedTextMessage={text:r.extendedTextMessage.text},r.extendedTextMessage.contextInfo&&(t.message.extendedTextMessage.contextInfo={stanzaId:r.extendedTextMessage.contextInfo.stanzaId,participant:r.extendedTextMessage.contextInfo.participant})),r.imageMessage&&(t.message.imageMessage={caption:r.imageMessage.caption,mimetype:r.imageMessage.mimetype}),r.videoMessage&&(t.message.videoMessage={caption:r.videoMessage.caption,mimetype:r.videoMessage.mimetype}),r.audioMessage&&(t.message.audioMessage={mimetype:r.audioMessage.mimetype,seconds:r.audioMessage.seconds}),r.documentMessage&&(t.message.documentMessage={title:r.documentMessage.title,fileName:r.documentMessage.fileName,mimetype:r.documentMessage.mimetype}),r.stickerMessage&&(t.message.stickerMessage={mimetype:r.stickerMessage.mimetype})}return t}var x$=F(()=>{"use strict"});function fu(e,t){let r=String(e.id||e.jid||""),n=String(e.name||e.verifiedName||e.notify||"WhatsApp User"),i=String(e.imgUrl||e.avatar||"");return{id:r,name:n,avatarUrl:i||void 0,platform:"whatsapp",phoneNumber:t||e.phoneNumber||void 0,rawContact:e}}function b$(e){let t=String(e.id||e.jid||""),r=String(e.name||e.displayName||"WhatsApp Chat"),n=String(e.imgUrl||e.avatar||""),i="direct";return(t.endsWith("@g.us")||e.isGroup)&&(i="group"),{id:t,name:r,avatarUrl:n||void 0,type:i,unreadCount:Number(e.unreadCount||0),platform:"whatsapp",rawConversation:e}}var v$=F(()=>{"use strict"});var E$={};qi(E$,{WhatsAppAdapter:()=>ww});var vo,w$,_$,S$,k$,ww,A$=F(()=>{"use strict";vo=le(require("@whiskeysockets/baileys")),w$=le(y$()),_$=le(Rd()),S$=le(Id()),k$=le(Dd());kl();x$();v$();ww=class{accountId;platform="whatsapp";eventBus=new ei;status="disconnected";socket=null;session=null;isReconnecting=!1;chatsMap=new Map;contactsMap=new Map;constructor(t){this.accountId=t}async initialize(t){this.session=t,this.status="connecting",this.eventBus.emit("session:status_changed","connecting");let r=t.authData.sessionPath||`./sessions/whatsapp_${this.accountId}`;try{let{state:n,saveCreds:i}=await(0,vo.useMultiFileAuthState)(r),o=(0,w$.default)({level:"silent"}),s=[2,3e3,1023223821];try{let c=await(0,vo.fetchLatestBaileysVersion)();c&&c.version&&(s=c.version)}catch{}let a={version:s,auth:n,logger:o,printQRInTerminal:!1,defaultQueryTimeoutMs:3e4,connectTimeoutMs:3e4};if(t.proxy){let c=this.createProxyAgent(t.proxy);c&&(a.agent=c)}this.socket=(0,vo.default)(a),this.socket.ev.on("creds.update",i),this.setupListeners()}catch(n){throw this.status="disconnected",this.eventBus.emit("session:status_changed","disconnected",n.message||String(n)),n}}async disconnect(){if(this.isReconnecting=!1,this.socket){try{this.socket.end(void 0)}catch{}this.socket=null}this.status="disconnected",this.eventBus.emit("session:status_changed","disconnected")}async sendMessage(t,r){if(!this.socket)throw new Error("WhatsApp adapter not initialized");await this.sendTyping(t,!0);let n=Math.floor(Math.random()*2e3)+1500;await new Promise(s=>setTimeout(s,n)),await this.sendTyping(t,!1);let i={};if(r.type==="text")i={text:r.text};else if(r.type==="image")i={image:{url:r.url||r.filePath},caption:r.caption||""};else if(r.type==="sticker")i={sticker:{url:r.url||r.filePath||r.stickerId}};else if(r.type==="file")i={document:{url:r.url||r.filePath},fileName:r.filename||"file"};else throw new Error(`Unsupported message payload type: ${r.type}`);r.quoteId&&(i.contextInfo={stanzaId:r.quoteId,participant:t.endsWith("@g.us")?void 0:t,quotedMessage:{conversation:"[Tr\xEDch d\u1EABn tin nh\u1EAFn]"}});let o=await this.socket.sendMessage(t,i);if(!o)throw new Error("Failed to send WhatsApp message");return em(o,this.accountId)}async getConversations(t=20){let r=Array.from(this.chatsMap.values());return r.sort((n,i)=>Number(i.conversationTimestamp||0)-Number(n.conversationTimestamp||0)),r.slice(0,t).map(b$)}async getMessageHistory(t,r=50,n){return[]}async getCurrentUser(){if(!this.socket)return null;let t=this.socket.authState?.creds?.me||this.socket.user;if(!t)return null;let r=t.id;r.includes(":")&&(r=r.split(":")[0]+"@s.whatsapp.net");let n=t.name||this.socket.user?.name||"WhatsApp User",i="";try{i=await this.socket.profilePictureUrl(r,"image")||""}catch{}return fu({id:r,name:n,imgUrl:i},this.accountId)}async getContactInfo(t){if(this.contactsMap.has(t))return fu(this.contactsMap.get(t));if(!this.socket)throw new Error("WhatsApp adapter not initialized");try{let r=await this.socket.profilePictureUrl(t,"image");return fu({id:t,name:"WhatsApp User",imgUrl:r})}catch{return fu({id:t,name:"WhatsApp User"})}}async markAsRead(t){if(this.socket)try{await this.socket.sendPresenceUpdate("paused",t)}catch{}}async sendTyping(t,r){if(this.socket)try{await this.socket.sendPresenceUpdate(r?"composing":"paused",t)}catch{}}getUnderlyingClient(){return this.socket}setupListeners(){this.socket&&(this.socket.ev.on("connection.update",t=>{let{connection:r,lastDisconnect:n,qr:i}=t;i&&this.eventBus.emit("auth:qr_received",i),r==="connecting"&&(this.status="connecting",this.eventBus.emit("session:status_changed","connecting")),r==="open"&&(this.status="connected",this.eventBus.emit("session:status_changed","connected")),r==="close"&&(n?.error?.output?.statusCode!==vo.DisconnectReason.loggedOut&&this.session?(this.isReconnecting=!0,this.initialize(this.session)):(this.status="disconnected",this.eventBus.emit("session:status_changed","disconnected","Session logged out or expired")))}),this.socket.ev.on("messages.upsert",t=>{if(t.type==="notify"){for(let r of t.messages)if(r.message)try{let n=em(r,this.accountId);this.eventBus.emit("message:received",n)}catch{}}}),this.socket.ev.on("presence.update",t=>{try{let r=t.id,n=Object.keys(t.presences);if(n.length>0){let i=n[0],o=t.presences[i];o&&this.eventBus.emit("chat:typing",{conversationId:r,senderId:i,isTyping:o.lastKnownPresence==="composing"})}}catch{}}),this.socket.ev.on("messaging-history.set",t=>{let{chats:r,contacts:n,messages:i}=t;if(r)for(let o of r)o.id&&this.chatsMap.set(o.id,o);if(n)for(let o of n)o.id&&this.contactsMap.set(o.id,o);if(i){for(let o of i)if(o.message)try{let s=em(o,this.accountId);this.eventBus.emit("message:received",s)}catch{}}}),this.socket.ev.on("chats.upsert",t=>{for(let r of t)r.id&&this.chatsMap.set(r.id,r)}),this.socket.ev.on("chats.update",t=>{for(let r of t)if(r.id&&this.chatsMap.has(r.id)){let n=this.chatsMap.get(r.id);this.chatsMap.set(r.id,{...n,...r})}}),this.socket.ev.on("contacts.upsert",t=>{for(let r of t)r.id&&this.contactsMap.set(r.id,r)}),this.socket.ev.on("contacts.update",t=>{for(let r of t)if(r.id&&this.contactsMap.has(r.id)){let n=this.contactsMap.get(r.id);this.contactsMap.set(r.id,{...n,...r})}}))}createProxyAgent(t){try{return t.startsWith("socks")?new _$.SocksProxyAgent(t):t.startsWith("https")?new k$.HttpsProxyAgent(t):new S$.HttpProxyAgent(t)}catch{return}}}});var C$={};qi(C$,{WhatsAppChannelRunner:()=>_w});var du,_w,R$=F(()=>{"use strict";du=le(nt()),_w=class{constructor(t,r,n,i){this.accountId=t;this.sessionData=r;this.proxyData=n;this.logger=i||(0,du.createLogger)(`WhatsAppRunner:${t}`)}platform="whatsapp";status="offline";logger;messageHandler;adapter;onMessage(t){this.messageHandler=t}async start(){let t=this.proxyData?` via resident proxy ${this.proxyData.host||this.proxyData.ip||"configured"}`:" (direct)";this.logger.info(`Starting 24/7 headless WhatsApp runner for account ${this.accountId}${t}...`);let r=this.sessionData;if(this.sessionData?.encryptedSession?r=du.CloudCrypto.parseCloudSession(this.sessionData.encryptedSession):typeof this.sessionData=="string"&&(r=du.CloudCrypto.parseCloudSession(this.sessionData)),!!(r?.sessionPath||r?.creds||r?.keys||r?.authSession))try{let{WhatsAppAdapter:i}=await Promise.resolve().then(()=>(A$(),E$));this.adapter=new i(this.accountId),this.adapter.eventBus.on("message:received",s=>{this.receiveIncomingMessage(s)});let o;if(this.proxyData?.host&&this.proxyData?.port){let s=this.proxyData.username&&this.proxyData.password?`${this.proxyData.username}:${this.proxyData.password}@`:"";o=`${this.proxyData.protocol||"http"}://${s}${this.proxyData.host}:${this.proxyData.port}`}await this.adapter.initialize({accountId:this.accountId,platform:"whatsapp",status:"connecting",authData:{sessionPath:r.sessionPath,creds:r.creds,keys:r.keys},proxy:o}),this.logger.info(`Headless WhatsApp socket connected & listening for ${this.accountId}`)}catch(i){this.logger.warn(`Could not initialize live WhatsApp client: ${i?.message}. Runner active in standby mode.`)}else this.logger.debug("No direct WhatsApp credentials/session provided. Running in standby mode.");this.status="active"}async stop(){if(this.logger.info(`Stopping headless WhatsApp runner for account ${this.accountId}...`),this.adapter)try{await this.adapter.disconnect()}catch(t){this.logger.debug(`Error disconnecting WhatsApp adapter for ${this.accountId}:`,t?.message)}this.status="offline"}getStatus(){return this.status}async sendMessage(t){if(this.adapter&&this.status==="active")try{return await this.adapter.sendMessage(t.threadId||t.conversationId,{type:t.messageType==="image"?"image":"text",text:t.content}),!0}catch(r){return this.logger.warn(`Failed to send WhatsApp message via adapter for ${this.accountId}:`,r?.message),!1}return this.logger.info(`Headless WhatsApp runner sending message ${t.id} to thread ${t.threadId}`),!0}receiveIncomingMessage(t){this.status==="active"&&(this.logger.info(`\u{1F4E9} [WhatsAppRunner:${this.accountId}] Received message ${t.id} from sender ${t.senderName||t.senderId}: "${(t.content||"").slice(0,60)}"`),this.messageHandler?.(t))}}});var Wt=le(require("fs")),oi=le(require("path")),mt=le(require("os")),K$=le(require("readline")),vt=require("child_process");var pi=le(require("os")),Hi=le(require("fs")),dc=le(require("path")),k_=le(require("crypto"));function OM(){return"1.0.37"}var Hr=OM();function Wu(){return{totalMemMb:Math.round(pi.default.totalmem()/(1024*1024)),freeMemMb:Math.round(pi.default.freemem()/(1024*1024)),cpuCount:pi.default.cpus()?.length||1,platform:pi.default.platform()}}function FM(e){try{let t=dc.default.join(pi.default.homedir(),".zplus");Hi.default.existsSync(t)||Hi.default.mkdirSync(t,{recursive:!0});let r=e?`_slot_${e.replace(/[^a-zA-Z0-9_-]/g,"")}`:"",n=dc.default.join(t,`worker_identity${r}.json`);if(Hi.default.existsSync(n)){let p=JSON.parse(Hi.default.readFileSync(n,"utf-8"));if(p&&p.workerId)return{workerId:p.workerId,workerName:p.workerName||p.workerId}}let o=(pi.default.hostname()||"node").replace(/[^a-zA-Z0-9_-]/g,"_").toLowerCase().slice(0,14),s=k_.default.randomBytes(2).toString("hex"),a=`worker_${o}${r}_${s}`,c=e?` #${e}`:"",u=`Worker ${o.toUpperCase()}${c}`,l={workerId:a,workerName:u,slot:e||"default",createdAt:new Date().toISOString()};return Hi.default.writeFileSync(n,JSON.stringify(l,null,2),"utf-8"),l}catch{let t=e?`_slot_${e}`:"",r=`worker_${pi.default.hostname().replace(/[^a-zA-Z0-9_-]/g,"_").slice(0,14)||"node"}${t}`;return{workerId:r,workerName:r}}}var Hu=class{static loadFromEnv(t=process.argv.slice(2)){let r=z=>{for(let C of t){if(C.startsWith(`--${z}=`))return C.split("=").slice(1).join("=");if(C===`--${z}`&&t[t.indexOf(C)+1])return t[t.indexOf(C)+1]}},n=r("cloud-provider")||process.env.CLOUD_PROVIDER||"appwrite",i=r("token")||process.env.CLOUD_AUTH_TOKEN||process.env.APPWRITE_SESSION_TOKEN||process.env.WORKER_TOKEN||process.env.SESSION_TOKEN,o=r("jwt")||process.env.CLOUD_JWT||process.env.APPWRITE_JWT||process.env.JWT,s=r("secret")||process.env.DESKTOP_SECRET,a=r("team-id")||process.env.TEAM_ID||"default",c=t.includes("--enable-http")||r("enable-http")==="true"||process.env.ENABLE_HTTP==="true"||!1,u=r("port")||process.env.PORT,l=u?Number(u):c?8080:void 0,p=r("endpoint")||process.env.CLOUD_ENDPOINT||process.env.CLOUD_API_ENDPOINT||process.env.APPWRITE_ENDPOINT||process.env.VITE_APPWRITE_ENDPOINT||"https://api.softty.net/v1",d=r("project-id")||process.env.CLOUD_PROJECT_ID||process.env.CLOUD_TENANT_ID||process.env.APPWRITE_PROJECT_ID||process.env.VITE_APPWRITE_PROJECT_ID||"699cfc3100136099c1c1",h=r("database-id")||process.env.CLOUD_DATABASE_ID||process.env.APPWRITE_DATABASE_ID||process.env.VITE_APPWRITE_DATABASE_ID||"zplus_app",g=r("storage-bucket-id")||process.env.STORAGE_BUCKET_ID||process.env.APPWRITE_STORAGE_BUCKET_ID||process.env.VITE_APPWRITE_STORAGE_BUCKET_ID||"zplus-media-vault",w=Math.max(1,Math.round(pi.default.totalmem()/(1024*1024*1024))),_=Math.min(200,Math.max(20,w*25)),m=r("max-capacity")||process.env.MAX_CAPACITY,v=Number(m||_),x=r("slot")||process.env.WORKER_SLOT||process.env.pm_id||process.env.NODE_APP_INSTANCE,y=FM(x),S=r("worker-id")||process.env.WORKER_ID||y.workerId,k=r("worker-name")||process.env.WORKER_NAME||process.env.HOSTNAME||y.workerName,T=r("user-id")||process.env.USER_ID||process.env.SOFTTY_USER_ID;return{workerId:S,version:Hr,enableHttp:c,port:l,userId:T,teamId:a,workerName:k,maxCapacity:v,recommendedCapacity:_,clusterPollIntervalMs:Number(r("poll-interval")||process.env.CLUSTER_POLL_INTERVAL_MS||5e3),cloudProvider:n,cloudEndpoint:p,cloudProjectId:d,cloudSessionToken:i,cloudJwt:o,cloudDatabaseId:h,appwriteEndpoint:p,appwriteProjectId:d,appwriteSessionToken:i,appwriteJwt:o,storageBucketId:g,desktopSecret:s,databaseId:h,heartbeatIntervalMs:Number(r("heartbeat-interval")||process.env.HEARTBEAT_INTERVAL_MS||3e4),geminiApiKey:r("gemini-api-key")||process.env.GEMINI_API_KEY||process.env.GOOGLE_API_KEY,openaiApiKey:r("openai-api-key")||process.env.OPENAI_API_KEY,deepseekApiKey:r("deepseek-api-key")||process.env.DEEPSEEK_API_KEY,anthropicApiKey:r("anthropic-api-key")||process.env.ANTHROPIC_API_KEY,customAiApiKey:r("custom-ai-api-key")||process.env.CUSTOM_AI_API_KEY,aiBaseUrl:r("ai-base-url")||process.env.AI_BASE_URL,aiProvider:r("ai-provider")||process.env.AI_PROVIDER,aiModel:r("ai-model")||process.env.AI_MODEL,nightSystemPrompt:r("night-system-prompt")||process.env.NIGHT_SYSTEM_PROMPT,nightFallbackReply:r("night-fallback-reply")||process.env.NIGHT_FALLBACK_REPLY,logLevel:r("log-level")||process.env.LOG_LEVEL||"info"}}};var wo=le(require("fs")),Ew=le(require("os")),ks=le(require("path")),V$=le(require("crypto")),J$=le(nt());var O_=le(nt()),Zu=class{runners=new Map;logger;constructor(t){this.logger=t||(0,O_.createLogger)("ChannelRunnerRegistry")}register(t){let r=`${t.platform}:${t.accountId}`;this.runners.has(r)&&this.logger.warn(`Overwriting existing runner for ${r}`),this.runners.set(r,t),this.logger.info(`Registered runner for ${r}`)}unregister(t,r){let n=`${t}:${r}`,i=this.runners.get(n);return i?(i.stop().catch(o=>{this.logger.error(`Error stopping runner ${n} during unregister`,o)}),this.runners.delete(n),this.logger.info(`Unregistered runner for ${n}`),!0):!1}get(t,r){return this.runners.get(`${t}:${r}`)}getAll(){return Array.from(this.runners.values())}getCount(){return this.runners.size}async startAll(){this.logger.info(`Starting all ${this.runners.size} registered channel runners...`);for(let[t,r]of this.runners.entries())try{await r.start()}catch(n){this.logger.error(`Failed to start runner ${t}:`,n)}}async stopAll(){this.logger.info(`Stopping all ${this.runners.size} channel runners...`);for(let[t,r]of this.runners.entries())try{await r.stop()}catch(n){this.logger.error(`Failed to stop runner ${t}:`,n)}this.runners.clear()}};var F_=le(nt()),Ku=class{constructor(t=6e4,r,n){this.defaultTtlMs=t;this.logger=r||(0,F_.createLogger)("DistributedLockManager"),this.storageProvider=n}logger;locks=new Map;preemptCallbacks=[];storageProvider;setStorageProvider(t){this.storageProvider=t}getStorageProvider(){return this.storageProvider}onPreempt(t){this.preemptCallbacks.push(t)}async acquireLockRemote(t,r,n=this.defaultTtlMs){return this.storageProvider&&!await this.storageProvider.acquireLock(t,r,n)?!1:this.acquireLock(t,r,n)}async releaseLockRemote(t,r){return this.storageProvider&&await this.storageProvider.releaseLock(t,r),this.releaseLock(t,r)}async renewLockRemote(t,r,n=this.defaultTtlMs){return this.storageProvider&&await this.storageProvider.renewLock(t,r,n),this.acquireLock(t,r,n)}acquireLock(t,r,n=this.defaultTtlMs){let i=Date.now(),o=this.locks.get(t);return o&&o.expiresAt>i&&o.ownerId!==r?(this.logger.warn(`Lock denied for account ${t}: currently held by ${o.ownerId} (expires in ${o.expiresAt-i}ms)`),!1):(this.locks.set(t,{accountId:t,ownerId:r,acquiredAt:i,expiresAt:i+n}),this.logger.info(`\u2705 Lock granted: account=${t}, owner=${r}, ttl=${n}ms`),!0)}async preemptLock(t,r){let n=this.locks.get(t);this.logger.info(`\u26A1 Preemption triggered for account ${t} by master ${r} (previous owner: ${n?.ownerId||"none"})`);let i=this.preemptCallbacks.map(s=>{try{return Promise.resolve(s(t,r))}catch(a){return this.logger.error(`Error in preempt callback for ${t}:`,a),Promise.resolve()}});await Promise.race([Promise.all(i),new Promise(s=>setTimeout(s,1e3))]);let o=Date.now();return this.locks.set(t,{accountId:t,ownerId:r,acquiredAt:o,expiresAt:o+this.defaultTtlMs}),this.logger.info(`\u2705 Account ${t} preempted successfully by ${r}.`),!0}releaseLock(t,r){let n=this.locks.get(t);return n?r&&n.ownerId!==r?(this.logger.warn(`Attempted unauthorized lock release for ${t} by ${r} (real owner: ${n.ownerId})`),!1):(this.locks.delete(t),this.logger.info(`\u{1F513} Lock released for account ${t}.`),!0):!0}releaseAllForOwner(t){let r=0;for(let[n,i]of this.locks.entries())i.ownerId===t&&(this.locks.delete(n),r++);return r}isLocked(t){let r=this.locks.get(t);return r?r.expiresAt>Date.now():!1}getLockOwner(t){let r=this.locks.get(t);return!r||r.expiresAt<=Date.now()?null:r.ownerId}};var $s=le(require("fs")),D_=le(require("path")),B_=le(nt()),Yu=class{logger;queue=[];maxCapacity;persistenceFilePath;constructor(t=1e4,r,n){this.maxCapacity=t,this.logger=r||(0,B_.createLogger)("CloudPendingMessageQueue"),this.persistenceFilePath=n,this.loadFromDisk()}loadFromDisk(){if(this.persistenceFilePath)try{if($s.default.existsSync(this.persistenceFilePath)){let t=$s.default.readFileSync(this.persistenceFilePath,"utf8");if(t&&t.trim()){let r=JSON.parse(t);Array.isArray(r)&&(this.queue.push(...r),this.logger.info(`\u{1F4E6} Restored ${r.length} pending delta messages from disk: ${this.persistenceFilePath}`))}}}catch(t){this.logger.warn(`Failed to restore pending messages from disk (${this.persistenceFilePath}): ${t?.message}`)}}saveToDisk(){if(this.persistenceFilePath)try{let t=D_.default.dirname(this.persistenceFilePath);$s.default.existsSync(t)||$s.default.mkdirSync(t,{recursive:!0}),$s.default.writeFileSync(this.persistenceFilePath,JSON.stringify(this.queue),"utf8")}catch(t){this.logger.warn(`Failed to save pending messages to disk (${this.persistenceFilePath}): ${t?.message}`)}}enqueue(t){if(this.queue.length>=this.maxCapacity){let r=this.queue.shift();this.logger.warn(`Queue capacity reached (${this.maxCapacity}). Dropped oldest message: ${r?.id}`)}this.queue.push(t),this.saveToDisk(),this.logger.debug(`Enqueued pending message ${t.id} for account ${t.accountId} (Total pending: ${this.queue.length})`)}getDeltas(t,r=0){return this.queue.filter(n=>{let i=!t||n.accountId===t,o=n.timestamp>=r;return i&&o})}purgeSynced(t,r){let n=this.queue.length,i=[];for(let s=0;s<this.queue.length;s++){let a=this.queue[s];a.timestamp<=t&&(!r||a.accountId===r)&&i.push(s)}for(let s=i.length-1;s>=0;s--)this.queue.splice(i[s],1);let o=n-this.queue.length;return o>0&&(this.saveToDisk(),this.logger.info(`Purged ${o} synced delta messages from queue.`)),o}getCount(){return this.queue.length}clear(){this.queue.length=0,this.saveToDisk()}};var L_=le(nt()),Xu=class{logger;campaigns=new Map;rules=new Map;threadHistory=new Map;lastReplyTimes=new Map;aiConfig={enabled:!1};constructor(t,r){this.logger=t||(0,L_.createLogger)("HeadlessAutomationEngine"),r&&this.configure(r)}configure(t){this.aiConfig={...this.aiConfig,...t},this.logger.info(`[HeadlessAutomation] Configured AI provider: ${this.aiConfig.provider||"none"} (model: ${this.aiConfig.model||"none"}, enabled: ${this.aiConfig.enabled===!0})`)}getAiConfig(){return{...this.aiConfig}}registerCampaign(t){this.campaigns.set(t.id,t),this.logger.info(`Loaded campaign ${t.id} (${t.name})`)}registerRule(t){this.rules.set(t.id,t),this.logger.info(`Loaded automation rule ${t.id} (${t.name})`)}async evaluateIncomingMessage(t){if(t.isSelf||t.senderType&&t.senderType!=="customer"||!t.content||typeof t.content!="string"||!t.content.trim())return null;let r=t.threadId||t.conversationId||t.senderId,n=Date.now(),i=this.lastReplyTimes.get(r)||0;if(n-i<3e3)return this.logger.debug(`[HeadlessAutomation] Rate limit hit for thread ${r}. Skipping reply.`),null;let o=t.content.trim(),s=this.getThreadHistory(r);if(s.push({role:"user",content:o,timestamp:n}),s.length>6&&s.splice(0,s.length-6),!this.aiConfig||this.aiConfig.enabled!==!0||!this.aiConfig.provider)return this.logger.debug(`[HeadlessAutomation] Bot AI is disabled or unconfigured. Message saved, no auto-reply sent for thread ${r}.`),null;let a=t.accountId,c=this.aiConfig.accountBotConfigs,u=a&&c?c[a]:void 0;if(!u||!u.isBotEnabled)return this.logger.debug(`[HeadlessAutomation] Account [${a||"unknown"}] has not been configured or enabled for Bot AI by user in Chatbot settings. Message saved, no auto-reply sent.`),null;let l=t,p=!!l.isGroup||!!l.groupId||typeof t.threadId=="string"&&t.threadId.startsWith("g")||typeof t.conversationId=="string"&&t.conversationId.startsWith("g"),d=u.replyTarget||"all";if(d==="individual"&&p)return this.logger.debug(`[HeadlessAutomation] Account [${a}] configured for individual chat only. Skipping group message ${r}.`),null;if(d==="group"&&!p)return this.logger.debug(`[HeadlessAutomation] Account [${a}] configured for group chat only. Skipping direct message ${r}.`),null;let h=u.scheduleType||"always";if(h!=="always"){let S=new Date().getHours(),k=u.scheduleStartHour??8,T=u.scheduleEndHour??18;if(h==="working_hours"){if(S<k||S>=T)return this.logger.debug(`[HeadlessAutomation] Outside working hours (${S}h, allowed: ${k}h-${T}h). Skipping reply.`),null}else if(h==="outside_hours"&&S>=k&&S<T)return this.logger.debug(`[HeadlessAutomation] Inside working hours (${S}h, allowed outside: ${k}h-${T}h). Skipping reply.`),null}let g=u.excludeContactIds||[];if(!p&&g.length>0){let S=String(t.senderId||"");if(g.includes(S))return this.logger.debug(`[HeadlessAutomation] Sender ${S} is in contact blacklist. Skipping reply.`),null}if(p){let S=String(l.groupId||l.threadId||r||""),k=u.excludeGroupIds||[],T=u.includeGroupIds||[];if(k.length>0&&k.includes(S))return this.logger.debug(`[HeadlessAutomation] Group ${S} is in group blacklist. Skipping reply.`),null;if(T.length>0&&!T.includes(S))return this.logger.debug(`[HeadlessAutomation] Group ${S} is not in group whitelist. Skipping reply.`),null}let w=u.excludeKeywords||[],_=u.includeKeywords||[],m=o.toLowerCase();if(w.length>0&&w.some(k=>{let T=k.trim().toLowerCase();return T.length>0&&m.includes(T)}))return this.logger.debug("[HeadlessAutomation] Message contains blacklisted keyword. Skipping reply."),null;if(_.length>0&&!_.some(k=>{let T=k.trim().toLowerCase();return T.length>0&&m.includes(T)}))return this.logger.debug("[HeadlessAutomation] Message does not match any whitelist keyword. Skipping reply."),null;let v=u.systemPrompt&&u.systemPrompt.trim()?u.systemPrompt:this.aiConfig.systemPrompt;if(this.aiConfig.provider==="rule_based")return this.aiConfig.fallbackMessage&&this.aiConfig.fallbackMessage.trim().length>0?(this.lastReplyTimes.set(r,n),this.aiConfig.fallbackMessage.trim()):null;let x=this.aiConfig.provider,y=this.aiConfig.apiKey;if(y||(x==="openai"?y=process.env.OPENAI_API_KEY:x==="deepseek"?y=process.env.DEEPSEEK_API_KEY:x==="anthropic"?y=process.env.ANTHROPIC_API_KEY:x==="custom"?y=process.env.CUSTOM_AI_API_KEY:x==="gemini"&&(y=process.env.GEMINI_API_KEY||process.env.GOOGLE_API_KEY)),!y&&x!=="custom")return this.logger.debug(`[HeadlessAutomation] No API key found for provider [${x}]. No auto-reply sent.`),null;try{let S=null;if(x==="openai"||x==="custom"||x==="deepseek")S=await this.callOpenAiCompatible(o,s,y||"",v);else if(x==="anthropic")S=await this.callAnthropic(o,s,y||"",v);else if(x==="gemini")S=await this.callGemini(o,s,y||"",v);else return this.logger.warn(`[HeadlessAutomation] Unsupported AI provider [${x}]. No reply generated.`),null;if(S&&S.trim().length>0){let k=S.trim();return s.push({role:"model",content:k,timestamp:Date.now()}),this.lastReplyTimes.set(r,Date.now()),k}}catch(S){this.logger.warn(`[HeadlessAutomation] AI generation error with provider [${x}] (${S?.message}).`)}return this.aiConfig.fallbackMessage&&this.aiConfig.fallbackMessage.trim().length>0?(this.lastReplyTimes.set(r,Date.now()),this.aiConfig.fallbackMessage.trim()):null}getThreadHistory(t){let r=this.threadHistory.get(t);return r||(r=[],this.threadHistory.set(t,r)),r}async callGemini(t,r,n,i){let s=`https://generativelanguage.googleapis.com/v1beta/models/${this.aiConfig.model||"gemini-2.0-flash"}:generateContent?key=${n}`,a=r.map(d=>({role:d.role==="model"?"model":"user",parts:[{text:d.content}]}));(a.length===0||a[a.length-1].parts[0]?.text!==t)&&a.push({role:"user",parts:[{text:t}]});let c={contents:a,generationConfig:{temperature:this.aiConfig.temperature??.7,maxOutputTokens:this.aiConfig.maxTokens??300}},u=i||this.aiConfig.systemPrompt;u&&u.trim()&&(c.systemInstruction={parts:[{text:u.trim()}]});let l=new AbortController,p=setTimeout(()=>l.abort(),7e3);try{let d=await fetch(s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(c),signal:l.signal});if(!d.ok){let w=await d.text();return this.logger.warn(`[HeadlessAutomation] Gemini API returned status ${d.status}: ${w.slice(0,200)}`),null}return(await d.json())?.candidates?.[0]?.content?.parts?.[0]?.text||null}finally{clearTimeout(p)}}async callOpenAiCompatible(t,r,n,i){let o=(this.aiConfig.baseUrl||(this.aiConfig.provider==="deepseek"?"https://api.deepseek.com/v1":"https://api.openai.com/v1")).replace(/\/+$/,"");o.includes("api.deepseek.com")&&!o.endsWith("/v1")?o+="/v1":(o.includes("11434")||o.includes("ollama"))&&(o=o.replace(/\/api$/,"").replace(/\/+$/,""),o.endsWith("/v1")||(o+="/v1"));let s=`${o}/chat/completions`,a=this.aiConfig.model||(this.aiConfig.provider==="deepseek"?"deepseek-chat":this.aiConfig.provider==="openai"?"gpt-4o-mini":"deepseek-chat"),c=i||this.aiConfig.systemPrompt,u=[...c&&c.trim()?[{role:"system",content:c.trim()}]:[],...r.map(h=>({role:h.role==="model"?"assistant":"user",content:h.content}))],l={"Content-Type":"application/json"};n&&(l.Authorization=`Bearer ${n}`);let p=new AbortController,d=setTimeout(()=>p.abort(),8e3);try{let h=await fetch(s,{method:"POST",headers:l,body:JSON.stringify({model:a,messages:u,temperature:this.aiConfig.temperature??.7,max_tokens:this.aiConfig.maxTokens??300}),signal:p.signal});if(!h.ok){let w=await h.text();return this.logger.warn(`[HeadlessAutomation] OpenAI-compatible API returned status ${h.status}: ${w.slice(0,200)}`),null}return(await h.json())?.choices?.[0]?.message?.content||null}finally{clearTimeout(d)}}async callAnthropic(t,r,n,i){let o="https://api.anthropic.com/v1/messages",s=this.aiConfig.model||"claude-3-5-haiku-20241022",a=r.map(l=>({role:l.role==="model"?"assistant":"user",content:l.content}));(a.length===0||a[a.length-1].content!==t)&&a.push({role:"user",content:t});let c=new AbortController,u=setTimeout(()=>c.abort(),8e3);try{let l=i||this.aiConfig.systemPrompt,p={model:s,messages:a,max_tokens:this.aiConfig.maxTokens??300,temperature:this.aiConfig.temperature??.7};l&&l.trim()&&(p.system=l.trim());let d=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":n,"anthropic-version":"2023-06-01"},body:JSON.stringify(p),signal:c.signal});if(!d.ok){let g=await d.text();return this.logger.warn(`[HeadlessAutomation] Anthropic API returned status ${d.status}: ${g.slice(0,200)}`),null}return(await d.json())?.content?.[0]?.text||null}finally{clearTimeout(u)}}clear(){this.campaigns.clear(),this.rules.clear(),this.threadHistory.clear(),this.lastReplyTimes.clear()}};var N_=le(nt()),Qu=class{logger;constructor(t){this.logger=t||(0,N_.createLogger)("PushNotificationDispatcher")}async dispatchMessageAlert(t,r){let n=`${r.senderName} (${r.platform.toUpperCase()})`,i=r.content||"New multimedia message received";return this.sendNotification({recipientToken:t,title:n,body:i,data:{messageId:r.id,threadId:r.threadId,platform:r.platform,accountId:r.accountId}})}async sendNotification(t){return this.logger.debug(`Dispatching push notification to device token: ${t.recipientToken.slice(0,8)}...`),!0}};var I$=le(require("http")),P$=require("url"),O$=le(nt());var T$=le(nt()),Ya=class{static logger=(0,T$.createLogger)("ChannelRunnerFactory");static async createRunner(t,r,n,i){let o=(t||"zalo").toLowerCase(),s=o==="web"||o.includes("zalo")?"zalo":o;try{if(s==="zalo"){let{ZaloChannelRunner:a}=await Promise.resolve().then(()=>(TL(),RL));return new a(r,n,i)}if(s==="facebook"){let{FacebookChannelRunner:a}=await Promise.resolve().then(()=>(p6(),u6));return new a(r,n,i)}if(s==="telegram"){let{TelegramChannelRunner:a}=await Promise.resolve().then(()=>(g6(),m6));return new a(r,n,i)}if(s==="whatsapp"){let{WhatsAppChannelRunner:a}=await Promise.resolve().then(()=>(R$(),C$));return new a(r,n,i)}return this.logger.warn(`Unsupported platform for ChannelRunner: ${t}`),null}catch(a){return this.logger.error(`Failed to dynamically initialize runner for ${s}:${r}:`,a?.message||a),null}}};var tm=class{constructor(t,r,n,i,o){this.port=t;this.engine=r;this.lockManager=n;this.deltaQueue=i;this.logger=o||(0,O$.createLogger)("WorkerHttpServer")}logger;server=null;async start(){if(!this.server)return new Promise((t,r)=>{this.server=I$.default.createServer((n,i)=>{this.handleRequest(n,i).catch(o=>{this.logger.error("Unhandled HTTP error:",o),i.headersSent||(i.writeHead(500,{"Content-Type":"application/json"}),i.end(JSON.stringify({error:"Internal Server Error"})))})}),this.server.listen(this.port,()=>{this.logger.info(`\u{1F680} Worker HTTP Server listening on port ${this.port}`),t()}),this.server.on("error",n=>{this.logger.error(`Worker HTTP Server error on port ${this.port}:`,n),r(n)})})}async stop(){if(this.server)return new Promise(t=>{this.server?.close(()=>{this.logger.info("Worker HTTP Server closed."),this.server=null,t()})})}async handleRequest(t,r){let n=new P$.URL(t.url||"/",`http://${t.headers.host||"localhost"}`),i=n.pathname,o=(t.method||"GET").toUpperCase();if(r.setHeader("Access-Control-Allow-Origin","*"),r.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS"),r.setHeader("Access-Control-Allow-Headers","Content-Type, X-Softty-User-Id, X-Desktop-Secret, Authorization"),o==="OPTIONS"){r.writeHead(204),r.end();return}if(o==="GET"&&i==="/health"){let s=this.engine.getMetrics();r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({status:"healthy",timestamp:Date.now(),pendingDeltaMessages:this.deltaQueue.getCount(),metrics:s}));return}if(i.startsWith("/api/v1/")){let s=this.engine.config.desktopSecret;if(s){let a=t.headers["x-desktop-secret"]||t.headers.authorization;if((typeof a=="string"&&a.startsWith("Bearer ")?a.slice(7):a)!==s){r.writeHead(401,{"Content-Type":"application/json"}),r.end(JSON.stringify({error:"Unauthorized: Invalid or missing X-Desktop-Secret"}));return}}}if(o==="POST"&&i==="/api/v1/sentinel/handover"){let s=await this.readJsonBody(t),{deviceId:a,sessions:c,aiConfig:u}=s||{};if(u&&(this.engine.automationEngine.configure(u),this.logger.info(`[Handover] Configured 24/7 AI automation engine with provider: ${u.provider||"gemini"}, model: ${u.model||"default"}`)),!Array.isArray(c)){r.writeHead(400,{"Content-Type":"application/json"}),r.end(JSON.stringify({error:"Invalid sessions array payload"}));return}this.logger.info(`[Handover] Received handover request from device ${a||"unknown"} with ${c.length} sessions.`);let l=0;for(let p of c){if(!p.id||!p.nightWorkerEnabled)continue;if(!this.lockManager.acquireLock(p.id,`worker_${p.id}`)){this.logger.warn(`Skipping account ${p.id} because lock was not acquired.`);continue}let h=(p.platform||"zalo").toLowerCase(),g=h==="web"||h.includes("zalo")?"zalo":h,w=await Ya.createRunner(g,p.id,p.sessionData);w&&(this.engine.registerRunner(w),await w.start(),this.engine.registerAccount({id:p.id,platform:g,accountName:p.accountName||p.id,status:"active",nightWorkerEnabled:!0}),l++)}r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({success:!0,message:"Sessions handed over successfully",activatedCount:l,timestamp:Date.now()}));return}if(o==="POST"&&i==="/api/v1/sentinel/reclaim"){let s=await this.readJsonBody(t),{deviceId:a}=s||{};this.logger.info(`[Reclaim] Master device ${a||"desktop"} reclaiming all active sessions. Stopping cloud runners...`);let c=this.engine.channelRunnerRegistry.getCount();await this.engine.channelRunnerRegistry.stopAll(),this.lockManager.releaseAllForOwner("worker"),r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({success:!0,reclaimedCount:c,timestamp:Date.now()}));return}if(i==="/api/v1/sentinel/night-config"){if(o==="POST"){let s=await this.readJsonBody(t);s&&(this.engine.automationEngine.configure(s),this.logger.info(`[NightConfig] Updated 24/7 AI config dynamically: provider=${s.provider||"gemini"}, model=${s.model||"default"}`)),r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({success:!0,config:this.engine.automationEngine.getAiConfig()}));return}else if(o==="GET"){r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({success:!0,config:this.engine.automationEngine.getAiConfig()}));return}}if(o==="GET"&&i==="/api/v1/sync/delta"){let s=n.searchParams.get("accountId")||void 0,a=parseInt(n.searchParams.get("since")||"0",10),c=this.deltaQueue.getDeltas(s,a);this.logger.info(`[DeltaSync] Serving ${c.length} night messages (since: ${a}, account: ${s||"all"})`),r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({success:!0,messages:c,count:c.length,syncedTimestamp:Date.now()}));return}r.writeHead(404,{"Content-Type":"application/json"}),r.end(JSON.stringify({error:"Endpoint not found"}))}readJsonBody(t){return new Promise(r=>{let n="";t.on("data",i=>{n+=i}),t.on("end",()=>{try{r(JSON.parse(n))}catch{r({})}})})}};var ec=le(nt());var Xa=require("child_process"),F$=le(nt()),rm=class e{logger;timer;isUpdating=!1;constructor(t){this.logger=t||(0,F$.createLogger)("WorkerAutoUpdater")}static isNewerVersion(t,r){let n=l=>l.replace(/^v/,"").trim().split(".").map(p=>parseInt(p,10)||0),[i=0,o=0,s=0]=n(t),[a=0,c=0,u=0]=n(r);return i>a||i===a&&o>c||i===a&&o===c&&s>u}async fetchLatestVersion(){let t="@softtynet/zplus-worker";try{let r=new AbortController,n=setTimeout(()=>r.abort(),5e3),i=await fetch(`https://registry.npmjs.org/${t}/latest`,{signal:r.signal,headers:{Accept:"application/json"}});if(clearTimeout(n),i.ok){let o=await i.json();if(o?.version)return String(o.version).trim()}}catch{}try{return(0,Xa.execSync)(`npm view ${t} version`,{encoding:"utf-8",timeout:8e3,stdio:["ignore","pipe","ignore"]}).trim()}catch{return null}}async checkUpdate(t){let r=await this.fetchLatestVersion();return r?{hasUpdate:e.isNewerVersion(r,t),latestVersion:r}:{hasUpdate:!1,latestVersion:t}}async performUpdateAndRestart(t){if(this.isUpdating)return this.logger.warn("C\u1EADp nh\u1EADt \u0111ang di\u1EC5n ra, b\u1ECF qua y\xEAu c\u1EA7u tr\xF9ng l\u1EB7p."),!1;this.isUpdating=!0;let r=t?`@softtynet/zplus-worker@${t}`:"@softtynet/zplus-worker@latest";this.logger.info(`\u{1F680} [AutoUpdater] B\u1EAFt \u0111\u1EA7u t\u1EF1 \u0111\u1ED9ng n\xE2ng c\u1EA5p Worker l\xEAn ${r}...`);try{return(0,Xa.execSync)(`npm install -g ${r}`,{stdio:"inherit",timeout:12e4}),this.logger.info(`\u2705 [AutoUpdater] \u0110\xE3 c\xE0i \u0111\u1EB7t th\xE0nh c\xF4ng ${r}!`),this.triggerRestart(),!0}catch(n){return this.isUpdating=!1,this.logger.error(`\u274C [AutoUpdater] N\xE2ng c\u1EA5p th\u1EA5t b\u1EA1i: ${n?.message||n}`),!1}}triggerRestart(){try{if((0,Xa.execSync)("pm2 jlist",{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:5e3}).includes("zplus-worker")){this.logger.info("\u{1F504} [AutoUpdater] \u0110ang ph\xE1t l\u1EC7nh kh\u1EDFi \u0111\u1ED9ng l\u1EA1i PM2 ti\u1EBFn tr\xECnh 'zplus-worker'..."),(0,Xa.spawn)("pm2",["restart","zplus-worker"],{detached:!0,stdio:"ignore"}).unref(),setTimeout(()=>process.exit(0),1e3);return}}catch{}if(!!process.stdout.isTTY&&!process.env.PM2_HOME&&!process.env.pm_id&&!process.env.INVOCATION_ID){this.logger.warn("\u26A0\uFE0F [AutoUpdater] \u0110\xE3 t\u1EA3i phi\xEAn b\u1EA3n m\u1EDBi. V\xEC \u0111ang ch\u1EA1y Worker tr\u1EF1c ti\u1EBFp tr\xEAn Terminal (kh\xF4ng qua PM2), vui l\xF2ng nh\u1EA5n Ctrl+C v\xE0 ch\u1EA1y l\u1EA1i \u0111\u1EC3 n\u1EA1p m\xE3 m\u1EDBi."),this.isUpdating=!1;return}this.logger.info("\u{1F504} [AutoUpdater] Ti\u1EBFn tr\xECnh s\u1EBD tho\xE1t an to\xE0n (exit 0) \u0111\u1EC3 h\u1EC7 th\u1ED1ng t\u1EF1 kh\u1EDFi \u0111\u1ED9ng l\u1EA1i v\u1EDBi b\u1EA3n m\u1EDBi..."),setTimeout(()=>process.exit(0),1500)}startPeriodicAutoUpdate(t,r=3600*1e3){this.timer&&clearInterval(this.timer),setTimeout(()=>{this.runCheckCycle(t).catch(()=>{})},6e4),this.timer=setInterval(()=>{this.runCheckCycle(t).catch(()=>{})},r),this.logger.info(`\u23F0 [AutoUpdater] \u0110\xE3 k\xEDch ho\u1EA1t c\u01A1 ch\u1EBF t\u1EF1 \u0111\u1ED9ng c\u1EADp nh\u1EADt ng\u1EA7m (chu k\u1EF3: ${Math.round(r/6e4)} ph\xFAt).`)}stop(){this.timer&&(clearInterval(this.timer),this.timer=void 0)}async runCheckCycle(t){try{let{hasUpdate:r,latestVersion:n}=await this.checkUpdate(t);r&&(this.logger.info(`\u{1F514} [AutoUpdater] Ph\xE1t hi\u1EC7n phi\xEAn b\u1EA3n m\u1EDBi: v${n} (hi\u1EC7n t\u1EA1i: v${t}). \u0110ang t\u1EF1 \u0111\u1ED9ng n\xE2ng c\u1EA5p...`),await this.performUpdateAndRestart(n))}catch(r){this.logger.debug("Auto-update check cycle error:",r?.message)}}};var Di=le(require("fs")),nm=le(require("path")),D$=le(require("os")),B$=le(require("readline")),im=le(nt()),Qa=class{logger;constructor(t){this.logger=t||(0,im.createLogger)("WorkerAuthManager")}getAuthFilePath(){let t=process.env.DATA_DIR||nm.default.join(D$.default.homedir(),".zplus");return nm.default.join(t,"worker_auth.json")}loadStoredAuth(){try{let t=this.getAuthFilePath();if(!Di.default.existsSync(t))return null;let r=Di.default.readFileSync(t,"utf-8"),n=JSON.parse(r);return!n||!n.sessionToken?null:n}catch(t){return this.logger.debug("Failed to read worker_auth.json:",t?.message),null}}saveAuth(t){try{let r=this.getAuthFilePath(),n=nm.default.dirname(r);Di.default.existsSync(n)||Di.default.mkdirSync(n,{recursive:!0,mode:448}),Di.default.writeFileSync(r,JSON.stringify(t,null,2),{encoding:"utf-8",mode:384});try{Di.default.chmodSync(r,384)}catch{}this.logger.info(`\u2705 Phi\xEAn x\xE1c th\u1EF1c \u0111\xE3 \u0111\u01B0\u1EE3c l\u01B0u an to\xE0n t\u1EA1i: ${r} (Quy\u1EC1n 0600 - Ch\u1EC9 Owner)`)}catch(r){this.logger.error("Could not save worker_auth.json:",r)}}clearAuth(){try{let t=this.getAuthFilePath();Di.default.existsSync(t)&&Di.default.unlinkSync(t),this.logger.info("\u0110\xE3 x\xF3a phi\xEAn \u0111\u0103ng nh\u1EADp c\u1EE7a Worker.")}catch(t){this.logger.debug("clearAuth error:",t?.message)}}async verifyEntitlements(t,r="https://api.softty.net/v1",n="699cfc3100136099c1c1",i="default"){try{let o=`${r}/account`,s=t.includes(".")&&t.split(".").length===3,a={"Content-Type":"application/json","X-Appwrite-Project":n};s?a["X-Appwrite-JWT"]=t:(a["X-Appwrite-Session"]=t,a.Cookie=`a_session_${n}=${t}; a_session_${n}_legacy=${t}`,t.startsWith("eyJ")&&(a["X-Fallback-Cookies"]=JSON.stringify({[`a_session_${n}`]:t,[`a_session_${n}_legacy`]:t})));let c=await fetch(o,{method:"GET",headers:a});if(!c.ok)return{allowed:!1,userId:"",userName:"Unknown",email:"",teamId:i,isOwner:!1,isPremium:!1,reason:`Phi\xEAn \u0111\u0103ng nh\u1EADp kh\xF4ng h\u1EE3p l\u1EC7 ho\u1EB7c \u0111\xE3 h\u1EBFt h\u1EA1n (HTTP ${c.status}).`};let u=await c.json(),l=u.$id||u.id||"",p=u.name||"Ng\u01B0\u1EDDi d\xF9ng ZPlus",d=u.email||"",h=Array.isArray(u.labels)?u.labels:[],g=u.prefs||{},_=!h.some(y=>y.toLowerCase()==="member")&&g.isOwner!==!1,m=h.some(y=>y.toLowerCase()==="free")||g.tier==="free",v=!m&&(g.isPremium===!0||h.some(y=>y.toLowerCase()==="premium"||y.toLowerCase()==="enterprise")),x=g.teamId||g.storage?.teamId||u.teamId||i;if((!x||x==="default")&&g.entitlements)try{let y=typeof g.entitlements=="string"?JSON.parse(g.entitlements):g.entitlements;y?.storage?.teamId&&(x=y.storage.teamId)}catch{}if((!x||x==="default")&&u.entitlements)try{let y=typeof u.entitlements=="string"?JSON.parse(u.entitlements):u.entitlements;y?.storage?.teamId&&(x=y.storage.teamId)}catch{}if(!x||x==="default")try{let y=await fetch(`${r}/teams`,{method:"GET",headers:a});if(y.ok){let S=await y.json().catch(()=>({})),k=Array.isArray(S.teams)?S.teams:[];k.length>0&&k[0].$id&&(x=k[0].$id)}}catch{}return m?{allowed:!1,userId:l,userName:p,email:d,teamId:x,isOwner:_,isPremium:!1,reason:`\u26A0\uFE0F T\xE0i kho\u1EA3n [${d}] \u0111ang \u1EDF G\xF3i Mi\u1EC5n Ph\xED (Free Tier). G\xF3i n\xE0y kh\xF4ng h\u1ED7 tr\u1EE3 c\u1EE5m Worker 24/7 (Y\xEAu c\u1EA7u g\xF3i Team Enterprise).`}:_?{allowed:!0,userId:l,userName:p,email:d,teamId:x,isOwner:!0,isPremium:!0,reason:`\u2705 X\xE1c th\u1EF1c th\xE0nh c\xF4ng: Tr\u01B0\u1EDFng nh\xF3m [${p}] (${d}) - G\xF3i Doanh Nghi\u1EC7p Active.`}:{allowed:!1,userId:l,userName:p,email:d,teamId:x,isOwner:!1,isPremium:v,reason:`\u26A0\uFE0F T\xE0i kho\u1EA3n [${d}] l\xE0 Th\xE0nh vi\xEAn (Member). \u0110\u1EC3 b\u1EA3o v\u1EC7 d\u1EEF li\u1EC7u c\xF4ng ty, ch\u1EC9 Tr\u01B0\u1EDFng nh\xF3m (Team Owner) m\u1EDBi c\xF3 quy\u1EC1n k\xEDch ho\u1EA1t c\u1EE5m Worker cho Team.`}}catch(o){return{allowed:!1,userId:"",userName:"Unknown",email:"",teamId:i,isOwner:!1,isPremium:!1,reason:`L\u1ED7i k\u1EBFt n\u1ED1i ki\u1EC3m tra quy\u1EC1n h\u1EA1n: ${o?.message}`}}}async loginWithCredentials(t,r,n="https://api.softty.net/v1",i="699cfc3100136099c1c1"){let o=t?.trim(),s=r;if(!o||!s){console.log(`
|
|
107
|
+
`),fe=yle.bind(null,{[s$]:"",[a$]:s,[l$]:V,[c$]:xw,[bw]:C,[u$]:N}),de="";p!==null&&(d===void 0?de=fe(p):de=fe(Object.assign({},p,{name:d})));let be=a instanceof Function?a:a?g$:Ule,xe=be().indexOf(":")+1;if(v&&!g)throw Error("customLevels is required if useOnlyCustomLevels is set true");if(_&&typeof _!="function")throw Error(`Unknown mixin type "${typeof _}" - expected "function"`);if(z&&typeof z!="string")throw Error(`Unknown msgPrefix type "${typeof z}" - expected "string"`);ple(h,g,v);let K=h$(g,v);typeof n.emit=="function"&&n.emit("message",{code:"PINO_CONFIG",config:{levels:K,messageKey:c,errorKey:u}}),hle(w);let ie=dle(w);return Object.assign(t,{levels:K,[Ole]:ie,[Fle]:v,[kle]:n,[_le]:be,[Sle]:xe,[c$]:xw,[bw]:C,[l$]:V,[Ale]:J,[Cle]:Q,[Rle]:c,[Tle]:u,[Ile]:l,[Ble]:l?`,${JSON.stringify(l)}:{`:"",[a$]:s,[Ple]:_,[Lle]:m,[s$]:de,[u$]:N,[Dle]:y,silent:ble,onChild:T,[Nle]:z}),Object.setPrototypeOf(t,lle()),fle(t),t[Ele](h),t}un.exports=vw;un.exports.destination=(e=process.stdout.fd)=>typeof e=="object"?(e.dest=o$(e.dest||process.stdout.fd),i$(e)):i$({dest:o$(e),minLength:0});un.exports.transport=rw();un.exports.multistream=n$();un.exports.levels=h$();un.exports.stdSerializers=Hle;un.exports.stdTimeFunctions=Object.assign({},f$);un.exports.symbols=d$;un.exports.version=vle;un.exports.default=vw;un.exports.pino=vw});function em(e,t){let r=e.key,n=e.message,i=r.remoteJid||"",o="";r.fromMe?o=t:o=r.participant||r.remoteJid||"";let s="",a="text",c="";n?n.conversation?(s=n.conversation,a="text"):n.extendedTextMessage?(s=n.extendedTextMessage.text||"",a="text"):n.imageMessage?(s=n.imageMessage.caption||"",a="image",c=n.imageMessage.url||""):n.videoMessage?(s=n.videoMessage.caption||"",a="video",c=n.videoMessage.url||""):n.audioMessage?(a="audio",c=n.audioMessage.url||""):n.documentMessage?(s=n.documentMessage.title||n.documentMessage.fileName||"",a="file",c=n.documentMessage.url||""):n.stickerMessage?(a="sticker",c=n.stickerMessage.url||""):n.protocolMessage||n.senderKeyDistributionMessage?(a="system",s="System message"):(a="other",s="[Tin nh\u1EAFn kh\xF4ng \u0111\u01B0\u1EE3c h\u1ED7 tr\u1EE3]"):(a="other",s="");let u={rawMsg:Wle(e)};if(e.pushName&&(u.pushName=e.pushName),n?.extendedTextMessage?.contextInfo?.quotedMessage){let p=n.extendedTextMessage.contextInfo;u.quotedMessage={participant:p.participant,stanzaId:p.stanzaId,text:p.quotedMessage?.conversation||p.quotedMessage?.extendedTextMessage?.text||""}}let l=e.messageTimestamp?Number(e.messageTimestamp)*1e3:Date.now();return{id:r.id||"",conversationId:i,senderId:o,senderName:e.pushName||void 0,text:s,type:a,mediaUrl:c,timestamp:l,platform:"whatsapp",isFromMe:!!r.fromMe,metadata:u}}function Wle(e){if(!e||typeof e!="object")return e;let t={};if(e.key&&(t.key={remoteJid:e.key.remoteJid,fromMe:e.key.fromMe,id:e.key.id,participant:e.key.participant}),e.pushName&&(t.pushName=e.pushName),e.messageTimestamp&&(t.messageTimestamp=e.messageTimestamp),e.status&&(t.status=e.status),e.message){let r=e.message;t.message={},r.conversation&&(t.message.conversation=r.conversation),r.extendedTextMessage&&(t.message.extendedTextMessage={text:r.extendedTextMessage.text},r.extendedTextMessage.contextInfo&&(t.message.extendedTextMessage.contextInfo={stanzaId:r.extendedTextMessage.contextInfo.stanzaId,participant:r.extendedTextMessage.contextInfo.participant})),r.imageMessage&&(t.message.imageMessage={caption:r.imageMessage.caption,mimetype:r.imageMessage.mimetype}),r.videoMessage&&(t.message.videoMessage={caption:r.videoMessage.caption,mimetype:r.videoMessage.mimetype}),r.audioMessage&&(t.message.audioMessage={mimetype:r.audioMessage.mimetype,seconds:r.audioMessage.seconds}),r.documentMessage&&(t.message.documentMessage={title:r.documentMessage.title,fileName:r.documentMessage.fileName,mimetype:r.documentMessage.mimetype}),r.stickerMessage&&(t.message.stickerMessage={mimetype:r.stickerMessage.mimetype})}return t}var x$=F(()=>{"use strict"});function fu(e,t){let r=String(e.id||e.jid||""),n=String(e.name||e.verifiedName||e.notify||"WhatsApp User"),i=String(e.imgUrl||e.avatar||"");return{id:r,name:n,avatarUrl:i||void 0,platform:"whatsapp",phoneNumber:t||e.phoneNumber||void 0,rawContact:e}}function b$(e){let t=String(e.id||e.jid||""),r=String(e.name||e.displayName||"WhatsApp Chat"),n=String(e.imgUrl||e.avatar||""),i="direct";return(t.endsWith("@g.us")||e.isGroup)&&(i="group"),{id:t,name:r,avatarUrl:n||void 0,type:i,unreadCount:Number(e.unreadCount||0),platform:"whatsapp",rawConversation:e}}var v$=F(()=>{"use strict"});var E$={};qi(E$,{WhatsAppAdapter:()=>ww});var vo,w$,_$,S$,k$,ww,A$=F(()=>{"use strict";vo=le(require("@whiskeysockets/baileys")),w$=le(y$()),_$=le(Rd()),S$=le(Id()),k$=le(Dd());kl();x$();v$();ww=class{accountId;platform="whatsapp";eventBus=new ei;status="disconnected";socket=null;session=null;isReconnecting=!1;chatsMap=new Map;contactsMap=new Map;constructor(t){this.accountId=t}async initialize(t){this.session=t,this.status="connecting",this.eventBus.emit("session:status_changed","connecting");let r=t.authData.sessionPath||`./sessions/whatsapp_${this.accountId}`;try{let{state:n,saveCreds:i}=await(0,vo.useMultiFileAuthState)(r),o=(0,w$.default)({level:"silent"}),s=[2,3e3,1023223821];try{let c=await(0,vo.fetchLatestBaileysVersion)();c&&c.version&&(s=c.version)}catch{}let a={version:s,auth:n,logger:o,printQRInTerminal:!1,defaultQueryTimeoutMs:3e4,connectTimeoutMs:3e4};if(t.proxy){let c=this.createProxyAgent(t.proxy);c&&(a.agent=c)}this.socket=(0,vo.default)(a),this.socket.ev.on("creds.update",i),this.setupListeners()}catch(n){throw this.status="disconnected",this.eventBus.emit("session:status_changed","disconnected",n.message||String(n)),n}}async disconnect(){if(this.isReconnecting=!1,this.socket){try{this.socket.end(void 0)}catch{}this.socket=null}this.status="disconnected",this.eventBus.emit("session:status_changed","disconnected")}async sendMessage(t,r){if(!this.socket)throw new Error("WhatsApp adapter not initialized");await this.sendTyping(t,!0);let n=Math.floor(Math.random()*2e3)+1500;await new Promise(s=>setTimeout(s,n)),await this.sendTyping(t,!1);let i={};if(r.type==="text")i={text:r.text};else if(r.type==="image")i={image:{url:r.url||r.filePath},caption:r.caption||""};else if(r.type==="sticker")i={sticker:{url:r.url||r.filePath||r.stickerId}};else if(r.type==="file")i={document:{url:r.url||r.filePath},fileName:r.filename||"file"};else throw new Error(`Unsupported message payload type: ${r.type}`);r.quoteId&&(i.contextInfo={stanzaId:r.quoteId,participant:t.endsWith("@g.us")?void 0:t,quotedMessage:{conversation:"[Tr\xEDch d\u1EABn tin nh\u1EAFn]"}});let o=await this.socket.sendMessage(t,i);if(!o)throw new Error("Failed to send WhatsApp message");return em(o,this.accountId)}async getConversations(t=20){let r=Array.from(this.chatsMap.values());return r.sort((n,i)=>Number(i.conversationTimestamp||0)-Number(n.conversationTimestamp||0)),r.slice(0,t).map(b$)}async getMessageHistory(t,r=50,n){return[]}async getCurrentUser(){if(!this.socket)return null;let t=this.socket.authState?.creds?.me||this.socket.user;if(!t)return null;let r=t.id;r.includes(":")&&(r=r.split(":")[0]+"@s.whatsapp.net");let n=t.name||this.socket.user?.name||"WhatsApp User",i="";try{i=await this.socket.profilePictureUrl(r,"image")||""}catch{}return fu({id:r,name:n,imgUrl:i},this.accountId)}async getContactInfo(t){if(this.contactsMap.has(t))return fu(this.contactsMap.get(t));if(!this.socket)throw new Error("WhatsApp adapter not initialized");try{let r=await this.socket.profilePictureUrl(t,"image");return fu({id:t,name:"WhatsApp User",imgUrl:r})}catch{return fu({id:t,name:"WhatsApp User"})}}async markAsRead(t){if(this.socket)try{await this.socket.sendPresenceUpdate("paused",t)}catch{}}async sendTyping(t,r){if(this.socket)try{await this.socket.sendPresenceUpdate(r?"composing":"paused",t)}catch{}}getUnderlyingClient(){return this.socket}setupListeners(){this.socket&&(this.socket.ev.on("connection.update",t=>{let{connection:r,lastDisconnect:n,qr:i}=t;i&&this.eventBus.emit("auth:qr_received",i),r==="connecting"&&(this.status="connecting",this.eventBus.emit("session:status_changed","connecting")),r==="open"&&(this.status="connected",this.eventBus.emit("session:status_changed","connected")),r==="close"&&(n?.error?.output?.statusCode!==vo.DisconnectReason.loggedOut&&this.session?(this.isReconnecting=!0,this.initialize(this.session)):(this.status="disconnected",this.eventBus.emit("session:status_changed","disconnected","Session logged out or expired")))}),this.socket.ev.on("messages.upsert",t=>{if(t.type==="notify"){for(let r of t.messages)if(r.message)try{let n=em(r,this.accountId);this.eventBus.emit("message:received",n)}catch{}}}),this.socket.ev.on("presence.update",t=>{try{let r=t.id,n=Object.keys(t.presences);if(n.length>0){let i=n[0],o=t.presences[i];o&&this.eventBus.emit("chat:typing",{conversationId:r,senderId:i,isTyping:o.lastKnownPresence==="composing"})}}catch{}}),this.socket.ev.on("messaging-history.set",t=>{let{chats:r,contacts:n,messages:i}=t;if(r)for(let o of r)o.id&&this.chatsMap.set(o.id,o);if(n)for(let o of n)o.id&&this.contactsMap.set(o.id,o);if(i){for(let o of i)if(o.message)try{let s=em(o,this.accountId);this.eventBus.emit("message:received",s)}catch{}}}),this.socket.ev.on("chats.upsert",t=>{for(let r of t)r.id&&this.chatsMap.set(r.id,r)}),this.socket.ev.on("chats.update",t=>{for(let r of t)if(r.id&&this.chatsMap.has(r.id)){let n=this.chatsMap.get(r.id);this.chatsMap.set(r.id,{...n,...r})}}),this.socket.ev.on("contacts.upsert",t=>{for(let r of t)r.id&&this.contactsMap.set(r.id,r)}),this.socket.ev.on("contacts.update",t=>{for(let r of t)if(r.id&&this.contactsMap.has(r.id)){let n=this.contactsMap.get(r.id);this.contactsMap.set(r.id,{...n,...r})}}))}createProxyAgent(t){try{return t.startsWith("socks")?new _$.SocksProxyAgent(t):t.startsWith("https")?new k$.HttpsProxyAgent(t):new S$.HttpProxyAgent(t)}catch{return}}}});var C$={};qi(C$,{WhatsAppChannelRunner:()=>_w});var du,_w,R$=F(()=>{"use strict";du=le(nt()),_w=class{constructor(t,r,n,i){this.accountId=t;this.sessionData=r;this.proxyData=n;this.logger=i||(0,du.createLogger)(`WhatsAppRunner:${t}`)}platform="whatsapp";status="offline";logger;messageHandler;adapter;onMessage(t){this.messageHandler=t}async start(){let t=this.proxyData?` via resident proxy ${this.proxyData.host||this.proxyData.ip||"configured"}`:" (direct)";this.logger.info(`Starting 24/7 headless WhatsApp runner for account ${this.accountId}${t}...`);let r=this.sessionData;if(this.sessionData?.encryptedSession?r=du.CloudCrypto.parseCloudSession(this.sessionData.encryptedSession):typeof this.sessionData=="string"&&(r=du.CloudCrypto.parseCloudSession(this.sessionData)),!!(r?.sessionPath||r?.creds||r?.keys||r?.authSession))try{let{WhatsAppAdapter:i}=await Promise.resolve().then(()=>(A$(),E$));this.adapter=new i(this.accountId),this.adapter.eventBus.on("message:received",s=>{this.receiveIncomingMessage(s)});let o;if(this.proxyData?.host&&this.proxyData?.port){let s=this.proxyData.username&&this.proxyData.password?`${this.proxyData.username}:${this.proxyData.password}@`:"";o=`${this.proxyData.protocol||"http"}://${s}${this.proxyData.host}:${this.proxyData.port}`}await this.adapter.initialize({accountId:this.accountId,platform:"whatsapp",status:"connecting",authData:{sessionPath:r.sessionPath,creds:r.creds,keys:r.keys},proxy:o}),this.logger.info(`Headless WhatsApp socket connected & listening for ${this.accountId}`)}catch(i){this.logger.warn(`Could not initialize live WhatsApp client: ${i?.message}. Runner active in standby mode.`)}else this.logger.debug("No direct WhatsApp credentials/session provided. Running in standby mode.");this.status="active"}async stop(){if(this.logger.info(`Stopping headless WhatsApp runner for account ${this.accountId}...`),this.adapter)try{await this.adapter.disconnect()}catch(t){this.logger.debug(`Error disconnecting WhatsApp adapter for ${this.accountId}:`,t?.message)}this.status="offline"}getStatus(){return this.status}async sendMessage(t){if(this.adapter&&this.status==="active")try{return await this.adapter.sendMessage(t.threadId||t.conversationId,{type:t.messageType==="image"?"image":"text",text:t.content}),!0}catch(r){return this.logger.warn(`Failed to send WhatsApp message via adapter for ${this.accountId}:`,r?.message),!1}return this.logger.info(`Headless WhatsApp runner sending message ${t.id} to thread ${t.threadId}`),!0}receiveIncomingMessage(t){this.status==="active"&&(this.logger.info(`\u{1F4E9} [WhatsAppRunner:${this.accountId}] Received message ${t.id} from sender ${t.senderName||t.senderId}: "${(t.content||"").slice(0,60)}"`),this.messageHandler?.(t))}}});var Wt=le(require("fs")),oi=le(require("path")),mt=le(require("os")),K$=le(require("readline")),vt=require("child_process");var pi=le(require("os")),Hi=le(require("fs")),dc=le(require("path")),k_=le(require("crypto"));function OM(){return"1.0.38"}var Hr=OM();function Wu(){return{totalMemMb:Math.round(pi.default.totalmem()/(1024*1024)),freeMemMb:Math.round(pi.default.freemem()/(1024*1024)),cpuCount:pi.default.cpus()?.length||1,platform:pi.default.platform()}}function FM(e){try{let t=dc.default.join(pi.default.homedir(),".zplus");Hi.default.existsSync(t)||Hi.default.mkdirSync(t,{recursive:!0});let r=e?`_slot_${e.replace(/[^a-zA-Z0-9_-]/g,"")}`:"",n=dc.default.join(t,`worker_identity${r}.json`);if(Hi.default.existsSync(n)){let p=JSON.parse(Hi.default.readFileSync(n,"utf-8"));if(p&&p.workerId)return{workerId:p.workerId,workerName:p.workerName||p.workerId}}let o=(pi.default.hostname()||"node").replace(/[^a-zA-Z0-9_-]/g,"_").toLowerCase().slice(0,14),s=k_.default.randomBytes(2).toString("hex"),a=`worker_${o}${r}_${s}`,c=e?` #${e}`:"",u=`Worker ${o.toUpperCase()}${c}`,l={workerId:a,workerName:u,slot:e||"default",createdAt:new Date().toISOString()};return Hi.default.writeFileSync(n,JSON.stringify(l,null,2),"utf-8"),l}catch{let t=e?`_slot_${e}`:"",r=`worker_${pi.default.hostname().replace(/[^a-zA-Z0-9_-]/g,"_").slice(0,14)||"node"}${t}`;return{workerId:r,workerName:r}}}var Hu=class{static loadFromEnv(t=process.argv.slice(2)){let r=z=>{for(let C of t){if(C.startsWith(`--${z}=`))return C.split("=").slice(1).join("=");if(C===`--${z}`&&t[t.indexOf(C)+1])return t[t.indexOf(C)+1]}},n=r("cloud-provider")||process.env.CLOUD_PROVIDER||"appwrite",i=r("token")||process.env.CLOUD_AUTH_TOKEN||process.env.APPWRITE_SESSION_TOKEN||process.env.WORKER_TOKEN||process.env.SESSION_TOKEN,o=r("jwt")||process.env.CLOUD_JWT||process.env.APPWRITE_JWT||process.env.JWT,s=r("secret")||process.env.DESKTOP_SECRET,a=r("team-id")||process.env.TEAM_ID||"default",c=t.includes("--enable-http")||r("enable-http")==="true"||process.env.ENABLE_HTTP==="true"||!1,u=r("port")||process.env.PORT,l=u?Number(u):c?8080:void 0,p=r("endpoint")||process.env.CLOUD_ENDPOINT||process.env.CLOUD_API_ENDPOINT||process.env.APPWRITE_ENDPOINT||process.env.VITE_APPWRITE_ENDPOINT||"https://api.softty.net/v1",d=r("project-id")||process.env.CLOUD_PROJECT_ID||process.env.CLOUD_TENANT_ID||process.env.APPWRITE_PROJECT_ID||process.env.VITE_APPWRITE_PROJECT_ID||"699cfc3100136099c1c1",h=r("database-id")||process.env.CLOUD_DATABASE_ID||process.env.APPWRITE_DATABASE_ID||process.env.VITE_APPWRITE_DATABASE_ID||"zplus_app",g=r("storage-bucket-id")||process.env.STORAGE_BUCKET_ID||process.env.APPWRITE_STORAGE_BUCKET_ID||process.env.VITE_APPWRITE_STORAGE_BUCKET_ID||"zplus-media-vault",w=Math.max(1,Math.round(pi.default.totalmem()/(1024*1024*1024))),_=Math.min(200,Math.max(20,w*25)),m=r("max-capacity")||process.env.MAX_CAPACITY,v=Number(m||_),x=r("slot")||process.env.WORKER_SLOT||process.env.pm_id||process.env.NODE_APP_INSTANCE,y=FM(x),S=r("worker-id")||process.env.WORKER_ID||y.workerId,k=r("worker-name")||process.env.WORKER_NAME||process.env.HOSTNAME||y.workerName,T=r("user-id")||process.env.USER_ID||process.env.SOFTTY_USER_ID;return{workerId:S,version:Hr,enableHttp:c,port:l,userId:T,teamId:a,workerName:k,maxCapacity:v,recommendedCapacity:_,clusterPollIntervalMs:Number(r("poll-interval")||process.env.CLUSTER_POLL_INTERVAL_MS||5e3),cloudProvider:n,cloudEndpoint:p,cloudProjectId:d,cloudSessionToken:i,cloudJwt:o,cloudDatabaseId:h,appwriteEndpoint:p,appwriteProjectId:d,appwriteSessionToken:i,appwriteJwt:o,storageBucketId:g,desktopSecret:s,databaseId:h,heartbeatIntervalMs:Number(r("heartbeat-interval")||process.env.HEARTBEAT_INTERVAL_MS||3e4),geminiApiKey:r("gemini-api-key")||process.env.GEMINI_API_KEY||process.env.GOOGLE_API_KEY,openaiApiKey:r("openai-api-key")||process.env.OPENAI_API_KEY,deepseekApiKey:r("deepseek-api-key")||process.env.DEEPSEEK_API_KEY,anthropicApiKey:r("anthropic-api-key")||process.env.ANTHROPIC_API_KEY,customAiApiKey:r("custom-ai-api-key")||process.env.CUSTOM_AI_API_KEY,aiBaseUrl:r("ai-base-url")||process.env.AI_BASE_URL,aiProvider:r("ai-provider")||process.env.AI_PROVIDER,aiModel:r("ai-model")||process.env.AI_MODEL,nightSystemPrompt:r("night-system-prompt")||process.env.NIGHT_SYSTEM_PROMPT,nightFallbackReply:r("night-fallback-reply")||process.env.NIGHT_FALLBACK_REPLY,logLevel:r("log-level")||process.env.LOG_LEVEL||"info"}}};var wo=le(require("fs")),Ew=le(require("os")),ks=le(require("path")),V$=le(require("crypto")),J$=le(nt());var O_=le(nt()),Zu=class{runners=new Map;logger;constructor(t){this.logger=t||(0,O_.createLogger)("ChannelRunnerRegistry")}register(t){let r=`${t.platform}:${t.accountId}`;this.runners.has(r)&&this.logger.warn(`Overwriting existing runner for ${r}`),this.runners.set(r,t),this.logger.info(`Registered runner for ${r}`)}unregister(t,r){let n=`${t}:${r}`,i=this.runners.get(n);return i?(i.stop().catch(o=>{this.logger.error(`Error stopping runner ${n} during unregister`,o)}),this.runners.delete(n),this.logger.info(`Unregistered runner for ${n}`),!0):!1}get(t,r){return this.runners.get(`${t}:${r}`)}getAll(){return Array.from(this.runners.values())}getCount(){return this.runners.size}async startAll(){this.logger.info(`Starting all ${this.runners.size} registered channel runners...`);for(let[t,r]of this.runners.entries())try{await r.start()}catch(n){this.logger.error(`Failed to start runner ${t}:`,n)}}async stopAll(){this.logger.info(`Stopping all ${this.runners.size} channel runners...`);for(let[t,r]of this.runners.entries())try{await r.stop()}catch(n){this.logger.error(`Failed to stop runner ${t}:`,n)}this.runners.clear()}};var F_=le(nt()),Ku=class{constructor(t=6e4,r,n){this.defaultTtlMs=t;this.logger=r||(0,F_.createLogger)("DistributedLockManager"),this.storageProvider=n}logger;locks=new Map;preemptCallbacks=[];storageProvider;setStorageProvider(t){this.storageProvider=t}getStorageProvider(){return this.storageProvider}onPreempt(t){this.preemptCallbacks.push(t)}async acquireLockRemote(t,r,n=this.defaultTtlMs){return this.storageProvider&&!await this.storageProvider.acquireLock(t,r,n)?!1:this.acquireLock(t,r,n)}async releaseLockRemote(t,r){return this.storageProvider&&await this.storageProvider.releaseLock(t,r),this.releaseLock(t,r)}async renewLockRemote(t,r,n=this.defaultTtlMs){return this.storageProvider&&await this.storageProvider.renewLock(t,r,n),this.acquireLock(t,r,n)}acquireLock(t,r,n=this.defaultTtlMs){let i=Date.now(),o=this.locks.get(t);return o&&o.expiresAt>i&&o.ownerId!==r?(this.logger.warn(`Lock denied for account ${t}: currently held by ${o.ownerId} (expires in ${o.expiresAt-i}ms)`),!1):(this.locks.set(t,{accountId:t,ownerId:r,acquiredAt:i,expiresAt:i+n}),this.logger.info(`\u2705 Lock granted: account=${t}, owner=${r}, ttl=${n}ms`),!0)}async preemptLock(t,r){let n=this.locks.get(t);this.logger.info(`\u26A1 Preemption triggered for account ${t} by master ${r} (previous owner: ${n?.ownerId||"none"})`);let i=this.preemptCallbacks.map(s=>{try{return Promise.resolve(s(t,r))}catch(a){return this.logger.error(`Error in preempt callback for ${t}:`,a),Promise.resolve()}});await Promise.race([Promise.all(i),new Promise(s=>setTimeout(s,1e3))]);let o=Date.now();return this.locks.set(t,{accountId:t,ownerId:r,acquiredAt:o,expiresAt:o+this.defaultTtlMs}),this.logger.info(`\u2705 Account ${t} preempted successfully by ${r}.`),!0}releaseLock(t,r){let n=this.locks.get(t);return n?r&&n.ownerId!==r?(this.logger.warn(`Attempted unauthorized lock release for ${t} by ${r} (real owner: ${n.ownerId})`),!1):(this.locks.delete(t),this.logger.info(`\u{1F513} Lock released for account ${t}.`),!0):!0}releaseAllForOwner(t){let r=0;for(let[n,i]of this.locks.entries())i.ownerId===t&&(this.locks.delete(n),r++);return r}isLocked(t){let r=this.locks.get(t);return r?r.expiresAt>Date.now():!1}getLockOwner(t){let r=this.locks.get(t);return!r||r.expiresAt<=Date.now()?null:r.ownerId}};var $s=le(require("fs")),D_=le(require("path")),B_=le(nt()),Yu=class{logger;queue=[];maxCapacity;persistenceFilePath;constructor(t=1e4,r,n){this.maxCapacity=t,this.logger=r||(0,B_.createLogger)("CloudPendingMessageQueue"),this.persistenceFilePath=n,this.loadFromDisk()}loadFromDisk(){if(this.persistenceFilePath)try{if($s.default.existsSync(this.persistenceFilePath)){let t=$s.default.readFileSync(this.persistenceFilePath,"utf8");if(t&&t.trim()){let r=JSON.parse(t);Array.isArray(r)&&(this.queue.push(...r),this.logger.info(`\u{1F4E6} Restored ${r.length} pending delta messages from disk: ${this.persistenceFilePath}`))}}}catch(t){this.logger.warn(`Failed to restore pending messages from disk (${this.persistenceFilePath}): ${t?.message}`)}}saveToDisk(){if(this.persistenceFilePath)try{let t=D_.default.dirname(this.persistenceFilePath);$s.default.existsSync(t)||$s.default.mkdirSync(t,{recursive:!0}),$s.default.writeFileSync(this.persistenceFilePath,JSON.stringify(this.queue),"utf8")}catch(t){this.logger.warn(`Failed to save pending messages to disk (${this.persistenceFilePath}): ${t?.message}`)}}enqueue(t){if(this.queue.length>=this.maxCapacity){let r=this.queue.shift();this.logger.warn(`Queue capacity reached (${this.maxCapacity}). Dropped oldest message: ${r?.id}`)}this.queue.push(t),this.saveToDisk(),this.logger.debug(`Enqueued pending message ${t.id} for account ${t.accountId} (Total pending: ${this.queue.length})`)}getDeltas(t,r=0){return this.queue.filter(n=>{let i=!t||n.accountId===t,o=n.timestamp>=r;return i&&o})}purgeSynced(t,r){let n=this.queue.length,i=[];for(let s=0;s<this.queue.length;s++){let a=this.queue[s];a.timestamp<=t&&(!r||a.accountId===r)&&i.push(s)}for(let s=i.length-1;s>=0;s--)this.queue.splice(i[s],1);let o=n-this.queue.length;return o>0&&(this.saveToDisk(),this.logger.info(`Purged ${o} synced delta messages from queue.`)),o}getCount(){return this.queue.length}clear(){this.queue.length=0,this.saveToDisk()}};var L_=le(nt()),Xu=class{logger;campaigns=new Map;rules=new Map;threadHistory=new Map;lastReplyTimes=new Map;aiConfig={enabled:!1};constructor(t,r){this.logger=t||(0,L_.createLogger)("HeadlessAutomationEngine"),r&&this.configure(r)}configure(t){this.aiConfig={...this.aiConfig,...t},this.logger.info(`[HeadlessAutomation] Configured AI provider: ${this.aiConfig.provider||"none"} (model: ${this.aiConfig.model||"none"}, enabled: ${this.aiConfig.enabled===!0})`)}getAiConfig(){return{...this.aiConfig}}registerCampaign(t){this.campaigns.set(t.id,t),this.logger.info(`Loaded campaign ${t.id} (${t.name})`)}registerRule(t){this.rules.set(t.id,t),this.logger.info(`Loaded automation rule ${t.id} (${t.name})`)}async evaluateIncomingMessage(t){if(t.isSelf||t.senderType&&t.senderType!=="customer"||!t.content||typeof t.content!="string"||!t.content.trim())return null;let r=t.threadId||t.conversationId||t.senderId,n=Date.now(),i=this.lastReplyTimes.get(r)||0;if(n-i<3e3)return this.logger.debug(`[HeadlessAutomation] Rate limit hit for thread ${r}. Skipping reply.`),null;let o=t.content.trim(),s=this.getThreadHistory(r);if(s.push({role:"user",content:o,timestamp:n}),s.length>6&&s.splice(0,s.length-6),!this.aiConfig||this.aiConfig.enabled!==!0||!this.aiConfig.provider)return this.logger.debug(`[HeadlessAutomation] Bot AI is disabled or unconfigured. Message saved, no auto-reply sent for thread ${r}.`),null;let a=t.accountId,c=this.aiConfig.accountBotConfigs,u=a&&c?c[a]:void 0;if(!u||!u.isBotEnabled)return this.logger.debug(`[HeadlessAutomation] Account [${a||"unknown"}] has not been configured or enabled for Bot AI by user in Chatbot settings. Message saved, no auto-reply sent.`),null;let l=t,p=!!l.isGroup||!!l.groupId||typeof t.threadId=="string"&&t.threadId.startsWith("g")||typeof t.conversationId=="string"&&t.conversationId.startsWith("g"),d=u.replyTarget||"all";if(d==="individual"&&p)return this.logger.debug(`[HeadlessAutomation] Account [${a}] configured for individual chat only. Skipping group message ${r}.`),null;if(d==="group"&&!p)return this.logger.debug(`[HeadlessAutomation] Account [${a}] configured for group chat only. Skipping direct message ${r}.`),null;let h=u.scheduleType||"always";if(h!=="always"){let S=new Date().getHours(),k=u.scheduleStartHour??8,T=u.scheduleEndHour??18;if(h==="working_hours"){if(S<k||S>=T)return this.logger.debug(`[HeadlessAutomation] Outside working hours (${S}h, allowed: ${k}h-${T}h). Skipping reply.`),null}else if(h==="outside_hours"&&S>=k&&S<T)return this.logger.debug(`[HeadlessAutomation] Inside working hours (${S}h, allowed outside: ${k}h-${T}h). Skipping reply.`),null}let g=u.excludeContactIds||[];if(!p&&g.length>0){let S=String(t.senderId||"");if(g.includes(S))return this.logger.debug(`[HeadlessAutomation] Sender ${S} is in contact blacklist. Skipping reply.`),null}if(p){let S=String(l.groupId||l.threadId||r||""),k=u.excludeGroupIds||[],T=u.includeGroupIds||[];if(k.length>0&&k.includes(S))return this.logger.debug(`[HeadlessAutomation] Group ${S} is in group blacklist. Skipping reply.`),null;if(T.length>0&&!T.includes(S))return this.logger.debug(`[HeadlessAutomation] Group ${S} is not in group whitelist. Skipping reply.`),null}let w=u.excludeKeywords||[],_=u.includeKeywords||[],m=o.toLowerCase();if(w.length>0&&w.some(k=>{let T=k.trim().toLowerCase();return T.length>0&&m.includes(T)}))return this.logger.debug("[HeadlessAutomation] Message contains blacklisted keyword. Skipping reply."),null;if(_.length>0&&!_.some(k=>{let T=k.trim().toLowerCase();return T.length>0&&m.includes(T)}))return this.logger.debug("[HeadlessAutomation] Message does not match any whitelist keyword. Skipping reply."),null;let v=u.systemPrompt&&u.systemPrompt.trim()?u.systemPrompt:this.aiConfig.systemPrompt;if(this.aiConfig.provider==="rule_based")return this.aiConfig.fallbackMessage&&this.aiConfig.fallbackMessage.trim().length>0?(this.lastReplyTimes.set(r,n),this.aiConfig.fallbackMessage.trim()):null;let x=this.aiConfig.provider,y=this.aiConfig.apiKey;if(y||(x==="openai"?y=process.env.OPENAI_API_KEY:x==="deepseek"?y=process.env.DEEPSEEK_API_KEY:x==="anthropic"?y=process.env.ANTHROPIC_API_KEY:x==="custom"?y=process.env.CUSTOM_AI_API_KEY:x==="gemini"&&(y=process.env.GEMINI_API_KEY||process.env.GOOGLE_API_KEY)),!y&&x!=="custom")return this.logger.debug(`[HeadlessAutomation] No API key found for provider [${x}]. No auto-reply sent.`),null;try{let S=null;if(x==="openai"||x==="custom"||x==="deepseek")S=await this.callOpenAiCompatible(o,s,y||"",v);else if(x==="anthropic")S=await this.callAnthropic(o,s,y||"",v);else if(x==="gemini")S=await this.callGemini(o,s,y||"",v);else return this.logger.warn(`[HeadlessAutomation] Unsupported AI provider [${x}]. No reply generated.`),null;if(S&&S.trim().length>0){let k=S.trim();return s.push({role:"model",content:k,timestamp:Date.now()}),this.lastReplyTimes.set(r,Date.now()),k}}catch(S){this.logger.warn(`[HeadlessAutomation] AI generation error with provider [${x}] (${S?.message}).`)}return this.aiConfig.fallbackMessage&&this.aiConfig.fallbackMessage.trim().length>0?(this.lastReplyTimes.set(r,Date.now()),this.aiConfig.fallbackMessage.trim()):null}getThreadHistory(t){let r=this.threadHistory.get(t);return r||(r=[],this.threadHistory.set(t,r)),r}async callGemini(t,r,n,i){let s=`https://generativelanguage.googleapis.com/v1beta/models/${this.aiConfig.model||"gemini-2.0-flash"}:generateContent?key=${n}`,a=r.map(d=>({role:d.role==="model"?"model":"user",parts:[{text:d.content}]}));(a.length===0||a[a.length-1].parts[0]?.text!==t)&&a.push({role:"user",parts:[{text:t}]});let c={contents:a,generationConfig:{temperature:this.aiConfig.temperature??.7,maxOutputTokens:this.aiConfig.maxTokens??300}},u=i||this.aiConfig.systemPrompt;u&&u.trim()&&(c.systemInstruction={parts:[{text:u.trim()}]});let l=new AbortController,p=setTimeout(()=>l.abort(),7e3);try{let d=await fetch(s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(c),signal:l.signal});if(!d.ok){let w=await d.text();return this.logger.warn(`[HeadlessAutomation] Gemini API returned status ${d.status}: ${w.slice(0,200)}`),null}return(await d.json())?.candidates?.[0]?.content?.parts?.[0]?.text||null}finally{clearTimeout(p)}}async callOpenAiCompatible(t,r,n,i){let o=(this.aiConfig.baseUrl||(this.aiConfig.provider==="deepseek"?"https://api.deepseek.com/v1":"https://api.openai.com/v1")).replace(/\/+$/,"");o.includes("api.deepseek.com")&&!o.endsWith("/v1")?o+="/v1":(o.includes("11434")||o.includes("ollama"))&&(o=o.replace(/\/api$/,"").replace(/\/+$/,""),o.endsWith("/v1")||(o+="/v1"));let s=`${o}/chat/completions`,a=this.aiConfig.model||(this.aiConfig.provider==="deepseek"?"deepseek-chat":this.aiConfig.provider==="openai"?"gpt-4o-mini":"deepseek-chat"),c=i||this.aiConfig.systemPrompt,u=[...c&&c.trim()?[{role:"system",content:c.trim()}]:[],...r.map(h=>({role:h.role==="model"?"assistant":"user",content:h.content}))],l={"Content-Type":"application/json"};n&&(l.Authorization=`Bearer ${n}`);let p=new AbortController,d=setTimeout(()=>p.abort(),8e3);try{let h=await fetch(s,{method:"POST",headers:l,body:JSON.stringify({model:a,messages:u,temperature:this.aiConfig.temperature??.7,max_tokens:this.aiConfig.maxTokens??300}),signal:p.signal});if(!h.ok){let w=await h.text();return this.logger.warn(`[HeadlessAutomation] OpenAI-compatible API returned status ${h.status}: ${w.slice(0,200)}`),null}return(await h.json())?.choices?.[0]?.message?.content||null}finally{clearTimeout(d)}}async callAnthropic(t,r,n,i){let o="https://api.anthropic.com/v1/messages",s=this.aiConfig.model||"claude-3-5-haiku-20241022",a=r.map(l=>({role:l.role==="model"?"assistant":"user",content:l.content}));(a.length===0||a[a.length-1].content!==t)&&a.push({role:"user",content:t});let c=new AbortController,u=setTimeout(()=>c.abort(),8e3);try{let l=i||this.aiConfig.systemPrompt,p={model:s,messages:a,max_tokens:this.aiConfig.maxTokens??300,temperature:this.aiConfig.temperature??.7};l&&l.trim()&&(p.system=l.trim());let d=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":n,"anthropic-version":"2023-06-01"},body:JSON.stringify(p),signal:c.signal});if(!d.ok){let g=await d.text();return this.logger.warn(`[HeadlessAutomation] Anthropic API returned status ${d.status}: ${g.slice(0,200)}`),null}return(await d.json())?.content?.[0]?.text||null}finally{clearTimeout(u)}}clear(){this.campaigns.clear(),this.rules.clear(),this.threadHistory.clear(),this.lastReplyTimes.clear()}};var N_=le(nt()),Qu=class{logger;constructor(t){this.logger=t||(0,N_.createLogger)("PushNotificationDispatcher")}async dispatchMessageAlert(t,r){let n=`${r.senderName} (${r.platform.toUpperCase()})`,i=r.content||"New multimedia message received";return this.sendNotification({recipientToken:t,title:n,body:i,data:{messageId:r.id,threadId:r.threadId,platform:r.platform,accountId:r.accountId}})}async sendNotification(t){return this.logger.debug(`Dispatching push notification to device token: ${t.recipientToken.slice(0,8)}...`),!0}};var I$=le(require("http")),P$=require("url"),O$=le(nt());var T$=le(nt()),Ya=class{static logger=(0,T$.createLogger)("ChannelRunnerFactory");static async createRunner(t,r,n,i){let o=(t||"zalo").toLowerCase(),s=o==="web"||o.includes("zalo")?"zalo":o;try{if(s==="zalo"){let{ZaloChannelRunner:a}=await Promise.resolve().then(()=>(TL(),RL));return new a(r,n,i)}if(s==="facebook"){let{FacebookChannelRunner:a}=await Promise.resolve().then(()=>(p6(),u6));return new a(r,n,i)}if(s==="telegram"){let{TelegramChannelRunner:a}=await Promise.resolve().then(()=>(g6(),m6));return new a(r,n,i)}if(s==="whatsapp"){let{WhatsAppChannelRunner:a}=await Promise.resolve().then(()=>(R$(),C$));return new a(r,n,i)}return this.logger.warn(`Unsupported platform for ChannelRunner: ${t}`),null}catch(a){return this.logger.error(`Failed to dynamically initialize runner for ${s}:${r}:`,a?.message||a),null}}};var tm=class{constructor(t,r,n,i,o){this.port=t;this.engine=r;this.lockManager=n;this.deltaQueue=i;this.logger=o||(0,O$.createLogger)("WorkerHttpServer")}logger;server=null;async start(){if(!this.server)return new Promise((t,r)=>{this.server=I$.default.createServer((n,i)=>{this.handleRequest(n,i).catch(o=>{this.logger.error("Unhandled HTTP error:",o),i.headersSent||(i.writeHead(500,{"Content-Type":"application/json"}),i.end(JSON.stringify({error:"Internal Server Error"})))})}),this.server.listen(this.port,()=>{this.logger.info(`\u{1F680} Worker HTTP Server listening on port ${this.port}`),t()}),this.server.on("error",n=>{this.logger.error(`Worker HTTP Server error on port ${this.port}:`,n),r(n)})})}async stop(){if(this.server)return new Promise(t=>{this.server?.close(()=>{this.logger.info("Worker HTTP Server closed."),this.server=null,t()})})}async handleRequest(t,r){let n=new P$.URL(t.url||"/",`http://${t.headers.host||"localhost"}`),i=n.pathname,o=(t.method||"GET").toUpperCase();if(r.setHeader("Access-Control-Allow-Origin","*"),r.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS"),r.setHeader("Access-Control-Allow-Headers","Content-Type, X-Softty-User-Id, X-Desktop-Secret, Authorization"),o==="OPTIONS"){r.writeHead(204),r.end();return}if(o==="GET"&&i==="/health"){let s=this.engine.getMetrics();r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({status:"healthy",timestamp:Date.now(),pendingDeltaMessages:this.deltaQueue.getCount(),metrics:s}));return}if(i.startsWith("/api/v1/")){let s=this.engine.config.desktopSecret;if(s){let a=t.headers["x-desktop-secret"]||t.headers.authorization;if((typeof a=="string"&&a.startsWith("Bearer ")?a.slice(7):a)!==s){r.writeHead(401,{"Content-Type":"application/json"}),r.end(JSON.stringify({error:"Unauthorized: Invalid or missing X-Desktop-Secret"}));return}}}if(o==="POST"&&i==="/api/v1/sentinel/handover"){let s=await this.readJsonBody(t),{deviceId:a,sessions:c,aiConfig:u}=s||{};if(u&&(this.engine.automationEngine.configure(u),this.logger.info(`[Handover] Configured 24/7 AI automation engine with provider: ${u.provider||"gemini"}, model: ${u.model||"default"}`)),!Array.isArray(c)){r.writeHead(400,{"Content-Type":"application/json"}),r.end(JSON.stringify({error:"Invalid sessions array payload"}));return}this.logger.info(`[Handover] Received handover request from device ${a||"unknown"} with ${c.length} sessions.`);let l=0;for(let p of c){if(!p.id||!p.nightWorkerEnabled)continue;if(!this.lockManager.acquireLock(p.id,`worker_${p.id}`)){this.logger.warn(`Skipping account ${p.id} because lock was not acquired.`);continue}let h=(p.platform||"zalo").toLowerCase(),g=h==="web"||h.includes("zalo")?"zalo":h,w=await Ya.createRunner(g,p.id,p.sessionData);w&&(this.engine.registerRunner(w),await w.start(),this.engine.registerAccount({id:p.id,platform:g,accountName:p.accountName||p.id,status:"active",nightWorkerEnabled:!0}),l++)}r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({success:!0,message:"Sessions handed over successfully",activatedCount:l,timestamp:Date.now()}));return}if(o==="POST"&&i==="/api/v1/sentinel/reclaim"){let s=await this.readJsonBody(t),{deviceId:a}=s||{};this.logger.info(`[Reclaim] Master device ${a||"desktop"} reclaiming all active sessions. Stopping cloud runners...`);let c=this.engine.channelRunnerRegistry.getCount();await this.engine.channelRunnerRegistry.stopAll(),this.lockManager.releaseAllForOwner("worker"),r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({success:!0,reclaimedCount:c,timestamp:Date.now()}));return}if(i==="/api/v1/sentinel/night-config"){if(o==="POST"){let s=await this.readJsonBody(t);s&&(this.engine.automationEngine.configure(s),this.logger.info(`[NightConfig] Updated 24/7 AI config dynamically: provider=${s.provider||"gemini"}, model=${s.model||"default"}`)),r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({success:!0,config:this.engine.automationEngine.getAiConfig()}));return}else if(o==="GET"){r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({success:!0,config:this.engine.automationEngine.getAiConfig()}));return}}if(o==="GET"&&i==="/api/v1/sync/delta"){let s=n.searchParams.get("accountId")||void 0,a=parseInt(n.searchParams.get("since")||"0",10),c=this.deltaQueue.getDeltas(s,a);this.logger.info(`[DeltaSync] Serving ${c.length} night messages (since: ${a}, account: ${s||"all"})`),r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({success:!0,messages:c,count:c.length,syncedTimestamp:Date.now()}));return}r.writeHead(404,{"Content-Type":"application/json"}),r.end(JSON.stringify({error:"Endpoint not found"}))}readJsonBody(t){return new Promise(r=>{let n="";t.on("data",i=>{n+=i}),t.on("end",()=>{try{r(JSON.parse(n))}catch{r({})}})})}};var ec=le(nt());var Xa=require("child_process"),F$=le(nt()),rm=class e{logger;timer;isUpdating=!1;constructor(t){this.logger=t||(0,F$.createLogger)("WorkerAutoUpdater")}static isNewerVersion(t,r){let n=l=>l.replace(/^v/,"").trim().split(".").map(p=>parseInt(p,10)||0),[i=0,o=0,s=0]=n(t),[a=0,c=0,u=0]=n(r);return i>a||i===a&&o>c||i===a&&o===c&&s>u}async fetchLatestVersion(){let t="@softtynet/zplus-worker";try{let r=new AbortController,n=setTimeout(()=>r.abort(),5e3),i=await fetch(`https://registry.npmjs.org/${t}/latest`,{signal:r.signal,headers:{Accept:"application/json"}});if(clearTimeout(n),i.ok){let o=await i.json();if(o?.version)return String(o.version).trim()}}catch{}try{return(0,Xa.execSync)(`npm view ${t} version`,{encoding:"utf-8",timeout:8e3,stdio:["ignore","pipe","ignore"]}).trim()}catch{return null}}async checkUpdate(t){let r=await this.fetchLatestVersion();return r?{hasUpdate:e.isNewerVersion(r,t),latestVersion:r}:{hasUpdate:!1,latestVersion:t}}async performUpdateAndRestart(t){if(this.isUpdating)return this.logger.warn("C\u1EADp nh\u1EADt \u0111ang di\u1EC5n ra, b\u1ECF qua y\xEAu c\u1EA7u tr\xF9ng l\u1EB7p."),!1;this.isUpdating=!0;let r=t?`@softtynet/zplus-worker@${t}`:"@softtynet/zplus-worker@latest";this.logger.info(`\u{1F680} [AutoUpdater] B\u1EAFt \u0111\u1EA7u t\u1EF1 \u0111\u1ED9ng n\xE2ng c\u1EA5p Worker l\xEAn ${r}...`);try{return(0,Xa.execSync)(`npm install -g ${r}`,{stdio:"inherit",timeout:12e4}),this.logger.info(`\u2705 [AutoUpdater] \u0110\xE3 c\xE0i \u0111\u1EB7t th\xE0nh c\xF4ng ${r}!`),this.triggerRestart(),!0}catch(n){return this.isUpdating=!1,this.logger.error(`\u274C [AutoUpdater] N\xE2ng c\u1EA5p th\u1EA5t b\u1EA1i: ${n?.message||n}`),!1}}triggerRestart(){try{if((0,Xa.execSync)("pm2 jlist",{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:5e3}).includes("zplus-worker")){this.logger.info("\u{1F504} [AutoUpdater] \u0110ang ph\xE1t l\u1EC7nh kh\u1EDFi \u0111\u1ED9ng l\u1EA1i PM2 ti\u1EBFn tr\xECnh 'zplus-worker'..."),(0,Xa.spawn)("pm2",["restart","zplus-worker"],{detached:!0,stdio:"ignore"}).unref(),setTimeout(()=>process.exit(0),1e3);return}}catch{}if(!!process.stdout.isTTY&&!process.env.PM2_HOME&&!process.env.pm_id&&!process.env.INVOCATION_ID){this.logger.warn("\u26A0\uFE0F [AutoUpdater] \u0110\xE3 t\u1EA3i phi\xEAn b\u1EA3n m\u1EDBi. V\xEC \u0111ang ch\u1EA1y Worker tr\u1EF1c ti\u1EBFp tr\xEAn Terminal (kh\xF4ng qua PM2), vui l\xF2ng nh\u1EA5n Ctrl+C v\xE0 ch\u1EA1y l\u1EA1i \u0111\u1EC3 n\u1EA1p m\xE3 m\u1EDBi."),this.isUpdating=!1;return}this.logger.info("\u{1F504} [AutoUpdater] Ti\u1EBFn tr\xECnh s\u1EBD tho\xE1t an to\xE0n (exit 0) \u0111\u1EC3 h\u1EC7 th\u1ED1ng t\u1EF1 kh\u1EDFi \u0111\u1ED9ng l\u1EA1i v\u1EDBi b\u1EA3n m\u1EDBi..."),setTimeout(()=>process.exit(0),1500)}startPeriodicAutoUpdate(t,r=3600*1e3){this.timer&&clearInterval(this.timer),setTimeout(()=>{this.runCheckCycle(t).catch(()=>{})},6e4),this.timer=setInterval(()=>{this.runCheckCycle(t).catch(()=>{})},r),this.logger.info(`\u23F0 [AutoUpdater] \u0110\xE3 k\xEDch ho\u1EA1t c\u01A1 ch\u1EBF t\u1EF1 \u0111\u1ED9ng c\u1EADp nh\u1EADt ng\u1EA7m (chu k\u1EF3: ${Math.round(r/6e4)} ph\xFAt).`)}stop(){this.timer&&(clearInterval(this.timer),this.timer=void 0)}async runCheckCycle(t){try{let{hasUpdate:r,latestVersion:n}=await this.checkUpdate(t);r&&(this.logger.info(`\u{1F514} [AutoUpdater] Ph\xE1t hi\u1EC7n phi\xEAn b\u1EA3n m\u1EDBi: v${n} (hi\u1EC7n t\u1EA1i: v${t}). \u0110ang t\u1EF1 \u0111\u1ED9ng n\xE2ng c\u1EA5p...`),await this.performUpdateAndRestart(n))}catch(r){this.logger.debug("Auto-update check cycle error:",r?.message)}}};var Di=le(require("fs")),nm=le(require("path")),D$=le(require("os")),B$=le(require("readline")),im=le(nt()),Qa=class{logger;constructor(t){this.logger=t||(0,im.createLogger)("WorkerAuthManager")}getAuthFilePath(){let t=process.env.DATA_DIR||nm.default.join(D$.default.homedir(),".zplus");return nm.default.join(t,"worker_auth.json")}loadStoredAuth(){try{let t=this.getAuthFilePath();if(!Di.default.existsSync(t))return null;let r=Di.default.readFileSync(t,"utf-8"),n=JSON.parse(r);return!n||!n.sessionToken?null:n}catch(t){return this.logger.debug("Failed to read worker_auth.json:",t?.message),null}}saveAuth(t){try{let r=this.getAuthFilePath(),n=nm.default.dirname(r);Di.default.existsSync(n)||Di.default.mkdirSync(n,{recursive:!0,mode:448}),Di.default.writeFileSync(r,JSON.stringify(t,null,2),{encoding:"utf-8",mode:384});try{Di.default.chmodSync(r,384)}catch{}this.logger.info(`\u2705 Phi\xEAn x\xE1c th\u1EF1c \u0111\xE3 \u0111\u01B0\u1EE3c l\u01B0u an to\xE0n t\u1EA1i: ${r} (Quy\u1EC1n 0600 - Ch\u1EC9 Owner)`)}catch(r){this.logger.error("Could not save worker_auth.json:",r)}}clearAuth(){try{let t=this.getAuthFilePath();Di.default.existsSync(t)&&Di.default.unlinkSync(t),this.logger.info("\u0110\xE3 x\xF3a phi\xEAn \u0111\u0103ng nh\u1EADp c\u1EE7a Worker.")}catch(t){this.logger.debug("clearAuth error:",t?.message)}}async verifyEntitlements(t,r="https://api.softty.net/v1",n="699cfc3100136099c1c1",i="default"){try{let o=`${r}/account`,s=t.includes(".")&&t.split(".").length===3,a={"Content-Type":"application/json","X-Appwrite-Project":n};s?a["X-Appwrite-JWT"]=t:(a["X-Appwrite-Session"]=t,a.Cookie=`a_session_${n}=${t}; a_session_${n}_legacy=${t}`,t.startsWith("eyJ")&&(a["X-Fallback-Cookies"]=JSON.stringify({[`a_session_${n}`]:t,[`a_session_${n}_legacy`]:t})));let c=await fetch(o,{method:"GET",headers:a});if(!c.ok)return{allowed:!1,userId:"",userName:"Unknown",email:"",teamId:i,isOwner:!1,isPremium:!1,reason:`Phi\xEAn \u0111\u0103ng nh\u1EADp kh\xF4ng h\u1EE3p l\u1EC7 ho\u1EB7c \u0111\xE3 h\u1EBFt h\u1EA1n (HTTP ${c.status}).`};let u=await c.json(),l=u.$id||u.id||"",p=u.name||"Ng\u01B0\u1EDDi d\xF9ng ZPlus",d=u.email||"",h=Array.isArray(u.labels)?u.labels:[],g=u.prefs||{},_=!h.some(y=>y.toLowerCase()==="member")&&g.isOwner!==!1,m=h.some(y=>y.toLowerCase()==="free")||g.tier==="free",v=!m&&(g.isPremium===!0||h.some(y=>y.toLowerCase()==="premium"||y.toLowerCase()==="enterprise")),x=g.teamId||g.storage?.teamId||u.teamId||i;if((!x||x==="default")&&g.entitlements)try{let y=typeof g.entitlements=="string"?JSON.parse(g.entitlements):g.entitlements;y?.storage?.teamId&&(x=y.storage.teamId)}catch{}if((!x||x==="default")&&u.entitlements)try{let y=typeof u.entitlements=="string"?JSON.parse(u.entitlements):u.entitlements;y?.storage?.teamId&&(x=y.storage.teamId)}catch{}if(!x||x==="default")try{let y=await fetch(`${r}/teams`,{method:"GET",headers:a});if(y.ok){let S=await y.json().catch(()=>({})),k=Array.isArray(S.teams)?S.teams:[];k.length>0&&k[0].$id&&(x=k[0].$id)}}catch{}return m?{allowed:!1,userId:l,userName:p,email:d,teamId:x,isOwner:_,isPremium:!1,reason:`\u26A0\uFE0F T\xE0i kho\u1EA3n [${d}] \u0111ang \u1EDF G\xF3i Mi\u1EC5n Ph\xED (Free Tier). G\xF3i n\xE0y kh\xF4ng h\u1ED7 tr\u1EE3 c\u1EE5m Worker 24/7 (Y\xEAu c\u1EA7u g\xF3i Team Enterprise).`}:_?{allowed:!0,userId:l,userName:p,email:d,teamId:x,isOwner:!0,isPremium:!0,reason:`\u2705 X\xE1c th\u1EF1c th\xE0nh c\xF4ng: Tr\u01B0\u1EDFng nh\xF3m [${p}] (${d}) - G\xF3i Doanh Nghi\u1EC7p Active.`}:{allowed:!1,userId:l,userName:p,email:d,teamId:x,isOwner:!1,isPremium:v,reason:`\u26A0\uFE0F T\xE0i kho\u1EA3n [${d}] l\xE0 Th\xE0nh vi\xEAn (Member). \u0110\u1EC3 b\u1EA3o v\u1EC7 d\u1EEF li\u1EC7u c\xF4ng ty, ch\u1EC9 Tr\u01B0\u1EDFng nh\xF3m (Team Owner) m\u1EDBi c\xF3 quy\u1EC1n k\xEDch ho\u1EA1t c\u1EE5m Worker cho Team.`}}catch(o){return{allowed:!1,userId:"",userName:"Unknown",email:"",teamId:i,isOwner:!1,isPremium:!1,reason:`L\u1ED7i k\u1EBFt n\u1ED1i ki\u1EC3m tra quy\u1EC1n h\u1EA1n: ${o?.message}`}}}async loginWithCredentials(t,r,n="https://api.softty.net/v1",i="699cfc3100136099c1c1"){let o=t?.trim(),s=r;if(!o||!s){console.log(`
|
|
108
108
|
==================================================================`),console.log("\u{1F510} ZPLUS WORKER TERMINAL LOGIN (HEADLESS LINUX / VPS)"),console.log("=================================================================="),console.log("\u2139\uFE0F \u0110\u0103ng nh\u1EADp b\u1EB1ng t\xE0i kho\u1EA3n Tr\u01B0\u1EDFng nh\xF3m (Softty ID) \u0111\u1EC3 c\u1EA5p quy\u1EC1n Worker."),console.log("------------------------------------------------------------------");let a=B$.default.createInterface({input:process.stdin,output:process.stdout}),c=u=>new Promise(l=>a.question(u,l));o||(o=(await c("? Nh\u1EADp Email Tr\u01B0\u1EDFng nh\xF3m (Softty ID): ")).trim()),s||(s=await c("? Nh\u1EADp M\u1EADt kh\u1EA9u: ")),a.close()}if(!o||!s)return console.error("\u274C L\u1ED7i: Email v\xE0 m\u1EADt kh\u1EA9u kh\xF4ng \u0111\u01B0\u1EE3c \u0111\u1EC3 tr\u1ED1ng."),null;try{console.log(`
|
|
109
109
|
\u23F3 \u0110ang x\xE1c th\u1EF1c v\u1EDBi m\xE1y ch\u1EE7 Softty Cloud...`);let a=`${n}/account/sessions/email`,c=await fetch(a,{method:"POST",headers:{"Content-Type":"application/json","X-Appwrite-Project":i},body:JSON.stringify({email:o,password:s})});if(!c.ok){let h=await c.json().catch(()=>({}));return console.error(`\u274C \u0110\u0103ng nh\u1EADp th\u1EA5t b\u1EA1i: ${h?.message||"Email ho\u1EB7c m\u1EADt kh\u1EA9u kh\xF4ng ch\xEDnh x\xE1c."}`),null}let l=(await c.json().catch(()=>({}))).secret||"";if(l||(l=c.headers.get("x-appwrite-session")||""),!l){let h=typeof c.headers.getSetCookie=="function"?c.headers.getSetCookie():[c.headers.get("set-cookie")||""];for(let g of h){let w=g.match(/a_session_[^=]+=([^;]+)/);if(w&&w[1]){l=decodeURIComponent(w[1]);break}}}if(!l)try{let h=c.headers.get("x-fallback-cookies");if(h){let g=JSON.parse(h);for(let w of Object.keys(g))if(w.startsWith("a_session_")){l=g[w];break}}}catch{}if(!l)return console.error("\u274C L\u1ED7i: M\xE1y ch\u1EE7 Appwrite kh\xF4ng tr\u1EA3 v\u1EC1 m\xE3 phi\xEAn x\xE1c th\u1EF1c (Session Secret)."),null;let p=await this.verifyEntitlements(l,n,i);if(console.log(`
|
|
110
110
|
`+p.reason),!p.allowed&&!p.userId)return console.warn(`
|
|
@@ -124,7 +124,7 @@ ${v}`),w.pop(),`{${k}}`}case"number":return isFinite(g)?String(g):t?t(g):"null";
|
|
|
124
124
|
$textNodes.Item(1).AppendChild($template.CreateTextNode('${u}')) > $null;
|
|
125
125
|
$toast = [Windows.UI.Notifications.ToastNotification]::new($template);
|
|
126
126
|
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('ZPlus Worker').Show($toast);
|
|
127
|
-
`;return(0,om.spawn)("powershell",["-Command",l],{detached:!0,stdio:"ignore"}).unref(),!0}}}catch{}return!1}};var am=class{constructor(t,r,n){this.config=t;this.engine=r;this.logger=n||(0,ec.createLogger)(`ClusterSentinel:${t.workerId}`),this.autoUpdater=new rm(this.logger),this.authManager=new Qa(this.logger)}logger;autoUpdater;authManager;refreshPromise=null;isRunning=!1;pollTimer;heartbeatTimer;cachedPeerWorkers=[];lastPeerCheckTime=0;lastNightConfigUpdatedAt=0;lastNightConfigCheck=0;isSyncingAccounts=!1;getHeaders(){let t=this.config.appwriteProjectId||"",r={"Content-Type":"application/json","X-Appwrite-Project":t};if(this.config.appwriteSessionToken){let n=this.config.appwriteSessionToken;n.includes(".")&&n.split(".").length===3?r["X-Appwrite-JWT"]=n:(r["X-Appwrite-Session"]=n,r.Cookie=`a_session_${t}=${n}; a_session_${t}_legacy=${n}`,n.startsWith("eyJ")&&(r["X-Fallback-Cookies"]=JSON.stringify({[`a_session_${t}`]:n,[`a_session_${t}_legacy`]:n})))}else this.config.appwriteJwt&&(r["X-Appwrite-JWT"]=this.config.appwriteJwt);return r}async handleAuthExpired(){return this.refreshPromise?await this.refreshPromise:(this.refreshPromise=(async()=>{try{this.logger.warn("\u26A0\uFE0F [ClusterSentinel] Phi\xEAn x\xE1c th\u1EF1c Cloud \u0111\xE3 h\u1EBFt h\u1EA1n (HTTP 401). \u0110ang k\xEDch ho\u1EA1t Silent Refresh Token 24/7...");let t=await this.authManager.ensureValidSession(this.config.appwriteEndpoint,this.config.appwriteProjectId,!0);return t?.sessionToken?(this.config.appwriteSessionToken=t.sessionToken,t.teamId&&t.teamId!=="default"&&(this.config.teamId=t.teamId),this.engine.setStatus("running"),this.logger.info(`\u2705 [ClusterSentinel] \u0110\xE3 t\u1EF1 \u0111\u1ED9ng kh\xF4i ph\u1EE5c quy\u1EC1n h\u1EA1n qua Refresh Token! (${t.userName})`),!0):(this.logger.error("\u274C [ClusterSentinel] Kh\xF4ng th\u1EC3 t\u1EF1 \u0111\u1ED9ng l\xE0m m\u1EDBi phi\xEAn. Vui l\xF2ng \u0111\u0103ng nh\u1EADp l\u1EA1i Worker qua l\u1EC7nh: zplus-worker login"),this.engine.setStatus("auth_error","M\xE1y ch\u1EE7 tr\u1EF1c ban 24/7 b\u1ECB h\u1EBFt h\u1EA1n phi\xEAn. Vui l\xF2ng ch\u1EA1y l\u1EC7nh 'zplus-worker login' \u0111\u1EC3 c\u1EA5p l\u1EA1i phi\xEAn l\xE0m vi\u1EC7c."),sm.notify("\u26A0\uFE0F Tr\u1EE3 L\xFD Tr\u1EF1c Ban 24/7 T\u1EA1m D\u1EEBng","Phi\xEAn l\xE0m vi\u1EC7c c\u1EE7a Worker \u0111\xE3 h\u1EBFt h\u1EA1n. Vui l\xF2ng ch\u1EA1y l\u1EC7nh 'zplus-worker login' \u0111\u1EC3 c\u1EA5p l\u1EA1i phi\xEAn l\xE0m vi\u1EC7c!","worker_auth_401",900*1e3),!1)}catch(t){return this.logger.error("\u274C [ClusterSentinel] L\u1ED7i ngo\u1EA1i l\u1EC7 trong Silent Refresh Token:",t?.message),this.engine.setStatus("auth_error",`L\u1ED7i ngo\u1EA1i l\u1EC7 x\xE1c th\u1EF1c: ${t?.message||"Kh\xF4ng x\xE1c \u0111\u1ECBnh"}`),!1}finally{this.refreshPromise=null}})(),await this.refreshPromise)}isCloudConfigured(){return!!(this.config.appwriteEndpoint&&this.config.appwriteProjectId&&(this.config.appwriteSessionToken||this.config.appwriteJwt))}async start(){if(this.isRunning)return;if(this.isRunning=!0,!this.isCloudConfigured()){this.logger.info("Appwrite Cloud credentials not fully configured. Running in standalone local mode.");return}this.logger.info(`\u{1F680} Initializing Team Cluster Sentinel for Team [${this.config.teamId}] (Worker: ${this.config.workerId}, Capacity: ${this.config.maxCapacity})`),await this.registerWorkerInstance(),this.heartbeatTimer=setInterval(()=>{this.pingWorkerHeartbeat().catch(r=>{this.logger.debug("Worker heartbeat ping error:",r?.message)})},15e3);let t=this.config.clusterPollIntervalMs||3e3;this.pollTimer=setInterval(()=>{this.syncTeamAccounts().catch(n=>{this.logger.debug("Cluster account sync error:",n?.message)});let r=Date.now();r-this.lastNightConfigCheck>3e4&&(this.lastNightConfigCheck=r,this.syncNightShiftConfig().catch(()=>{}))},t),this.syncTeamAccounts().catch(()=>{}),this.syncNightShiftConfig().catch(()=>{}),this.autoUpdater.startPeriodicAutoUpdate(this.config.version||Hr)}async stop(){this.isRunning=!1,this.autoUpdater.stop(),this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=void 0),this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=void 0),this.isCloudConfigured()&&await this.markWorkerOffline(),this.logger.info("Cluster Sentinel stopped.")}async syncNightShiftConfig(){if(!(!this.isRunning||!this.isCloudConfigured()||!this.config.teamId))try{let t=this.config.appwriteEndpoint,r=this.config.databaseId||"zplus_app",n=`night_cfg_${this.config.teamId}`.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,36),i=`${t}/databases/${r}/collections/cluster_settings/documents/${n}`,o=await fetch(i,{method:"GET",headers:this.getHeaders()});if(!o.ok)return;let s=await o.json(),a=Number(s.updated_at||0);if(a>this.lastNightConfigUpdatedAt&&s.config_json)try{let c=JSON.parse(s.config_json);this.engine.automationEngine.configure(c),this.lastNightConfigUpdatedAt=a,this.logger.info(`\u{1F319} [ClusterSentinel] Synchronized latest Night AI config from Cloud DB (Provider: ${c.provider||"default"}, Enabled: ${c.enabled})`)}catch(c){this.logger.debug("Failed to parse night config JSON from Cloud DB:",c?.message)}}catch{}}async getActivePeerWorkers(){let t=Date.now();if(t-this.lastPeerCheckTime<15e3&&this.cachedPeerWorkers.length>0)return this.cachedPeerWorkers;try{let r=this.config.appwriteEndpoint,n=this.config.databaseId||"zplus_app",i=JSON.stringify({method:"equal",attribute:"team_id",values:[this.config.teamId]}),o=JSON.stringify({method:"limit",values:[25]}),s=`${r}/databases/${n}/collections/team_workers/documents?queries[]=${encodeURIComponent(i)}&queries[]=${encodeURIComponent(o)}`,a=await fetch(s,{method:"GET",headers:this.getHeaders()});if(a.ok){let c=await a.json(),u=Array.isArray(c?.documents)?c.documents:[];this.cachedPeerWorkers=u.filter(l=>l.worker_id!==this.config.workerId&&l.status==="online"&&t-Number(l.last_ping||0)<45e3).map(l=>({workerId:l.worker_id,currentLoad:Number(l.current_load||0),maxCapacity:Number(l.max_capacity||50),lastPing:Number(l.last_ping||0)})),this.lastPeerCheckTime=t}}catch{}return this.cachedPeerWorkers}async registerWorkerInstance(){try{let t=this.config.appwriteEndpoint,r=this.config.databaseId||"zplus_app",n=this.config.workerId.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,36),i=Wu(),o=this.engine.channelRunnerRegistry.getCount(),s=o>this.config.maxCapacity,a=`${t}/databases/${r}/collections/team_workers/documents/${n}`,c={data:{worker_id:this.config.workerId,team_id:this.config.teamId,worker_name:this.config.workerName,max_capacity:this.config.maxCapacity,recommended_capacity:this.config.recommendedCapacity||this.config.maxCapacity,current_load:o,is_overloaded:s,system_specs:JSON.stringify({...i,version:this.config.version||Hr}),status:"online",last_ping:Date.now()}},u=await fetch(a,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify(c)});if(u.status===401&&await this.handleAuthExpired()&&(u=await fetch(a,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify(c)})),u.ok){this.logger.info(`\u2705 Worker registered in Team Cluster: ${this.config.workerId}`);return}if(u.status===404){let l=`${t}/databases/${r}/collections/team_workers/documents`,p=await fetch(l,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({documentId:n,permissions:['read("users")','update("users")','delete("users")'],...c})});if(p.status===401&&await this.handleAuthExpired()&&(p=await fetch(l,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({documentId:n,permissions:['read("users")','update("users")','delete("users")'],...c})})),!p.ok&&p.status===400){let d={data:{worker_id:this.config.workerId,team_id:this.config.teamId,worker_name:this.config.workerName,max_capacity:this.config.maxCapacity,current_load:o,status:"online",last_ping:Date.now()}};p=await fetch(l,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({documentId:n,permissions:['read("users")','update("users")','delete("users")'],...d})})}p.ok?this.logger.info(`\u2705 Worker registered in Team Cluster: ${this.config.workerId}`):this.logger.warn(`\u26A0\uFE0F Could not register in team_workers: HTTP ${p.status}`)}else this.logger.warn(`\u26A0\uFE0F Could not patch team_workers: HTTP ${u.status}`)}catch(t){this.logger.warn("Could not register in team_workers:",t?.message)}}async pingWorkerHeartbeat(){if(!(!this.isRunning||!this.isCloudConfigured()))try{let t=this.config.appwriteEndpoint,r=this.config.databaseId||"zplus_app",n=this.config.workerId.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,36),i=`${t}/databases/${r}/collections/team_workers/documents/${n}`,o=Wu(),s=this.engine.channelRunnerRegistry.getCount(),a=s>this.config.maxCapacity,c={current_load:s,is_overloaded:a,system_specs:JSON.stringify({...o,version:this.config.version||Hr}),last_ping:Date.now(),status:"online"},u=await fetch(i,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify({data:c})});if(u.status===401){await this.handleAuthExpired();return}if(u.ok)try{let d=await u.json()||{};d?.command==="UPGRADE"&&(this.logger.info("\u{1F4E1} [ClusterSentinel] Nh\u1EADn l\u1EC7nh UPGRADE t\u1EEB xa!"),this.autoUpdater.performUpdateAndRestart().catch(()=>{})),d?.max_capacity&&Number(d.max_capacity)!==this.config.maxCapacity&&(this.config.maxCapacity=Number(d.max_capacity),this.logger.info(`\u2699\uFE0F [ClusterSentinel] \u0110\xE3 c\u1EADp nh\u1EADt gi\u1EDBi h\u1EA1n t\u1EA3i t\u1EEB xa: ${this.config.maxCapacity}`))}catch{}else u.status===404?await this.registerWorkerInstance():u.status===400&&await fetch(i,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify({data:{current_load:s,last_ping:Date.now(),status:"online"}})}).catch(()=>{});let l=this.config.workerId.startsWith("worker_")?this.config.workerId:`worker_${this.config.workerId}`,p=this.engine.channelRunnerRegistry.getAll();for(let d of p)try{await this.engine.lockManager.renewLockRemote(d.accountId,l,6e4)}catch{}}catch{}}async markWorkerOffline(){try{let t=this.config.appwriteEndpoint,r=this.config.databaseId||"zplus_app",n=this.config.workerId.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,36),i=`${t}/databases/${r}/collections/team_workers/documents/${n}`;await fetch(i,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify({data:{status:"offline",last_ping:Date.now()}})})}catch{}}async syncTeamAccounts(){if(!(!this.isRunning||!this.isCloudConfigured()||this.isSyncingAccounts)){this.isSyncingAccounts=!0;try{let t=this.config.appwriteEndpoint,r=this.config.databaseId||"zplus_app",n=Date.now(),i=this.config.maxCapacity,o=0,s=100,a=!0;for(;a&&this.isRunning;){let c=Array.from(new Set([this.config.teamId,"default"].filter(Boolean))),u=JSON.stringify({method:"equal",attribute:"team_id",values:c}),l=JSON.stringify({method:"limit",values:[s]}),p=JSON.stringify({method:"offset",values:[o]}),d=`${t}/databases/${r}/collections/channel_accounts/documents?queries[]=${encodeURIComponent(u)}&queries[]=${encodeURIComponent(l)}&queries[]=${encodeURIComponent(p)}`,h=await fetch(d,{method:"GET",headers:this.getHeaders()});if(!h.ok){h.status===401&&await this.handleAuthExpired();let _=await h.text().catch(()=>""),m=`HTTP ${h.status}`;try{let v=JSON.parse(_);v?.message&&(m+=`: ${v.message}`)}catch{if(_.includes("<title>")){let v=_.match(/<title>([^<]+)<\/title>/i);v&&(m+=`: ${v[1].trim()}`)}else _&&_.length<150&&(m+=`: ${_.trim()}`)}this.logger.warn((0,ec.formatActionableError)({context:"ClusterSentinel",action:"\u0110\u1ED3ng b\u1ED9 t\xE0i kho\u1EA3n Team t\u1EEB Cloud",error:m}));break}let g=await h.json(),w=Array.isArray(g?.documents)?g.documents:[];w.length<s?a=!1:o+=s;for(let _ of w){let m=_.$id||_.id,v=(_.platform||"zalo").toLowerCase(),x=v==="web"||v.includes("zalo")?"zalo":v,y=_.owner_type,S=_.current_owner,k=_.status,T=Number(_.lock_expires_at||0),z=Number(_.last_heartbeat||0),C=!!this.engine.channelRunnerRegistry.get(x,m);if(!(_.nightWorkerEnabled===!0||_.night_worker_enabled===1||_.night_worker_enabled===!0)){C&&(this.logger.warn(`\u{1F6AB} [Unselected Account] T\xE0i kho\u1EA3n ${m} (${_.accountName||""}) kh\xF4ng \u0111\u01B0\u1EE3c ch\u1ECDn ch\u1EA1y Worker 24/7 (nightWorkerEnabled=false). Bu\u1ED9c ng\u1EAFt WSS ngay l\u1EADp t\u1EE9c...`),this.engine.channelRunnerRegistry.unregister(x,m),this.engine.unregisterAccount(m),this.engine.lockManager.releaseLock(m));continue}if(C&&(y==="desktop"||k==="active_desktop")){this.logger.info(`\u26A1 Master Preemption: Desktop reclaimed account ${m}. Stopping worker runner...`),this.engine.channelRunnerRegistry.unregister(x,m),this.engine.unregisterAccount(m),this.engine.lockManager.releaseLock(m);continue}let P=this.config.workerId.startsWith("worker_")?this.config.workerId:`worker_${this.config.workerId}`;if(k==="expired"||k==="error"||k==="disabled"||k==="checkpoint"){C&&(this.engine.channelRunnerRegistry.unregister(x,m),this.engine.unregisterAccount(m),this.engine.lockManager.releaseLock(m));continue}let V=y==="worker"&&S===P,Q=y==="desktop"&&n-z>6e4,J=y==="worker"&&T<n;if((k==="needs_worker"||V||Q&&T<n||J)&&!C){let de=this.engine.channelRunnerRegistry.getCount(),be=de>=i;if(!V&&(be||de/i>.8)){let ie=(await this.getActivePeerWorkers()).find(oe=>oe.currentLoad/oe.maxCapacity<de/i-.25);if(ie){this.logger.debug(`[Least-Loaded Yield] Nh\u01B0\u1EDDng t\xE0i kho\u1EA3n ${m} cho worker r\u1EA3nh h\u01A1n: ${ie.workerId} (T\u1EA3i peer: ${ie.currentLoad}/${ie.maxCapacity}, T\u1EA3i hi\u1EC7n t\u1EA1i: ${de}/${i})`);continue}}if(be){let K=Wu();this.logger.warn(`\u26A0\uFE0F [Server Spec Capacity Alert] Worker ${this.config.workerId} hi\u1EC7n \u0111ang m\u1EDF ${de+1}/${i} k\u1EBFt n\u1ED1i WSS. \u0110\xE3 v\u01B0\u1EE3t ng\u01B0\u1EE1ng khuy\u1EBFn ngh\u1ECB theo c\u1EA5u h\xECnh m\xE1y ch\u1EE7 (${Math.round(K.totalMemMb/1024)}GB RAM, ${K.cpuCount} CPUs, ${K.freeMemMb}MB Free). Theo ch\xEDnh s\xE1ch trao quy\u1EC1n quy\u1EBFt \u0111\u1ECBnh cho kh\xE1ch h\xE0ng, Worker v\u1EABn ti\u1EBFp t\u1EE5c k\u1EBFt n\u1ED1i WSS cho t\xE0i kho\u1EA3n ${m}.`)}if(await this.engine.lockManager.acquireLockRemote(m,P,6e4)){let K=V?"Resumed previous session":J?"Failover takeover (previous worker died)":be?"Over-capacity active takeover (per customer policy)":"Active takeover";this.logger.info(`\u2705 Cluster takeover: [${K}] Claimed account ${m} for team ${this.config.teamId}`),await this.spawnRunnerForAccount(_)}}}}}catch(t){this.logger.debug("syncTeamAccounts warning:",t?.message)}finally{this.isSyncingAccounts=!1}}}async spawnRunnerForAccount(t){let r=t.$id||t.id,n=(t.platform||"zalo").toLowerCase(),i=n==="web"||n.includes("zalo")?"zalo":n;if(this.engine.channelRunnerRegistry.get(i,r))return;if(!(t.nightWorkerEnabled===!0||t.night_worker_enabled===1||t.night_worker_enabled===!0)){this.logger.warn(`\u{1F6AB} [ClusterSentinel] T\u1EEB ch\u1ED1i kh\u1EDFi ch\u1EA1y WSS cho t\xE0i kho\u1EA3n unselected: ${r}`);return}let s={};if(t.authSession){let c=[];if(Array.isArray(t.$permissions))for(let p of t.$permissions){let d=String(p).match(/user:([a-zA-Z0-9_-]+)/);d&&d[1]&&c.push(d[1])}t.user_id&&c.push(t.user_id),t.userId&&c.push(t.userId),this.config.userId&&c.push(this.config.userId);let u=Array.from(new Set([this.config.teamId,t.team_id,t.teamId,...c,"6a842e9400304c01746a","default"].filter(Boolean)));s=ec.CloudCrypto.parseCloudSession(t.authSession,this.config.teamId,u)||{},!!(s?.cookie||s?.cookies||s?.accessToken||s?.token||s?.botToken)?this.logger.info(`[ClusterSentinel] \u{1F513} Gi\u1EA3i m\xE3 th\xE0nh c\xF4ng phi\xEAn ho\u1EA1t \u0111\u1ED9ng cho ${r} qua CloudCrypto.`):this.logger.warn(`[ClusterSentinel] \u26A0\uFE0F Kh\xF4ng th\u1EC3 gi\u1EA3i m\xE3 phi\xEAn h\u1EE3p l\u1EC7 cho ${r}. Scopes \u0111\xE3 th\u1EED: [${u.join(", ")}]`)}let a=await Ya.createRunner(i,r,s);if(a){this.engine.registerRunner(a),await a.start();let c=a.getStatus();if(c==="expired"||c==="error"){this.logger.warn(`\u274C [ClusterSentinel] Phi\xEAn \u0111\u0103ng nh\u1EADp c\u1EE7a t\xE0i kho\u1EA3n ${r} \u0111\xE3 h\u1EBFt h\u1EA1n/l\u1ED7i [status: ${c}]. T\u1EF1 \u0111\u1ED9ng g\u1EA1t t\u1EAFt tr\u1EF1c chi\u1EBFn v\xE0 gi\u1EA3i ph\xF3ng lock...`),this.engine.channelRunnerRegistry.unregister(i,r),this.engine.unregisterAccount(r),await this.engine.lockManager.releaseLock(r);try{let u=this.config.appwriteEndpoint,l=this.config.databaseId||"zplus_app",p=`${u}/databases/${l}/collections/channel_accounts/documents/${r}`;await fetch(p,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify({data:{status:c,nightWorkerEnabled:!1,current_owner:null,owner_type:"none"}})})}catch(u){this.logger.debug(`[ClusterSentinel] Cloud mark expired error for ${r}:`,u?.message)}return}this.engine.registerAccount({id:r,platform:i,accountName:t.accountName||r,status:c,nightWorkerEnabled:!0}),this.logger.info(`\u2705 Runner registered for ${i} account ${r} [status: ${c}]`)}}};var q$=le(nt());var N$=le(nt()),cm=class{constructor(t,r){this.config=t;this.logger=r||(0,N$.createLogger)("AppwriteDbDriver"),this.databaseId=t.databaseId||"zplus_app"}logger;databaseId;getHeaders(){let t={"Content-Type":"application/json","X-Appwrite-Project":this.config.projectId};return this.config.sessionToken?(t["X-Appwrite-Session"]=this.config.sessionToken,t.Cookie=`a_session_${this.config.projectId}=${this.config.sessionToken}; a_session_${this.config.projectId}_legacy=${this.config.sessionToken}`,this.config.sessionToken.startsWith("eyJ")&&(t["X-Fallback-Cookies"]=JSON.stringify({[`a_session_${this.config.projectId}`]:this.config.sessionToken,[`a_session_${this.config.projectId}_legacy`]:this.config.sessionToken}))):this.config.jwt&&(t["X-Appwrite-JWT"]=this.config.jwt),t}async getDocument(t,r){try{let n=`${this.config.endpoint}/databases/${this.databaseId}/collections/${t}/documents/${r}`,i=await fetch(n,{method:"GET",headers:this.getHeaders()});if(!i.ok){if(i.status===404)return null;throw new Error(`Failed to get document: HTTP ${i.status}`)}return await i.json()}catch(n){return this.logger.debug(`getDocument error for ${t}/${r}:`,n?.message),null}}async createDocument(t,r,n){let i=r.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,36),o=`${this.config.endpoint}/databases/${this.databaseId}/collections/${t}/documents`,s=await fetch(o,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({documentId:i,data:n})});if(!s.ok){let a=await this.parseCleanError(s,"T\u1EA1o document th\u1EA5t b\u1EA1i");throw new Error(`Failed to create document in ${t}: ${a}`)}return await s.json()}async parseCleanError(t,r){try{let n=await t.text();try{let i=JSON.parse(n);if(i?.message)return`HTTP ${t.status}: ${i.message}`}catch{if(n.includes("<title>")){let i=n.match(/<title>([^<]+)<\/title>/i);if(i)return`HTTP ${t.status}: ${i[1].trim()}`}else if(n&&n.length<150)return`HTTP ${t.status}: ${n.trim()}`}}catch{}return`HTTP ${t.status} (${t.statusText||r})`}async updateDocument(t,r,n){let i=r.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,36),o=`${this.config.endpoint}/databases/${this.databaseId}/collections/${t}/documents/${i}`,s=await fetch(o,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify({data:n})});if(!s.ok){let a=await this.parseCleanError(s,"C\u1EADp nh\u1EADt document th\u1EA5t b\u1EA1i");throw new Error(`Failed to update document in ${t}: ${a}`)}return await s.json()}async upsertDocument(t,r,n){try{return await this.updateDocument(t,r,n)}catch(i){if(String(i?.message||"").includes("404"))return await this.createDocument(t,r,n);throw i}}async queryDocuments(t,r){try{let n=[];if(r.filters&&r.filters.length>0)for(let c of r.filters)c.operator==="eq"?n.push(JSON.stringify({method:"equal",attribute:c.field,values:Array.isArray(c.value)?c.value:[c.value]})):c.operator==="neq"?n.push(JSON.stringify({method:"notEqual",attribute:c.field,values:Array.isArray(c.value)?c.value:[c.value]})):c.operator==="gt"?n.push(JSON.stringify({method:"greaterThan",attribute:c.field,values:[c.value]})):c.operator==="gte"?n.push(JSON.stringify({method:"greaterThanEqual",attribute:c.field,values:[c.value]})):c.operator==="lt"?n.push(JSON.stringify({method:"lessThan",attribute:c.field,values:[c.value]})):c.operator==="lte"?n.push(JSON.stringify({method:"lessThanEqual",attribute:c.field,values:[c.value]})):c.operator==="in"&&Array.isArray(c.value)&&n.push(JSON.stringify({method:"equal",attribute:c.field,values:c.value}));r.limit&&n.push(JSON.stringify({method:"limit",values:[r.limit]})),r.offset&&n.push(JSON.stringify({method:"offset",values:[r.offset]})),r.orderBy&&n.push(JSON.stringify({method:r.orderBy.direction==="desc"?"orderDesc":"orderAsc",attribute:r.orderBy.field}));let i=n.map(c=>`queries[]=${encodeURIComponent(c)}`).join("&"),o=`${this.config.endpoint}/databases/${this.databaseId}/collections/${t}/documents${i?`?${i}`:""}`,s=await fetch(o,{method:"GET",headers:this.getHeaders()});if(!s.ok)return[];let a=await s.json();return Array.isArray(a?.documents)?a.documents:[]}catch(n){return this.logger.debug(`queryDocuments error in ${t}:`,n?.message),[]}}async deleteDocument(t,r){try{let n=`${this.config.endpoint}/databases/${this.databaseId}/collections/${t}/documents/${r}`;return(await fetch(n,{method:"DELETE",headers:this.getHeaders()})).ok}catch{return!1}}};var U$=le(nt()),lm=class{constructor(t,r){this.config=t;this.logger=r||(0,U$.createLogger)("AppwriteLockDriver"),this.collectionId=t.collectionId||"channel_accounts",this.databaseId=t.databaseId||"zplus_app"}logger;collectionId;databaseId;getHeaders(){let t={"Content-Type":"application/json","X-Appwrite-Project":this.config.projectId};return this.config.sessionToken?(t["X-Appwrite-Session"]=this.config.sessionToken,t.Cookie=`a_session_${this.config.projectId}=${this.config.sessionToken}; a_session_${this.config.projectId}_legacy=${this.config.sessionToken}`,this.config.sessionToken.startsWith("eyJ")&&(t["X-Fallback-Cookies"]=JSON.stringify({[`a_session_${this.config.projectId}`]:this.config.sessionToken,[`a_session_${this.config.projectId}_legacy`]:this.config.sessionToken}))):this.config.jwt&&(t["X-Appwrite-JWT"]=this.config.jwt),t}async acquireLock(t,r,n){let i=Date.now();try{let o=`${this.config.endpoint}/databases/${this.databaseId}/collections/${this.collectionId}/documents/${t}`,s=await fetch(o,{method:"GET",headers:this.getHeaders()});if(!s.ok)return!1;let a=await s.json(),c=a.current_owner,u=Number(a.lock_expires_at||0);if(c&&c!==r&&u>i)return!1;let l=`${this.config.endpoint}/databases/${this.databaseId}/collections/${this.collectionId}/documents/${t}`;if((await fetch(l,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify({data:{current_owner:r,owner_type:r.startsWith("worker")?"worker":"desktop",lock_expires_at:i+n,last_heartbeat:i,status:r.startsWith("worker")?"active_worker":"active_desktop"}})})).ok){await new Promise(h=>setTimeout(h,30+Math.floor(Math.random()*40)));let d=await fetch(o,{method:"GET",headers:this.getHeaders()});if(d.ok&&(await d.json()).current_owner===r)return!0}return!1}catch(o){return this.logger.debug("acquireLock error:",o?.message),!1}}async releaseLock(t,r){try{if(r){let o=`${this.config.endpoint}/databases/${this.databaseId}/collections/${this.collectionId}/documents/${t}`,s=await fetch(o,{method:"GET",headers:this.getHeaders()});if(s.ok){let a=await s.json();if(a.current_owner&&a.current_owner!==r)return!1}}let n=`${this.config.endpoint}/databases/${this.databaseId}/collections/${this.collectionId}/documents/${t}`;return(await fetch(n,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify({data:{current_owner:null,owner_type:"none",lock_expires_at:0,status:"offline"}})})).ok}catch{return!1}}async renewLock(t,r,n){try{let i=`${this.config.endpoint}/databases/${this.databaseId}/collections/${this.collectionId}/documents/${t}`;return(await fetch(i,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify({data:{lock_expires_at:Date.now()+n,last_heartbeat:Date.now()}})})).ok}catch{return!1}}async getLock(t){try{let r=`${this.config.endpoint}/databases/${this.databaseId}/collections/${this.collectionId}/documents/${t}`,n=await fetch(r,{method:"GET",headers:this.getHeaders()});if(!n.ok)return null;let i=await n.json();return{resourceId:t,ownerId:i.current_owner||"",ownerType:i.owner_type,expiresAt:Number(i.lock_expires_at||0),lastHeartbeat:Number(i.last_heartbeat||0)}}catch{return null}}};var j$=le(nt()),um=class{constructor(t,r){this.config=t;this.logger=r||(0,j$.createLogger)("AppwriteCoordinator"),this.databaseId=t.databaseId||"zplus_app"}logger;databaseId;getHeaders(){let t={"Content-Type":"application/json","X-Appwrite-Project":this.config.projectId};return this.config.sessionToken?(t["X-Appwrite-Session"]=this.config.sessionToken,t.Cookie=`a_session_${this.config.projectId}=${this.config.sessionToken}; a_session_${this.config.projectId}_legacy=${this.config.sessionToken}`,this.config.sessionToken.startsWith("eyJ")&&(t["X-Fallback-Cookies"]=JSON.stringify({[`a_session_${this.config.projectId}`]:this.config.sessionToken,[`a_session_${this.config.projectId}_legacy`]:this.config.sessionToken}))):this.config.jwt&&(t["X-Appwrite-JWT"]=this.config.jwt),t}async registerNode(t){try{let r=t.workerId.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,36),n=`${this.config.endpoint}/databases/${this.databaseId}/collections/team_workers/documents/${r}`,i={data:{worker_id:t.workerId,team_id:t.teamId,worker_name:t.workerName,max_capacity:t.maxCapacity,recommended_capacity:t.recommendedCapacity||t.maxCapacity,current_load:t.currentLoad,is_overloaded:t.isOverloaded??!1,system_specs:t.systemSpecs?JSON.stringify(t.systemSpecs):void 0,status:t.status,last_ping:Date.now()}};if((await fetch(n,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify(i)})).status===404){let s=`${this.config.endpoint}/databases/${this.databaseId}/collections/team_workers/documents`;await fetch(s,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({documentId:r,...i})})}}catch(r){this.logger.warn("registerNode warning:",r?.message)}}async pingHeartbeat(t,r){try{let n=t.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,36),i=`${this.config.endpoint}/databases/${this.databaseId}/collections/team_workers/documents/${n}`;await fetch(i,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify({data:{current_load:r.currentLoad,is_overloaded:r.isOverloaded??!1,system_specs:r.systemSpecs?JSON.stringify(r.systemSpecs):void 0,last_ping:r.lastPing,status:r.status||"online"}})})}catch{}}async fetchPendingAccounts(t,r=100,n=0){try{let i=[`queries[]=${encodeURIComponent(JSON.stringify({method:"equal",attribute:"team_id",values:[t]}))}`,`queries[]=${encodeURIComponent(JSON.stringify({method:"limit",values:[r]}))}`,`queries[]=${encodeURIComponent(JSON.stringify({method:"offset",values:[n]}))}`].join("&"),o=`${this.config.endpoint}/databases/${this.databaseId}/collections/channel_accounts/documents?${i}`,s=await fetch(o,{method:"GET",headers:this.getHeaders()});if(!s.ok)return[];let a=await s.json();return Array.isArray(a?.documents)?a.documents:[]}catch(i){return this.logger.debug("fetchPendingAccounts error:",i?.message),[]}}async fetchActiveNodes(t){try{let r=[`queries[]=${encodeURIComponent(JSON.stringify({method:"equal",attribute:"team_id",values:[t]}))}`,`queries[]=${encodeURIComponent(JSON.stringify({method:"limit",values:[50]}))}`].join("&"),n=`${this.config.endpoint}/databases/${this.databaseId}/collections/team_workers/documents?${r}`,i=await fetch(n,{method:"GET",headers:this.getHeaders()});if(!i.ok)return[];let o=await i.json();return(Array.isArray(o?.documents)?o.documents:[]).map(a=>({workerId:a.worker_id||a.$id,teamId:a.team_id,workerName:a.worker_name||"",maxCapacity:Number(a.max_capacity||50),currentLoad:Number(a.current_load||0),status:a.status||"online",lastPing:Number(a.last_ping||0),isOverloaded:!!a.is_overloaded,recommendedCapacity:Number(a.recommended_capacity||a.max_capacity||50),systemSpecs:a.system_specs?typeof a.system_specs=="string"?JSON.parse(a.system_specs):a.system_specs:void 0}))}catch(r){return this.logger.debug("fetchActiveNodes error:",r?.message),[]}}async markNodeOffline(t){try{let r=t.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,36),n=`${this.config.endpoint}/databases/${this.databaseId}/collections/team_workers/documents/${r}`;await fetch(n,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify({data:{status:"offline",last_ping:Date.now()}})})}catch{}}};var $$=le(nt()),pm=class{constructor(t,r){this.config=t;this.logger=r||(0,$$.createLogger)("AppwriteAuthDriver")}logger;async verifySessionToken(t){try{let r=`${this.config.endpoint}/account`,n=await fetch(r,{method:"GET",headers:{"Content-Type":"application/json","X-Appwrite-Project":this.config.projectId,"X-Appwrite-Session":t,Cookie:`a_session_${this.config.projectId}=${t}; a_session_${this.config.projectId}_legacy=${t}`,...t.startsWith("eyJ")?{"X-Fallback-Cookies":JSON.stringify({[`a_session_${this.config.projectId}`]:t,[`a_session_${this.config.projectId}_legacy`]:t})}:{}}});if(!n.ok)return{allowed:!1,userId:"",userName:"Unknown",email:"",teamId:"default",isOwner:!1,isPremium:!1,reason:`Phi\xEAn \u0111\u0103ng nh\u1EADp kh\xF4ng h\u1EE3p l\u1EC7 (HTTP ${n.status}).`};let i=await n.json(),o=i.$id||i.id||"",s=i.name||"Ng\u01B0\u1EDDi d\xF9ng ZPlus",a=i.email||"",c=i.prefs||{},u=c.entitlements||{},l=!!(u.isPremium??c.isPremium??c.plan==="enterprise"),p=!!(u.isOwner??c.isOwner??!0),d=c.teamId||u.teamId||"default";return{allowed:l||p,userId:o,userName:s,email:a,teamId:d,isOwner:p,isPremium:l,reason:l||p?"H\u1EE3p l\u1EC7":"Y\xEAu c\u1EA7u quy\u1EC1n Enterprise \u0111\u1EC3 ch\u1EA1y Worker 24/7."}}catch(r){return this.logger.error("verifySessionToken error:",r),{allowed:!1,userId:"",userName:"Unknown",email:"",teamId:"default",isOwner:!1,isPremium:!1,reason:r?.message||"L\u1ED7i k\u1EBFt n\u1ED1i x\xE1c th\u1EF1c."}}}async checkEntitlements(t){return this.config.sessionToken?this.verifySessionToken(this.config.sessionToken):{allowed:!0,userId:t,userName:"Worker Node",email:"",teamId:"default",isOwner:!0,isPremium:!0}}};var Sw=le(require("fs")),kw=require("stream"),z$=require("stream/promises"),M$=le(nt()),fm=class{constructor(t,r){this.config=t;this.logger=r||(0,M$.createLogger)("AppwriteStorageDriver")}logger;getHeaders(){let t={"X-Appwrite-Project":this.config.projectId};return this.config.sessionToken?(t["X-Appwrite-Session"]=this.config.sessionToken,t.Cookie=`a_session_${this.config.projectId}=${this.config.sessionToken}; a_session_${this.config.projectId}_legacy=${this.config.sessionToken}`,this.config.sessionToken.startsWith("eyJ")&&(t["X-Fallback-Cookies"]=JSON.stringify({[`a_session_${this.config.projectId}`]:this.config.sessionToken,[`a_session_${this.config.projectId}_legacy`]:this.config.sessionToken}))):this.config.jwt&&(t["X-Appwrite-JWT"]=this.config.jwt),t}async createFile(t,r,n,i,o){let s=r==="unique()"?"unique()":r.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,36),a=`${this.config.endpoint}/storage/buckets/${t}/files`,c=new FormData;c.append("fileId",s);let u=Buffer.isBuffer(n)?n:Buffer.from(n),l=new Blob([u]);if(c.append("file",l,i),o&&o.length>0)for(let h=0;h<o.length;h++)c.append(`permissions[${h}]`,o[h]);let p=await fetch(a,{method:"POST",headers:this.getHeaders(),body:c});if(!p.ok){let h=await p.text();throw new Error(`Failed to upload file to storage: HTTP ${p.status} - ${h}`)}let d=await p.json();return{$id:d.$id||r,name:d.name||i,sizeOriginal:d.sizeOriginal||u.length,mimeType:d.mimeType,$createdAt:d.$createdAt,$updatedAt:d.$updatedAt}}async getFileDownload(t,r){let n=`${this.config.endpoint}/storage/buckets/${t}/files/${r}/download`,i=await fetch(n,{method:"GET",headers:this.getHeaders()});if(!i.ok)throw new Error(`Failed to download file: HTTP ${i.status}`);let o=await i.arrayBuffer();return Buffer.from(o)}async downloadFileToPath(t,r,n){let i=`${this.config.endpoint}/storage/buckets/${t}/files/${r}/download`,o=await fetch(i,{method:"GET",headers:this.getHeaders()});if(!o.ok)throw new Error(`Failed to download file: HTTP ${o.status}`);if(typeof kw.Readable.fromWeb=="function"&&o.body)await(0,z$.pipeline)(kw.Readable.fromWeb(o.body),Sw.default.createWriteStream(n));else{let s=await o.arrayBuffer();await Sw.default.promises.writeFile(n,Buffer.from(s))}return!0}async deleteFile(t,r){let n=`${this.config.endpoint}/storage/buckets/${t}/files/${r}`;return(await fetch(n,{method:"DELETE",headers:this.getHeaders()})).ok}async listFiles(t){let r=`${this.config.endpoint}/storage/buckets/${t}/files`,n=await fetch(r,{method:"GET",headers:this.getHeaders()});if(!n.ok)return{files:[],total:0};let i=await n.json();return{files:(i.files||[]).map(o=>({$id:o.$id,name:o.name,sizeOriginal:o.sizeOriginal,mimeType:o.mimeType})),total:i.total||0}}async getFile(t,r){let n=`${this.config.endpoint}/storage/buckets/${t}/files/${r}`,i=await fetch(n,{method:"GET",headers:this.getHeaders()});return i.ok?await i.json():null}};var dm=class{constructor(t,r){this.config=t;this.logger=r||(0,q$.createLogger)("AppwriteCloudAdapter");let n={get endpoint(){return t.cloudEndpoint||t.appwriteEndpoint||"https://api.softty.net/v1"},get projectId(){return t.cloudProjectId||t.appwriteProjectId||"699cfc3100136099c1c1"},get databaseId(){return t.cloudDatabaseId||t.databaseId||"zplus_app"},get sessionToken(){return t.cloudSessionToken||t.appwriteSessionToken},get jwt(){return t.cloudJwt||t.appwriteJwt}};this.database=new cm(n,this.logger),this.lockStorage=new lm(n,this.logger),this.coordinator=new um(n,this.logger),this.auth=new pm(n,this.logger),this.storage=new fm(n,this.logger)}providerName="appwrite";database;lockStorage;coordinator;auth;storage;logger;async start(){this.logger.info("\u2705 Appwrite Cloud Adapter initialized.")}async stop(){this.logger.info("Appwrite Cloud Adapter stopped.")}};var H$=le(nt()),hm=class{constructor(t,r){this.config=t;this.logger=r||(0,H$.createLogger)("CustomApiAdapter");let n=t.cloudEndpoint||"https://api.softty.net/custom/v1",o={"Content-Type":"application/json",Authorization:`Bearer ${t.cloudSessionToken||t.cloudJwt||""}`,"X-Tenant-ID":t.teamId||"default"};this.database={async getDocument(s,a){try{let c=await fetch(`${n}/data/${s}/${a}`,{headers:o});return c.ok?await c.json():null}catch{return null}},async createDocument(s,a,c){return await(await fetch(`${n}/data/${s}`,{method:"POST",headers:o,body:JSON.stringify({id:a,...c})})).json()},async updateDocument(s,a,c){return await(await fetch(`${n}/data/${s}/${a}`,{method:"PATCH",headers:o,body:JSON.stringify(c)})).json()},async upsertDocument(s,a,c){return await(await fetch(`${n}/data/${s}/${a}/upsert`,{method:"POST",headers:o,body:JSON.stringify(c)})).json()},async queryDocuments(s,a){try{let c=await fetch(`${n}/data/${s}/query`,{method:"POST",headers:o,body:JSON.stringify(a)});if(!c.ok)return[];let u=await c.json();return Array.isArray(u?.items)?u.items:[]}catch{return[]}},async deleteDocument(s,a){try{return(await fetch(`${n}/data/${s}/${a}`,{method:"DELETE",headers:o})).ok}catch{return!1}}},this.lockStorage={async acquireLock(s,a,c){try{let u=await fetch(`${n}/locks/acquire`,{method:"POST",headers:o,body:JSON.stringify({resourceId:s,ownerId:a,ttlMs:c})});return u.ok?!!(await u.json())?.acquired:!1}catch{return!1}},async releaseLock(s,a){try{return(await fetch(`${n}/locks/release`,{method:"POST",headers:o,body:JSON.stringify({resourceId:s,ownerId:a})})).ok}catch{return!1}},async renewLock(s,a,c){try{return(await fetch(`${n}/locks/renew`,{method:"POST",headers:o,body:JSON.stringify({resourceId:s,ownerId:a,ttlMs:c})})).ok}catch{return!1}},async getLock(s){try{let a=await fetch(`${n}/locks/${s}`,{headers:o});return a.ok?await a.json():null}catch{return null}}},this.coordinator={async registerNode(s){try{await fetch(`${n}/cluster/nodes/register`,{method:"POST",headers:o,body:JSON.stringify(s)})}catch{}},async pingHeartbeat(s,a){try{await fetch(`${n}/cluster/nodes/${s}/heartbeat`,{method:"POST",headers:o,body:JSON.stringify(a)})}catch{}},async fetchPendingAccounts(s,a=100,c=0){try{let u=await fetch(`${n}/cluster/accounts/pending?teamId=${s}&limit=${a}&offset=${c}`,{headers:o});if(!u.ok)return[];let l=await u.json();return Array.isArray(l?.accounts)?l.accounts:[]}catch{return[]}},async markNodeOffline(s){try{await fetch(`${n}/cluster/nodes/${s}/offline`,{method:"POST",headers:o})}catch{}}},this.auth={async verifySessionToken(s){try{let a=await fetch(`${n}/auth/verify`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`}});return a.ok?await a.json():{allowed:!1,userId:"",userName:"Unknown",email:"",teamId:"default",isOwner:!1,isPremium:!1,reason:"Invalid session token"}}catch(a){return{allowed:!1,userId:"",userName:"Unknown",email:"",teamId:"default",isOwner:!1,isPremium:!1,reason:a?.message}}},async checkEntitlements(s){return{allowed:!0,userId:s,userName:"User",email:"",teamId:"default",isOwner:!0,isPremium:!0}}}}providerName="custom-api";database;lockStorage;coordinator;auth;logger;async start(){this.logger.info("\u{1F50C} Custom API Cloud Adapter initialized.")}async stop(){this.logger.info("Custom API Cloud Adapter stopped.")}};var W$=le(nt()),mm=class{providerName="in-memory";database;lockStorage;coordinator;auth;logger;tables=new Map;locks=new Map;nodes=new Map;constructor(t,r){this.logger=r||(0,W$.createLogger)("InMemoryCloudAdapter");let n=i=>{let o=this.tables.get(i);return o||(o=new Map,this.tables.set(i,o)),o};this.database={async getDocument(i,o){return n(i).get(o)||null},async createDocument(i,o,s){return n(i).set(o,{$id:o,id:o,...s}),n(i).get(o)},async updateDocument(i,o,s){let c={...n(i).get(o)||{$id:o,id:o},...s};return n(i).set(o,c),c},async upsertDocument(i,o,s){return this.updateDocument(i,o,s)},async queryDocuments(i,o){let s=Array.from(n(i).values());if(o.filters)for(let a of o.filters)a.operator==="eq"&&(s=s.filter(c=>c[a.field]===a.value));return o.limit&&(s=s.slice(0,o.limit)),s},async deleteDocument(i,o){return n(i).delete(o)}},this.lockStorage={acquireLock:async(i,o,s)=>{let a=Date.now(),c=this.locks.get(i);return c&&c.expiresAt>a&&c.ownerId!==o?!1:(this.locks.set(i,{resourceId:i,ownerId:o,ownerType:o.startsWith("worker")?"worker":"desktop",expiresAt:a+s,lastHeartbeat:a}),!0)},releaseLock:async(i,o)=>{let s=this.locks.get(i);return s?o&&s.ownerId!==o?!1:(this.locks.delete(i),!0):!0},renewLock:async(i,o,s)=>this.lockStorage.acquireLock(i,o,s),getLock:async i=>this.locks.get(i)||null},this.coordinator={registerNode:async i=>{this.nodes.set(i.workerId,i)},pingHeartbeat:async(i,o)=>{let s=this.nodes.get(i);s&&(s.currentLoad=o.currentLoad,s.lastPing=o.lastPing,s.status=o.status||"online")},fetchPendingAccounts:async i=>Array.from(n("channel_accounts").values()).filter(s=>s.team_id===i||s.teamId===i),markNodeOffline:async i=>{let o=this.nodes.get(i);o&&(o.status="offline")}},this.auth={verifySessionToken:async i=>({allowed:!!i,userId:"user_test_in_memory",userName:"Test User",email:"test@softty.net",teamId:"team_test",isOwner:!0,isPremium:!0}),checkEntitlements:async i=>({allowed:!0,userId:i,userName:"Test User",email:"test@softty.net",teamId:"team_test",isOwner:!0,isPremium:!0})}}async start(){this.logger.info("\u{1F9EA} In-Memory Cloud Adapter initialized.")}async stop(){this.logger.info("In-Memory Cloud Adapter stopped.")}};var G$=le(nt()),gm=class{static create(t,r){let n=r||(0,G$.createLogger)("CloudAdapterFactory");switch(t.cloudProvider||"appwrite"){case"custom-api":return n.info("Creating Custom API Cloud Adapter..."),new hm(t,n);case"in-memory":return n.info("Creating In-Memory Cloud Adapter..."),new mm(t,n);case"appwrite":default:return n.info("Creating Appwrite Cloud Adapter..."),new dm(t,n)}}};var ym=class{logger;channelRunnerRegistry;lockManager;deltaQueue;automationEngine;pushDispatcher;httpServer;clusterSentinel;cloudAdapter;status="idle";lastError;startTime=0;activeAccounts=new Map;messagesProcessed=0;heartbeatTimer;storageQuotaExceeded=!1;config;constructor(t){this.config={enableHttp:!1,teamId:"default",workerName:`Worker_${t.workerId}`,version:t.version||Hr,maxCapacity:50,clusterPollIntervalMs:5e3,heartbeatIntervalMs:15e3,logLevel:"info",...t,workerId:t.workerId},this.logger=(0,J$.createLogger)(`WorkerEngine:${this.config.workerId}`),this.channelRunnerRegistry=new Zu(this.logger),this.lockManager=new Ku(6e4,this.logger),this.cloudAdapter=gm.create(this.config,this.logger),(this.config.cloudEndpoint||this.config.appwriteEndpoint)&&this.lockManager.setStorageProvider(this.cloudAdapter.lockStorage);let r=process.env.WORKER_DATA_DIR||ks.default.join(process.cwd(),".data"),n=ks.default.join(r,`pending_messages_${this.config.workerId}.json`);this.deltaQueue=new Yu(1e4,this.logger,n),this.automationEngine=new Xu(this.logger,{enabled:!1,apiKey:this.config.deepseekApiKey||this.config.geminiApiKey||this.config.openaiApiKey||this.config.anthropicApiKey||this.config.customAiApiKey,baseUrl:this.config.aiBaseUrl,provider:this.config.aiProvider,model:this.config.aiModel,systemPrompt:this.config.nightSystemPrompt,fallbackMessage:this.config.nightFallbackReply}),this.pushDispatcher=new Qu(this.logger),this.clusterSentinel=new am(this.config,this,this.logger),this.httpServer=this.config.enableHttp&&this.config.port?new tm(this.config.port,this,this.lockManager,this.deltaQueue,this.logger):null,this.lockManager.onPreempt(async i=>{this.logger.info(`Preemption callback: stopping WSS for account ${i}...`);let o=this.channelRunnerRegistry.getAll();for(let s of o)s.accountId===i&&await s.stop()})}async start(){if(this.status==="running"){this.logger.warn("Worker is already running.");return}if(this.logger.info("Starting ZPlus 24/7 Headless Worker Engine..."),this.status="initializing",this.startTime=Date.now(),this.httpServer)try{await this.httpServer.start()}catch(r){this.logger.error("Failed to start Worker HTTP Ingress Server:",r)}else this.logger.info("\u{1F6E1}\uFE0F Ch\u1EBF \u0111\u1ED9 Zero-Port (Outbound-only) \u0111ang ho\u1EA1t \u0111\u1ED9ng: Worker kh\xF4ng m\u1EDF b\u1EA5t k\u1EF3 c\u1ED5ng l\u1EAFng nghe Inbound n\xE0o.");try{await this.cloudAdapter.start()}catch(r){this.logger.error("Failed to start Cloud Adapter:",r)}if(this.config.isStandby){this.status="idle",this.logger.warn(`\u23F8\uFE0F Worker is in STANDBY mode: ${this.config.standbyReason||"Unauthorized / Free Tier / Non-owner"}. Worker will NOT process accounts.`);return}this.heartbeatTimer=setInterval(()=>{this.sendHeartbeat()},this.config.heartbeatIntervalMs);try{await this.clusterSentinel.start()}catch(r){this.logger.error("Failed to start Cluster Sentinel:",r)}this.status="running",this.writeLocalHeartbeat();let t=this.config.enableHttp?`Port: ${this.config.port}`:"Zero-Port Headless Daemon";this.logger.info(`\u2705 ZPlus Worker Engine started successfully [ID: ${this.config.workerId}, Mode: ${t}]`);try{typeof global.gc=="function"&&global.gc()}catch{}}async stop(){this.logger.info("Stopping ZPlus Worker Engine..."),this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=void 0),await this.clusterSentinel.stop(),await this.cloudAdapter.stop(),this.httpServer&&await this.httpServer.stop(),this.clearLocalHeartbeat(),await this.channelRunnerRegistry.stopAll(),this.status="stopped",this.logger.info("ZPlus Worker Engine stopped.")}registerRunner(t){t.onMessage?.(r=>{this.handleIncomingMessage(r,t)}),this.channelRunnerRegistry.register(t)}registerAccount(t){this.activeAccounts.set(t.id,t),this.logger.info(`Registered active account: ${t.accountName} [${t.platform}]`),this.writeLocalHeartbeat()}unregisterAccount(t){this.activeAccounts.delete(t),this.logger.info(`Unregistered account: ${t}`),this.writeLocalHeartbeat()}recordMessageProcessed(){this.messagesProcessed++}async handleIncomingMessage(t,r){this.recordMessageProcessed(),this.deltaQueue.enqueue(t),await this.pushMessageToCloud(t);try{let n=await this.automationEngine.evaluateIncomingMessage(t);if(n&&r){this.logger.info(`[NightAutoReply] Sending automated reply to thread ${t.threadId}: "${n}"`);let i={id:`reply_${Date.now()}`,platform:t.platform,conversationId:t.conversationId,threadId:t.threadId,accountId:t.accountId,senderId:t.accountId,senderName:"ZPlus Night Assistant",senderType:"agent",messageType:"text",content:n,timestamp:Date.now(),isSelf:!0,status:"sent"};await r.sendMessage(i)?(this.deltaQueue.enqueue(i),await this.pushMessageToCloud(i)):this.logger.warn(`[NightAutoReply] Socket delivery failed for thread ${t.threadId}. Skipped cloud push to prevent ghost message.`)}}catch(n){this.logger.warn("Auto-reply evaluation notice:",n)}try{await this.pushDispatcher.dispatchMessageAlert("fcm_token_mobile_owner",t)}catch(n){this.logger.debug("Push notification dispatch notice:",n)}}async pushMessageToCloud(t){if(!(!this.config.cloudEndpoint&&!this.config.appwriteEndpoint))try{let r=t.id.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,36),n=new Date().toISOString(),i=t.threadId||t.conversationId,o=t.mediaUrl||t.metadata?.mediaUrl||Array.isArray(t.attachments)&&t.attachments[0]?.url||void 0,s;if(o&&this.cloudAdapter.storage&&!this.storageQuotaExceeded&&["chat.photo","chat.voice","chat.sticker","chat.doodle","image","audio","voice"].includes((t.messageType||t.type||"").toLowerCase()))try{let u=(t.messageType||t.type||"").toLowerCase(),l=u.includes("voice")||u.includes("audio")?".aac":".jpg",p=`media_${r}${l}`,d=await fetch(o,{headers:{"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",Referer:"https://chat.zalo.me/"}});if(d.ok){let h=await d.arrayBuffer(),g=Buffer.from(h);if(g.length>0&&g.length<=20*1024*1024){let w=this.config.storageBucketId||"zplus-media-vault",_=await this.cloudAdapter.storage.createFile(w,r,g,p);_?.$id&&(s=_.$id,this.logger.info(`\u2601\uFE0F [MediaSync] In-memory streamed media (${(g.length/1024).toFixed(1)} KB) to Cloud Storage: ${s}`))}}else d.status===403&&this.logger.warn(`[MediaSync] Media URL already expired (403): ${o}`)}catch(u){let l=String(u?.message||"").toLowerCase();l.includes("quota")||l.includes("403")||l.includes("limit")?(this.storageQuotaExceeded=!0,this.logger.warn(`\u26A0\uFE0F [MediaSync] Cloud Storage quota exceeded for team ${this.config.teamId}. Pausing cloud media uploads.`)):this.logger.debug("[MediaSync] Cloud media upload notice:",u)}let a={...typeof t.payload=="object"?t.payload:{},mediaUrl:o,cloud_file_id:s,attachments:t.attachments,metadata:t.metadata},c={conversation_id:t.conversationId||t.threadId,thread_id:i,account_id:t.accountId,sender_id:t.senderId,sender_name:(t.senderName||"").slice(0,255),senderType:t.senderType||"customer",messageType:t.messageType||t.type||"text",content:(t.content||t.text||"").slice(0,3e3),payload:typeof t.payload=="string"?t.payload.slice(0,3e3):JSON.stringify(a).slice(0,3e3),timestamp:t.timestamp||Date.now(),is_self:!!(t.isSelf||t.senderId==="0"||t.accountId&&String(t.senderId)===String(t.accountId)),is_recall:0,status:t.status||"sent",team_id:this.config.teamId||"",zplus_action:"INSERT",zplus_updated_at:n};if(await this.cloudAdapter.database.upsertDocument("messages",r,c),this.logger.info(`\u2601\uFE0F [CloudSync] Pushed message ${t.id} to Cloud DB via ${this.cloudAdapter.providerName}.`),i&&t.accountId)try{let u=`${i}:${t.accountId}`,p=`z_${V$.default.createHash("md5").update(`conversations:${u}`).digest("hex")}`,d=(t.content||t.text||"").slice(0,500),h={thread_id:i,account_id:t.accountId,name:(t.senderName||i).slice(0,255),last_message:JSON.stringify({content:d,senderId:t.senderId,timestamp:t.timestamp||Date.now(),msgType:t.msgType||t.messageType||"chat.text"}),timestamp:t.timestamp||Date.now(),unread_count:1,peerId:t.senderId,peerName:(t.senderName||"").slice(0,255),platform:t.platform||"zalo",isPinned:!1,zplus_action:"UPDATE",zplus_updated_at:n};await this.cloudAdapter.database.upsertDocument("conversations",p,h)}catch(u){this.logger.debug(`[CloudSync] Note updating conversations on cloud: ${u?.message}`)}}catch(r){this.logger.error(`\u274C [CloudSync] Failed to push message ${t.id} to Cloud DB: ${r?.message||r}`)}}getMetrics(){let t=this.startTime>0?Math.floor((Date.now()-this.startTime)/1e3):0,r=process.memoryUsage().rss/(1024*1024);return{workerId:this.config.workerId,status:this.status,uptimeSeconds:t,activeAccountsCount:this.activeAccounts.size,totalMessagesProcessed:this.messagesProcessed,memoryUsageMb:Math.round(r*100)/100,lastHeartbeat:new Date().toISOString()}}sendHeartbeat(){let t=this.getMetrics();this.writeLocalHeartbeat(),this.logger.info(`\u{1F493} Heartbeat: status=${t.status}, accounts=${t.activeAccountsCount}, msgs=${t.totalMessagesProcessed}, pendingDelta=${this.deltaQueue.getCount()}, uptime=${t.uptimeSeconds}s`)}setStatus(t,r){this.status=t,r!==void 0&&(this.lastError=r),this.writeLocalHeartbeat()}writeLocalHeartbeat(){try{let t=process.env.ZPLUS_HOME||ks.default.join(Ew.default.homedir(),".zplus");wo.default.existsSync(t)||wo.default.mkdirSync(t,{recursive:!0});let r=ks.default.join(t,"worker_heartbeat.json"),n=this.getMetrics(),i={vendor:"Softtynet Co., Ltd.",product:"Softty ZPlus Omnichannel Platform",daemonTitle:"ZPlus 24/7 Headless Worker Daemon",version:this.config.version||"1.0.10",homepage:"https://softty.net",supportEmail:"support@softty.net",processTitle:process.title||"zplus-worker (Softtynet Co., Ltd.)",status:this.status,lastError:this.lastError||null,workerId:this.config.workerId,workerName:this.config.workerName,teamId:this.config.teamId,pid:process.pid,uptimeSeconds:n.uptimeSeconds,activeAccountsCount:n.activeAccountsCount,activeRunners:this.channelRunnerRegistry.getCount(),totalMessagesProcessed:n.totalMessagesProcessed,pendingDeltaMessages:this.deltaQueue.getCount(),memoryUsageMb:n.memoryUsageMb,isZeroPort:!this.config.enableHttp,port:this.config.enableHttp?this.config.port:null,lastPing:Date.now(),timestamp:Date.now()},o=`${r}.${process.pid}.tmp`;wo.default.writeFileSync(o,JSON.stringify(i,null,2)),wo.default.renameSync(o,r)}catch{}}clearLocalHeartbeat(){try{let t=process.env.ZPLUS_HOME||ks.default.join(Ew.default.homedir(),".zplus"),r=ks.default.join(t,"worker_heartbeat.json");if(wo.default.existsSync(r)){let n={status:"stopped",workerId:this.config.workerId,pid:process.pid,lastPing:Date.now(),timestamp:Date.now()},i=`${r}.${process.pid}.tmp`;wo.default.writeFileSync(i,JSON.stringify(n,null,2)),wo.default.renameSync(i,r)}}catch{}}};var Cn=le(require("os")),xt=le(require("fs")),Ht=le(require("path")),ht=require("child_process"),Z$=le(nt()),xm=class{logger;constructor(t){this.logger=t||(0,Z$.createLogger)("WorkerAutostartManager")}getExecutableInfo(){let t=process.execPath,r=Ht.default.resolve(__dirname,"cli.js");if(xt.default.existsSync(r)||(r=Ht.default.resolve(__dirname,"../dist/cli.js")),!xt.default.existsSync(r))try{let n=process.platform==="win32"?"where zplus-worker":"which zplus-worker",i=(0,ht.execSync)(n,{encoding:"utf-8"}).trim().split(`
|
|
127
|
+
`;return(0,om.spawn)("powershell",["-Command",l],{detached:!0,stdio:"ignore"}).unref(),!0}}}catch{}return!1}};var am=class{constructor(t,r,n){this.config=t;this.engine=r;this.logger=n||(0,ec.createLogger)(`ClusterSentinel:${t.workerId}`),this.autoUpdater=new rm(this.logger),this.authManager=new Qa(this.logger)}logger;autoUpdater;authManager;refreshPromise=null;isRunning=!1;pollTimer;heartbeatTimer;cachedPeerWorkers=[];lastPeerCheckTime=0;lastNightConfigUpdatedAt=0;lastNightConfigCheck=0;isSyncingAccounts=!1;getHeaders(){let t=this.config.appwriteProjectId||"",r={"Content-Type":"application/json","X-Appwrite-Project":t};if(this.config.appwriteSessionToken){let n=this.config.appwriteSessionToken;n.includes(".")&&n.split(".").length===3?r["X-Appwrite-JWT"]=n:(r["X-Appwrite-Session"]=n,r.Cookie=`a_session_${t}=${n}; a_session_${t}_legacy=${n}`,n.startsWith("eyJ")&&(r["X-Fallback-Cookies"]=JSON.stringify({[`a_session_${t}`]:n,[`a_session_${t}_legacy`]:n})))}else this.config.appwriteJwt&&(r["X-Appwrite-JWT"]=this.config.appwriteJwt);return r}async handleAuthExpired(){return this.refreshPromise?await this.refreshPromise:(this.refreshPromise=(async()=>{try{this.logger.warn("\u26A0\uFE0F [ClusterSentinel] Phi\xEAn x\xE1c th\u1EF1c Cloud \u0111\xE3 h\u1EBFt h\u1EA1n (HTTP 401). \u0110ang k\xEDch ho\u1EA1t Silent Refresh Token 24/7...");let t=await this.authManager.ensureValidSession(this.config.appwriteEndpoint,this.config.appwriteProjectId,!0);return t?.sessionToken?(this.config.appwriteSessionToken=t.sessionToken,t.teamId&&t.teamId!=="default"&&(this.config.teamId=t.teamId),this.engine.setStatus("running"),this.logger.info(`\u2705 [ClusterSentinel] \u0110\xE3 t\u1EF1 \u0111\u1ED9ng kh\xF4i ph\u1EE5c quy\u1EC1n h\u1EA1n qua Refresh Token! (${t.userName})`),!0):(this.logger.error("\u274C [ClusterSentinel] Kh\xF4ng th\u1EC3 t\u1EF1 \u0111\u1ED9ng l\xE0m m\u1EDBi phi\xEAn. Vui l\xF2ng \u0111\u0103ng nh\u1EADp l\u1EA1i Worker qua l\u1EC7nh: zplus-worker login"),this.engine.setStatus("auth_error","M\xE1y ch\u1EE7 tr\u1EF1c ban 24/7 b\u1ECB h\u1EBFt h\u1EA1n phi\xEAn. Vui l\xF2ng ch\u1EA1y l\u1EC7nh 'zplus-worker login' \u0111\u1EC3 c\u1EA5p l\u1EA1i phi\xEAn l\xE0m vi\u1EC7c."),sm.notify("\u26A0\uFE0F Tr\u1EE3 L\xFD Tr\u1EF1c Ban 24/7 T\u1EA1m D\u1EEBng","Phi\xEAn l\xE0m vi\u1EC7c c\u1EE7a Worker \u0111\xE3 h\u1EBFt h\u1EA1n. Vui l\xF2ng ch\u1EA1y l\u1EC7nh 'zplus-worker login' \u0111\u1EC3 c\u1EA5p l\u1EA1i phi\xEAn l\xE0m vi\u1EC7c!","worker_auth_401",900*1e3),!1)}catch(t){return this.logger.error("\u274C [ClusterSentinel] L\u1ED7i ngo\u1EA1i l\u1EC7 trong Silent Refresh Token:",t?.message),this.engine.setStatus("auth_error",`L\u1ED7i ngo\u1EA1i l\u1EC7 x\xE1c th\u1EF1c: ${t?.message||"Kh\xF4ng x\xE1c \u0111\u1ECBnh"}`),!1}finally{this.refreshPromise=null}})(),await this.refreshPromise)}isCloudConfigured(){return!!(this.config.appwriteEndpoint&&this.config.appwriteProjectId&&(this.config.appwriteSessionToken||this.config.appwriteJwt))}async start(){if(this.isRunning)return;if(this.isRunning=!0,!this.isCloudConfigured()){this.logger.info("Appwrite Cloud credentials not fully configured. Running in standalone local mode.");return}this.logger.info(`\u{1F680} Initializing Team Cluster Sentinel for Team [${this.config.teamId}] (Worker: ${this.config.workerId}, Capacity: ${this.config.maxCapacity})`),await this.registerWorkerInstance(),this.heartbeatTimer=setInterval(()=>{this.pingWorkerHeartbeat().catch(r=>{this.logger.debug("Worker heartbeat ping error:",r?.message)})},15e3);let t=this.config.clusterPollIntervalMs||3e3;this.pollTimer=setInterval(()=>{this.syncTeamAccounts().catch(n=>{this.logger.debug("Cluster account sync error:",n?.message)});let r=Date.now();r-this.lastNightConfigCheck>3e4&&(this.lastNightConfigCheck=r,this.syncNightShiftConfig().catch(()=>{}))},t),this.syncTeamAccounts().catch(()=>{}),this.syncNightShiftConfig().catch(()=>{}),this.autoUpdater.startPeriodicAutoUpdate(this.config.version||Hr)}async stop(){this.isRunning=!1,this.autoUpdater.stop(),this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=void 0),this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=void 0),this.isCloudConfigured()&&await this.markWorkerOffline(),this.logger.info("Cluster Sentinel stopped.")}async syncNightShiftConfig(){if(!(!this.isRunning||!this.isCloudConfigured()||!this.config.teamId))try{let t=this.config.appwriteEndpoint,r=this.config.databaseId||"zplus_app",n=`night_cfg_${this.config.teamId}`.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,36),i=`${t}/databases/${r}/collections/cluster_settings/documents/${n}`,o=await fetch(i,{method:"GET",headers:this.getHeaders()});if(!o.ok)return;let s=await o.json(),a=Number(s.updated_at||0);if(a>this.lastNightConfigUpdatedAt&&s.config_json)try{let c=JSON.parse(s.config_json);this.engine.automationEngine.configure(c),this.lastNightConfigUpdatedAt=a,this.logger.info(`\u{1F319} [ClusterSentinel] Synchronized latest Night AI config from Cloud DB (Provider: ${c.provider||"default"}, Enabled: ${c.enabled})`)}catch(c){this.logger.debug("Failed to parse night config JSON from Cloud DB:",c?.message)}}catch{}}async getActivePeerWorkers(){let t=Date.now();if(t-this.lastPeerCheckTime<15e3&&this.cachedPeerWorkers.length>0)return this.cachedPeerWorkers;try{let r=this.config.appwriteEndpoint,n=this.config.databaseId||"zplus_app",i=JSON.stringify({method:"equal",attribute:"team_id",values:[this.config.teamId]}),o=JSON.stringify({method:"limit",values:[25]}),s=`${r}/databases/${n}/collections/team_workers/documents?queries[]=${encodeURIComponent(i)}&queries[]=${encodeURIComponent(o)}`,a=await fetch(s,{method:"GET",headers:this.getHeaders()});if(a.ok){let c=await a.json(),u=Array.isArray(c?.documents)?c.documents:[];this.cachedPeerWorkers=u.filter(l=>l.worker_id!==this.config.workerId&&l.status==="online"&&t-Number(l.last_ping||0)<45e3).map(l=>({workerId:l.worker_id,currentLoad:Number(l.current_load||0),maxCapacity:Number(l.max_capacity||50),lastPing:Number(l.last_ping||0)})),this.lastPeerCheckTime=t}}catch{}return this.cachedPeerWorkers}async registerWorkerInstance(){try{let t=this.config.appwriteEndpoint,r=this.config.databaseId||"zplus_app",n=this.config.workerId.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,36),i=Wu(),o=this.engine.channelRunnerRegistry.getCount(),s=o>this.config.maxCapacity,a=`${t}/databases/${r}/collections/team_workers/documents/${n}`,c={data:{worker_id:this.config.workerId,team_id:this.config.teamId,worker_name:this.config.workerName,max_capacity:this.config.maxCapacity,recommended_capacity:this.config.recommendedCapacity||this.config.maxCapacity,current_load:o,is_overloaded:s,system_specs:JSON.stringify({...i,version:this.config.version||Hr}),status:"online",last_ping:Date.now()}},u=await fetch(a,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify(c)});if(u.status===401&&await this.handleAuthExpired()&&(u=await fetch(a,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify(c)})),u.ok){this.logger.info(`\u2705 Worker registered in Team Cluster: ${this.config.workerId}`);return}if(u.status===404){let l=`${t}/databases/${r}/collections/team_workers/documents`,p=await fetch(l,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({documentId:n,permissions:['read("users")','update("users")','delete("users")'],...c})});if(p.status===401&&await this.handleAuthExpired()&&(p=await fetch(l,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({documentId:n,permissions:['read("users")','update("users")','delete("users")'],...c})})),!p.ok&&p.status===400){let d={data:{worker_id:this.config.workerId,team_id:this.config.teamId,worker_name:this.config.workerName,max_capacity:this.config.maxCapacity,current_load:o,status:"online",last_ping:Date.now()}};p=await fetch(l,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({documentId:n,permissions:['read("users")','update("users")','delete("users")'],...d})})}p.ok?this.logger.info(`\u2705 Worker registered in Team Cluster: ${this.config.workerId}`):this.logger.warn(`\u26A0\uFE0F Could not register in team_workers: HTTP ${p.status}`)}else this.logger.warn(`\u26A0\uFE0F Could not patch team_workers: HTTP ${u.status}`)}catch(t){this.logger.warn("Could not register in team_workers:",t?.message)}}async pingWorkerHeartbeat(){if(!(!this.isRunning||!this.isCloudConfigured()))try{let t=this.config.appwriteEndpoint,r=this.config.databaseId||"zplus_app",n=this.config.workerId.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,36),i=`${t}/databases/${r}/collections/team_workers/documents/${n}`,o=Wu(),s=this.engine.channelRunnerRegistry.getCount(),a=s>this.config.maxCapacity,c={current_load:s,is_overloaded:a,system_specs:JSON.stringify({...o,version:this.config.version||Hr}),last_ping:Date.now(),status:"online"},u=await fetch(i,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify({data:c})});if(u.status===401){await this.handleAuthExpired();return}if(u.ok)try{let d=await u.json()||{};d?.command==="UPGRADE"&&(this.logger.info("\u{1F4E1} [ClusterSentinel] Nh\u1EADn l\u1EC7nh UPGRADE t\u1EEB xa!"),this.autoUpdater.performUpdateAndRestart().catch(()=>{})),d?.max_capacity&&Number(d.max_capacity)!==this.config.maxCapacity&&(this.config.maxCapacity=Number(d.max_capacity),this.logger.info(`\u2699\uFE0F [ClusterSentinel] \u0110\xE3 c\u1EADp nh\u1EADt gi\u1EDBi h\u1EA1n t\u1EA3i t\u1EEB xa: ${this.config.maxCapacity}`))}catch{}else u.status===404?await this.registerWorkerInstance():u.status===400&&await fetch(i,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify({data:{current_load:s,last_ping:Date.now(),status:"online"}})}).catch(()=>{});let l=this.config.workerId.startsWith("worker_")?this.config.workerId:`worker_${this.config.workerId}`,p=this.engine.channelRunnerRegistry.getAll();for(let d of p)try{await this.engine.lockManager.renewLockRemote(d.accountId,l,6e4)}catch{}}catch{}}async markWorkerOffline(){try{let t=this.config.appwriteEndpoint,r=this.config.databaseId||"zplus_app",n=this.config.workerId.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,36),i=`${t}/databases/${r}/collections/team_workers/documents/${n}`;await fetch(i,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify({data:{status:"offline",last_ping:Date.now()}})})}catch{}}async syncTeamAccounts(){if(!(!this.isRunning||!this.isCloudConfigured()||this.isSyncingAccounts)){this.isSyncingAccounts=!0;try{let t=this.config.appwriteEndpoint,r=this.config.databaseId||"zplus_app",n=Date.now(),i=this.config.maxCapacity,o=0,s=100,a=!0;for(;a&&this.isRunning;){let c=Array.from(new Set([this.config.teamId,"default"].filter(Boolean))),u=JSON.stringify({method:"equal",attribute:"team_id",values:c}),l=JSON.stringify({method:"limit",values:[s]}),p=JSON.stringify({method:"offset",values:[o]}),d=`${t}/databases/${r}/collections/channel_accounts/documents?queries[]=${encodeURIComponent(u)}&queries[]=${encodeURIComponent(l)}&queries[]=${encodeURIComponent(p)}`,h=await fetch(d,{method:"GET",headers:this.getHeaders()});if(!h.ok){h.status===401&&await this.handleAuthExpired();let _=await h.text().catch(()=>""),m=`HTTP ${h.status}`;try{let v=JSON.parse(_);v?.message&&(m+=`: ${v.message}`)}catch{if(_.includes("<title>")){let v=_.match(/<title>([^<]+)<\/title>/i);v&&(m+=`: ${v[1].trim()}`)}else _&&_.length<150&&(m+=`: ${_.trim()}`)}this.logger.warn((0,ec.formatActionableError)({context:"ClusterSentinel",action:"\u0110\u1ED3ng b\u1ED9 t\xE0i kho\u1EA3n Team t\u1EEB Cloud",error:m}));break}let g=await h.json(),w=Array.isArray(g?.documents)?g.documents:[];w.length<s?a=!1:o+=s;for(let _ of w){let m=_.$id||_.id,v=(_.platform||"zalo").toLowerCase(),x=v==="web"||v.includes("zalo")?"zalo":v,y=_.owner_type,S=_.current_owner,k=_.status,T=Number(_.lock_expires_at||0),z=Number(_.last_heartbeat||0),C=!!this.engine.channelRunnerRegistry.get(x,m);if(!(_.nightWorkerEnabled===!0||_.night_worker_enabled===1||_.night_worker_enabled===!0)){C&&(this.logger.warn(`\u{1F6AB} [Unselected Account] T\xE0i kho\u1EA3n ${m} (${_.accountName||""}) kh\xF4ng \u0111\u01B0\u1EE3c ch\u1ECDn ch\u1EA1y Worker 24/7 (nightWorkerEnabled=false). Bu\u1ED9c ng\u1EAFt WSS ngay l\u1EADp t\u1EE9c...`),this.engine.channelRunnerRegistry.unregister(x,m),this.engine.unregisterAccount(m),this.engine.lockManager.releaseLock(m));continue}if(C&&(y==="desktop"||k==="active_desktop")){this.logger.info(`\u26A1 Master Preemption: Desktop reclaimed account ${m}. Stopping worker runner...`),this.engine.channelRunnerRegistry.unregister(x,m),this.engine.unregisterAccount(m),this.engine.lockManager.releaseLock(m);continue}let P=this.config.workerId.startsWith("worker_")?this.config.workerId:`worker_${this.config.workerId}`;if(k==="expired"||k==="error"||k==="disabled"||k==="checkpoint"){C&&(this.engine.channelRunnerRegistry.unregister(x,m),this.engine.unregisterAccount(m),this.engine.lockManager.releaseLock(m));continue}let V=y==="worker"&&S===P,Q=y==="desktop"&&n-z>6e4,J=y==="worker"&&T<n;if((k==="needs_worker"||V||Q&&T<n||J)&&!C){let de=this.engine.channelRunnerRegistry.getCount(),be=de>=i;if(!V&&(be||de/i>.8)){let ie=(await this.getActivePeerWorkers()).find(oe=>oe.currentLoad/oe.maxCapacity<de/i-.25);if(ie){this.logger.debug(`[Least-Loaded Yield] Nh\u01B0\u1EDDng t\xE0i kho\u1EA3n ${m} cho worker r\u1EA3nh h\u01A1n: ${ie.workerId} (T\u1EA3i peer: ${ie.currentLoad}/${ie.maxCapacity}, T\u1EA3i hi\u1EC7n t\u1EA1i: ${de}/${i})`);continue}}if(be){let K=Wu();this.logger.warn(`\u26A0\uFE0F [Server Spec Capacity Alert] Worker ${this.config.workerId} hi\u1EC7n \u0111ang m\u1EDF ${de+1}/${i} k\u1EBFt n\u1ED1i WSS. \u0110\xE3 v\u01B0\u1EE3t ng\u01B0\u1EE1ng khuy\u1EBFn ngh\u1ECB theo c\u1EA5u h\xECnh m\xE1y ch\u1EE7 (${Math.round(K.totalMemMb/1024)}GB RAM, ${K.cpuCount} CPUs, ${K.freeMemMb}MB Free). Theo ch\xEDnh s\xE1ch trao quy\u1EC1n quy\u1EBFt \u0111\u1ECBnh cho kh\xE1ch h\xE0ng, Worker v\u1EABn ti\u1EBFp t\u1EE5c k\u1EBFt n\u1ED1i WSS cho t\xE0i kho\u1EA3n ${m}.`)}if(await this.engine.lockManager.acquireLockRemote(m,P,6e4)){let K=V?"Resumed previous session":J?"Failover takeover (previous worker died)":be?"Over-capacity active takeover (per customer policy)":"Active takeover";this.logger.info(`\u2705 Cluster takeover: [${K}] Claimed account ${m} for team ${this.config.teamId}`),await this.spawnRunnerForAccount(_)}}}}}catch(t){this.logger.debug("syncTeamAccounts warning:",t?.message)}finally{this.isSyncingAccounts=!1}}}async spawnRunnerForAccount(t){let r=t.$id||t.id,n=(t.platform||"zalo").toLowerCase(),i=n==="web"||n.includes("zalo")?"zalo":n;if(this.engine.channelRunnerRegistry.get(i,r))return;if(!(t.nightWorkerEnabled===!0||t.night_worker_enabled===1||t.night_worker_enabled===!0)){this.logger.warn(`\u{1F6AB} [ClusterSentinel] T\u1EEB ch\u1ED1i kh\u1EDFi ch\u1EA1y WSS cho t\xE0i kho\u1EA3n unselected: ${r}`);return}let s={};if(t.authSession){let c=[];if(Array.isArray(t.$permissions))for(let p of t.$permissions){let d=String(p).match(/user:([a-zA-Z0-9_-]+)/);d&&d[1]&&c.push(d[1])}t.user_id&&c.push(t.user_id),t.userId&&c.push(t.userId),this.config.userId&&c.push(this.config.userId);let u=Array.from(new Set([this.config.teamId,t.team_id,t.teamId,...c,"default"].filter(Boolean)));s=ec.CloudCrypto.parseCloudSession(t.authSession,this.config.teamId,u)||{},!!(s?.cookie||s?.cookies||s?.accessToken||s?.token||s?.botToken)?this.logger.info(`[ClusterSentinel] \u{1F513} Gi\u1EA3i m\xE3 th\xE0nh c\xF4ng phi\xEAn ho\u1EA1t \u0111\u1ED9ng cho ${r} qua CloudCrypto.`):this.logger.warn(`[ClusterSentinel] \u26A0\uFE0F Kh\xF4ng th\u1EC3 gi\u1EA3i m\xE3 phi\xEAn h\u1EE3p l\u1EC7 cho ${r}. Scopes \u0111\xE3 th\u1EED: [${u.join(", ")}]`)}let a=await Ya.createRunner(i,r,s);if(a){this.engine.registerRunner(a),await a.start();let c=a.getStatus();if(c==="expired"||c==="error"){this.logger.warn(`\u274C [ClusterSentinel] Phi\xEAn \u0111\u0103ng nh\u1EADp c\u1EE7a t\xE0i kho\u1EA3n ${r} \u0111\xE3 h\u1EBFt h\u1EA1n/l\u1ED7i [status: ${c}]. T\u1EF1 \u0111\u1ED9ng g\u1EA1t t\u1EAFt tr\u1EF1c chi\u1EBFn v\xE0 gi\u1EA3i ph\xF3ng lock...`),this.engine.channelRunnerRegistry.unregister(i,r),this.engine.unregisterAccount(r),await this.engine.lockManager.releaseLock(r);try{let u=this.config.appwriteEndpoint,l=this.config.databaseId||"zplus_app",p=`${u}/databases/${l}/collections/channel_accounts/documents/${r}`;await fetch(p,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify({data:{status:c,nightWorkerEnabled:!1,current_owner:null,owner_type:"none"}})})}catch(u){this.logger.debug(`[ClusterSentinel] Cloud mark expired error for ${r}:`,u?.message)}return}this.engine.registerAccount({id:r,platform:i,accountName:t.accountName||r,status:c,nightWorkerEnabled:!0}),this.logger.info(`\u2705 Runner registered for ${i} account ${r} [status: ${c}]`)}}};var q$=le(nt());var N$=le(nt()),cm=class{constructor(t,r){this.config=t;this.logger=r||(0,N$.createLogger)("AppwriteDbDriver"),this.databaseId=t.databaseId||"zplus_app"}logger;databaseId;getHeaders(){let t={"Content-Type":"application/json","X-Appwrite-Project":this.config.projectId};return this.config.sessionToken?(t["X-Appwrite-Session"]=this.config.sessionToken,t.Cookie=`a_session_${this.config.projectId}=${this.config.sessionToken}; a_session_${this.config.projectId}_legacy=${this.config.sessionToken}`,this.config.sessionToken.startsWith("eyJ")&&(t["X-Fallback-Cookies"]=JSON.stringify({[`a_session_${this.config.projectId}`]:this.config.sessionToken,[`a_session_${this.config.projectId}_legacy`]:this.config.sessionToken}))):this.config.jwt&&(t["X-Appwrite-JWT"]=this.config.jwt),t}async getDocument(t,r){try{let n=`${this.config.endpoint}/databases/${this.databaseId}/collections/${t}/documents/${r}`,i=await fetch(n,{method:"GET",headers:this.getHeaders()});if(!i.ok){if(i.status===404)return null;throw new Error(`Failed to get document: HTTP ${i.status}`)}return await i.json()}catch(n){return this.logger.debug(`getDocument error for ${t}/${r}:`,n?.message),null}}async createDocument(t,r,n){let i=r.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,36),o=`${this.config.endpoint}/databases/${this.databaseId}/collections/${t}/documents`,s=await fetch(o,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({documentId:i,data:n})});if(!s.ok){let a=await this.parseCleanError(s,"T\u1EA1o document th\u1EA5t b\u1EA1i");throw new Error(`Failed to create document in ${t}: ${a}`)}return await s.json()}async parseCleanError(t,r){try{let n=await t.text();try{let i=JSON.parse(n);if(i?.message)return`HTTP ${t.status}: ${i.message}`}catch{if(n.includes("<title>")){let i=n.match(/<title>([^<]+)<\/title>/i);if(i)return`HTTP ${t.status}: ${i[1].trim()}`}else if(n&&n.length<150)return`HTTP ${t.status}: ${n.trim()}`}}catch{}return`HTTP ${t.status} (${t.statusText||r})`}async updateDocument(t,r,n){let i=r.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,36),o=`${this.config.endpoint}/databases/${this.databaseId}/collections/${t}/documents/${i}`,s=await fetch(o,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify({data:n})});if(!s.ok){let a=await this.parseCleanError(s,"C\u1EADp nh\u1EADt document th\u1EA5t b\u1EA1i");throw new Error(`Failed to update document in ${t}: ${a}`)}return await s.json()}async upsertDocument(t,r,n){try{return await this.updateDocument(t,r,n)}catch(i){if(String(i?.message||"").includes("404"))return await this.createDocument(t,r,n);throw i}}async queryDocuments(t,r){try{let n=[];if(r.filters&&r.filters.length>0)for(let c of r.filters)c.operator==="eq"?n.push(JSON.stringify({method:"equal",attribute:c.field,values:Array.isArray(c.value)?c.value:[c.value]})):c.operator==="neq"?n.push(JSON.stringify({method:"notEqual",attribute:c.field,values:Array.isArray(c.value)?c.value:[c.value]})):c.operator==="gt"?n.push(JSON.stringify({method:"greaterThan",attribute:c.field,values:[c.value]})):c.operator==="gte"?n.push(JSON.stringify({method:"greaterThanEqual",attribute:c.field,values:[c.value]})):c.operator==="lt"?n.push(JSON.stringify({method:"lessThan",attribute:c.field,values:[c.value]})):c.operator==="lte"?n.push(JSON.stringify({method:"lessThanEqual",attribute:c.field,values:[c.value]})):c.operator==="in"&&Array.isArray(c.value)&&n.push(JSON.stringify({method:"equal",attribute:c.field,values:c.value}));r.limit&&n.push(JSON.stringify({method:"limit",values:[r.limit]})),r.offset&&n.push(JSON.stringify({method:"offset",values:[r.offset]})),r.orderBy&&n.push(JSON.stringify({method:r.orderBy.direction==="desc"?"orderDesc":"orderAsc",attribute:r.orderBy.field}));let i=n.map(c=>`queries[]=${encodeURIComponent(c)}`).join("&"),o=`${this.config.endpoint}/databases/${this.databaseId}/collections/${t}/documents${i?`?${i}`:""}`,s=await fetch(o,{method:"GET",headers:this.getHeaders()});if(!s.ok)return[];let a=await s.json();return Array.isArray(a?.documents)?a.documents:[]}catch(n){return this.logger.debug(`queryDocuments error in ${t}:`,n?.message),[]}}async deleteDocument(t,r){try{let n=`${this.config.endpoint}/databases/${this.databaseId}/collections/${t}/documents/${r}`;return(await fetch(n,{method:"DELETE",headers:this.getHeaders()})).ok}catch{return!1}}};var U$=le(nt()),lm=class{constructor(t,r){this.config=t;this.logger=r||(0,U$.createLogger)("AppwriteLockDriver"),this.collectionId=t.collectionId||"channel_accounts",this.databaseId=t.databaseId||"zplus_app"}logger;collectionId;databaseId;getHeaders(){let t={"Content-Type":"application/json","X-Appwrite-Project":this.config.projectId};return this.config.sessionToken?(t["X-Appwrite-Session"]=this.config.sessionToken,t.Cookie=`a_session_${this.config.projectId}=${this.config.sessionToken}; a_session_${this.config.projectId}_legacy=${this.config.sessionToken}`,this.config.sessionToken.startsWith("eyJ")&&(t["X-Fallback-Cookies"]=JSON.stringify({[`a_session_${this.config.projectId}`]:this.config.sessionToken,[`a_session_${this.config.projectId}_legacy`]:this.config.sessionToken}))):this.config.jwt&&(t["X-Appwrite-JWT"]=this.config.jwt),t}async acquireLock(t,r,n){let i=Date.now();try{let o=`${this.config.endpoint}/databases/${this.databaseId}/collections/${this.collectionId}/documents/${t}`,s=await fetch(o,{method:"GET",headers:this.getHeaders()});if(!s.ok)return!1;let a=await s.json(),c=a.current_owner,u=Number(a.lock_expires_at||0);if(c&&c!==r&&u>i)return!1;let l=`${this.config.endpoint}/databases/${this.databaseId}/collections/${this.collectionId}/documents/${t}`;if((await fetch(l,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify({data:{current_owner:r,owner_type:r.startsWith("worker")?"worker":"desktop",lock_expires_at:i+n,last_heartbeat:i,status:r.startsWith("worker")?"active_worker":"active_desktop"}})})).ok){await new Promise(h=>setTimeout(h,30+Math.floor(Math.random()*40)));let d=await fetch(o,{method:"GET",headers:this.getHeaders()});if(d.ok&&(await d.json()).current_owner===r)return!0}return!1}catch(o){return this.logger.debug("acquireLock error:",o?.message),!1}}async releaseLock(t,r){try{if(r){let o=`${this.config.endpoint}/databases/${this.databaseId}/collections/${this.collectionId}/documents/${t}`,s=await fetch(o,{method:"GET",headers:this.getHeaders()});if(s.ok){let a=await s.json();if(a.current_owner&&a.current_owner!==r)return!1}}let n=`${this.config.endpoint}/databases/${this.databaseId}/collections/${this.collectionId}/documents/${t}`;return(await fetch(n,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify({data:{current_owner:null,owner_type:"none",lock_expires_at:0,status:"offline"}})})).ok}catch{return!1}}async renewLock(t,r,n){try{let i=`${this.config.endpoint}/databases/${this.databaseId}/collections/${this.collectionId}/documents/${t}`;return(await fetch(i,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify({data:{lock_expires_at:Date.now()+n,last_heartbeat:Date.now()}})})).ok}catch{return!1}}async getLock(t){try{let r=`${this.config.endpoint}/databases/${this.databaseId}/collections/${this.collectionId}/documents/${t}`,n=await fetch(r,{method:"GET",headers:this.getHeaders()});if(!n.ok)return null;let i=await n.json();return{resourceId:t,ownerId:i.current_owner||"",ownerType:i.owner_type,expiresAt:Number(i.lock_expires_at||0),lastHeartbeat:Number(i.last_heartbeat||0)}}catch{return null}}};var j$=le(nt()),um=class{constructor(t,r){this.config=t;this.logger=r||(0,j$.createLogger)("AppwriteCoordinator"),this.databaseId=t.databaseId||"zplus_app"}logger;databaseId;getHeaders(){let t={"Content-Type":"application/json","X-Appwrite-Project":this.config.projectId};return this.config.sessionToken?(t["X-Appwrite-Session"]=this.config.sessionToken,t.Cookie=`a_session_${this.config.projectId}=${this.config.sessionToken}; a_session_${this.config.projectId}_legacy=${this.config.sessionToken}`,this.config.sessionToken.startsWith("eyJ")&&(t["X-Fallback-Cookies"]=JSON.stringify({[`a_session_${this.config.projectId}`]:this.config.sessionToken,[`a_session_${this.config.projectId}_legacy`]:this.config.sessionToken}))):this.config.jwt&&(t["X-Appwrite-JWT"]=this.config.jwt),t}async registerNode(t){try{let r=t.workerId.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,36),n=`${this.config.endpoint}/databases/${this.databaseId}/collections/team_workers/documents/${r}`,i={data:{worker_id:t.workerId,team_id:t.teamId,worker_name:t.workerName,max_capacity:t.maxCapacity,recommended_capacity:t.recommendedCapacity||t.maxCapacity,current_load:t.currentLoad,is_overloaded:t.isOverloaded??!1,system_specs:t.systemSpecs?JSON.stringify(t.systemSpecs):void 0,status:t.status,last_ping:Date.now()}};if((await fetch(n,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify(i)})).status===404){let s=`${this.config.endpoint}/databases/${this.databaseId}/collections/team_workers/documents`;await fetch(s,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({documentId:r,...i})})}}catch(r){this.logger.warn("registerNode warning:",r?.message)}}async pingHeartbeat(t,r){try{let n=t.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,36),i=`${this.config.endpoint}/databases/${this.databaseId}/collections/team_workers/documents/${n}`;await fetch(i,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify({data:{current_load:r.currentLoad,is_overloaded:r.isOverloaded??!1,system_specs:r.systemSpecs?JSON.stringify(r.systemSpecs):void 0,last_ping:r.lastPing,status:r.status||"online"}})})}catch{}}async fetchPendingAccounts(t,r=100,n=0){try{let i=[`queries[]=${encodeURIComponent(JSON.stringify({method:"equal",attribute:"team_id",values:[t]}))}`,`queries[]=${encodeURIComponent(JSON.stringify({method:"limit",values:[r]}))}`,`queries[]=${encodeURIComponent(JSON.stringify({method:"offset",values:[n]}))}`].join("&"),o=`${this.config.endpoint}/databases/${this.databaseId}/collections/channel_accounts/documents?${i}`,s=await fetch(o,{method:"GET",headers:this.getHeaders()});if(!s.ok)return[];let a=await s.json();return Array.isArray(a?.documents)?a.documents:[]}catch(i){return this.logger.debug("fetchPendingAccounts error:",i?.message),[]}}async fetchActiveNodes(t){try{let r=[`queries[]=${encodeURIComponent(JSON.stringify({method:"equal",attribute:"team_id",values:[t]}))}`,`queries[]=${encodeURIComponent(JSON.stringify({method:"limit",values:[50]}))}`].join("&"),n=`${this.config.endpoint}/databases/${this.databaseId}/collections/team_workers/documents?${r}`,i=await fetch(n,{method:"GET",headers:this.getHeaders()});if(!i.ok)return[];let o=await i.json();return(Array.isArray(o?.documents)?o.documents:[]).map(a=>({workerId:a.worker_id||a.$id,teamId:a.team_id,workerName:a.worker_name||"",maxCapacity:Number(a.max_capacity||50),currentLoad:Number(a.current_load||0),status:a.status||"online",lastPing:Number(a.last_ping||0),isOverloaded:!!a.is_overloaded,recommendedCapacity:Number(a.recommended_capacity||a.max_capacity||50),systemSpecs:a.system_specs?typeof a.system_specs=="string"?JSON.parse(a.system_specs):a.system_specs:void 0}))}catch(r){return this.logger.debug("fetchActiveNodes error:",r?.message),[]}}async markNodeOffline(t){try{let r=t.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,36),n=`${this.config.endpoint}/databases/${this.databaseId}/collections/team_workers/documents/${r}`;await fetch(n,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify({data:{status:"offline",last_ping:Date.now()}})})}catch{}}};var $$=le(nt()),pm=class{constructor(t,r){this.config=t;this.logger=r||(0,$$.createLogger)("AppwriteAuthDriver")}logger;async verifySessionToken(t){try{let r=`${this.config.endpoint}/account`,n=await fetch(r,{method:"GET",headers:{"Content-Type":"application/json","X-Appwrite-Project":this.config.projectId,"X-Appwrite-Session":t,Cookie:`a_session_${this.config.projectId}=${t}; a_session_${this.config.projectId}_legacy=${t}`,...t.startsWith("eyJ")?{"X-Fallback-Cookies":JSON.stringify({[`a_session_${this.config.projectId}`]:t,[`a_session_${this.config.projectId}_legacy`]:t})}:{}}});if(!n.ok)return{allowed:!1,userId:"",userName:"Unknown",email:"",teamId:"default",isOwner:!1,isPremium:!1,reason:`Phi\xEAn \u0111\u0103ng nh\u1EADp kh\xF4ng h\u1EE3p l\u1EC7 (HTTP ${n.status}).`};let i=await n.json(),o=i.$id||i.id||"",s=i.name||"Ng\u01B0\u1EDDi d\xF9ng ZPlus",a=i.email||"",c=i.prefs||{},u=c.entitlements||{},l=!!(u.isPremium??c.isPremium??c.plan==="enterprise"),p=!!(u.isOwner??c.isOwner??!0),d=c.teamId||u.teamId||"default";return{allowed:l||p,userId:o,userName:s,email:a,teamId:d,isOwner:p,isPremium:l,reason:l||p?"H\u1EE3p l\u1EC7":"Y\xEAu c\u1EA7u quy\u1EC1n Enterprise \u0111\u1EC3 ch\u1EA1y Worker 24/7."}}catch(r){return this.logger.error("verifySessionToken error:",r),{allowed:!1,userId:"",userName:"Unknown",email:"",teamId:"default",isOwner:!1,isPremium:!1,reason:r?.message||"L\u1ED7i k\u1EBFt n\u1ED1i x\xE1c th\u1EF1c."}}}async checkEntitlements(t){return this.config.sessionToken?this.verifySessionToken(this.config.sessionToken):{allowed:!0,userId:t,userName:"Worker Node",email:"",teamId:"default",isOwner:!0,isPremium:!0}}};var Sw=le(require("fs")),kw=require("stream"),z$=require("stream/promises"),M$=le(nt()),fm=class{constructor(t,r){this.config=t;this.logger=r||(0,M$.createLogger)("AppwriteStorageDriver")}logger;getHeaders(){let t={"X-Appwrite-Project":this.config.projectId};return this.config.sessionToken?(t["X-Appwrite-Session"]=this.config.sessionToken,t.Cookie=`a_session_${this.config.projectId}=${this.config.sessionToken}; a_session_${this.config.projectId}_legacy=${this.config.sessionToken}`,this.config.sessionToken.startsWith("eyJ")&&(t["X-Fallback-Cookies"]=JSON.stringify({[`a_session_${this.config.projectId}`]:this.config.sessionToken,[`a_session_${this.config.projectId}_legacy`]:this.config.sessionToken}))):this.config.jwt&&(t["X-Appwrite-JWT"]=this.config.jwt),t}async createFile(t,r,n,i,o){let s=r==="unique()"?"unique()":r.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,36),a=`${this.config.endpoint}/storage/buckets/${t}/files`,c=new FormData;c.append("fileId",s);let u=Buffer.isBuffer(n)?n:Buffer.from(n),l=new Blob([u]);if(c.append("file",l,i),o&&o.length>0)for(let h=0;h<o.length;h++)c.append(`permissions[${h}]`,o[h]);let p=await fetch(a,{method:"POST",headers:this.getHeaders(),body:c});if(!p.ok){let h=await p.text();throw new Error(`Failed to upload file to storage: HTTP ${p.status} - ${h}`)}let d=await p.json();return{$id:d.$id||r,name:d.name||i,sizeOriginal:d.sizeOriginal||u.length,mimeType:d.mimeType,$createdAt:d.$createdAt,$updatedAt:d.$updatedAt}}async getFileDownload(t,r){let n=`${this.config.endpoint}/storage/buckets/${t}/files/${r}/download`,i=await fetch(n,{method:"GET",headers:this.getHeaders()});if(!i.ok)throw new Error(`Failed to download file: HTTP ${i.status}`);let o=await i.arrayBuffer();return Buffer.from(o)}async downloadFileToPath(t,r,n){let i=`${this.config.endpoint}/storage/buckets/${t}/files/${r}/download`,o=await fetch(i,{method:"GET",headers:this.getHeaders()});if(!o.ok)throw new Error(`Failed to download file: HTTP ${o.status}`);if(typeof kw.Readable.fromWeb=="function"&&o.body)await(0,z$.pipeline)(kw.Readable.fromWeb(o.body),Sw.default.createWriteStream(n));else{let s=await o.arrayBuffer();await Sw.default.promises.writeFile(n,Buffer.from(s))}return!0}async deleteFile(t,r){let n=`${this.config.endpoint}/storage/buckets/${t}/files/${r}`;return(await fetch(n,{method:"DELETE",headers:this.getHeaders()})).ok}async listFiles(t){let r=`${this.config.endpoint}/storage/buckets/${t}/files`,n=await fetch(r,{method:"GET",headers:this.getHeaders()});if(!n.ok)return{files:[],total:0};let i=await n.json();return{files:(i.files||[]).map(o=>({$id:o.$id,name:o.name,sizeOriginal:o.sizeOriginal,mimeType:o.mimeType})),total:i.total||0}}async getFile(t,r){let n=`${this.config.endpoint}/storage/buckets/${t}/files/${r}`,i=await fetch(n,{method:"GET",headers:this.getHeaders()});return i.ok?await i.json():null}};var dm=class{constructor(t,r){this.config=t;this.logger=r||(0,q$.createLogger)("AppwriteCloudAdapter");let n={get endpoint(){return t.cloudEndpoint||t.appwriteEndpoint||"https://api.softty.net/v1"},get projectId(){return t.cloudProjectId||t.appwriteProjectId||"699cfc3100136099c1c1"},get databaseId(){return t.cloudDatabaseId||t.databaseId||"zplus_app"},get sessionToken(){return t.cloudSessionToken||t.appwriteSessionToken},get jwt(){return t.cloudJwt||t.appwriteJwt}};this.database=new cm(n,this.logger),this.lockStorage=new lm(n,this.logger),this.coordinator=new um(n,this.logger),this.auth=new pm(n,this.logger),this.storage=new fm(n,this.logger)}providerName="appwrite";database;lockStorage;coordinator;auth;storage;logger;async start(){this.logger.info("\u2705 Appwrite Cloud Adapter initialized.")}async stop(){this.logger.info("Appwrite Cloud Adapter stopped.")}};var H$=le(nt()),hm=class{constructor(t,r){this.config=t;this.logger=r||(0,H$.createLogger)("CustomApiAdapter");let n=t.cloudEndpoint||"https://api.softty.net/custom/v1",o={"Content-Type":"application/json",Authorization:`Bearer ${t.cloudSessionToken||t.cloudJwt||""}`,"X-Tenant-ID":t.teamId||"default"};this.database={async getDocument(s,a){try{let c=await fetch(`${n}/data/${s}/${a}`,{headers:o});return c.ok?await c.json():null}catch{return null}},async createDocument(s,a,c){return await(await fetch(`${n}/data/${s}`,{method:"POST",headers:o,body:JSON.stringify({id:a,...c})})).json()},async updateDocument(s,a,c){return await(await fetch(`${n}/data/${s}/${a}`,{method:"PATCH",headers:o,body:JSON.stringify(c)})).json()},async upsertDocument(s,a,c){return await(await fetch(`${n}/data/${s}/${a}/upsert`,{method:"POST",headers:o,body:JSON.stringify(c)})).json()},async queryDocuments(s,a){try{let c=await fetch(`${n}/data/${s}/query`,{method:"POST",headers:o,body:JSON.stringify(a)});if(!c.ok)return[];let u=await c.json();return Array.isArray(u?.items)?u.items:[]}catch{return[]}},async deleteDocument(s,a){try{return(await fetch(`${n}/data/${s}/${a}`,{method:"DELETE",headers:o})).ok}catch{return!1}}},this.lockStorage={async acquireLock(s,a,c){try{let u=await fetch(`${n}/locks/acquire`,{method:"POST",headers:o,body:JSON.stringify({resourceId:s,ownerId:a,ttlMs:c})});return u.ok?!!(await u.json())?.acquired:!1}catch{return!1}},async releaseLock(s,a){try{return(await fetch(`${n}/locks/release`,{method:"POST",headers:o,body:JSON.stringify({resourceId:s,ownerId:a})})).ok}catch{return!1}},async renewLock(s,a,c){try{return(await fetch(`${n}/locks/renew`,{method:"POST",headers:o,body:JSON.stringify({resourceId:s,ownerId:a,ttlMs:c})})).ok}catch{return!1}},async getLock(s){try{let a=await fetch(`${n}/locks/${s}`,{headers:o});return a.ok?await a.json():null}catch{return null}}},this.coordinator={async registerNode(s){try{await fetch(`${n}/cluster/nodes/register`,{method:"POST",headers:o,body:JSON.stringify(s)})}catch{}},async pingHeartbeat(s,a){try{await fetch(`${n}/cluster/nodes/${s}/heartbeat`,{method:"POST",headers:o,body:JSON.stringify(a)})}catch{}},async fetchPendingAccounts(s,a=100,c=0){try{let u=await fetch(`${n}/cluster/accounts/pending?teamId=${s}&limit=${a}&offset=${c}`,{headers:o});if(!u.ok)return[];let l=await u.json();return Array.isArray(l?.accounts)?l.accounts:[]}catch{return[]}},async markNodeOffline(s){try{await fetch(`${n}/cluster/nodes/${s}/offline`,{method:"POST",headers:o})}catch{}}},this.auth={async verifySessionToken(s){try{let a=await fetch(`${n}/auth/verify`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`}});return a.ok?await a.json():{allowed:!1,userId:"",userName:"Unknown",email:"",teamId:"default",isOwner:!1,isPremium:!1,reason:"Invalid session token"}}catch(a){return{allowed:!1,userId:"",userName:"Unknown",email:"",teamId:"default",isOwner:!1,isPremium:!1,reason:a?.message}}},async checkEntitlements(s){return{allowed:!0,userId:s,userName:"User",email:"",teamId:"default",isOwner:!0,isPremium:!0}}}}providerName="custom-api";database;lockStorage;coordinator;auth;logger;async start(){this.logger.info("\u{1F50C} Custom API Cloud Adapter initialized.")}async stop(){this.logger.info("Custom API Cloud Adapter stopped.")}};var W$=le(nt()),mm=class{providerName="in-memory";database;lockStorage;coordinator;auth;logger;tables=new Map;locks=new Map;nodes=new Map;constructor(t,r){this.logger=r||(0,W$.createLogger)("InMemoryCloudAdapter");let n=i=>{let o=this.tables.get(i);return o||(o=new Map,this.tables.set(i,o)),o};this.database={async getDocument(i,o){return n(i).get(o)||null},async createDocument(i,o,s){return n(i).set(o,{$id:o,id:o,...s}),n(i).get(o)},async updateDocument(i,o,s){let c={...n(i).get(o)||{$id:o,id:o},...s};return n(i).set(o,c),c},async upsertDocument(i,o,s){return this.updateDocument(i,o,s)},async queryDocuments(i,o){let s=Array.from(n(i).values());if(o.filters)for(let a of o.filters)a.operator==="eq"&&(s=s.filter(c=>c[a.field]===a.value));return o.limit&&(s=s.slice(0,o.limit)),s},async deleteDocument(i,o){return n(i).delete(o)}},this.lockStorage={acquireLock:async(i,o,s)=>{let a=Date.now(),c=this.locks.get(i);return c&&c.expiresAt>a&&c.ownerId!==o?!1:(this.locks.set(i,{resourceId:i,ownerId:o,ownerType:o.startsWith("worker")?"worker":"desktop",expiresAt:a+s,lastHeartbeat:a}),!0)},releaseLock:async(i,o)=>{let s=this.locks.get(i);return s?o&&s.ownerId!==o?!1:(this.locks.delete(i),!0):!0},renewLock:async(i,o,s)=>this.lockStorage.acquireLock(i,o,s),getLock:async i=>this.locks.get(i)||null},this.coordinator={registerNode:async i=>{this.nodes.set(i.workerId,i)},pingHeartbeat:async(i,o)=>{let s=this.nodes.get(i);s&&(s.currentLoad=o.currentLoad,s.lastPing=o.lastPing,s.status=o.status||"online")},fetchPendingAccounts:async i=>Array.from(n("channel_accounts").values()).filter(s=>s.team_id===i||s.teamId===i),markNodeOffline:async i=>{let o=this.nodes.get(i);o&&(o.status="offline")}},this.auth={verifySessionToken:async i=>({allowed:!!i,userId:"user_test_in_memory",userName:"Test User",email:"test@softty.net",teamId:"team_test",isOwner:!0,isPremium:!0}),checkEntitlements:async i=>({allowed:!0,userId:i,userName:"Test User",email:"test@softty.net",teamId:"team_test",isOwner:!0,isPremium:!0})}}async start(){this.logger.info("\u{1F9EA} In-Memory Cloud Adapter initialized.")}async stop(){this.logger.info("In-Memory Cloud Adapter stopped.")}};var G$=le(nt()),gm=class{static create(t,r){let n=r||(0,G$.createLogger)("CloudAdapterFactory");switch(t.cloudProvider||"appwrite"){case"custom-api":return n.info("Creating Custom API Cloud Adapter..."),new hm(t,n);case"in-memory":return n.info("Creating In-Memory Cloud Adapter..."),new mm(t,n);case"appwrite":default:return n.info("Creating Appwrite Cloud Adapter..."),new dm(t,n)}}};var ym=class{logger;channelRunnerRegistry;lockManager;deltaQueue;automationEngine;pushDispatcher;httpServer;clusterSentinel;cloudAdapter;status="idle";lastError;startTime=0;activeAccounts=new Map;messagesProcessed=0;heartbeatTimer;storageQuotaExceeded=!1;config;constructor(t){this.config={enableHttp:!1,teamId:"default",workerName:`Worker_${t.workerId}`,version:t.version||Hr,maxCapacity:50,clusterPollIntervalMs:5e3,heartbeatIntervalMs:15e3,logLevel:"info",...t,workerId:t.workerId},this.logger=(0,J$.createLogger)(`WorkerEngine:${this.config.workerId}`),this.channelRunnerRegistry=new Zu(this.logger),this.lockManager=new Ku(6e4,this.logger),this.cloudAdapter=gm.create(this.config,this.logger),(this.config.cloudEndpoint||this.config.appwriteEndpoint)&&this.lockManager.setStorageProvider(this.cloudAdapter.lockStorage);let r=process.env.WORKER_DATA_DIR||ks.default.join(process.cwd(),".data"),n=ks.default.join(r,`pending_messages_${this.config.workerId}.json`);this.deltaQueue=new Yu(1e4,this.logger,n),this.automationEngine=new Xu(this.logger,{enabled:!1,apiKey:this.config.deepseekApiKey||this.config.geminiApiKey||this.config.openaiApiKey||this.config.anthropicApiKey||this.config.customAiApiKey,baseUrl:this.config.aiBaseUrl,provider:this.config.aiProvider,model:this.config.aiModel,systemPrompt:this.config.nightSystemPrompt,fallbackMessage:this.config.nightFallbackReply}),this.pushDispatcher=new Qu(this.logger),this.clusterSentinel=new am(this.config,this,this.logger),this.httpServer=this.config.enableHttp&&this.config.port?new tm(this.config.port,this,this.lockManager,this.deltaQueue,this.logger):null,this.lockManager.onPreempt(async i=>{this.logger.info(`Preemption callback: stopping WSS for account ${i}...`);let o=this.channelRunnerRegistry.getAll();for(let s of o)s.accountId===i&&await s.stop()})}async start(){if(this.status==="running"){this.logger.warn("Worker is already running.");return}if(this.logger.info("Starting ZPlus 24/7 Headless Worker Engine..."),this.status="initializing",this.startTime=Date.now(),this.httpServer)try{await this.httpServer.start()}catch(r){this.logger.error("Failed to start Worker HTTP Ingress Server:",r)}else this.logger.info("\u{1F6E1}\uFE0F Ch\u1EBF \u0111\u1ED9 Zero-Port (Outbound-only) \u0111ang ho\u1EA1t \u0111\u1ED9ng: Worker kh\xF4ng m\u1EDF b\u1EA5t k\u1EF3 c\u1ED5ng l\u1EAFng nghe Inbound n\xE0o.");try{await this.cloudAdapter.start()}catch(r){this.logger.error("Failed to start Cloud Adapter:",r)}if(this.config.isStandby){this.status="idle",this.logger.warn(`\u23F8\uFE0F Worker is in STANDBY mode: ${this.config.standbyReason||"Unauthorized / Free Tier / Non-owner"}. Worker will NOT process accounts.`);return}this.heartbeatTimer=setInterval(()=>{this.sendHeartbeat()},this.config.heartbeatIntervalMs);try{await this.clusterSentinel.start()}catch(r){this.logger.error("Failed to start Cluster Sentinel:",r)}this.status="running",this.writeLocalHeartbeat();let t=this.config.enableHttp?`Port: ${this.config.port}`:"Zero-Port Headless Daemon";this.logger.info(`\u2705 ZPlus Worker Engine started successfully [ID: ${this.config.workerId}, Mode: ${t}]`);try{typeof global.gc=="function"&&global.gc()}catch{}}async stop(){this.logger.info("Stopping ZPlus Worker Engine..."),this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=void 0),await this.clusterSentinel.stop(),await this.cloudAdapter.stop(),this.httpServer&&await this.httpServer.stop(),this.clearLocalHeartbeat(),await this.channelRunnerRegistry.stopAll(),this.status="stopped",this.logger.info("ZPlus Worker Engine stopped.")}registerRunner(t){t.onMessage?.(r=>{this.handleIncomingMessage(r,t)}),this.channelRunnerRegistry.register(t)}registerAccount(t){this.activeAccounts.set(t.id,t),this.logger.info(`Registered active account: ${t.accountName} [${t.platform}]`),this.writeLocalHeartbeat()}unregisterAccount(t){this.activeAccounts.delete(t),this.logger.info(`Unregistered account: ${t}`),this.writeLocalHeartbeat()}recordMessageProcessed(){this.messagesProcessed++}async handleIncomingMessage(t,r){this.recordMessageProcessed(),this.deltaQueue.enqueue(t),await this.pushMessageToCloud(t);try{let n=await this.automationEngine.evaluateIncomingMessage(t);if(n&&r){this.logger.info(`[NightAutoReply] Sending automated reply to thread ${t.threadId}: "${n}"`);let i={id:`reply_${Date.now()}`,platform:t.platform,conversationId:t.conversationId,threadId:t.threadId,accountId:t.accountId,senderId:t.accountId,senderName:"ZPlus Night Assistant",senderType:"agent",messageType:"text",content:n,timestamp:Date.now(),isSelf:!0,status:"sent"};await r.sendMessage(i)?(this.deltaQueue.enqueue(i),await this.pushMessageToCloud(i)):this.logger.warn(`[NightAutoReply] Socket delivery failed for thread ${t.threadId}. Skipped cloud push to prevent ghost message.`)}}catch(n){this.logger.warn("Auto-reply evaluation notice:",n)}try{await this.pushDispatcher.dispatchMessageAlert("fcm_token_mobile_owner",t)}catch(n){this.logger.debug("Push notification dispatch notice:",n)}}async pushMessageToCloud(t){if(!(!this.config.cloudEndpoint&&!this.config.appwriteEndpoint))try{let r=t.id.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,36),n=new Date().toISOString(),i=t.threadId||t.conversationId,o=t.mediaUrl||t.metadata?.mediaUrl||Array.isArray(t.attachments)&&t.attachments[0]?.url||void 0,s;if(o&&this.cloudAdapter.storage&&!this.storageQuotaExceeded&&["chat.photo","chat.voice","chat.sticker","chat.doodle","image","audio","voice"].includes((t.messageType||t.type||"").toLowerCase()))try{let u=(t.messageType||t.type||"").toLowerCase(),l=u.includes("voice")||u.includes("audio")?".aac":".jpg",p=`media_${r}${l}`,d=await fetch(o,{headers:{"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",Referer:"https://chat.zalo.me/"}});if(d.ok){let h=await d.arrayBuffer(),g=Buffer.from(h);if(g.length>0&&g.length<=20*1024*1024){let w=this.config.storageBucketId||"zplus-media-vault",_=await this.cloudAdapter.storage.createFile(w,r,g,p);_?.$id&&(s=_.$id,this.logger.info(`\u2601\uFE0F [MediaSync] In-memory streamed media (${(g.length/1024).toFixed(1)} KB) to Cloud Storage: ${s}`))}}else d.status===403&&this.logger.warn(`[MediaSync] Media URL already expired (403): ${o}`)}catch(u){let l=String(u?.message||"").toLowerCase();l.includes("quota")||l.includes("403")||l.includes("limit")?(this.storageQuotaExceeded=!0,this.logger.warn(`\u26A0\uFE0F [MediaSync] Cloud Storage quota exceeded for team ${this.config.teamId}. Pausing cloud media uploads.`)):this.logger.debug("[MediaSync] Cloud media upload notice:",u)}let a={...typeof t.payload=="object"?t.payload:{},mediaUrl:o,cloud_file_id:s,attachments:t.attachments,metadata:t.metadata},c={conversation_id:t.conversationId||t.threadId,thread_id:i,account_id:t.accountId,sender_id:t.senderId,sender_name:(t.senderName||"").slice(0,255),senderType:t.senderType||"customer",messageType:t.messageType||t.type||"text",content:(t.content||t.text||"").slice(0,3e3),payload:typeof t.payload=="string"?t.payload.slice(0,3e3):JSON.stringify(a).slice(0,3e3),timestamp:t.timestamp||Date.now(),is_self:!!(t.isSelf||t.senderId==="0"||t.accountId&&String(t.senderId)===String(t.accountId)),is_recall:0,status:t.status||"sent",team_id:this.config.teamId||"",zplus_action:"INSERT",zplus_updated_at:n};if(await this.cloudAdapter.database.upsertDocument("messages",r,c),this.logger.info(`\u2601\uFE0F [CloudSync] Pushed message ${t.id} to Cloud DB via ${this.cloudAdapter.providerName}.`),i&&t.accountId)try{let u=`${i}:${t.accountId}`,p=`z_${V$.default.createHash("md5").update(`conversations:${u}`).digest("hex")}`,d=(t.content||t.text||"").slice(0,500),h={thread_id:i,account_id:t.accountId,name:(t.senderName||i).slice(0,255),last_message:JSON.stringify({content:d,senderId:t.senderId,timestamp:t.timestamp||Date.now(),msgType:t.msgType||t.messageType||"chat.text"}),timestamp:t.timestamp||Date.now(),unread_count:1,peerId:t.senderId,peerName:(t.senderName||"").slice(0,255),platform:t.platform||"zalo",isPinned:!1,zplus_action:"UPDATE",zplus_updated_at:n};await this.cloudAdapter.database.upsertDocument("conversations",p,h)}catch(u){this.logger.debug(`[CloudSync] Note updating conversations on cloud: ${u?.message}`)}}catch(r){this.logger.error(`\u274C [CloudSync] Failed to push message ${t.id} to Cloud DB: ${r?.message||r}`)}}getMetrics(){let t=this.startTime>0?Math.floor((Date.now()-this.startTime)/1e3):0,r=process.memoryUsage().rss/(1024*1024);return{workerId:this.config.workerId,status:this.status,uptimeSeconds:t,activeAccountsCount:this.activeAccounts.size,totalMessagesProcessed:this.messagesProcessed,memoryUsageMb:Math.round(r*100)/100,lastHeartbeat:new Date().toISOString()}}sendHeartbeat(){let t=this.getMetrics();this.writeLocalHeartbeat(),this.logger.info(`\u{1F493} Heartbeat: status=${t.status}, accounts=${t.activeAccountsCount}, msgs=${t.totalMessagesProcessed}, pendingDelta=${this.deltaQueue.getCount()}, uptime=${t.uptimeSeconds}s`)}setStatus(t,r){this.status=t,r!==void 0&&(this.lastError=r),this.writeLocalHeartbeat()}writeLocalHeartbeat(){try{let t=process.env.ZPLUS_HOME||ks.default.join(Ew.default.homedir(),".zplus");wo.default.existsSync(t)||wo.default.mkdirSync(t,{recursive:!0});let r=ks.default.join(t,"worker_heartbeat.json"),n=this.getMetrics(),i={vendor:"Softtynet Co., Ltd.",product:"Softty ZPlus Omnichannel Platform",daemonTitle:"ZPlus 24/7 Headless Worker Daemon",version:this.config.version||"1.0.10",homepage:"https://softty.net",supportEmail:"support@softty.net",processTitle:process.title||"zplus-worker (Softtynet Co., Ltd.)",status:this.status,lastError:this.lastError||null,workerId:this.config.workerId,workerName:this.config.workerName,teamId:this.config.teamId,pid:process.pid,uptimeSeconds:n.uptimeSeconds,activeAccountsCount:n.activeAccountsCount,activeRunners:this.channelRunnerRegistry.getCount(),totalMessagesProcessed:n.totalMessagesProcessed,pendingDeltaMessages:this.deltaQueue.getCount(),memoryUsageMb:n.memoryUsageMb,isZeroPort:!this.config.enableHttp,port:this.config.enableHttp?this.config.port:null,lastPing:Date.now(),timestamp:Date.now()},o=`${r}.${process.pid}.tmp`;wo.default.writeFileSync(o,JSON.stringify(i,null,2)),wo.default.renameSync(o,r)}catch{}}clearLocalHeartbeat(){try{let t=process.env.ZPLUS_HOME||ks.default.join(Ew.default.homedir(),".zplus"),r=ks.default.join(t,"worker_heartbeat.json");if(wo.default.existsSync(r)){let n={status:"stopped",workerId:this.config.workerId,pid:process.pid,lastPing:Date.now(),timestamp:Date.now()},i=`${r}.${process.pid}.tmp`;wo.default.writeFileSync(i,JSON.stringify(n,null,2)),wo.default.renameSync(i,r)}}catch{}}};var Cn=le(require("os")),xt=le(require("fs")),Ht=le(require("path")),ht=require("child_process"),Z$=le(nt()),xm=class{logger;constructor(t){this.logger=t||(0,Z$.createLogger)("WorkerAutostartManager")}getExecutableInfo(){let t=process.execPath,r=Ht.default.resolve(__dirname,"cli.js");if(xt.default.existsSync(r)||(r=Ht.default.resolve(__dirname,"../dist/cli.js")),!xt.default.existsSync(r))try{let n=process.platform==="win32"?"where zplus-worker":"which zplus-worker",i=(0,ht.execSync)(n,{encoding:"utf-8"}).trim().split(`
|
|
128
128
|
`)[0].trim();i&&(r=i)}catch{r=Ht.default.resolve(process.cwd(),"dist/cli.js")}return{nodePath:t,cliPath:r}}getStatus(){let t=process.platform;if(t==="linux"){let r=Ht.default.join(Cn.default.homedir(),".config/systemd/user/zplus-worker.service"),n="/etc/systemd/system/zplus-worker.service",i=xt.default.existsSync(r)||xt.default.existsSync(n),o=!1;try{o=(0,ht.execSync)("pm2 list",{encoding:"utf-8",stdio:["pipe","pipe","ignore"]}).includes("zplus-worker")}catch{o=!1}return{platform:"linux",isSupported:!0,isEnabled:i||o,serviceType:i?"systemd":o?"pm2":"systemd",targetPath:xt.default.existsSync(r)?r:n,details:i?"\u0110\xE3 c\u1EA5u h\xECnh Systemd t\u1EF1 kh\u1EDFi \u0111\u1ED9ng c\xF9ng Linux.":o?"\u0110ang ch\u1EA1y v\xE0 t\u1EF1 duy tr\xEC qua PM2 Daemon.":"Ch\u01B0a k\xEDch ho\u1EA1t t\u1EF1 kh\u1EDFi \u0111\u1ED9ng."}}if(t==="darwin"){let r=Ht.default.join(Cn.default.homedir(),"Library/LaunchAgents/net.softty.zplus-worker.plist"),n=xt.default.existsSync(r);return{platform:"darwin",isSupported:!0,isEnabled:n,serviceType:"launchd",targetPath:r,details:n?"\u0110\xE3 c\u1EA5u h\xECnh macOS LaunchAgent t\u1EF1 b\u1EADt khi kh\u1EDFi \u0111\u1ED9ng m\xE1y.":"Ch\u01B0a k\xEDch ho\u1EA1t t\u1EF1 kh\u1EDFi \u0111\u1ED9ng tr\xEAn macOS."}}if(t==="win32"){let r=!1;try{r=(0,ht.execSync)('schtasks /query /tn "ZPlusWorker"',{encoding:"utf-8",stdio:["pipe","pipe","ignore"]}).includes("ZPlusWorker")}catch{r=!1}return{platform:"win32",isSupported:!0,isEnabled:r,serviceType:"schtasks",details:r?"\u0110\xE3 c\u1EA5u h\xECnh Windows Task Scheduler t\u1EF1 kh\u1EDFi \u0111\u1ED9ng c\xF9ng Windows (onstart).":"Ch\u01B0a k\xEDch ho\u1EA1t t\u1EF1 kh\u1EDFi \u0111\u1ED9ng tr\xEAn Windows."}}return{platform:t,isSupported:!1,isEnabled:!1,serviceType:"unknown",details:`H\u1EC7 \u0111i\u1EC1u h\xE0nh [${t}] kh\xF4ng h\u1ED7 tr\u1EE3 tr\xECnh t\u1EF1 kh\u1EDFi \u0111\u1ED9ng t\u1EF1 \u0111\u1ED9ng.`}}enableAutostart(){let t=process.platform,{nodePath:r,cliPath:n}=this.getExecutableInfo(),i=Ht.default.join(Cn.default.homedir(),".zplus");xt.default.existsSync(i)||xt.default.mkdirSync(i,{recursive:!0});try{if(t==="linux"){let o=typeof process.getuid=="function"&&process.getuid()===0,s=`[Unit]
|
|
129
129
|
Description=Softty ZPlus 24/7 Omnichannel Automation Worker Daemon (Softtynet Co., Ltd.)
|
|
130
130
|
Documentation=https://softty.net https://docs.zplus.app
|