@softtynet/zplus-worker 1.0.56 → 1.0.57
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 +1 -1
- package/package.json +5 -2
package/dist/cli.js
CHANGED
|
@@ -68,7 +68,7 @@ Minimum version required to store current data is: `+a+`.
|
|
|
68
68
|
`}return s+=c+`
|
|
69
69
|
`,typeof r=="function"&&r(null,s),s}});var JD=P(VD=>{var FV="\x1B[47m",DV="\x1B[40m",wy="\x1B[37m",_y="\x1B[30m",Ba="\x1B[0m",BV=FV+_y,NV=DV+wy,LV=function(e,t,r){return{"00":Ba+" "+e,"01":Ba+t+"\u2584"+e,"02":Ba+r+"\u2584"+e,10:Ba+t+"\u2580"+e,11:" ",12:"\u2584",20:Ba+r+"\u2580"+e,21:"\u2580",22:"\u2588"}},WD=function(e,t,r,n){let i=t+1;if(r>=i||n>=i||n<-1||r<-1)return"0";if(r>=t||n>=t||n<0||r<0)return"1";let a=n*t+r;return e[a]?"2":"1"},GD=function(e,t,r,n){return WD(e,t,r,n)+WD(e,t,r,n+1)};VD.render=function(e,t,r){let n=e.modules.size,i=e.modules.data,a=!!(t&&t.inverse),o=t&&t.inverse?NV:BV,l=LV(o,a?_y:wy,a?wy:_y),u=Ba+`
|
|
70
70
|
`+o,p=o;for(let f=-1;f<n+1;f+=2){for(let h=-1;h<n;h++)p+=l[GD(i,n,h,f)];p+=l[GD(i,n,n,f)]+u}return p+=Ba,typeof r=="function"&&r(null,p),p}});var KD=P(ZD=>{var UV=HD(),zV=JD();ZD.render=function(e,t,r){return t&&t.small?zV.render(e,t,r):UV.render(e,t,r)}});var Sy=P(QD=>{var MV=$c();function YD(e,t){let r=e.a/255,n=t+'="'+e.hex+'"';return r<1?n+" "+t+'-opacity="'+r.toFixed(2).slice(1)+'"':n}function ky(e,t,r){let n=e+t;return typeof r<"u"&&(n+=" "+r),n}function $V(e,t,r){let n="",i=0,a=!1,o=0;for(let s=0;s<e.length;s++){let c=Math.floor(s%t),l=Math.floor(s/t);!c&&!a&&(a=!0),e[s]?(o++,s>0&&c>0&&e[s-1]||(n+=a?ky("M",c+r,.5+l+r):ky("m",i,0),i=0,a=!1),c+1<t&&e[s+1]||(n+=ky("h",o),o=0)):i++}return n}QD.render=function(t,r,n){let i=MV.getOptions(r),a=t.modules.size,o=t.modules.data,s=a+i.margin*2,c=i.color.light.a?"<path "+YD(i.color.light,"fill")+' d="M0 0h'+s+"v"+s+'H0z"/>':"",l="<path "+YD(i.color.dark,"stroke")+' d="'+$V(o,a,i.margin)+'"/>',u='viewBox="0 0 '+s+" "+s+'"',f='<svg xmlns="http://www.w3.org/2000/svg" '+(i.width?'width="'+i.width+'" height="'+i.width+'" ':"")+u+' shape-rendering="crispEdges">'+c+l+`</svg>
|
|
71
|
-
`;return typeof n=="function"&&n(null,f),f}});var XD=P(jp=>{var jV=Sy();jp.render=jV.render;jp.renderToFile=function(t,r,n,i){typeof i>"u"&&(i=n,n=void 0);let a=require("fs"),s='<?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'+jp.render(r,n);a.writeFile(t,s,i)}});var eB=P(qp=>{var Ey=$c();function qV(e,t,r){e.clearRect(0,0,t.width,t.height),t.style||(t.style={}),t.height=r,t.width=r,t.style.height=r+"px",t.style.width=r+"px"}function HV(){try{return document.createElement("canvas")}catch{throw new Error("You need to specify a canvas element")}}qp.render=function(t,r,n){let i=n,a=r;typeof i>"u"&&(!r||!r.getContext)&&(i=r,r=void 0),r||(a=HV()),i=Ey.getOptions(i);let o=Ey.getImageWidth(t.modules.size,i),s=a.getContext("2d"),c=s.createImageData(o,o);return Ey.qrToImageData(c.data,t,i),qV(s,a,o),s.putImageData(c,0,0),a};qp.renderToDataURL=function(t,r,n){let i=n;typeof i>"u"&&(!r||!r.getContext)&&(i=r,r=void 0),i||(i={});let a=qp.render(t,r,i),o=i.type||"image/png",s=i.rendererOpts||{};return a.toDataURL(o,s.quality)}});var rB=P(jc=>{var WV=zg(),Ay=iy(),tB=eB(),GV=Sy();function Cy(e,t,r,n,i){let a=[].slice.call(arguments,1),o=a.length,s=typeof a[o-1]=="function";if(!s&&!WV())throw new Error("Callback required as last argument");if(s){if(o<2)throw new Error("Too few arguments provided");o===2?(i=r,r=t,t=n=void 0):o===3&&(t.getContext&&typeof i>"u"?(i=n,n=void 0):(i=n,n=r,r=t,t=void 0))}else{if(o<1)throw new Error("Too few arguments provided");return o===1?(r=t,t=n=void 0):o===2&&!t.getContext&&(n=r,r=t,t=void 0),new Promise(function(c,l){try{let u=Ay.create(r,n);c(e(u,t,n))}catch(u){l(u)}})}try{let c=Ay.create(r,n);i(null,e(c,t,n))}catch(c){i(c)}}jc.create=Ay.create;jc.toCanvas=Cy.bind(null,tB.render);jc.toDataURL=Cy.bind(null,tB.renderToDataURL);jc.toString=Cy.bind(null,function(e,t,r){return GV.render(e,r)})});var oB=P($i=>{var nB=zg(),Iy=iy(),VV=$D(),iB=jD(),JV=KD(),aB=XD();function qc(e,t,r){if(typeof e>"u")throw new Error("String required as first argument");if(typeof r>"u"&&(r=t,t={}),typeof r!="function")if(nB())t=r||{},r=null;else throw new Error("Callback required as last argument");return{opts:t,cb:r}}function ZV(e){return e.slice((e.lastIndexOf(".")-1>>>0)+2).toLowerCase()}function Hp(e){switch(e){case"svg":return aB;case"txt":case"utf8":return iB;case"png":case"image/png":default:return VV}}function KV(e){switch(e){case"svg":return aB;case"terminal":return JV;case"utf8":default:return iB}}function Hc(e,t,r){if(!r.cb)return new Promise(function(n,i){try{let a=Iy.create(t,r.opts);return e(a,r.opts,function(o,s){return o?i(o):n(s)})}catch(a){i(a)}});try{let n=Iy.create(t,r.opts);return e(n,r.opts,r.cb)}catch(n){r.cb(n)}}$i.create=Iy.create;$i.toCanvas=rB().toCanvas;$i.toString=function(t,r,n){let i=qc(t,r,n),a=i.opts?i.opts.type:void 0,o=KV(a);return Hc(o.render,t,i)};$i.toDataURL=function(t,r,n){let i=qc(t,r,n),a=Hp(i.opts.type);return Hc(a.renderToDataURL,t,i)};$i.toBuffer=function(t,r,n){let i=qc(t,r,n),a=Hp(i.opts.type);return Hc(a.renderToBuffer,t,i)};$i.toFile=function(t,r,n,i){if(typeof t!="string"||!(typeof r=="string"||typeof r=="object"))throw new Error("Invalid argument");if(arguments.length<3&&!nB())throw new Error("Too few arguments provided");let a=qc(r,n,i),o=a.opts.type||ZV(t),c=Hp(o).renderToFile.bind(null,t);return Hc(c,r,a)};$i.toFileStream=function(t,r,n){if(arguments.length<2)throw new Error("Too few arguments provided");let i=qc(r,n,t.emit.bind(t,"error")),o=Hp("png").renderToFileStream.bind(null,t);Hc(o,r,i)}});var cB=P((Jfe,sB)=>{sB.exports=oB()});var Ve=le(require("fs")),_t=le(require("path")),tt=le(require("os")),CB=le(require("dns")),We=require("child_process");var Mn=le(require("os")),hi=le(require("fs")),vs=le(require("path")),Pb=le(require("crypto"));function lN(){return"1.0.56"}var er=lN();function wl(){return{totalMemMb:Math.round(Mn.default.totalmem()/(1024*1024)),freeMemMb:Math.round(Mn.default.freemem()/(1024*1024)),cpuCount:Mn.default.cpus()?.length||1,platform:Mn.default.platform()}}function uN(e){try{let t=vs.default.join(Mn.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=vs.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 a=(Mn.default.hostname()||"node").replace(/[^a-zA-Z0-9_-]/g,"_").toLowerCase().slice(0,14),o=Pb.default.randomBytes(2).toString("hex"),s=`worker_${a}${r}_${o}`,c=e?` #${e}`:"",l=`Worker ${a.toUpperCase()}${c}`,u={workerId:s,workerName:l,slot:e||"default",createdAt:new Date().toISOString()};return hi.default.writeFileSync(n,JSON.stringify(u,null,2),"utf-8"),u}catch{let t=e?`_slot_${e}`:"",r=`worker_${Mn.default.hostname().replace(/[^a-zA-Z0-9_-]/g,"_").slice(0,14)||"node"}${t}`;return{workerId:r,workerName:r}}}var vl=class{static loadFromEnv(t=process.argv.slice(2)){let r=F=>{for(let I of t){if(I.startsWith(`--${F}=`))return I.split("=").slice(1).join("=");if(I===`--${F}`&&t[t.indexOf(I)+1])return t[t.indexOf(I)+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,a=r("jwt")||process.env.CLOUD_JWT||process.env.APPWRITE_JWT||process.env.JWT,o=r("secret")||process.env.DESKTOP_SECRET,s=r("team-id")||process.env.TEAM_ID||"default",c=t.includes("--enable-http")||r("enable-http")==="true"||process.env.ENABLE_HTTP==="true"||!1,l=r("port")||process.env.PORT,u=l?Number(l):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",f=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",b=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",v=Math.max(1,Math.round(Mn.default.totalmem()/(1024*1024*1024))),_=Math.min(200,Math.max(20,v*25)),m=r("max-capacity")||process.env.MAX_CAPACITY,x=Number(m||_),w=r("slot")||process.env.WORKER_SLOT||process.env.pm_id||process.env.NODE_APP_INSTANCE,g=uN(w),k=r("worker-id")||process.env.WORKER_ID||g.workerId,S=r("worker-name")||process.env.WORKER_NAME||process.env.HOSTNAME||g.workerName,C=r("user-id")||process.env.USER_ID||process.env.SOFTTY_USER_ID;return{workerId:k,version:er,enableHttp:c,port:u,userId:C,teamId:s,workerName:S,maxCapacity:x,recommendedCapacity:_,clusterPollIntervalMs:Number(r("poll-interval")||process.env.CLUSTER_POLL_INTERVAL_MS||5e3),cloudProvider:n,cloudEndpoint:p,cloudProjectId:f,cloudSessionToken:i,cloudJwt:a,cloudDatabaseId:h,appwriteEndpoint:p,appwriteProjectId:f,appwriteSessionToken:i,appwriteJwt:a,storageBucketId:b,desktopSecret:o,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 ji=le(require("fs")),nf=le(require("os")),Ua=le(require("path")),EB=le(require("crypto")),os=le(at());var $b=le(at()),Cl=class{runners=new Map;logger;constructor(t){this.logger=t||(0,$b.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(a=>{this.logger.error(`Error stopping runner ${n} during unregister`,a)}),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()}async pauseAll(){this.logger.info(`Pausing all ${this.runners.size} channel runners due to worker auth/standby status...`);for(let[t,r]of this.runners.entries())try{typeof r.pause=="function"&&await r.pause()}catch(n){this.logger.error(`Failed to pause runner ${t}:`,n)}}async resumeAll(){this.logger.info(`Resuming all ${this.runners.size} channel runners...`);for(let[t,r]of this.runners.entries())try{typeof r.resume=="function"&&await r.resume()}catch(n){this.logger.error(`Failed to resume runner ${t}:`,n)}}};var jb=le(at()),Il=class{constructor(t=6e4,r,n){this.defaultTtlMs=t;this.logger=r||(0,jb.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(),a=this.locks.get(t);return a&&a.expiresAt>i&&a.ownerId!==r?(this.logger.warn(`Lock denied for account ${t}: currently held by ${a.ownerId} (expires in ${a.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(o=>{try{return Promise.resolve(o(t,r))}catch(s){return this.logger.error(`Error in preempt callback for ${t}:`,s),Promise.resolve()}});await Promise.race([Promise.all(i),new Promise(o=>setTimeout(o,1e3))]);let a=Date.now();return this.locks.set(t,{accountId:t,ownerId:r,acquiredAt:a,expiresAt:a+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 to=le(require("fs")),qb=le(require("path")),Hb=le(at()),Tl=class{logger;queue=[];maxCapacity;persistenceFilePath;constructor(t=1e4,r,n){this.maxCapacity=t,this.logger=r||(0,Hb.createLogger)("CloudPendingMessageQueue"),this.persistenceFilePath=n,this.loadFromDisk()}loadFromDisk(){if(this.persistenceFilePath)try{if(to.default.existsSync(this.persistenceFilePath)){let t=to.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=qb.default.dirname(this.persistenceFilePath);to.default.existsSync(t)||to.default.mkdirSync(t,{recursive:!0}),to.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,a=n.timestamp>=r;return i&&a})}purgeSynced(t,r){let n=this.queue.length,i=[];for(let o=0;o<this.queue.length;o++){let s=this.queue[o];s.timestamp<=t&&(!r||s.accountId===r)&&i.push(o)}for(let o=i.length-1;o>=0;o--)this.queue.splice(i[o],1);let a=n-this.queue.length;return a>0&&(this.saveToDisk(),this.logger.info(`Purged ${a} synced delta messages from queue.`)),a}getCount(){return this.queue.length}getAll(){return[...this.queue]}remove(t){let r=this.queue.findIndex(n=>n.id===t);return r!==-1?(this.queue.splice(r,1),this.saveToDisk(),!0):!1}clear(){this.queue.length=0,this.saveToDisk()}};var Wb=le(at()),Rl=class{logger;campaigns=new Map;rules=new Map;threadHistory=new Map;lastReplyTimes=new Map;aiConfig={enabled:!1};constructor(t,r){this.logger=t||(0,Wb.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 a=t.content.trim(),o=this.getThreadHistory(r);if(o.push({role:"user",content:a,timestamp:n}),o.length>6&&o.splice(0,o.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 s=t.accountId,c=this.aiConfig.accountBotConfigs,l=s&&c?c[s]:void 0;if(!l||!l.isBotEnabled)return this.logger.debug(`[HeadlessAutomation] Account [${s||"unknown"}] has not been configured or enabled for Bot AI by user in Chatbot settings. Message saved, no auto-reply sent.`),null;let u=t,p=!!u.isGroup||!!u.groupId||typeof t.threadId=="string"&&t.threadId.startsWith("g")||typeof t.conversationId=="string"&&t.conversationId.startsWith("g"),f=l.replyTarget||"all";if(f==="individual"&&p)return this.logger.debug(`[HeadlessAutomation] Account [${s}] configured for individual chat only. Skipping group message ${r}.`),null;if(f==="group"&&!p)return this.logger.debug(`[HeadlessAutomation] Account [${s}] configured for group chat only. Skipping direct message ${r}.`),null;let h=l.scheduleType||"always";if(h!=="always"){let S=new Date().getHours(),C=l.scheduleStartHour??8,F=l.scheduleEndHour??18;if(h==="working_hours"){if(S<C||S>=F)return this.logger.debug(`[HeadlessAutomation] Outside working hours (${S}h, allowed: ${C}h-${F}h). Skipping reply.`),null}else if(h==="outside_hours"&&S>=C&&S<F)return this.logger.debug(`[HeadlessAutomation] Inside working hours (${S}h, allowed outside: ${C}h-${F}h). Skipping reply.`),null}let b=l.excludeContactIds||[];if(!p&&b.length>0){let S=String(t.senderId||"");if(b.includes(S))return this.logger.debug(`[HeadlessAutomation] Sender ${S} is in contact blacklist. Skipping reply.`),null}if(p){let S=String(u.groupId||u.threadId||r||""),C=l.excludeGroupIds||[],F=l.includeGroupIds||[];if(C.length>0&&C.includes(S))return this.logger.debug(`[HeadlessAutomation] Group ${S} is in group blacklist. Skipping reply.`),null;if(F.length>0&&!F.includes(S))return this.logger.debug(`[HeadlessAutomation] Group ${S} is not in group whitelist. Skipping reply.`),null}let v=l.excludeKeywords||[],_=l.includeKeywords||[],m=a.toLowerCase();if(v.length>0&&v.some(C=>{let F=C.trim().toLowerCase();return F.length>0&&m.includes(F)}))return this.logger.debug("[HeadlessAutomation] Message contains blacklisted keyword. Skipping reply."),null;if(_.length>0&&!_.some(C=>{let F=C.trim().toLowerCase();return F.length>0&&m.includes(F)}))return this.logger.debug("[HeadlessAutomation] Message does not match any whitelist keyword. Skipping reply."),null;let x=t.tagIds||t.tags||t.metadata?.tagIds;if(Array.isArray(x)){let S=x.map(I=>typeof I=="string"?I:String(I?.id||"")),C=l.excludeTagIds||[],F=l.includeTagIds||[];if(C.length>0&&S.some(I=>C.includes(I)))return this.logger.debug("[HeadlessAutomation] Customer has excluded CRM tag. Skipping reply."),null;if(F.length>0){if(S.length===0){if(l.replyUntaggedCustomers===!1)return null}else if(!S.some(I=>F.includes(I)))return null}}let w=l.systemPrompt&&l.systemPrompt.trim()?l.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 g=this.aiConfig.provider,k=this.aiConfig.apiKey;if(k||(g==="openai"?k=process.env.OPENAI_API_KEY:g==="deepseek"?k=process.env.DEEPSEEK_API_KEY:g==="anthropic"?k=process.env.ANTHROPIC_API_KEY:g==="custom"?k=process.env.CUSTOM_AI_API_KEY:g==="gemini"&&(k=process.env.GEMINI_API_KEY||process.env.GOOGLE_API_KEY)),!k&&g!=="custom")return this.logger.debug(`[HeadlessAutomation] No API key found for provider [${g}]. No auto-reply sent.`),null;try{let S=null;if(g==="openai"||g==="custom"||g==="deepseek")S=await this.callOpenAiCompatible(a,o,k||"",w);else if(g==="anthropic")S=await this.callAnthropic(a,o,k||"",w);else if(g==="gemini")S=await this.callGemini(a,o,k||"",w);else return this.logger.warn(`[HeadlessAutomation] Unsupported AI provider [${g}]. No reply generated.`),null;if(S&&S.trim().length>0){let C=S.trim();return o.push({role:"model",content:C,timestamp:Date.now()}),this.lastReplyTimes.set(r,Date.now()),C}}catch(S){this.logger.warn(`[HeadlessAutomation] AI generation error with provider [${g}] (${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 o=`https://generativelanguage.googleapis.com/v1beta/models/${this.aiConfig.model||"gemini-2.0-flash"}:generateContent?key=${n}`,s=r.map(f=>({role:f.role==="model"?"model":"user",parts:[{text:f.content}]}));(s.length===0||s[s.length-1].parts[0]?.text!==t)&&s.push({role:"user",parts:[{text:t}]});let c={contents:s,generationConfig:{temperature:this.aiConfig.temperature??.7,maxOutputTokens:this.aiConfig.maxTokens??300}},l=i||this.aiConfig.systemPrompt;l&&l.trim()&&(c.systemInstruction={parts:[{text:l.trim()}]});let u=new AbortController,p=setTimeout(()=>u.abort(),7e3);try{let f=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(c),signal:u.signal});if(!f.ok){let v=await f.text();return this.logger.warn(`[HeadlessAutomation] Gemini API returned status ${f.status}: ${v.slice(0,200)}`),null}return(await f.json())?.candidates?.[0]?.content?.parts?.[0]?.text||null}finally{clearTimeout(p)}}async callOpenAiCompatible(t,r,n,i){let a=(this.aiConfig.baseUrl||(this.aiConfig.provider==="deepseek"?"https://api.deepseek.com/v1":"https://api.openai.com/v1")).replace(/\/+$/,"");a.includes("api.deepseek.com")&&!a.endsWith("/v1")?a+="/v1":(a.includes("11434")||a.includes("ollama"))&&(a=a.replace(/\/api$/,"").replace(/\/+$/,""),a.endsWith("/v1")||(a+="/v1"));let o=`${a}/chat/completions`,s=this.aiConfig.model||(this.aiConfig.provider==="deepseek"?"deepseek-chat":this.aiConfig.provider==="openai"?"gpt-4o-mini":"deepseek-chat"),c=i||this.aiConfig.systemPrompt,l=[...c&&c.trim()?[{role:"system",content:c.trim()}]:[],...r.map(h=>({role:h.role==="model"?"assistant":"user",content:h.content}))],u={"Content-Type":"application/json"};n&&(u.Authorization=`Bearer ${n}`);let p=new AbortController,f=setTimeout(()=>p.abort(),8e3);try{let h=await fetch(o,{method:"POST",headers:u,body:JSON.stringify({model:s,messages:l,temperature:this.aiConfig.temperature??.7,max_tokens:this.aiConfig.maxTokens??300}),signal:p.signal});if(!h.ok){let v=await h.text();return this.logger.warn(`[HeadlessAutomation] OpenAI-compatible API returned status ${h.status}: ${v.slice(0,200)}`),null}return(await h.json())?.choices?.[0]?.message?.content||null}finally{clearTimeout(f)}}async callAnthropic(t,r,n,i){let a="https://api.anthropic.com/v1/messages",o=this.aiConfig.model||"claude-3-5-haiku-20241022",s=r.map(u=>({role:u.role==="model"?"assistant":"user",content:u.content}));(s.length===0||s[s.length-1].content!==t)&&s.push({role:"user",content:t});let c=new AbortController,l=setTimeout(()=>c.abort(),8e3);try{let u=i||this.aiConfig.systemPrompt,p={model:o,messages:s,max_tokens:this.aiConfig.maxTokens??300,temperature:this.aiConfig.temperature??.7};u&&u.trim()&&(p.system=u.trim());let f=await fetch(a,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":n,"anthropic-version":"2023-06-01"},body:JSON.stringify(p),signal:c.signal});if(!f.ok){let b=await f.text();return this.logger.warn(`[HeadlessAutomation] Anthropic API returned status ${f.status}: ${b.slice(0,200)}`),null}return(await f.json())?.content?.[0]?.text||null}finally{clearTimeout(l)}}clear(){this.campaigns.clear(),this.rules.clear(),this.threadHistory.clear(),this.lastReplyTimes.clear()}};var Gb=le(at()),Pl=class{logger;endpoint;projectId;apiKey;constructor(t,r){this.logger=t||(0,Gb.createLogger)("PushNotificationDispatcher"),this.endpoint=r?.endpoint||process.env.APPWRITE_ENDPOINT||"https://api.softty.net/v1",this.projectId=r?.projectId||process.env.APPWRITE_PROJECT_ID||"699cfc3100136099c1c1",this.apiKey=r?.apiKey||process.env.APPWRITE_API_KEY}formatMessagePreview(t){if(t.isRecall)return"[Tin nh\u1EAFn \u0111\xE3 \u0111\u01B0\u1EE3c thu h\u1ED3i]";let r=t.content,n=String(t.messageType||"").toLowerCase(),i=null;if(typeof r=="string"&&r.trim().startsWith("{")&&r.trim().endsWith("}"))try{i=JSON.parse(r)}catch{}else typeof r=="object"&&r!==null&&(i=r);let a=c=>!!(c&&(/\.(png|jpg|jpeg|gif|webp)(\?|#|$)/i.test(c)||c.includes("photo-stal")||c.includes("zdn.vn"))),o=c=>!!(c&&/\.(mp3|m4a|wav|aac|ogg|opus)(\?|#|$)/i.test(c)),s=c=>!!(c&&/\.(mp4|avi|mov|mkv|wmv|flv)(\?|#|$)/i.test(c));if(i){let c=String(i.msgType||i.type||n).toLowerCase(),l=String(i.title||i.fileName||i.filename||i.name||"").trim(),u=String(i.href||i.url||i.rawUrl||"");if(i.id&&(i.cateId!==void 0||i.type==="sticker")||c.includes("sticker"))return"[Nh\xE3n d\xE1n]";if(c.includes("photo")||c.includes("image")||a(u)||a(l))return l&&!l.startsWith("http")&&!a(l)?`[H\xECnh \u1EA3nh] ${l}`:"[H\xECnh \u1EA3nh]";if(c.includes("video")||s(l)||s(u))return l&&!l.startsWith("http")?`[Video] ${l}`:"[Video]";if(c.includes("voice")||c.includes("audio")||o(l)||o(u))return"[Tin nh\u1EAFn tho\u1EA1i]";if(c.includes("file")||i.fileSize!==void 0)return o(l)?"[Tin nh\u1EAFn tho\u1EA1i]":s(l)?`[Video] ${l}`:a(l)?`[H\xECnh \u1EA3nh] ${l}`:l?`[T\u1EADp tin] ${l}`:"[T\u1EADp tin]";if(c.includes("contact")||String(i.action||"").includes("recommended.user"))return l?`[Danh thi\u1EBFp] ${l}`:"[Danh thi\u1EBFp]";if(c.includes("location")||i.lat!==void 0)return i.address||l?`[V\u1ECB tr\xED] ${i.address||l}`:"[V\u1ECB tr\xED]";if(c.includes("poll"))return i.question||i.topic?`[B\xECnh ch\u1ECDn] ${i.question||i.topic}`:"[B\xECnh ch\u1ECDn]";if(c.includes("bank"))return"[Th\xF4ng tin chuy\u1EC3n kho\u1EA3n]";if(c.includes("link"))return l&&!l.startsWith("http")?`[Li\xEAn k\u1EBFt] ${l}`:"[Li\xEAn k\u1EBFt]";if(i.text||i.msg||i.message)return String(i.text||i.msg||i.message)}if(n==="image"||n.includes("photo"))return"[H\xECnh \u1EA3nh]";if(n==="video")return"[Video]";if(n==="audio"||n.includes("voice"))return"[Tin nh\u1EAFn tho\u1EA1i]";if(n==="file")return"[T\u1EADp tin]";if(n==="sticker")return"[Nh\xE3n d\xE1n]";if(n==="location")return"[V\u1ECB tr\xED]";if(n==="contact")return"[Danh thi\u1EBFp]";if(typeof r=="string"){let c=r.trim();return c?a(c)?"[H\xECnh \u1EA3nh]":c.startsWith("{")&&c.endsWith("}")?c.includes("photo-stal")?"[H\xECnh \u1EA3nh]":"[\u0110\xEDnh k\xE8m ph\u01B0\u01A1ng ti\u1EC7n]":c.length>120?`${c.slice(0,117)}...`:c:"\u0110\xE3 g\u1EEDi m\u1ED9t tin nh\u1EAFn m\u1EDBi"}return"\u0110\xE3 g\u1EEDi m\u1ED9t tin nh\u1EAFn m\u1EDBi"}extractMessageRichMedia(t){let r=t.content,n=String(t.messageType||"").toLowerCase(),i=Array.isArray(t.attachments)?t.attachments:[],a=i.length>0?i[0]:null;if(a){let s=String(a.url||a.href||a.hdUrl||"").trim(),c=String(a.thumb||a.thumbnail||"").trim(),l=String(a.fileType||a.type||n).toLowerCase();if(l.includes("sticker"))return{mediaUrl:s.startsWith("http")?s:"",mediaType:"sticker"};if(l.includes("video"))return{mediaUrl:c.startsWith("http")?c:"",mediaType:"video"};if(l.includes("image")||l.includes("photo"))return{mediaUrl:s.startsWith("http")?s:c.startsWith("http")?c:"",mediaType:"image"};if(l.includes("voice")||l.includes("audio"))return{mediaUrl:"",mediaType:"audio"};if(l.includes("file"))return{mediaUrl:"",mediaType:"file"}}let o=null;if(typeof r=="string"&&r.trim().startsWith("{")&&r.trim().endsWith("}"))try{o=JSON.parse(r)}catch{}else typeof r=="object"&&r!==null&&(o=r);if(o){let s=String(o.msgType||o.type||n).toLowerCase(),c=String(o.href||o.hdUrl||o.url||o.rawUrl||o.src||o.normalUrl||"").trim(),l=String(o.thumb||o.thumbUrl||o.thumbnail||"").trim(),u=String(o.stickerUrl||o.stickerWebpUrl||(s.includes("sticker")?c||l:"")).trim();if(s.includes("sticker")||o.type==="sticker")return{mediaUrl:u.startsWith("http")?u:"",mediaType:"sticker"};if(s.includes("video"))return{mediaUrl:l.startsWith("http")?l:"",mediaType:"video"};if(s.includes("photo")||s.includes("image"))return{mediaUrl:c.startsWith("http")?c:l.startsWith("http")?l:"",mediaType:"image"};if(s.includes("voice")||s.includes("audio"))return{mediaUrl:"",mediaType:"audio"};if(s.includes("file")||o.fileSize!==void 0)return{mediaUrl:"",mediaType:"file"}}return typeof r=="string"&&r.trim().startsWith("http")&&/\.(png|jpg|jpeg|gif|webp)(\?|#|$)/i.test(r.trim())?{mediaUrl:r.trim(),mediaType:"image"}:{mediaUrl:"",mediaType:n||"text"}}async dispatchMessageAlert(t,r,n,i){if(r.isRecall||r.deleted_at)return!1;let a=r.timestamp??r.time,o=Number(a||0);if(o>0){let h=o<1e11?o*1e3:o,b=Date.now()-h;if(b>12e4||b<-6e4)return this.logger.debug(`Suppressed stale push alert for message ${r.id} (age: ${Math.round(b/1e3)}s)`),!1}let s=r.metadata?.rawPayload||r.rawPayload||r,c=!!(r.isGroup||s?.isGroup||Number(s?.type)===1||Number(s?.data?.type)===1||s?.groupId||s?.data?.groupId||r.type==="group"||r.threadType===1||r.threadType==="group"||String(r.threadId||"").startsWith("g")),l=r.groupName||r.threadName||s?.groupName||s?.data?.groupName||"Nh\xF3m Zalo",u=this.formatMessagePreview(r),p=c?l:r.senderName||"Kh\xE1ch h\xE0ng",f=c?`${r.senderName||"Th\xE0nh vi\xEAn"}: ${u}`:u;return f.length>130&&(f=`${f.slice(0,127)}...`),this.sendNotification({recipientToken:t,title:p,body:f,platform:n,userId:i,data:{messageId:r.id,threadId:r.threadId,platform:r.platform,accountId:r.accountId}})}async enqueueNotification(t,r,n){if(t.isSelf||t.isRecall||t.deleted_at)return!1;let i=t.timestamp??t.time,a=Number(i||0);if(a>0){let _=a<1e11?a*1e3:a,m=Date.now()-_;if(m>12e4||m<-6e4)return this.logger.debug(`Suppressed stale push alert for message ${t.id} (age: ${Math.round(m/1e3)}s)`),!1}let o=t.metadata?.rawPayload||t.rawPayload||t,s=!!(t.isGroup||o?.isGroup||Number(o?.type)===1||Number(o?.data?.type)===1||o?.groupId||o?.data?.groupId||t.type==="group"||t.threadType===1||t.threadType==="group"||String(t.threadId||"").startsWith("g")),c=t.groupName||t.threadName||o?.groupName||o?.data?.groupName||"Nh\xF3m Zalo",l=this.formatMessagePreview(t),u=s?c:t.senderName||"Kh\xE1ch h\xE0ng",p=s?`${t.senderName||"Th\xE0nh vi\xEAn"}: ${l}`:l;p.length>130&&(p=`${p.slice(0,127)}...`);let f=`pn_${Date.now()}_${Math.random().toString(36).slice(2,8)}`,h=this.extractMessageRichMedia(t),b=(s?t.groupAvatar||o?.groupAvatar||o?.data?.groupAvatar:void 0)||t.avatar||t.senderAvatar||t.groupAvatar||"",v=String(t.accountName||n.accountName||o?.accountName||"").trim();try{return await r.createDocument("push_notification_queue",f,{teamId:n.teamId||"",userId:n.userId||"",channelAccountId:n.channelAccountId||t.accountId||"",accountName:v,senderName:t.senderName||"Kh\xE1ch h\xE0ng",title:u,body:p,avatarUrl:b,mediaUrl:t.mediaUrl||h.mediaUrl||"",mediaType:t.mediaType||h.mediaType||"text",threadId:t.threadId||t.conversationId||"",platform:t.platform||"zalo",msgId:t.id||f}),this.logger.debug(`Enqueued push notification ${f} for message ${t.id}`),!0}catch(_){return this.logger.warn(`Failed to enqueue push notification: ${_?.message}`),!1}}async sendNotification(t){if(this.logger.debug(`Dispatching push notification to device token: ${t.recipientToken.slice(0,8)}...`),t.recipientToken.startsWith("ExponentPushToken")||t.recipientToken.startsWith("ExpoPushToken"))try{return(await fetch("https://exp.host/--/api/v2/push/send",{method:"POST",headers:{Accept:"application/json","Accept-encoding":"gzip, deflate","Content-Type":"application/json"},body:JSON.stringify({to:t.recipientToken,title:t.title,body:t.body,data:t.data,sound:"default",priority:"high",channelId:"default"})})).ok}catch(r){this.logger.warn(`Expo push send error: ${r?.message}`)}if(this.apiKey)try{let r=t.platform==="ios"||t.recipientToken.length===64,n=t.recipientToken.replace(/[^a-zA-Z0-9]/g,""),i=`${r?"apns":"fcm"}_${n.slice(0,31)}`,a=`${this.endpoint}/messaging/messages/push`;if((await fetch(a,{method:"POST",headers:{"Content-Type":"application/json","X-Appwrite-Project":this.projectId,"X-Appwrite-Key":this.apiKey},body:JSON.stringify({messageId:`push_${Date.now()}_${Math.random().toString(36).slice(2,7)}`,title:t.title,body:t.body,data:t.data||{},targets:[i],draft:!1})})).ok)return!0}catch(r){this.logger.warn(`Appwrite push send error: ${r?.message}`)}return!0}};var GO=le(require("http")),VO=require("url"),JO=le(at());var WO=le(at()),Vo=class{static logger=(0,WO.createLogger)("ChannelRunnerFactory");static async createRunner(t,r,n,i){let a=(t||"zalo").toLowerCase(),o=a==="web"||a.includes("zalo")?"zalo":a;try{if(o==="zalo"){let{ZaloChannelRunner:s}=await Promise.resolve().then(()=>(HO(),qO));return new s(r,n,i)}return this.logger.warn(`Unsupported platform for ChannelRunner: ${t}`),null}catch(s){return this.logger.error(`Failed to dynamically initialize runner for ${o}:${r}:`,s?.message||s),null}}};var Ip=class{constructor(t,r,n,i,a){this.port=t;this.engine=r;this.lockManager=n;this.deltaQueue=i;this.logger=a||(0,JO.createLogger)("WorkerHttpServer")}logger;server=null;async start(){if(!this.server)return new Promise((t,r)=>{this.server=GO.default.createServer((n,i)=>{this.handleRequest(n,i).catch(a=>{this.logger.error("Unhandled HTTP error:",a),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 VO.URL(t.url||"/",`http://${t.headers.host||"localhost"}`),i=n.pathname,a=(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"),a==="OPTIONS"){r.writeHead(204),r.end();return}if(a==="GET"&&i==="/health"){let o=this.engine.getMetrics();r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({status:"healthy",timestamp:Date.now(),pendingDeltaMessages:this.deltaQueue.getCount(),metrics:o}));return}if(i.startsWith("/api/v1/")){let o=this.engine.config.desktopSecret;if(o){let s=t.headers["x-desktop-secret"]||t.headers.authorization;if((typeof s=="string"&&s.startsWith("Bearer ")?s.slice(7):s)!==o){r.writeHead(401,{"Content-Type":"application/json"}),r.end(JSON.stringify({error:"Unauthorized: Invalid or missing X-Desktop-Secret"}));return}}}if(a==="POST"&&i==="/api/v1/sentinel/handover"){let o=await this.readJsonBody(t),{deviceId:s,sessions:c,aiConfig:l}=o||{};if(l&&(this.engine.automationEngine.configure(l),this.logger.info(`[Handover] Configured 24/7 AI automation engine with provider: ${l.provider||"gemini"}, model: ${l.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 ${s||"unknown"} with ${c.length} sessions.`);let u=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(),b=h==="web"||h.includes("zalo")?"zalo":h,v=await Vo.createRunner(b,p.id,p.sessionData);v&&(this.engine.registerRunner(v),await v.start(),this.engine.registerAccount({id:p.id,platform:b,accountName:p.accountName||p.id,status:"active",nightWorkerEnabled:!0}),u++)}r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({success:!0,message:"Sessions handed over successfully",activatedCount:u,timestamp:Date.now()}));return}if(a==="POST"&&i==="/api/v1/sentinel/reclaim"){let o=await this.readJsonBody(t),{deviceId:s}=o||{};this.logger.info(`[Reclaim] Master device ${s||"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(a==="POST"){let o=await this.readJsonBody(t);o&&(this.engine.automationEngine.configure(o),this.logger.info(`[NightConfig] Updated 24/7 AI config dynamically: provider=${o.provider||"gemini"}, model=${o.model||"default"}`)),r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({success:!0,config:this.engine.automationEngine.getAiConfig()}));return}else if(a==="GET"){r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({success:!0,config:this.engine.automationEngine.getAiConfig()}));return}}if(a==="GET"&&i==="/api/v1/sync/delta"){let o=n.searchParams.get("accountId")||void 0,s=parseInt(n.searchParams.get("since")||"0",10),c=this.deltaQueue.getDeltas(o,s);this.logger.info(`[DeltaSync] Serving ${c.length} night messages (since: ${s}, account: ${o||"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 as=le(at());var Tp=le(require("fs")),Ug=le(require("path")),Jo=require("child_process"),XO=le(at());var vt=le(require("fs")),ZO=le(require("os")),Ta=le(require("path")),KO=le(require("zlib")),Lg=le(require("crypto")),YO=le(require("module")),QO=le(at()),Ng="__ZPLUS_RUNTIME_BOOTSTRAPPED__",Di=class{static PACKAGE_NAME="@softtynet/zplus-worker";static getRuntimeDir(){let t=process.env.ZPLUS_HOME||process.env.DATA_DIR||Ta.default.join(ZO.default.homedir(),".zplus");return Ta.default.join(t,"runtime")}static getRuntimeCliPath(){return Ta.default.join(this.getRuntimeDir(),"cli.js")}static getRuntimeVersionPath(){return Ta.default.join(this.getRuntimeDir(),"version.json")}static isNewerVersion(t,r){let n=u=>u.replace(/^v/,"").trim().split("-")[0].split(".").map(p=>parseInt(p,10)||0),[i=0,a=0,o=0]=n(t),[s=0,c=0,l=0]=n(r);return i!==s?i>s:a!==c?a>c:o>l}static getInstalledRuntimeVersion(){try{let t=this.getRuntimeVersionPath(),r=this.getRuntimeCliPath();if(!vt.default.existsSync(t)||!vt.default.existsSync(r)||vt.default.statSync(r).size<1024)return null;let n=JSON.parse(vt.default.readFileSync(t,"utf-8"));return n?.version?String(n.version).trim():null}catch{return null}}static extractFileFromTarGz(t,r="package/dist/cli.js"){let n=KO.default.gunzipSync(t),i=0;for(;i+512<=n.length;){let a=n.subarray(i,i+512);if(a.every(v=>v===0))break;let o=(v,_)=>a.subarray(v,_).toString("utf-8").replace(/\0.*$/,"").trim(),s=o(0,100),c=o(345,500),l=c?`${c}/${s}`:s,u=parseInt(o(124,136),8)||0,p=a[156],f=p===0||p===48,h=i+512,b=h+u;if(f&&u>0&&b<=n.length&&(l===r||l.endsWith("/dist/cli.js")))return Buffer.from(n.subarray(h,b));i=h+Math.ceil(u/512)*512}return null}static async downloadAndInstallRuntimeBundle(t="latest",r=(0,QO.createLogger)("RuntimeBundleManager")){try{let n=t.replace(/^v/,"").trim()||"latest",i=await fetch(`https://registry.npmjs.org/${this.PACKAGE_NAME}/${n}`,{headers:{Accept:"application/json"},signal:AbortSignal.timeout(1e4)});if(!i.ok)throw new Error(`NPM Registry metadata HTTP ${i.status}`);let a=await i.json(),o=String(a?.version||"").trim(),s=String(a?.dist?.tarball||"").trim(),c=String(a?.dist?.shasum||"").trim(),l=String(a?.dist?.integrity||"").trim();if(!o||!s)throw new Error("Thi\u1EBFu th\xF4ng tin version ho\u1EB7c tarball t\u1EEB NPM Registry");let u=await fetch(s,{signal:AbortSignal.timeout(6e4)});if(!u.ok)throw new Error(`T\u1EA3i tarball th\u1EA5t b\u1EA1i: HTTP ${u.status}`);let p=Buffer.from(await u.arrayBuffer());if(l.startsWith("sha512-")){let w=l.slice(7);if(Lg.default.createHash("sha512").update(p).digest("base64")!==w)throw new Error("M\xE3 ki\u1EC3m tra to\xE0n v\u1EB9n SHA-512 kh\xF4ng kh\u1EDBp!")}else if(c&&Lg.default.createHash("sha1").update(p).digest("hex")!==c)throw new Error("M\xE3 ki\u1EC3m tra to\xE0n v\u1EB9n SHA-1 (shasum) kh\xF4ng kh\u1EDBp!");let f=this.extractFileFromTarGz(p,"package/dist/cli.js");if(!f||f.length<1024)throw new Error("Kh\xF4ng t\xECm th\u1EA5y ho\u1EB7c t\u1EC7p dist/cli.js trong g\xF3i kh\xF4ng h\u1EE3p l\u1EC7");let h=this.getRuntimeDir();vt.default.existsSync(h)||vt.default.mkdirSync(h,{recursive:!0});let b=this.getRuntimeCliPath(),v=`${b}.${process.pid}.tmp`;vt.default.writeFileSync(v,f,{mode:493}),vt.default.renameSync(v,b);let _={version:o,updatedAt:new Date().toISOString(),integrity:l||c},m=`${this.getRuntimeVersionPath()}.${process.pid}.tmp`;vt.default.writeFileSync(m,JSON.stringify(_,null,2)),vt.default.renameSync(m,this.getRuntimeVersionPath());let x="/app/cli.js";if(vt.default.existsSync(x))try{vt.default.accessSync(x,vt.default.constants.W_OK);try{let w=`${x}.${process.pid}.tmp`;vt.default.writeFileSync(w,f,{mode:493}),vt.default.renameSync(w,x)}catch{vt.default.writeFileSync(x,f,{mode:493})}}catch{}return r.info(`\u{1F4E6} [RuntimeBundle] \u0110\xE3 t\u1EA3i v\xE0 x\xE1c th\u1EF1c g\xF3i v${o} v\xE0o b\u1ED9 nh\u1EDB b\u1EC1n v\u1EEFng (${b})`),{success:!0,version:o,cliPath:b}}catch(n){return r.warn(`\u26A0\uFE0F [RuntimeBundle] Kh\xF4ng th\u1EC3 t\u1EA3i tr\u1EF1c ti\u1EBFp bundle t\u1EEB Registry: ${n?.message||n}`),{success:!1}}}static tryBootstrapNewerRuntime(t){if(globalThis[Ng])return!1;try{let r=this.getInstalledRuntimeVersion();if(!r||!this.isNewerVersion(r,t))return!1;let n=this.getRuntimeCliPath();return Ta.default.resolve(process.argv[1]||"")===Ta.default.resolve(n)?!1:(globalThis[Ng]=r,YO.default.createRequire(n)(n),!0)}catch{globalThis[Ng]=void 0;try{vt.default.existsSync(this.getRuntimeVersionPath())&&vt.default.unlinkSync(this.getRuntimeVersionPath())}catch{}return!1}}};var Rp=class e{logger;timer;isUpdating=!1;constructor(t){this.logger=t||(0,XO.createLogger)("WorkerAutoUpdater")}static getNpmExecutionInfo(){let t=Ug.default.dirname(process.execPath),r=Ug.default.join(t,process.platform==="win32"?"npm.cmd":"npm"),n=Tp.default.existsSync(r)?`"${r}"`:"npm",i={...process.env,PATH:`${t}:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:${process.env.PATH||""}`};return{npmBin:n,env:i}}static isDocker(){return Tp.default.existsSync("/.dockerenv")||Tp.default.existsSync("/run/.containerenv")||!!process.env.DOCKER_CONTAINER}static isNewerVersion(t,r){return Di.isNewerVersion(t,r)}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 a=await i.json();if(a?.version)return String(a.version).trim()}}catch{}try{let{npmBin:r,env:n}=e.getNpmExecutionInfo();return(0,Jo.execSync)(`${r} view ${t} version`,{encoding:"utf-8",timeout:8e3,stdio:["ignore","pipe","ignore"],env:n}).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||"latest",n=`@softtynet/zplus-worker@${r}`,i=e.isDocker();this.logger.info(`\u{1F680} [AutoUpdater] B\u1EAFt \u0111\u1EA7u t\u1EF1 \u0111\u1ED9ng n\xE2ng c\u1EA5p Worker l\xEAn ${n} (M\xF4i tr\u01B0\u1EDDng: ${i?"Docker Container":"Host NPM"})...`);let a=!1,o=!1;try{if(a=(await Di.downloadAndInstallRuntimeBundle(r,this.logger)).success,!i)try{let{npmBin:c,env:l}=e.getNpmExecutionInfo();(0,Jo.execSync)(`${c} install -g ${n}`,{stdio:"inherit",timeout:12e4,env:l}),o=!0,this.logger.info(`\u2705 [AutoUpdater] \u0110\xE3 c\u1EADp nh\u1EADt g\xF3i NPM to\xE0n c\u1EE5c: ${n}!`)}catch(c){if(a)this.logger.info("\u2139\uFE0F [AutoUpdater] B\u1ECF qua c\u1EADp nh\u1EADt global npm (thi\u1EBFu quy\u1EC1n root), \u0111\xE3 s\u1EED d\u1EE5ng Runtime Bundle t\u1EA1i ~/.zplus/runtime/cli.js.");else throw c}if(!a&&!o)throw new Error("Kh\xF4ng th\u1EC3 c\u1EADp nh\u1EADt qua c\u1EA3 Runtime Bundle l\u1EABn NPM Global.");return this.logger.info(`\u2705 [AutoUpdater] \u0110\xE3 ho\xE0n t\u1EA5t n\xE2ng c\u1EA5p l\xEAn ${n}! \u0110ang kh\u1EDFi \u0111\u1ED9ng l\u1EA1i d\u1ECBch v\u1EE5...`),this.triggerRestart(),!0}catch(s){return this.isUpdating=!1,this.logger.error(`\u274C [AutoUpdater] N\xE2ng c\u1EA5p th\u1EA5t b\u1EA1i: ${s?.message||s}`),!1}}triggerRestart(){if(!e.isDocker()){try{if((0,Jo.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'...");let n=(0,Jo.spawn)("pm2",["restart","zplus-worker"],{detached:!0,stdio:"ignore"});n.on("error",()=>{}),n.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/Daemon), 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 (Docker / OS Service) 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 cho c\u1EA3 NPM & Docker (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 tr\xEAn NPM Registry: 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 ai=le(require("fs")),Wp=le(require("path")),La=le(require("os")),pB=le(require("dns")),fB=require("child_process"),ns=le(at());var lB=le(cB());function uB(e=36){return process.env.ZPLUS_NO_QR==="1"?!1:process.stdout.isTTY?(process.stdout.columns||80)>=e:!0}function dB(e,t={}){let r=lB.default.create(e,{errorCorrectionLevel:"L"}),n=r.modules.size,i=r.modules.data,a=t.margin??2,o=t.indent??" ",s=t.useAnsiColors??process.env.NO_COLOR===void 0,c=n+a*2,l=s?"\x1B[97;40m":"",u=s?"\x1B[0m":"",p=(h,b)=>{let v=h-a,_=b-a;return v<0||_<0||v>=n||_>=n?!1:!!i[_*n+v]},f=[];for(let h=0;h<c;h+=2){let b="";for(let v=0;v<c;v++){let _=p(v,h),m=h+1<c?p(v,h+1):!1;!_&&!m?b+="\u2588":_&&m?b+=" ":_&&!m?b+="\u2584":b+="\u2580"}f.push(`${o}${l}${b}${u}`)}return f.join(`
|
|
71
|
+
`;return typeof n=="function"&&n(null,f),f}});var XD=P(jp=>{var jV=Sy();jp.render=jV.render;jp.renderToFile=function(t,r,n,i){typeof i>"u"&&(i=n,n=void 0);let a=require("fs"),s='<?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'+jp.render(r,n);a.writeFile(t,s,i)}});var eB=P(qp=>{var Ey=$c();function qV(e,t,r){e.clearRect(0,0,t.width,t.height),t.style||(t.style={}),t.height=r,t.width=r,t.style.height=r+"px",t.style.width=r+"px"}function HV(){try{return document.createElement("canvas")}catch{throw new Error("You need to specify a canvas element")}}qp.render=function(t,r,n){let i=n,a=r;typeof i>"u"&&(!r||!r.getContext)&&(i=r,r=void 0),r||(a=HV()),i=Ey.getOptions(i);let o=Ey.getImageWidth(t.modules.size,i),s=a.getContext("2d"),c=s.createImageData(o,o);return Ey.qrToImageData(c.data,t,i),qV(s,a,o),s.putImageData(c,0,0),a};qp.renderToDataURL=function(t,r,n){let i=n;typeof i>"u"&&(!r||!r.getContext)&&(i=r,r=void 0),i||(i={});let a=qp.render(t,r,i),o=i.type||"image/png",s=i.rendererOpts||{};return a.toDataURL(o,s.quality)}});var rB=P(jc=>{var WV=zg(),Ay=iy(),tB=eB(),GV=Sy();function Cy(e,t,r,n,i){let a=[].slice.call(arguments,1),o=a.length,s=typeof a[o-1]=="function";if(!s&&!WV())throw new Error("Callback required as last argument");if(s){if(o<2)throw new Error("Too few arguments provided");o===2?(i=r,r=t,t=n=void 0):o===3&&(t.getContext&&typeof i>"u"?(i=n,n=void 0):(i=n,n=r,r=t,t=void 0))}else{if(o<1)throw new Error("Too few arguments provided");return o===1?(r=t,t=n=void 0):o===2&&!t.getContext&&(n=r,r=t,t=void 0),new Promise(function(c,l){try{let u=Ay.create(r,n);c(e(u,t,n))}catch(u){l(u)}})}try{let c=Ay.create(r,n);i(null,e(c,t,n))}catch(c){i(c)}}jc.create=Ay.create;jc.toCanvas=Cy.bind(null,tB.render);jc.toDataURL=Cy.bind(null,tB.renderToDataURL);jc.toString=Cy.bind(null,function(e,t,r){return GV.render(e,r)})});var oB=P($i=>{var nB=zg(),Iy=iy(),VV=$D(),iB=jD(),JV=KD(),aB=XD();function qc(e,t,r){if(typeof e>"u")throw new Error("String required as first argument");if(typeof r>"u"&&(r=t,t={}),typeof r!="function")if(nB())t=r||{},r=null;else throw new Error("Callback required as last argument");return{opts:t,cb:r}}function ZV(e){return e.slice((e.lastIndexOf(".")-1>>>0)+2).toLowerCase()}function Hp(e){switch(e){case"svg":return aB;case"txt":case"utf8":return iB;case"png":case"image/png":default:return VV}}function KV(e){switch(e){case"svg":return aB;case"terminal":return JV;case"utf8":default:return iB}}function Hc(e,t,r){if(!r.cb)return new Promise(function(n,i){try{let a=Iy.create(t,r.opts);return e(a,r.opts,function(o,s){return o?i(o):n(s)})}catch(a){i(a)}});try{let n=Iy.create(t,r.opts);return e(n,r.opts,r.cb)}catch(n){r.cb(n)}}$i.create=Iy.create;$i.toCanvas=rB().toCanvas;$i.toString=function(t,r,n){let i=qc(t,r,n),a=i.opts?i.opts.type:void 0,o=KV(a);return Hc(o.render,t,i)};$i.toDataURL=function(t,r,n){let i=qc(t,r,n),a=Hp(i.opts.type);return Hc(a.renderToDataURL,t,i)};$i.toBuffer=function(t,r,n){let i=qc(t,r,n),a=Hp(i.opts.type);return Hc(a.renderToBuffer,t,i)};$i.toFile=function(t,r,n,i){if(typeof t!="string"||!(typeof r=="string"||typeof r=="object"))throw new Error("Invalid argument");if(arguments.length<3&&!nB())throw new Error("Too few arguments provided");let a=qc(r,n,i),o=a.opts.type||ZV(t),c=Hp(o).renderToFile.bind(null,t);return Hc(c,r,a)};$i.toFileStream=function(t,r,n){if(arguments.length<2)throw new Error("Too few arguments provided");let i=qc(r,n,t.emit.bind(t,"error")),o=Hp("png").renderToFileStream.bind(null,t);Hc(o,r,i)}});var cB=P((Jfe,sB)=>{sB.exports=oB()});var Ve=le(require("fs")),_t=le(require("path")),tt=le(require("os")),CB=le(require("dns")),We=require("child_process");var Mn=le(require("os")),hi=le(require("fs")),vs=le(require("path")),Pb=le(require("crypto"));function lN(){return"1.0.57"}var er=lN();function wl(){return{totalMemMb:Math.round(Mn.default.totalmem()/(1024*1024)),freeMemMb:Math.round(Mn.default.freemem()/(1024*1024)),cpuCount:Mn.default.cpus()?.length||1,platform:Mn.default.platform()}}function uN(e){try{let t=vs.default.join(Mn.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=vs.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 a=(Mn.default.hostname()||"node").replace(/[^a-zA-Z0-9_-]/g,"_").toLowerCase().slice(0,14),o=Pb.default.randomBytes(2).toString("hex"),s=`worker_${a}${r}_${o}`,c=e?` #${e}`:"",l=`Worker ${a.toUpperCase()}${c}`,u={workerId:s,workerName:l,slot:e||"default",createdAt:new Date().toISOString()};return hi.default.writeFileSync(n,JSON.stringify(u,null,2),"utf-8"),u}catch{let t=e?`_slot_${e}`:"",r=`worker_${Mn.default.hostname().replace(/[^a-zA-Z0-9_-]/g,"_").slice(0,14)||"node"}${t}`;return{workerId:r,workerName:r}}}var vl=class{static loadFromEnv(t=process.argv.slice(2)){let r=F=>{for(let I of t){if(I.startsWith(`--${F}=`))return I.split("=").slice(1).join("=");if(I===`--${F}`&&t[t.indexOf(I)+1])return t[t.indexOf(I)+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,a=r("jwt")||process.env.CLOUD_JWT||process.env.APPWRITE_JWT||process.env.JWT,o=r("secret")||process.env.DESKTOP_SECRET,s=r("team-id")||process.env.TEAM_ID||"default",c=t.includes("--enable-http")||r("enable-http")==="true"||process.env.ENABLE_HTTP==="true"||!1,l=r("port")||process.env.PORT,u=l?Number(l):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",f=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",b=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",v=Math.max(1,Math.round(Mn.default.totalmem()/(1024*1024*1024))),_=Math.min(200,Math.max(20,v*25)),m=r("max-capacity")||process.env.MAX_CAPACITY,x=Number(m||_),w=r("slot")||process.env.WORKER_SLOT||process.env.pm_id||process.env.NODE_APP_INSTANCE,g=uN(w),k=r("worker-id")||process.env.WORKER_ID||g.workerId,S=r("worker-name")||process.env.WORKER_NAME||process.env.HOSTNAME||g.workerName,C=r("user-id")||process.env.USER_ID||process.env.SOFTTY_USER_ID;return{workerId:k,version:er,enableHttp:c,port:u,userId:C,teamId:s,workerName:S,maxCapacity:x,recommendedCapacity:_,clusterPollIntervalMs:Number(r("poll-interval")||process.env.CLUSTER_POLL_INTERVAL_MS||5e3),cloudProvider:n,cloudEndpoint:p,cloudProjectId:f,cloudSessionToken:i,cloudJwt:a,cloudDatabaseId:h,appwriteEndpoint:p,appwriteProjectId:f,appwriteSessionToken:i,appwriteJwt:a,storageBucketId:b,desktopSecret:o,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 ji=le(require("fs")),nf=le(require("os")),Ua=le(require("path")),EB=le(require("crypto")),os=le(at());var $b=le(at()),Cl=class{runners=new Map;logger;constructor(t){this.logger=t||(0,$b.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(a=>{this.logger.error(`Error stopping runner ${n} during unregister`,a)}),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()}async pauseAll(){this.logger.info(`Pausing all ${this.runners.size} channel runners due to worker auth/standby status...`);for(let[t,r]of this.runners.entries())try{typeof r.pause=="function"&&await r.pause()}catch(n){this.logger.error(`Failed to pause runner ${t}:`,n)}}async resumeAll(){this.logger.info(`Resuming all ${this.runners.size} channel runners...`);for(let[t,r]of this.runners.entries())try{typeof r.resume=="function"&&await r.resume()}catch(n){this.logger.error(`Failed to resume runner ${t}:`,n)}}};var jb=le(at()),Il=class{constructor(t=6e4,r,n){this.defaultTtlMs=t;this.logger=r||(0,jb.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(),a=this.locks.get(t);return a&&a.expiresAt>i&&a.ownerId!==r?(this.logger.warn(`Lock denied for account ${t}: currently held by ${a.ownerId} (expires in ${a.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(o=>{try{return Promise.resolve(o(t,r))}catch(s){return this.logger.error(`Error in preempt callback for ${t}:`,s),Promise.resolve()}});await Promise.race([Promise.all(i),new Promise(o=>setTimeout(o,1e3))]);let a=Date.now();return this.locks.set(t,{accountId:t,ownerId:r,acquiredAt:a,expiresAt:a+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 to=le(require("fs")),qb=le(require("path")),Hb=le(at()),Tl=class{logger;queue=[];maxCapacity;persistenceFilePath;constructor(t=1e4,r,n){this.maxCapacity=t,this.logger=r||(0,Hb.createLogger)("CloudPendingMessageQueue"),this.persistenceFilePath=n,this.loadFromDisk()}loadFromDisk(){if(this.persistenceFilePath)try{if(to.default.existsSync(this.persistenceFilePath)){let t=to.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=qb.default.dirname(this.persistenceFilePath);to.default.existsSync(t)||to.default.mkdirSync(t,{recursive:!0}),to.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,a=n.timestamp>=r;return i&&a})}purgeSynced(t,r){let n=this.queue.length,i=[];for(let o=0;o<this.queue.length;o++){let s=this.queue[o];s.timestamp<=t&&(!r||s.accountId===r)&&i.push(o)}for(let o=i.length-1;o>=0;o--)this.queue.splice(i[o],1);let a=n-this.queue.length;return a>0&&(this.saveToDisk(),this.logger.info(`Purged ${a} synced delta messages from queue.`)),a}getCount(){return this.queue.length}getAll(){return[...this.queue]}remove(t){let r=this.queue.findIndex(n=>n.id===t);return r!==-1?(this.queue.splice(r,1),this.saveToDisk(),!0):!1}clear(){this.queue.length=0,this.saveToDisk()}};var Wb=le(at()),Rl=class{logger;campaigns=new Map;rules=new Map;threadHistory=new Map;lastReplyTimes=new Map;aiConfig={enabled:!1};constructor(t,r){this.logger=t||(0,Wb.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 a=t.content.trim(),o=this.getThreadHistory(r);if(o.push({role:"user",content:a,timestamp:n}),o.length>6&&o.splice(0,o.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 s=t.accountId,c=this.aiConfig.accountBotConfigs,l=s&&c?c[s]:void 0;if(!l||!l.isBotEnabled)return this.logger.debug(`[HeadlessAutomation] Account [${s||"unknown"}] has not been configured or enabled for Bot AI by user in Chatbot settings. Message saved, no auto-reply sent.`),null;let u=t,p=!!u.isGroup||!!u.groupId||typeof t.threadId=="string"&&t.threadId.startsWith("g")||typeof t.conversationId=="string"&&t.conversationId.startsWith("g"),f=l.replyTarget||"all";if(f==="individual"&&p)return this.logger.debug(`[HeadlessAutomation] Account [${s}] configured for individual chat only. Skipping group message ${r}.`),null;if(f==="group"&&!p)return this.logger.debug(`[HeadlessAutomation] Account [${s}] configured for group chat only. Skipping direct message ${r}.`),null;let h=l.scheduleType||"always";if(h!=="always"){let S=new Date().getHours(),C=l.scheduleStartHour??8,F=l.scheduleEndHour??18;if(h==="working_hours"){if(S<C||S>=F)return this.logger.debug(`[HeadlessAutomation] Outside working hours (${S}h, allowed: ${C}h-${F}h). Skipping reply.`),null}else if(h==="outside_hours"&&S>=C&&S<F)return this.logger.debug(`[HeadlessAutomation] Inside working hours (${S}h, allowed outside: ${C}h-${F}h). Skipping reply.`),null}let b=l.excludeContactIds||[];if(!p&&b.length>0){let S=String(t.senderId||"");if(b.includes(S))return this.logger.debug(`[HeadlessAutomation] Sender ${S} is in contact blacklist. Skipping reply.`),null}if(p){let S=String(u.groupId||u.threadId||r||""),C=l.excludeGroupIds||[],F=l.includeGroupIds||[];if(C.length>0&&C.includes(S))return this.logger.debug(`[HeadlessAutomation] Group ${S} is in group blacklist. Skipping reply.`),null;if(F.length>0&&!F.includes(S))return this.logger.debug(`[HeadlessAutomation] Group ${S} is not in group whitelist. Skipping reply.`),null}let v=l.excludeKeywords||[],_=l.includeKeywords||[],m=a.toLowerCase();if(v.length>0&&v.some(C=>{let F=C.trim().toLowerCase();return F.length>0&&m.includes(F)}))return this.logger.debug("[HeadlessAutomation] Message contains blacklisted keyword. Skipping reply."),null;if(_.length>0&&!_.some(C=>{let F=C.trim().toLowerCase();return F.length>0&&m.includes(F)}))return this.logger.debug("[HeadlessAutomation] Message does not match any whitelist keyword. Skipping reply."),null;let x=t.tagIds||t.tags||t.metadata?.tagIds;if(Array.isArray(x)){let S=x.map(I=>typeof I=="string"?I:String(I?.id||"")),C=l.excludeTagIds||[],F=l.includeTagIds||[];if(C.length>0&&S.some(I=>C.includes(I)))return this.logger.debug("[HeadlessAutomation] Customer has excluded CRM tag. Skipping reply."),null;if(F.length>0){if(S.length===0){if(l.replyUntaggedCustomers===!1)return null}else if(!S.some(I=>F.includes(I)))return null}}let w=l.systemPrompt&&l.systemPrompt.trim()?l.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 g=this.aiConfig.provider,k=this.aiConfig.apiKey;if(k||(g==="openai"?k=process.env.OPENAI_API_KEY:g==="deepseek"?k=process.env.DEEPSEEK_API_KEY:g==="anthropic"?k=process.env.ANTHROPIC_API_KEY:g==="custom"?k=process.env.CUSTOM_AI_API_KEY:g==="gemini"&&(k=process.env.GEMINI_API_KEY||process.env.GOOGLE_API_KEY)),!k&&g!=="custom")return this.logger.debug(`[HeadlessAutomation] No API key found for provider [${g}]. No auto-reply sent.`),null;try{let S=null;if(g==="openai"||g==="custom"||g==="deepseek")S=await this.callOpenAiCompatible(a,o,k||"",w);else if(g==="anthropic")S=await this.callAnthropic(a,o,k||"",w);else if(g==="gemini")S=await this.callGemini(a,o,k||"",w);else return this.logger.warn(`[HeadlessAutomation] Unsupported AI provider [${g}]. No reply generated.`),null;if(S&&S.trim().length>0){let C=S.trim();return o.push({role:"model",content:C,timestamp:Date.now()}),this.lastReplyTimes.set(r,Date.now()),C}}catch(S){this.logger.warn(`[HeadlessAutomation] AI generation error with provider [${g}] (${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 o=`https://generativelanguage.googleapis.com/v1beta/models/${this.aiConfig.model||"gemini-2.0-flash"}:generateContent?key=${n}`,s=r.map(f=>({role:f.role==="model"?"model":"user",parts:[{text:f.content}]}));(s.length===0||s[s.length-1].parts[0]?.text!==t)&&s.push({role:"user",parts:[{text:t}]});let c={contents:s,generationConfig:{temperature:this.aiConfig.temperature??.7,maxOutputTokens:this.aiConfig.maxTokens??300}},l=i||this.aiConfig.systemPrompt;l&&l.trim()&&(c.systemInstruction={parts:[{text:l.trim()}]});let u=new AbortController,p=setTimeout(()=>u.abort(),7e3);try{let f=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(c),signal:u.signal});if(!f.ok){let v=await f.text();return this.logger.warn(`[HeadlessAutomation] Gemini API returned status ${f.status}: ${v.slice(0,200)}`),null}return(await f.json())?.candidates?.[0]?.content?.parts?.[0]?.text||null}finally{clearTimeout(p)}}async callOpenAiCompatible(t,r,n,i){let a=(this.aiConfig.baseUrl||(this.aiConfig.provider==="deepseek"?"https://api.deepseek.com/v1":"https://api.openai.com/v1")).replace(/\/+$/,"");a.includes("api.deepseek.com")&&!a.endsWith("/v1")?a+="/v1":(a.includes("11434")||a.includes("ollama"))&&(a=a.replace(/\/api$/,"").replace(/\/+$/,""),a.endsWith("/v1")||(a+="/v1"));let o=`${a}/chat/completions`,s=this.aiConfig.model||(this.aiConfig.provider==="deepseek"?"deepseek-chat":this.aiConfig.provider==="openai"?"gpt-4o-mini":"deepseek-chat"),c=i||this.aiConfig.systemPrompt,l=[...c&&c.trim()?[{role:"system",content:c.trim()}]:[],...r.map(h=>({role:h.role==="model"?"assistant":"user",content:h.content}))],u={"Content-Type":"application/json"};n&&(u.Authorization=`Bearer ${n}`);let p=new AbortController,f=setTimeout(()=>p.abort(),8e3);try{let h=await fetch(o,{method:"POST",headers:u,body:JSON.stringify({model:s,messages:l,temperature:this.aiConfig.temperature??.7,max_tokens:this.aiConfig.maxTokens??300}),signal:p.signal});if(!h.ok){let v=await h.text();return this.logger.warn(`[HeadlessAutomation] OpenAI-compatible API returned status ${h.status}: ${v.slice(0,200)}`),null}return(await h.json())?.choices?.[0]?.message?.content||null}finally{clearTimeout(f)}}async callAnthropic(t,r,n,i){let a="https://api.anthropic.com/v1/messages",o=this.aiConfig.model||"claude-3-5-haiku-20241022",s=r.map(u=>({role:u.role==="model"?"assistant":"user",content:u.content}));(s.length===0||s[s.length-1].content!==t)&&s.push({role:"user",content:t});let c=new AbortController,l=setTimeout(()=>c.abort(),8e3);try{let u=i||this.aiConfig.systemPrompt,p={model:o,messages:s,max_tokens:this.aiConfig.maxTokens??300,temperature:this.aiConfig.temperature??.7};u&&u.trim()&&(p.system=u.trim());let f=await fetch(a,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":n,"anthropic-version":"2023-06-01"},body:JSON.stringify(p),signal:c.signal});if(!f.ok){let b=await f.text();return this.logger.warn(`[HeadlessAutomation] Anthropic API returned status ${f.status}: ${b.slice(0,200)}`),null}return(await f.json())?.content?.[0]?.text||null}finally{clearTimeout(l)}}clear(){this.campaigns.clear(),this.rules.clear(),this.threadHistory.clear(),this.lastReplyTimes.clear()}};var Gb=le(at()),Pl=class{logger;endpoint;projectId;apiKey;constructor(t,r){this.logger=t||(0,Gb.createLogger)("PushNotificationDispatcher"),this.endpoint=r?.endpoint||process.env.APPWRITE_ENDPOINT||"https://api.softty.net/v1",this.projectId=r?.projectId||process.env.APPWRITE_PROJECT_ID||"699cfc3100136099c1c1",this.apiKey=r?.apiKey||process.env.APPWRITE_API_KEY}formatMessagePreview(t){if(t.isRecall)return"[Tin nh\u1EAFn \u0111\xE3 \u0111\u01B0\u1EE3c thu h\u1ED3i]";let r=t.content,n=String(t.messageType||"").toLowerCase(),i=null;if(typeof r=="string"&&r.trim().startsWith("{")&&r.trim().endsWith("}"))try{i=JSON.parse(r)}catch{}else typeof r=="object"&&r!==null&&(i=r);let a=c=>!!(c&&(/\.(png|jpg|jpeg|gif|webp)(\?|#|$)/i.test(c)||c.includes("photo-stal")||c.includes("zdn.vn"))),o=c=>!!(c&&/\.(mp3|m4a|wav|aac|ogg|opus)(\?|#|$)/i.test(c)),s=c=>!!(c&&/\.(mp4|avi|mov|mkv|wmv|flv)(\?|#|$)/i.test(c));if(i){let c=String(i.msgType||i.type||n).toLowerCase(),l=String(i.title||i.fileName||i.filename||i.name||"").trim(),u=String(i.href||i.url||i.rawUrl||"");if(i.id&&(i.cateId!==void 0||i.type==="sticker")||c.includes("sticker"))return"[Nh\xE3n d\xE1n]";if(c.includes("photo")||c.includes("image")||a(u)||a(l))return l&&!l.startsWith("http")&&!a(l)?`[H\xECnh \u1EA3nh] ${l}`:"[H\xECnh \u1EA3nh]";if(c.includes("video")||s(l)||s(u))return l&&!l.startsWith("http")?`[Video] ${l}`:"[Video]";if(c.includes("voice")||c.includes("audio")||o(l)||o(u))return"[Tin nh\u1EAFn tho\u1EA1i]";if(c.includes("file")||i.fileSize!==void 0)return o(l)?"[Tin nh\u1EAFn tho\u1EA1i]":s(l)?`[Video] ${l}`:a(l)?`[H\xECnh \u1EA3nh] ${l}`:l?`[T\u1EADp tin] ${l}`:"[T\u1EADp tin]";if(c.includes("contact")||String(i.action||"").includes("recommended.user"))return l?`[Danh thi\u1EBFp] ${l}`:"[Danh thi\u1EBFp]";if(c.includes("location")||i.lat!==void 0)return i.address||l?`[V\u1ECB tr\xED] ${i.address||l}`:"[V\u1ECB tr\xED]";if(c.includes("poll"))return i.question||i.topic?`[B\xECnh ch\u1ECDn] ${i.question||i.topic}`:"[B\xECnh ch\u1ECDn]";if(c.includes("bank"))return"[Th\xF4ng tin chuy\u1EC3n kho\u1EA3n]";if(c.includes("link"))return l&&!l.startsWith("http")?`[Li\xEAn k\u1EBFt] ${l}`:"[Li\xEAn k\u1EBFt]";if(i.text||i.msg||i.message)return String(i.text||i.msg||i.message)}if(n==="image"||n.includes("photo"))return"[H\xECnh \u1EA3nh]";if(n==="video")return"[Video]";if(n==="audio"||n.includes("voice"))return"[Tin nh\u1EAFn tho\u1EA1i]";if(n==="file")return"[T\u1EADp tin]";if(n==="sticker")return"[Nh\xE3n d\xE1n]";if(n==="location")return"[V\u1ECB tr\xED]";if(n==="contact")return"[Danh thi\u1EBFp]";if(typeof r=="string"){let c=r.trim();return c?a(c)?"[H\xECnh \u1EA3nh]":c.startsWith("{")&&c.endsWith("}")?c.includes("photo-stal")?"[H\xECnh \u1EA3nh]":"[\u0110\xEDnh k\xE8m ph\u01B0\u01A1ng ti\u1EC7n]":c.length>120?`${c.slice(0,117)}...`:c:"\u0110\xE3 g\u1EEDi m\u1ED9t tin nh\u1EAFn m\u1EDBi"}return"\u0110\xE3 g\u1EEDi m\u1ED9t tin nh\u1EAFn m\u1EDBi"}extractMessageRichMedia(t){let r=t.content,n=String(t.messageType||"").toLowerCase(),i=Array.isArray(t.attachments)?t.attachments:[],a=i.length>0?i[0]:null;if(a){let s=String(a.url||a.href||a.hdUrl||"").trim(),c=String(a.thumb||a.thumbnail||"").trim(),l=String(a.fileType||a.type||n).toLowerCase();if(l.includes("sticker"))return{mediaUrl:s.startsWith("http")?s:"",mediaType:"sticker"};if(l.includes("video"))return{mediaUrl:c.startsWith("http")?c:"",mediaType:"video"};if(l.includes("image")||l.includes("photo"))return{mediaUrl:s.startsWith("http")?s:c.startsWith("http")?c:"",mediaType:"image"};if(l.includes("voice")||l.includes("audio"))return{mediaUrl:"",mediaType:"audio"};if(l.includes("file"))return{mediaUrl:"",mediaType:"file"}}let o=null;if(typeof r=="string"&&r.trim().startsWith("{")&&r.trim().endsWith("}"))try{o=JSON.parse(r)}catch{}else typeof r=="object"&&r!==null&&(o=r);if(o){let s=String(o.msgType||o.type||n).toLowerCase(),c=String(o.href||o.hdUrl||o.url||o.rawUrl||o.src||o.normalUrl||"").trim(),l=String(o.thumb||o.thumbUrl||o.thumbnail||"").trim(),u=String(o.stickerUrl||o.stickerWebpUrl||(s.includes("sticker")?c||l:"")).trim();if(s.includes("sticker")||o.type==="sticker")return{mediaUrl:u.startsWith("http")?u:"",mediaType:"sticker"};if(s.includes("video"))return{mediaUrl:l.startsWith("http")?l:"",mediaType:"video"};if(s.includes("photo")||s.includes("image"))return{mediaUrl:c.startsWith("http")?c:l.startsWith("http")?l:"",mediaType:"image"};if(s.includes("voice")||s.includes("audio"))return{mediaUrl:"",mediaType:"audio"};if(s.includes("file")||o.fileSize!==void 0)return{mediaUrl:"",mediaType:"file"}}return typeof r=="string"&&r.trim().startsWith("http")&&/\.(png|jpg|jpeg|gif|webp)(\?|#|$)/i.test(r.trim())?{mediaUrl:r.trim(),mediaType:"image"}:{mediaUrl:"",mediaType:n||"text"}}async dispatchMessageAlert(t,r,n,i){if(r.isRecall||r.deleted_at)return!1;let a=r.timestamp??r.time,o=Number(a||0);if(o>0){let h=o<1e11?o*1e3:o,b=Date.now()-h;if(b>12e4||b<-6e4)return this.logger.debug(`Suppressed stale push alert for message ${r.id} (age: ${Math.round(b/1e3)}s)`),!1}let s=r.metadata?.rawPayload||r.rawPayload||r,c=!!(r.isGroup||s?.isGroup||Number(s?.type)===1||Number(s?.data?.type)===1||s?.groupId||s?.data?.groupId||r.type==="group"||r.threadType===1||r.threadType==="group"||String(r.threadId||"").startsWith("g")),l=r.groupName||r.threadName||s?.groupName||s?.data?.groupName||"Nh\xF3m Zalo",u=this.formatMessagePreview(r),p=c?l:r.senderName||"Kh\xE1ch h\xE0ng",f=c?`${r.senderName||"Th\xE0nh vi\xEAn"}: ${u}`:u;return f.length>130&&(f=`${f.slice(0,127)}...`),this.sendNotification({recipientToken:t,title:p,body:f,platform:n,userId:i,data:{messageId:r.id,threadId:r.threadId,platform:r.platform,accountId:r.accountId}})}async enqueueNotification(t,r,n){if(t.isSelf||t.isRecall||t.deleted_at)return!1;let i=t.timestamp??t.time,a=Number(i||0);if(a>0){let _=a<1e11?a*1e3:a,m=Date.now()-_;if(m>12e4||m<-6e4)return this.logger.debug(`Suppressed stale push alert for message ${t.id} (age: ${Math.round(m/1e3)}s)`),!1}let o=t.metadata?.rawPayload||t.rawPayload||t,s=!!(t.isGroup||o?.isGroup||Number(o?.type)===1||Number(o?.data?.type)===1||o?.groupId||o?.data?.groupId||t.type==="group"||t.threadType===1||t.threadType==="group"||String(t.threadId||"").startsWith("g")),c=t.groupName||t.threadName||o?.groupName||o?.data?.groupName||"Nh\xF3m Zalo",l=this.formatMessagePreview(t),u=s?c:t.senderName||"Kh\xE1ch h\xE0ng",p=s?`${t.senderName||"Th\xE0nh vi\xEAn"}: ${l}`:l;p.length>130&&(p=`${p.slice(0,127)}...`);let f=`pn_${Date.now()}_${Math.random().toString(36).slice(2,8)}`,h=this.extractMessageRichMedia(t),b=(s?t.groupAvatar||o?.groupAvatar||o?.data?.groupAvatar:void 0)||t.avatar||t.senderAvatar||t.groupAvatar||"",v=String(t.accountName||n.accountName||o?.accountName||"").trim();try{return await r.createDocument("push_notification_queue",f,{teamId:n.teamId||"",userId:n.userId||"",channelAccountId:n.channelAccountId||t.accountId||"",accountName:v,senderName:t.senderName||"Kh\xE1ch h\xE0ng",title:u,body:p,avatarUrl:b,mediaUrl:t.mediaUrl||h.mediaUrl||"",mediaType:t.mediaType||h.mediaType||"text",threadId:t.threadId||t.conversationId||"",platform:t.platform||"zalo",msgId:t.id||f}),this.logger.debug(`Enqueued push notification ${f} for message ${t.id}`),!0}catch(_){return this.logger.warn(`Failed to enqueue push notification: ${_?.message}`),!1}}async sendNotification(t){if(this.logger.debug(`Dispatching push notification to device token: ${t.recipientToken.slice(0,8)}...`),t.recipientToken.startsWith("ExponentPushToken")||t.recipientToken.startsWith("ExpoPushToken"))try{return(await fetch("https://exp.host/--/api/v2/push/send",{method:"POST",headers:{Accept:"application/json","Accept-encoding":"gzip, deflate","Content-Type":"application/json"},body:JSON.stringify({to:t.recipientToken,title:t.title,body:t.body,data:t.data,sound:"default",priority:"high",channelId:"default"})})).ok}catch(r){this.logger.warn(`Expo push send error: ${r?.message}`)}if(this.apiKey)try{let r=t.platform==="ios"||t.recipientToken.length===64,n=t.recipientToken.replace(/[^a-zA-Z0-9]/g,""),i=`${r?"apns":"fcm"}_${n.slice(0,31)}`,a=`${this.endpoint}/messaging/messages/push`;if((await fetch(a,{method:"POST",headers:{"Content-Type":"application/json","X-Appwrite-Project":this.projectId,"X-Appwrite-Key":this.apiKey},body:JSON.stringify({messageId:`push_${Date.now()}_${Math.random().toString(36).slice(2,7)}`,title:t.title,body:t.body,data:t.data||{},targets:[i],draft:!1})})).ok)return!0}catch(r){this.logger.warn(`Appwrite push send error: ${r?.message}`)}return!0}};var GO=le(require("http")),VO=require("url"),JO=le(at());var WO=le(at()),Vo=class{static logger=(0,WO.createLogger)("ChannelRunnerFactory");static async createRunner(t,r,n,i){let a=(t||"zalo").toLowerCase(),o=a==="web"||a.includes("zalo")?"zalo":a;try{if(o==="zalo"){let{ZaloChannelRunner:s}=await Promise.resolve().then(()=>(HO(),qO));return new s(r,n,i)}return this.logger.warn(`Unsupported platform for ChannelRunner: ${t}`),null}catch(s){return this.logger.error(`Failed to dynamically initialize runner for ${o}:${r}:`,s?.message||s),null}}};var Ip=class{constructor(t,r,n,i,a){this.port=t;this.engine=r;this.lockManager=n;this.deltaQueue=i;this.logger=a||(0,JO.createLogger)("WorkerHttpServer")}logger;server=null;async start(){if(!this.server)return new Promise((t,r)=>{this.server=GO.default.createServer((n,i)=>{this.handleRequest(n,i).catch(a=>{this.logger.error("Unhandled HTTP error:",a),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 VO.URL(t.url||"/",`http://${t.headers.host||"localhost"}`),i=n.pathname,a=(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"),a==="OPTIONS"){r.writeHead(204),r.end();return}if(a==="GET"&&i==="/health"){let o=this.engine.getMetrics();r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({status:"healthy",timestamp:Date.now(),pendingDeltaMessages:this.deltaQueue.getCount(),metrics:o}));return}if(i.startsWith("/api/v1/")){let o=this.engine.config.desktopSecret;if(o){let s=t.headers["x-desktop-secret"]||t.headers.authorization;if((typeof s=="string"&&s.startsWith("Bearer ")?s.slice(7):s)!==o){r.writeHead(401,{"Content-Type":"application/json"}),r.end(JSON.stringify({error:"Unauthorized: Invalid or missing X-Desktop-Secret"}));return}}}if(a==="POST"&&i==="/api/v1/sentinel/handover"){let o=await this.readJsonBody(t),{deviceId:s,sessions:c,aiConfig:l}=o||{};if(l&&(this.engine.automationEngine.configure(l),this.logger.info(`[Handover] Configured 24/7 AI automation engine with provider: ${l.provider||"gemini"}, model: ${l.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 ${s||"unknown"} with ${c.length} sessions.`);let u=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(),b=h==="web"||h.includes("zalo")?"zalo":h,v=await Vo.createRunner(b,p.id,p.sessionData);v&&(this.engine.registerRunner(v),await v.start(),this.engine.registerAccount({id:p.id,platform:b,accountName:p.accountName||p.id,status:"active",nightWorkerEnabled:!0}),u++)}r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({success:!0,message:"Sessions handed over successfully",activatedCount:u,timestamp:Date.now()}));return}if(a==="POST"&&i==="/api/v1/sentinel/reclaim"){let o=await this.readJsonBody(t),{deviceId:s}=o||{};this.logger.info(`[Reclaim] Master device ${s||"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(a==="POST"){let o=await this.readJsonBody(t);o&&(this.engine.automationEngine.configure(o),this.logger.info(`[NightConfig] Updated 24/7 AI config dynamically: provider=${o.provider||"gemini"}, model=${o.model||"default"}`)),r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({success:!0,config:this.engine.automationEngine.getAiConfig()}));return}else if(a==="GET"){r.writeHead(200,{"Content-Type":"application/json"}),r.end(JSON.stringify({success:!0,config:this.engine.automationEngine.getAiConfig()}));return}}if(a==="GET"&&i==="/api/v1/sync/delta"){let o=n.searchParams.get("accountId")||void 0,s=parseInt(n.searchParams.get("since")||"0",10),c=this.deltaQueue.getDeltas(o,s);this.logger.info(`[DeltaSync] Serving ${c.length} night messages (since: ${s}, account: ${o||"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 as=le(at());var Tp=le(require("fs")),Ug=le(require("path")),Jo=require("child_process"),XO=le(at());var vt=le(require("fs")),ZO=le(require("os")),Ta=le(require("path")),KO=le(require("zlib")),Lg=le(require("crypto")),YO=le(require("module")),QO=le(at()),Ng="__ZPLUS_RUNTIME_BOOTSTRAPPED__",Di=class{static PACKAGE_NAME="@softtynet/zplus-worker";static getRuntimeDir(){let t=process.env.ZPLUS_HOME||process.env.DATA_DIR||Ta.default.join(ZO.default.homedir(),".zplus");return Ta.default.join(t,"runtime")}static getRuntimeCliPath(){return Ta.default.join(this.getRuntimeDir(),"cli.js")}static getRuntimeVersionPath(){return Ta.default.join(this.getRuntimeDir(),"version.json")}static isNewerVersion(t,r){let n=u=>u.replace(/^v/,"").trim().split("-")[0].split(".").map(p=>parseInt(p,10)||0),[i=0,a=0,o=0]=n(t),[s=0,c=0,l=0]=n(r);return i!==s?i>s:a!==c?a>c:o>l}static getInstalledRuntimeVersion(){try{let t=this.getRuntimeVersionPath(),r=this.getRuntimeCliPath();if(!vt.default.existsSync(t)||!vt.default.existsSync(r)||vt.default.statSync(r).size<1024)return null;let n=JSON.parse(vt.default.readFileSync(t,"utf-8"));return n?.version?String(n.version).trim():null}catch{return null}}static extractFileFromTarGz(t,r="package/dist/cli.js"){let n=KO.default.gunzipSync(t),i=0;for(;i+512<=n.length;){let a=n.subarray(i,i+512);if(a.every(v=>v===0))break;let o=(v,_)=>a.subarray(v,_).toString("utf-8").replace(/\0.*$/,"").trim(),s=o(0,100),c=o(345,500),l=c?`${c}/${s}`:s,u=parseInt(o(124,136),8)||0,p=a[156],f=p===0||p===48,h=i+512,b=h+u;if(f&&u>0&&b<=n.length&&(l===r||l.endsWith("/dist/cli.js")))return Buffer.from(n.subarray(h,b));i=h+Math.ceil(u/512)*512}return null}static async downloadAndInstallRuntimeBundle(t="latest",r=(0,QO.createLogger)("RuntimeBundleManager")){try{let n=t.replace(/^v/,"").trim()||"latest",i=await fetch(`https://registry.npmjs.org/${this.PACKAGE_NAME}/${n}`,{headers:{Accept:"application/json"},signal:AbortSignal.timeout(1e4)});if(!i.ok)throw new Error(`NPM Registry metadata HTTP ${i.status}`);let a=await i.json(),o=String(a?.version||"").trim(),s=String(a?.dist?.tarball||"").trim(),c=String(a?.dist?.shasum||"").trim(),l=String(a?.dist?.integrity||"").trim();if(!o||!s)throw new Error("Thi\u1EBFu th\xF4ng tin version ho\u1EB7c tarball t\u1EEB NPM Registry");let u=await fetch(s,{signal:AbortSignal.timeout(6e4)});if(!u.ok)throw new Error(`T\u1EA3i tarball th\u1EA5t b\u1EA1i: HTTP ${u.status}`);let p=Buffer.from(await u.arrayBuffer());if(l.startsWith("sha512-")){let w=l.slice(7);if(Lg.default.createHash("sha512").update(p).digest("base64")!==w)throw new Error("M\xE3 ki\u1EC3m tra to\xE0n v\u1EB9n SHA-512 kh\xF4ng kh\u1EDBp!")}else if(c&&Lg.default.createHash("sha1").update(p).digest("hex")!==c)throw new Error("M\xE3 ki\u1EC3m tra to\xE0n v\u1EB9n SHA-1 (shasum) kh\xF4ng kh\u1EDBp!");let f=this.extractFileFromTarGz(p,"package/dist/cli.js");if(!f||f.length<1024)throw new Error("Kh\xF4ng t\xECm th\u1EA5y ho\u1EB7c t\u1EC7p dist/cli.js trong g\xF3i kh\xF4ng h\u1EE3p l\u1EC7");let h=this.getRuntimeDir();vt.default.existsSync(h)||vt.default.mkdirSync(h,{recursive:!0});let b=this.getRuntimeCliPath(),v=`${b}.${process.pid}.tmp`;vt.default.writeFileSync(v,f,{mode:493}),vt.default.renameSync(v,b);let _={version:o,updatedAt:new Date().toISOString(),integrity:l||c},m=`${this.getRuntimeVersionPath()}.${process.pid}.tmp`;vt.default.writeFileSync(m,JSON.stringify(_,null,2)),vt.default.renameSync(m,this.getRuntimeVersionPath());let x="/app/cli.js";if(vt.default.existsSync(x))try{vt.default.accessSync(x,vt.default.constants.W_OK);try{let w=`${x}.${process.pid}.tmp`;vt.default.writeFileSync(w,f,{mode:493}),vt.default.renameSync(w,x)}catch{vt.default.writeFileSync(x,f,{mode:493})}}catch{}return r.info(`\u{1F4E6} [RuntimeBundle] \u0110\xE3 t\u1EA3i v\xE0 x\xE1c th\u1EF1c g\xF3i v${o} v\xE0o b\u1ED9 nh\u1EDB b\u1EC1n v\u1EEFng (${b})`),{success:!0,version:o,cliPath:b}}catch(n){return r.warn(`\u26A0\uFE0F [RuntimeBundle] Kh\xF4ng th\u1EC3 t\u1EA3i tr\u1EF1c ti\u1EBFp bundle t\u1EEB Registry: ${n?.message||n}`),{success:!1}}}static tryBootstrapNewerRuntime(t){if(globalThis[Ng])return!1;try{let r=this.getInstalledRuntimeVersion();if(!r||!this.isNewerVersion(r,t))return!1;let n=this.getRuntimeCliPath();return Ta.default.resolve(process.argv[1]||"")===Ta.default.resolve(n)?!1:(globalThis[Ng]=r,YO.default.createRequire(n)(n),!0)}catch{globalThis[Ng]=void 0;try{vt.default.existsSync(this.getRuntimeVersionPath())&&vt.default.unlinkSync(this.getRuntimeVersionPath())}catch{}return!1}}};var Rp=class e{logger;timer;isUpdating=!1;constructor(t){this.logger=t||(0,XO.createLogger)("WorkerAutoUpdater")}static getNpmExecutionInfo(){let t=Ug.default.dirname(process.execPath),r=Ug.default.join(t,process.platform==="win32"?"npm.cmd":"npm"),n=Tp.default.existsSync(r)?`"${r}"`:"npm",i={...process.env,PATH:`${t}:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:${process.env.PATH||""}`};return{npmBin:n,env:i}}static isDocker(){return Tp.default.existsSync("/.dockerenv")||Tp.default.existsSync("/run/.containerenv")||!!process.env.DOCKER_CONTAINER}static isNewerVersion(t,r){return Di.isNewerVersion(t,r)}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 a=await i.json();if(a?.version)return String(a.version).trim()}}catch{}try{let{npmBin:r,env:n}=e.getNpmExecutionInfo();return(0,Jo.execSync)(`${r} view ${t} version`,{encoding:"utf-8",timeout:8e3,stdio:["ignore","pipe","ignore"],env:n}).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||"latest",n=`@softtynet/zplus-worker@${r}`,i=e.isDocker();this.logger.info(`\u{1F680} [AutoUpdater] B\u1EAFt \u0111\u1EA7u t\u1EF1 \u0111\u1ED9ng n\xE2ng c\u1EA5p Worker l\xEAn ${n} (M\xF4i tr\u01B0\u1EDDng: ${i?"Docker Container":"Host NPM"})...`);let a=!1,o=!1;try{if(a=(await Di.downloadAndInstallRuntimeBundle(r,this.logger)).success,!i)try{let{npmBin:c,env:l}=e.getNpmExecutionInfo();(0,Jo.execSync)(`${c} install -g ${n}`,{stdio:"inherit",timeout:12e4,env:l}),o=!0,this.logger.info(`\u2705 [AutoUpdater] \u0110\xE3 c\u1EADp nh\u1EADt g\xF3i NPM to\xE0n c\u1EE5c: ${n}!`)}catch(c){if(a)this.logger.info("\u2139\uFE0F [AutoUpdater] B\u1ECF qua c\u1EADp nh\u1EADt global npm (thi\u1EBFu quy\u1EC1n root), \u0111\xE3 s\u1EED d\u1EE5ng Runtime Bundle t\u1EA1i ~/.zplus/runtime/cli.js.");else throw c}if(!a&&!o)throw new Error("Kh\xF4ng th\u1EC3 c\u1EADp nh\u1EADt qua c\u1EA3 Runtime Bundle l\u1EABn NPM Global.");return this.logger.info(`\u2705 [AutoUpdater] \u0110\xE3 ho\xE0n t\u1EA5t n\xE2ng c\u1EA5p l\xEAn ${n}! \u0110ang kh\u1EDFi \u0111\u1ED9ng l\u1EA1i d\u1ECBch v\u1EE5...`),this.triggerRestart(),!0}catch(s){return this.isUpdating=!1,this.logger.error(`\u274C [AutoUpdater] N\xE2ng c\u1EA5p th\u1EA5t b\u1EA1i: ${s?.message||s}`),!1}}triggerRestart(){if(!e.isDocker()){try{if((0,Jo.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'...");let n=(0,Jo.spawn)("pm2",["restart","zplus-worker"],{detached:!0,stdio:"ignore"});n.on("error",()=>{}),n.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/Daemon), 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 (Docker / OS Service) 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 cho c\u1EA3 NPM & Docker (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 tr\xEAn NPM Registry: 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 ai=le(require("fs")),Wp=le(require("path")),La=le(require("os")),pB=le(require("dns")),fB=require("child_process"),ns=le(at());var lB=le(cB());function uB(e=36){return process.env.ZPLUS_NO_QR==="1"?!1:process.stdout.isTTY?(process.stdout.columns||80)>=e:!0}function dB(e,t={}){let r=lB.default.create(e,{errorCorrectionLevel:"L"}),n=r.modules.size,i=r.modules.data,a=t.margin??2,o=t.indent??" ",s=t.useAnsiColors??process.env.NO_COLOR===void 0,c=n+a*2,l=s?"\x1B[97;40m":"",u=s?"\x1B[0m":"",p=(h,b)=>{let v=h-a,_=b-a;return v<0||_<0||v>=n||_>=n?!1:!!i[_*n+v]},f=[];for(let h=0;h<c;h+=2){let b="";for(let v=0;v<c;v++){let _=p(v,h),m=h+1<c?p(v,h+1):!1;!_&&!m?b+="\u2588":_&&m?b+=" ":_&&!m?b+="\u2584":b+="\u2580"}f.push(`${o}${l}${b}${u}`)}return f.join(`
|
|
72
72
|
`)}try{pB.default.setDefaultResultOrder("ipv4first")}catch{}var Na=(process.env.SOFTTY_ACCOUNTS_URL||"https://accounts.softty.net").replace(/\/+$/,""),Ty=process.env.SOFTTY_CLI_CLIENT_ID||"1dfe43354fcf678ad1adca29980b03c4",YV=e=>new Promise(t=>setTimeout(t,e));function QV(e){if(process.env.VITEST||process.env.NODE_ENV==="test"||process.env.SSH_CONNECTION||process.env.SSH_CLIENT||process.env.SSH_TTY||process.platform==="linux"&&!process.env.DISPLAY&&!process.env.WAYLAND_DISPLAY)return;let t=process.platform==="darwin"?`open "${e}"`:process.platform==="win32"?`start "" "${e}"`:`xdg-open "${e}"`;(0,fB.exec)(t,()=>{})}var is=class{logger;lastReconciledToken="";lastReconciledAt=0;constructor(t){this.logger=t||(0,ns.createLogger)("WorkerAuthManager")}getWorkerDeviceKey(){let r=(process.env.WORKER_ID||process.env.HOSTNAME||La.default.hostname()||"default").replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,48);return r.startsWith("worker_")?r:`worker_${r}`}async reconcileWorkerSession(t,r=process.env.APPWRITE_ENDPOINT||"https://api.softty.net/v1",n=process.env.APPWRITE_PROJECT_ID||"699cfc3100136099c1c1",i=!1){if(!t)return;let a=Date.now();if(!(!i&&this.lastReconciledToken===t&&a-this.lastReconciledAt<1800*1e3))try{let o=this.getWorkerDeviceKey();(await ns.AppwriteSessionJanitor.reconcileDeviceSession({endpoint:r,projectId:n,sessionSecret:t,deviceKey:o,deviceType:"worker",deviceName:`ZPlus Worker (${La.default.hostname()})`,pinned:!0})).currentSessionId&&(this.lastReconciledToken=t,this.lastReconciledAt=a)}catch(o){this.logger.debug("reconcileWorkerSession warning:",o?.message)}}extractSessionTokenFromResponse(t,r){let n=r?.secret||"";if(!n&&t?.headers?.get&&(n=t.headers.get("x-appwrite-session")||""),!n&&t?.headers){let i=typeof t.headers.getSetCookie=="function"?t.headers.getSetCookie():[t.headers.get&&t.headers.get("set-cookie")||""];for(let a of i){let o=a.match(/a_session_[^=]+=([^;]+)/);if(o&&o[1]){n=decodeURIComponent(o[1]);break}}}if(!n&&t?.headers?.get)try{let i=t.headers.get("x-fallback-cookies");if(i){let a=JSON.parse(i);for(let o of Object.keys(a))if(o.startsWith("a_session_")){n=a[o];break}}}catch{}return n}getAuthFilePath(){let t=process.env.DATA_DIR||Wp.default.join(La.default.homedir(),".zplus");return Wp.default.join(t,"worker_auth.json")}loadStoredAuth(){try{let t=this.getAuthFilePath();if(!ai.default.existsSync(t))return null;let r=ai.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=Wp.default.dirname(r);ai.default.existsSync(n)||ai.default.mkdirSync(n,{recursive:!0,mode:448}),ai.default.writeFileSync(r,JSON.stringify(t,null,2),{encoding:"utf-8",mode:384});try{ai.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(t=process.env.APPWRITE_ENDPOINT||"https://api.softty.net/v1",r=process.env.APPWRITE_PROJECT_ID||"699cfc3100136099c1c1"){try{let n=this.loadStoredAuth();n?.sessionToken&&ns.AppwriteSessionJanitor.revokeCurrentDeviceSession({endpoint:t,projectId:r,sessionSecret:n.sessionToken,deviceKey:this.getWorkerDeviceKey()}).catch(()=>{}),n?.refreshToken&&fetch(`${Na}/api/oauth/v2/revoke`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:n.refreshToken,client_id:n.clientId||Ty})}).catch(()=>{});let i=this.getAuthFilePath();ai.default.existsSync(i)&&ai.default.unlinkSync(i),this.logger.info("\u0110\xE3 x\xF3a phi\xEAn \u0111\u0103ng nh\u1EADp c\u1EE7a Worker.")}catch(n){this.logger.debug("clearAuth error:",n?.message)}}async verifyEntitlements(t,r=process.env.APPWRITE_ENDPOINT||"https://api.softty.net/v1",n=process.env.APPWRITE_PROJECT_ID||"699cfc3100136099c1c1",i="default"){try{let a=`${r}/account`,o=t.includes(".")&&t.split(".").length===3,s={"Content-Type":"application/json","X-Appwrite-Project":n};o?s["X-Appwrite-JWT"]=t:(s["X-Appwrite-Session"]=t,s.Cookie=`a_session_${n}=${t}; a_session_${n}_legacy=${t}`,t.startsWith("eyJ")&&(s["X-Fallback-Cookies"]=JSON.stringify({[`a_session_${n}`]:t,[`a_session_${n}_legacy`]:t})));let c=await fetch(a,{method:"GET",headers:s});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 l=await c.json(),u=l.$id||l.id||"",p=l.name||"Ng\u01B0\u1EDDi d\xF9ng ZPlus",f=l.email||"",h=Array.isArray(l.labels)?l.labels:[],b=l.prefs||{},v=ns.AppwriteSessionJanitor.parseRegistry(b),_=this.getWorkerDeviceKey();(!v[_]?.sessionId||!v[_]?.pinned)&&(this.lastReconciledAt=0);let m=null;if(b.entitlements)try{m=typeof b.entitlements=="string"?JSON.parse(b.entitlements):b.entitlements}catch{}if(!m&&l.entitlements)try{m=typeof l.entitlements=="string"?JSON.parse(l.entitlements):l.entitlements}catch{}let x=!1;for(let[U,B]of Object.entries(b))if(U.endsWith("_entitlements")&&typeof B=="string")try{let G=JSON.parse(B);if(Array.isArray(G.features))for(let Q of G.features){let X=String(Q).toUpperCase();if(X.includes("PREMIUM")||X.includes("ENTERPRISE")){x=!0;break}}}catch{}let g=!h.some(U=>U.toLowerCase()==="member")&&b.isOwner!==!1,S=!(h.some(U=>U.toLowerCase()==="free")||b.tier==="free"||m?.tier==="FREE"||m?.isPremium===!1)&&!!(x||(m?.isPremium??b.isPremium??h.some(U=>U.toLowerCase()==="premium"||U.toLowerCase()==="enterprise"))),C=S?-1:Number(m?.cloudTtlDays||b.cloudTtlDays||7),F=(i&&i!=="default"?i:"")||b.teamId||b.storage?.teamId||m?.storage?.teamId||l.teamId||"",I=b.teamName||m?.teamName||"";try{let U=await fetch(`${r}/teams`,{method:"GET",headers:s});if(U.ok){let B=await U.json().catch(()=>({})),G=Array.isArray(B.teams)?B.teams:[];if(G.length>0){let Q=F&&F!=="default"&&G.find(X=>X.$id===F)||G[0];Q&&((!F||F==="default")&&(F=Q.$id),I=Q.name||I)}}}catch{}return(!F||F==="default")&&(F=u||i),S?{allowed:!0,userId:u,userName:p,email:f,teamId:F,teamName:I||void 0,isOwner:g,isPremium:!0,cloudTtlDays:-1,reason:`\u2705 X\xE1c th\u1EF1c th\xE0nh c\xF4ng: [${p}] (${f}) - G\xF3i Doanh Nghi\u1EC7p / Premium Active.`}:{allowed:!0,userId:u,userName:p,email:f,teamId:F,teamName:I||void 0,isOwner:g,isPremium:!1,cloudTtlDays:C,reason:`\u2705 X\xE1c th\u1EF1c th\xE0nh c\xF4ng: T\xE0i kho\u1EA3n Mi\u1EC5n Ph\xED [${p}] (${f}) - Tr\u1EF1c ban 24/7 (\u0110\u1EC7m Cloud ${C} ng\xE0y).`}}catch(a){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: ${a?.message}`}}}async bridgeAccessTokenToAppwrite(t,r,n,i){let a=`${Na}/api/oauth/v2/exchange-appwrite`,o=`${Na}/api/oauth/v2/userinfo?app=zplus${i&&i!=="default"?`&team_id=${encodeURIComponent(i)}`:""}`,[s,c]=await Promise.all([fetch(a,{method:"POST",headers:{Authorization:`Bearer ${t}`,"Content-Type":"application/json"},body:JSON.stringify({})}),fetch(o,{method:"GET",headers:{Authorization:`Bearer ${t}`}}).catch(()=>null)]);if(!s.ok){let k=await s.text().catch(()=>"");return this.logger.warn(`[OAuth Bridge] L\u1ED7i exchange-appwrite: HTTP ${s.status} ${k}`),null}let l=await s.json().catch(()=>({})),u=l.sessionSecret,p=l.secret,f=l.userId;if(!u&&p&&f)try{let k=await fetch(`${r}/account/sessions/token`,{method:"POST",headers:{"Content-Type":"application/json","X-Appwrite-Project":n},body:JSON.stringify({userId:f,secret:p})});if(k.ok){let S=await k.json().catch(()=>({})),C=this.extractSessionTokenFromResponse(k,S);C&&(u=C)}}catch(k){this.logger.debug("[OAuth Bridge] /account/sessions/token fallback error:",k?.message)}let h=u||p||l.jwt;if(!h)return null;let b=null;c&&c.ok&&(b=await c.json().catch(()=>null));let v=b?.products?.zplus,_=b?.softty_entitlements||{},m=!!(v?.has_access||_?.ZPLUS_ENTERPRISE?.status==="active"||_?.ZPLUS_ENTERPRISE?.status==="lifetime"||_?.ZPLUS_PREMIUM?.status==="active"||_?.ZPLUS_PREMIUM?.status==="lifetime"||_?.ZPLUS_PREMIUM_BASE?.status==="active"||_?.ZPLUS_PREMIUM_BASE?.status==="lifetime"||b?.entitlements?.isPremium===!0),x=(i&&i!=="default"?i:"")||b?.team_id||b?.teamId||b?.organization?.team_id||f,w=b?.team_name||b?.teamName||b?.organization?.name||void 0,g=String(b?.org_role||b?.orgRole||"owner").toLowerCase();return{sessionToken:h,userId:f||b?.sub,teamId:x,teamName:w,isPremium:m?!0:void 0,isOwner:g!=="member",userName:b?.name,email:b?.email}}async loginWithDeviceFlow(t=process.env.APPWRITE_ENDPOINT||"https://api.softty.net/v1",r=process.env.APPWRITE_PROJECT_ID||"699cfc3100136099c1c1",n="default",i={}){let a=i.clientId||Ty,o=`${La.default.type()} ${La.default.arch()} (${La.default.hostname()})`;try{let s=await fetch(`${Na}/api/oauth/v2/device/code`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({client_id:a,scope:"openid profile email",device_name:o})});if(!s.ok){let m=await s.json().catch(()=>({}));return console.error(`\u274C Kh\xF4ng th\u1EC3 kh\u1EDFi t\u1EA1o phi\xEAn x\xE1c th\u1EF1c thi\u1EBFt b\u1ECB: ${m.error_description||m.error||`HTTP ${s.status}`}`),null}let c=await s.json(),l=c.device_code,u=c.user_code,p=c.verification_uri||`${Na}/device`,f=c.verification_uri_complete||`${p}?user_code=${encodeURIComponent(u)}`,h=Number(c.expires_in||600),b=Number(c.interval||5);console.log(`
|
|
73
73
|
========================================================================`),console.log("\u{1F510} \u0110\u0102NG NH\u1EACP ZPLUS CLI \u2014 X\xC1C TH\u1EF0C THI\u1EBET B\u1ECA (SOFTTY PASSPORT)"),console.log("========================================================================"),!i.noQr&&uB()&&(console.log(`
|
|
74
74
|
\u{1F4F1} C\xC1CH 1: \u0110\u01B0a Camera \u0111i\u1EC7n tho\u1EA1i (ho\u1EB7c Zalo) qu\xE9t m\xE3 QR d\u01B0\u1EDBi \u0111\xE2y:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softtynet/zplus-worker",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.57",
|
|
4
4
|
"description": "ZPlus 24/7 Headless Personal Zalo Automation Worker & Cloud Sync Sentinel",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -25,8 +25,11 @@
|
|
|
25
25
|
"start": "node dist/cli.js",
|
|
26
26
|
"dev": "node --loader ts-node/esm src/cli.ts"
|
|
27
27
|
},
|
|
28
|
-
"dependencies": {
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"qrcode": "^1.5.4"
|
|
30
|
+
},
|
|
29
31
|
"devDependencies": {
|
|
32
|
+
"@types/qrcode": "^1.5.6",
|
|
30
33
|
"@zplus/contracts": "^1.0.0",
|
|
31
34
|
"@zplus/core": "^1.0.0",
|
|
32
35
|
"@zplus/zocial": "^0.1.0",
|