@forsion/extend 0.9.5 → 0.9.7
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/CHANGELOG.md +20 -0
- package/README.md +12 -0
- package/SIGNATURE +7 -7
- package/dist/desktop.mjs +46 -35
- package/dist/main.js +203 -45
- package/manifest.json +2 -2
- package/package.json +1 -1
package/dist/desktop.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
var or=null;function Is(t){or=t}function Se(){if(!or)throw new Error("core host not set (call setCoreHost first)");return or}var Ps=new TextEncoder,pa=new TextDecoder("utf-8",{ignoreBOM:!0}),jt=t=>Ps.encode(t),ot=t=>pa.decode(t),ir=t=>typeof t=="string"?Ps.encode(t).length:t.length;function Rs(t){let e="";for(let n=0;n<t.length;n+=32768)e+=String.fromCharCode(...t.subarray(n,n+32768));return btoa(e)}function wn(t){let e=t.replace(/-/g,"+").replace(/_/g,"/");return Uint8Array.from(atob(e.padEnd(Math.ceil(e.length/4)*4,"=")),n=>n.charCodeAt(0))}async function Ds(t){let e=new Blob([t]).stream().pipeThrough(new CompressionStream("gzip"));return new Uint8Array(await new Response(e).arrayBuffer())}function Xe(t,e){if(typeof e!="string"||!e.startsWith("/"))return null;let n=String(t||"").replace(/\/+$/,"").replace(/\/api$/,"");if(!n)return null;let r,s;try{r=new URL(n),s=new URL(n+"/api"+e)}catch{return null}return r.protocol!=="http:"&&r.protocol!=="https:"||s.origin!==r.origin||!s.pathname.startsWith("/api/")?null:s.toString()}function Ut(t,e,n){return t.fetch?t.fetch(e,n):fetch(e,{...n,headers:{Authorization:`Bearer ${t.token}`,...n.headers}})}async function Ae(t,e,n,r,s=6e4){let o=await(t.fetch??fetch)(t.base+n,{method:e,headers:{"Content-Type":"application/json","X-Project-Source":"connect",...t.token&&!t.fetch?{Authorization:`Bearer ${t.token}`}:{}},body:r===void 0?void 0:JSON.stringify(r),signal:AbortSignal.timeout(s)}),i=await o.json().catch(()=>({}));return{status:o.status,json:i}}var ma=50*1024*1024,ga=new Set(["mode","type","source","name","summary","githubRepoUrl","npmPackage","version","readme","description","tags","minAppVersion","maxAppVersion","platforms"]);function ya(t){if(!t||typeof t!="object")return null;let e=t;if(e.id!==void 0&&(typeof e.id!="string"||!/^[a-zA-Z0-9_-]{1,128}$/.test(e.id))||!e.fields||typeof e.fields!="object"||Array.isArray(e.fields))return null;let n=new FormData,r=0;for(let[s,o]of Object.entries(e.fields)){if(!ga.has(s)||typeof o!="string"||(r+=o.length,r>25e4)||e.id&&!["mode","name","summary","version","readme","description","tags","minAppVersion","maxAppVersion","platforms"].includes(s))return null;n.append(s,o)}if(e.zip!==void 0){if(!e.zip||typeof e.zip.name!="string"||!/\.zip$/i.test(e.zip.name)||!(e.zip.data instanceof Uint8Array)||!e.zip.data.byteLength||e.zip.data.byteLength>ma)return null;n.append("zip",new Blob([new Uint8Array(e.zip.data)],{type:"application/zip"}),e.zip.name.replace(/[\\/]/g,"_").slice(-255))}return{path:`${e.id?`/market/mine/${e.id}/update`:"/market/submit"}${e.dryRun===!0?"?dryRun=1":""}`,body:n}}function $s(t){t.handle("cloud:marketSubmit",async(e,n)=>{if(!t.isTrustedSender(e))return{status:0,error:"untrusted"};let r=ya(n);if(!r)return{status:400,json:{error:"invalid_request"}};let s=await t.getCloud();if(!s.token)return{status:401,error:"not_signed_in"};let o=Xe(s.base,r.path);if(!o)return{status:0,error:"no_cloud_url"};try{let i=await Ut(s,o,{method:"POST",body:r.body,redirect:"error",signal:AbortSignal.timeout(12e4)});return{status:i.status,json:await i.json().catch(()=>null)}}catch(i){return{status:0,error:String(i?.message||i)}}})}async function Os(t){if(!t.token)return"";try{let e=await Ae(t,"POST","/api/auth/handoff",{},5e3);if(e.status===200&&typeof e.json?.code=="string"&&e.json.code)return`code=${encodeURIComponent(e.json.code)}`;if((e.status===404||e.status===405)&&!t.fetch)return`token=${encodeURIComponent(t.token)}`}catch{}return""}var Ms=["membership","credits","storefront"],Ns=["monthly","quarterly","yearly"],wa=/^[A-Za-z0-9_-]{1,64}$/;function js(t){let e={status:0,error:"untrusted"},n={ok:!1,error:"untrusted"};t.handle("auth:openAccountCenter",async(s,o)=>{if(!t.isTrustedSender(s))return n;let i=await t.getCloud(),a=i.base;if(!a)return{ok:!1};let l=o&&/^[a-z0-9-]+$/i.test(o)?`#${o}`:"",c=await Os(i),u=`${a}/account${c?`?${c}`:""}${l}`;return i.signal?.throwIfAborted(),await t.openExternal(u),{ok:!0}}),t.handle("auth:openPayCenter",async(s,o,i,a)=>{if(!t.isTrustedSender(s))return n;if(o!==void 0&&!Ms.includes(o))return{ok:!1,error:"invalid_tab"};if(i!==void 0&&(typeof i!="string"||!wa.test(i)))return{ok:!1,error:"invalid_plan"};if(a!==void 0&&!Ns.includes(a))return{ok:!1,error:"invalid_period"};let l=(o??"membership")==="membership"&&i?`&plan=${encodeURIComponent(i)}${a?`&period=${a}`:""}`:"",c=await t.getCloud(),u=c.base;if(!u)return{ok:!1};let f=await Os(c),m=`${u}/pay?tab=${o??"membership"}${l}${f?`&${f}`:""}&redirect=${encodeURIComponent(`${u}/account`)}`;return c.signal?.throwIfAborted(),await t.openExternal(m),{ok:!0}}),t.handle("profile:publicOrigin",async s=>{if(!t.isTrustedSender(s))return n;let{base:o}=await t.getCloud();if(!o)return{ok:!1};try{let i=await fetch(`${o}/account`,{redirect:"manual",signal:AbortSignal.timeout(4e3)});i.body?.cancel().catch(()=>{});let a=i.status>=300&&i.status<400?i.headers.get("location"):null;return a&&/^https?:\/\//i.test(a)?{ok:!0,origin:new URL(a).origin}:{ok:!1}}catch{return{ok:!1}}});let r=()=>t.getCloud();t.handle("account:quota",async s=>{if(!t.isTrustedSender(s))return e;let o=await r();if(!o.token)return{status:401,json:null};try{return await Ae(o,"GET","/api/token-quota/my",void 0,15e3)}catch(i){return{status:0,json:{detail:String(i?.message||i)}}}}),t.handle("account:useResetCard",async(s,o)=>{if(!t.isTrustedSender(s))return e;let i=await r();if(!i.token)return{status:401,json:null};if(o!==void 0&&o!=="both")return{status:400,json:{error:"invalid_type",detail:`invalid reset card type: ${o}`}};let a=o??"both";try{return await Ae(i,"POST","/api/token-quota/reset-card/use",{type:a},15e3)}catch(l){return{status:0,json:{detail:String(l?.message||l)}}}}),t.handle("account:bgConvert",async(s,o)=>{if(!t.isTrustedSender(s))return e;let i=await r();if(!i.token)return{status:401,json:null};if(!Number.isInteger(o)||o<1||o>100)return{status:400,json:{error:"invalid_percent"}};try{return await Ae(i,"POST","/api/token-quota/background/convert",{percent:o},15e3)}catch(a){return{status:0,json:{detail:String(a?.message||a)}}}}),t.handle("account:bgAutoMain",async(s,o)=>{if(!t.isTrustedSender(s))return e;let i=await r();if(!i.token)return{status:401,json:null};if(typeof o!="boolean")return{status:400,json:{error:"invalid_request"}};try{return await Ae(i,"POST","/api/token-quota/background/auto-main",{enabled:o},15e3)}catch(a){return{status:0,json:{detail:String(a?.message||a)}}}}),t.handle("feedback:submit",async(s,o)=>{if(!t.isTrustedSender(s))return n;let i=await t.getCloud();if(!i.base||!i.token)return{ok:!1,error:"not-logged-in"};let a=(o?.description||"").trim();if(!a)return{ok:!1,error:"empty"};if(a.length>1e4)return{ok:!1,error:"description-too-long"};let l=[],c=!1;if(o?.sessionLogJson){let u=jt(o.sessionLogJson);if(u.length>5*1024*1024)return{ok:!1,error:"attachment-too-large"};l.push({filename:o.sessionLogName||"tangu-session.json",mime_type:"application/json",size:u.length,data_base64:Rs(u)})}try{let u=await Ut(i,`${i.base}/api/feedback`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({description:a,attachments:l}),signal:AbortSignal.timeout(2e4)});if(!u.ok){let m=`HTTP ${u.status}`;try{m=(await u.json())?.detail||m}catch{}return{ok:!1,error:m}}return{ok:!0,id:(await u.json().catch(()=>({})))?.id??null,attachmentSkipped:c}}catch(u){return{ok:!1,error:u?.message||String(u)}}}),t.handle("cloud:fetch",async(s,o)=>{if(!t.isTrustedSender(s))return{status:0,error:"untrusted"};let i=o??{},a=typeof i.path=="string"?i.path:"",l=i.projectSource===void 0?null:i.projectSource;if(l!==null&&(typeof l!="string"||!/^[a-z0-9][a-z0-9-]{0,63}$/.test(l)))return{status:0,error:"bad_project_source"};let c=Math.min(12e4,Math.max(1e3,Number(i.timeoutMs)||15e3)),u=typeof i.method=="string"?i.method.toUpperCase():"GET";if(!/^(GET|POST|PUT|PATCH|DELETE)$/.test(u))return{status:0,error:"bad_method"};if(!a.startsWith("/"))return{status:0,error:"bad_path"};let f=await t.getCloud();if(!String(f.base||""))return{status:0,error:"no_cloud_url"};let m=Xe(f.base,a);if(!m)return{status:0,error:"bad_path"};if(!f.token)return{status:401,error:"not_signed_in"};let h=i.body!==void 0&&u!=="GET"&&u!=="DELETE",g=new AbortController,p=setTimeout(()=>g.abort(),c);try{let y=await Ut(f,m,{method:u,headers:{...h?{"Content-Type":"application/json"}:{},...l?{"X-Project-Source":l}:{}},body:h?JSON.stringify(i.body):void 0,signal:g.signal});return{status:y.status,json:await y.json().catch(()=>null)}}catch(y){return{status:0,error:String(y?.message||y)}}finally{clearTimeout(p)}}),$s(t)}import{createHash as ul}from"node:crypto";import{existsSync as dl,promises as fl}from"node:fs";import hl from"node:path";import{EventEmitter as Ya}from"node:events";import{stat as Ja}from"node:fs";import{readdir as Ga,stat as Xa}from"node:fs/promises";import*as re from"node:path";import{lstat as Us,readdir as ba,realpath as Sa,stat as va}from"node:fs/promises";import{join as ka,resolve as Ea,sep as Fs}from"node:path";import{Readable as _a}from"node:stream";var $e={FILE_TYPE:"files",DIR_TYPE:"directories",FILE_DIR_TYPE:"files_directories",EVERYTHING_TYPE:"all"},kt={root:".",fileFilter:t=>!0,directoryFilter:t=>!0,type:$e.FILE_TYPE,lstat:!1,depth:2147483648,alwaysStat:!1,highWaterMark:256};Object.freeze(kt);var qs="READDIRP_RECURSIVE_ERROR",Ca=new Set(["ENOENT","EPERM","EACCES","ELOOP",qs]),Ls=[$e.DIR_TYPE,$e.EVERYTHING_TYPE,$e.FILE_DIR_TYPE,$e.FILE_TYPE],xa=new Set([$e.DIR_TYPE,$e.EVERYTHING_TYPE,$e.FILE_DIR_TYPE]),Ta=new Set([$e.EVERYTHING_TYPE,$e.FILE_DIR_TYPE,$e.FILE_TYPE]),Aa=t=>Ca.has(t.code),Ia=process.platform==="win32",zs=t=>!0,Hs=t=>{if(t===void 0)return zs;if(typeof t=="function")return t;if(typeof t=="string"){let e=t.trim();return n=>n.basename===e}if(Array.isArray(t)){let e=t.map(n=>n.trim());return n=>e.some(r=>n.basename===r)}return zs},ar=class extends _a{parents;reading;parent;_stat;_maxDepth;_wantsDir;_wantsFile;_wantsEverything;_root;_isDirent;_statsProp;_rdOptions;_fileFilter;_directoryFilter;_relStart;constructor(e={}){super({objectMode:!0,autoDestroy:!0,highWaterMark:e.highWaterMark??kt.highWaterMark});let n={...kt,...e},r=n.root??kt.root,s=n.type??kt.type;this._fileFilter=Hs(n.fileFilter),this._directoryFilter=Hs(n.directoryFilter);let o=n.lstat?Us:va;Ia?this._stat=a=>o(a,{bigint:!0}):this._stat=o,this._maxDepth=n.depth!=null&&Number.isSafeInteger(n.depth)?n.depth:kt.depth,this._wantsDir=xa.has(s),this._wantsFile=Ta.has(s),this._wantsEverything=s===$e.EVERYTHING_TYPE,this._root=Ea(r),this._relStart=this._root.endsWith(Fs)?this._root.length:this._root.length+1,this._isDirent=!n.alwaysStat,this._statsProp=this._isDirent?"dirent":"stats",this._rdOptions={encoding:"utf8",withFileTypes:this._isDirent};let i={path:this._root,depth:1};i.pending=this._exploreDir(this._root,1),this.parents=[i],this.reading=!1,this.parent=void 0}async _read(e){if(!this.reading){this.reading=!0;try{for(;!this.destroyed&&e>0;){let n=this.parent,r=n&&n.files;if(r&&r.length>0){let{path:s,depth:o}=n,i=r.splice(0,e).map(l=>this._formatEntry(l,s)),a=this._isDirent?i:await Promise.all(i);for(let l of a){if(!l)continue;if(this.destroyed)return;let c=this._getEntryType(l);typeof c!="string"&&(c=await c),c==="directory"&&this._directoryFilter(l)?(o<=this._maxDepth&&this.parents.push({path:l.fullPath,depth:o+1}),this._wantsDir&&(this.push(l),e--)):(c==="file"||this._includeAsFile(l))&&this._fileFilter(l)&&this._wantsFile&&(this.push(l),e--)}}else{let s=this.parents.pop();if(!s){this.push(null);break}let o=s.pending??this._exploreDir(s.path,s.depth),i=this.parents[this.parents.length-1];if(i&&!i.pending&&(i.pending=this._exploreDir(i.path,i.depth)),this.parent=await o,this.destroyed)return}}}catch(n){this.destroy(n)}finally{this.reading=!1}}}async _exploreDir(e,n){let r;try{r=await ba(e,this._rdOptions)}catch(s){this._onError(s)}return{files:r,depth:n,path:e}}_formatEntry(e,n){let r=this._isDirent?e.name:e,s=ka(n,r),o={path:s.slice(this._relStart),fullPath:s,basename:r};return this._isDirent?(o.dirent=e,o):this._stat(s).then(i=>(o.stats=i,o),i=>{this._onError(i)})}_onError(e){Aa(e)&&!this.destroyed?this.emit("warn",e):this.destroy(e)}_getEntryType(e){if(!e||!(this._statsProp in e))return"";let n=e[this._statsProp];return n.isFile()?"file":n.isDirectory()?"directory":n.isSymbolicLink()?this._getSymlinkEntryType(e):""}async _getSymlinkEntryType(e){let n=e.fullPath;try{let r=await Sa(n),s=await Us(r);if(s.isFile())return"file";if(s.isDirectory()){let o=r.length;if(n.startsWith(r)&&n[o]===Fs){let i=new Error(`Circular symlink detected: "${n}" points to "${r}"`);return i.code=qs,this._onError(i),""}return"directory"}}catch(r){this._onError(r)}return""}_includeAsFile(e){let n=e&&e[this._statsProp];return n&&this._wantsEverything&&!n.isDirectory()}};function Bs(t,e={}){let n=e.entryType||e.type;if(n==="both"&&(n=$e.FILE_DIR_TYPE),t){if(typeof t!="string")throw new TypeError("readdirp: root argument must be a string. Usage: readdirp(root, options)");if(n&&!Ls.includes(n))throw new Error(`readdirp: Invalid type passed. Use one of ${Ls.join(", ")}`)}else throw new Error("readdirp: root argument is required. Usage: readdirp(root, options)");let r={...e,root:t};return n&&(r.type=n),new ar(r)}import{watch as Pa,unwatchFile as Ws,watchFile as Ra}from"node:fs";import{realpath as lr,lstat as Da,open as $a,stat as Ys}from"node:fs/promises";import{type as Oa}from"node:os";import*as me from"node:path";var Ma="data",dr="end",Js="close",En=()=>{};var _n=process.platform,fr=_n==="win32",Na=_n==="darwin",ja=_n==="linux",Ua=_n==="freebsd",Gs=Oa()==="OS400",ge={ALL:"all",READY:"ready",ADD:"add",CHANGE:"change",ADD_DIR:"addDir",UNLINK:"unlink",UNLINK_DIR:"unlinkDir",RAW:"raw",ERROR:"error"},Fe=ge,Fa="watch",La={lstat:Da,stat:Ys},pt="listeners",bn="errHandlers",Et="rawEmitters",za=[pt,bn,Et],Ha=new Set(["3dm","3ds","3g2","3gp","7z","a","aac","adp","afdesign","afphoto","afpub","ai","aif","aiff","alz","ape","apk","appimage","ar","arj","asf","au","avi","bak","baml","bh","bin","bk","bmp","btif","bz2","bzip2","cab","caf","cgm","class","cmx","cpio","cr2","cur","dat","dcm","deb","dex","djvu","dll","dmg","dng","doc","docm","docx","dot","dotm","dra","DS_Store","dsk","dts","dtshd","dvb","dwg","dxf","ecelp4800","ecelp7470","ecelp9600","egg","eol","eot","epub","exe","f4v","fbs","fh","fla","flac","flatpak","fli","flv","fpx","fst","fvt","g3","gh","gif","graffle","gz","gzip","h261","h263","h264","icns","ico","ief","img","ipa","iso","jar","jpeg","jpg","jpgv","jpm","jxr","key","ktx","lha","lib","lvp","lz","lzh","lzma","lzo","m3u","m4a","m4v","mar","mdi","mht","mid","midi","mj2","mka","mkv","mmr","mng","mobi","mov","movie","mp3","mp4","mp4a","mpeg","mpg","mpga","mxu","nef","npx","numbers","nupkg","o","odp","ods","odt","oga","ogg","ogv","otf","ott","pages","pbm","pcx","pdb","pdf","pea","pgm","pic","png","pnm","pot","potm","potx","ppa","ppam","ppm","pps","ppsm","ppsx","ppt","pptm","pptx","psd","pya","pyc","pyo","pyv","qt","rar","ras","raw","resources","rgb","rip","rlc","rmf","rmvb","rpm","rtf","rz","s3m","s7z","scpt","sgi","shar","snap","sil","sketch","slk","smv","snk","so","stl","suo","sub","swf","tar","tbz","tbz2","tga","tgz","thmx","tif","tiff","tlz","ttc","ttf","txz","udf","uvh","uvi","uvm","uvp","uvs","uvu","viv","vob","war","wav","wax","wbmp","wdp","weba","webm","webp","whl","wim","wm","wma","wmv","wmx","woff","woff2","wrm","wvx","xbm","xif","xla","xlam","xls","xlsb","xlsm","xlsx","xlt","xltm","xltx","xm","xmind","xpi","xpm","xwd","xz","z","zip","zipx"]),qa=t=>Ha.has(me.extname(t).slice(1).toLowerCase()),ur=(t,e)=>{t instanceof Set?t.forEach(e):e(t)},Ft=(t,e,n)=>{let r=t[e];r instanceof Set||(t[e]=r=new Set([r])),r.add(n)},Ba=t=>e=>{let n=t[e];n instanceof Set?n.clear():delete t[e]},Lt=(t,e,n)=>{let r=t[e];r instanceof Set?r.delete(n):r===n&&delete t[e]},Xs=t=>t instanceof Set?t.size===0:!t,Sn=new Map;function Vs(t,e,n,r,s){let o=(i,a)=>{n(t),s(i,a,{watchedPath:t}),a&&t!==a&&vn(me.resolve(t,a),pt,me.join(t,a))};try{return Pa(t,{persistent:e.persistent},o)}catch(i){r(i);return}}var vn=(t,e,n,r,s)=>{let o=Sn.get(t);o&&ur(o[e],i=>{i(n,r,s)})},Wa=(t,e,n,r)=>{let{listener:s,errHandler:o,rawEmitter:i}=r,a=Sn.get(e),l;if(!n.persistent)return l=Vs(t,n,s,o,i),l?l.close.bind(l):void 0;if(a)Ft(a,pt,s),Ft(a,bn,o),Ft(a,Et,i);else{if(l=Vs(t,n,vn.bind(null,e,pt),o,vn.bind(null,e,Et)),!l)return;l.on(Fe.ERROR,async c=>{let u=vn.bind(null,e,bn);if(a&&(a.watcherUnusable=!0),fr&&c.code==="EPERM")try{await(await $a(t,"r")).close(),u(c)}catch{}else u(c)}),a={listeners:s,errHandlers:o,rawEmitters:i,watcher:l},Sn.set(e,a)}return()=>{Lt(a,pt,s),Lt(a,bn,o),Lt(a,Et,i),Xs(a.listeners)&&(a.watcher.close(),Sn.delete(e),za.forEach(Ba(a)),a.watcher=void 0,Object.freeze(a))}},cr=new Map,Va=(t,e,n,r)=>{let{listener:s,rawEmitter:o}=r,i=cr.get(e),a=i&&i.options;return a&&(a.persistent<n.persistent||a.interval>n.interval)&&(Ws(e),i=void 0),i?(Ft(i,pt,s),Ft(i,Et,o)):(i={listeners:s,rawEmitters:o,options:n,watcher:Ra(e,n,(l,c)=>{ur(i.rawEmitters,f=>{f(Fe.CHANGE,e,{curr:l,prev:c})});let u=l.mtimeMs;(l.size!==c.size||u>c.mtimeMs||u===0)&&ur(i.listeners,f=>f(t,l))})},cr.set(e,i)),()=>{Lt(i,pt,s),Lt(i,Et,o),Xs(i.listeners)&&(cr.delete(e),Ws(e),i.options=i.watcher=void 0,Object.freeze(i))}},kn=class{fsw;_boundHandleError;constructor(e){this.fsw=e,this._boundHandleError=n=>e._handleError(n)}_watchWithNodeFs(e,n){let r=this.fsw.options,s=me.dirname(e),o=me.basename(e);this.fsw._getWatchedDir(s).add(o);let a=me.resolve(e),l={persistent:r.persistent};n||(n=En);let c;if(r.usePolling){let u=r.interval!==r.binaryInterval;l.interval=u&&qa(o)?r.binaryInterval:r.interval,c=Va(e,a,l,{listener:n,rawEmitter:this.fsw._emitRaw})}else c=Wa(e,a,l,{listener:n,errHandler:this._boundHandleError,rawEmitter:this.fsw._emitRaw});return c}_handleFile(e,n,r){if(this.fsw.closed)return;let s=me.dirname(e),o=me.basename(e),i=this.fsw._getWatchedDir(s),a=n;if(i.has(o))return;let l=async(u,f)=>{if(this.fsw._throttle(Fa,e,5)){if(!f||f.mtimeMs===0)try{let m=await Ys(e);if(this.fsw.closed)return;let h=m.atimeMs,g=m.mtimeMs;if((!h||h<=g||g!==a.mtimeMs)&&this.fsw._emit(Fe.CHANGE,e,m),(Na||ja||Ua)&&a.ino!==m.ino){this.fsw._closeFile(u),a=m;let p=this._watchWithNodeFs(e,l);p&&this.fsw._addPathCloser(u,p)}else a=m}catch{this.fsw._remove(s,o)}else if(i.has(o)){let m=f.atimeMs,h=f.mtimeMs;(!m||m<=h||h!==a.mtimeMs)&&this.fsw._emit(Fe.CHANGE,e,f),a=f}}},c=this._watchWithNodeFs(e,l);if(!(r&&this.fsw.options.ignoreInitial)&&this.fsw._isntIgnored(e)){if(!this.fsw._throttle(Fe.ADD,e,0))return;this.fsw._emit(Fe.ADD,e,n)}return c}async _handleSymlink(e,n,r,s){if(this.fsw.closed)return;let o=e.fullPath,i=this.fsw._getWatchedDir(n);if(!this.fsw.options.followSymlinks){this.fsw._incrReadyCount();let a;try{a=await lr(r)}catch{return this.fsw._emitReady(),!0}return this.fsw.closed?void 0:(i.has(s)?this.fsw._symlinkPaths.get(o)!==a&&(this.fsw._symlinkPaths.set(o,a),this.fsw._emit(Fe.CHANGE,r,e.stats)):(i.add(s),this.fsw._symlinkPaths.set(o,a),this.fsw._emit(Fe.ADD,r,e.stats)),this.fsw._emitReady(),!0)}if(this.fsw._symlinkPaths.has(o))return!0;this.fsw._symlinkPaths.set(o,!0)}_handleRead(e,n,r,s,o,i,a){e=me.join(e,"");let l=s?`${e}:${s}`:e;if(a=this.fsw._throttle("readdir",l,1e3),!a)return;let c=this.fsw._getWatchedDir(r.path),u=new Set,f=this.fsw._readdirp(e,{fileFilter:m=>r.filterPath(m),directoryFilter:m=>r.filterDir(m)});if(f)return f.on(Ma,async m=>{if(this.fsw.closed){f=void 0;return}let h=m.path,g=me.join(e,h);if(u.add(h),!(m.stats.isSymbolicLink()&&await this._handleSymlink(m,e,g,h))){if(this.fsw.closed){f=void 0;return}(h===s||!s&&!c.has(h))&&(this.fsw._incrReadyCount(),g=me.join(o,me.relative(o,g)),this._addToNodeFs(g,n,r,i+1))}}).on(Fe.ERROR,this._boundHandleError),new Promise((m,h)=>{if(!f)return h();f.once(dr,()=>{if(this.fsw.closed){f=void 0;return}let g=a?a.clear():!1;m(void 0),c.getChildren().filter(p=>p!==e&&!u.has(p)).forEach(p=>{this.fsw._remove(e,p)}),f=void 0,g&&this._handleRead(e,!1,r,s,o,i,a)})})}async _handleDir(e,n,r,s,o,i,a){let l=this.fsw._getWatchedDir(me.dirname(e)),c=l.has(me.basename(e));!(r&&this.fsw.options.ignoreInitial)&&!o&&!c&&this.fsw._emit(Fe.ADD_DIR,e,n),l.add(me.basename(e)),this.fsw._getWatchedDir(e);let u,f,m=this.fsw.options.depth;if((m==null||s<=m)&&!this.fsw._symlinkPaths.has(a)){if(!o&&(await this._handleRead(e,r,i,o,e,s,u),this.fsw.closed))return;f=this._watchWithNodeFs(e,(h,g)=>{g&&g.mtimeMs===0||this._handleRead(h,!1,i,o,e,s,u)})}return f}async _addToNodeFs(e,n,r,s,o){let i=this.fsw._emitReady;if(this.fsw._isIgnored(e)||this.fsw.closed)return i(),!1;let a=this.fsw._getWatchHelpers(e);r&&(a.filterPath=l=>r.filterPath(l),a.filterDir=l=>r.filterDir(l));try{let l=await La[a.statMethod](a.watchPath);if(this.fsw.closed)return;if(this.fsw._isIgnored(a.watchPath,l))return i(),!1;let c=this.fsw.options.followSymlinks,u;if(l.isDirectory()){let f=me.resolve(e),m=c?await lr(e):e;if(this.fsw.closed||(u=await this._handleDir(a.watchPath,l,n,s,o,a,m),this.fsw.closed))return;f!==m&&m!==void 0&&this.fsw._symlinkPaths.set(f,m)}else if(l.isSymbolicLink()){let f=c?await lr(e):e;if(this.fsw.closed)return;let m=me.dirname(a.watchPath);if(this.fsw._getWatchedDir(m).add(a.watchPath),this.fsw._emit(Fe.ADD,a.watchPath,l),u=await this._handleDir(m,l,n,s,e,a,f),this.fsw.closed)return;f!==void 0&&this.fsw._symlinkPaths.set(me.resolve(e),f)}else u=this._handleFile(a.watchPath,l,n);return i(),u&&this.fsw._addPathCloser(e,u),!1}catch(l){if(this.fsw._handleError(l))return i(),e}}};var hr="/",Ka="//",to=".",Za="..",Qa="string",el=/\\/g,no=/\/\//g,tl=/\..*\.(sw[px])$|~$|\.subl.*\.tmp/,nl=/^\.[/\\]/;function Cn(t){return Array.isArray(t)?t:[t]}var pr=t=>typeof t=="object"&&t!==null&&!(t instanceof RegExp);function rl(t){return typeof t=="function"?t:typeof t=="string"?e=>t===e:t instanceof RegExp?e=>t.test(e):typeof t=="object"&&t!==null?e=>{if(t.path===e)return!0;if(t.recursive){let n=re.relative(t.path,e);return n?!n.startsWith("..")&&!re.isAbsolute(n):!1}return!1}:()=>!1}function sl(t){if(typeof t!="string")throw new Error("string expected");t=re.normalize(t),t=t.replace(/\\/g,"/");let e=!1;return t.startsWith("//")&&(e=!0),t=t.replace(no,"/"),e&&(t="/"+t),t}function Ks(t,e,n){let r=sl(e);for(let s=0;s<t.length;s++){let o=t[s];if(o(r,n))return!0}return!1}function ol(t,e){if(t==null)throw new TypeError("anymatch: specify first argument");let r=Cn(t).map(s=>rl(s));return e==null?(s,o)=>Ks(r,s,o):Ks(r,e)}var Zs=t=>{let e=Cn(t).flat();if(!e.every(n=>typeof n===Qa))throw new TypeError(`Non-string provided as watch path: ${e}`);return e.map(ro)},Qs=t=>{let e=t.replace(el,hr),n=!1;return e.startsWith(Ka)&&(n=!0),e=e.replace(no,hr),n&&(e=hr+e),e},ro=t=>Qs(re.normalize(Qs(t))),eo=(t="")=>e=>typeof e=="string"?ro(re.isAbsolute(e)?e:re.join(t,e)):e,il=(t,e)=>re.isAbsolute(t)?t:re.join(e,t),al=Object.freeze(new Set),mr=class{path;_removeWatcher;items;constructor(e,n){this.path=e,this._removeWatcher=n,this.items=new Set}add(e){let{items:n}=this;n&&e!==to&&e!==Za&&n.add(e)}async remove(e){let{items:n}=this;if(!n||(n.delete(e),n.size>0))return;let r=this.path;try{await Ga(r)}catch{this._removeWatcher&&this._removeWatcher(re.dirname(r),re.basename(r))}}has(e){let{items:n}=this;if(n)return n.has(e)}getChildren(){let{items:e}=this;return e?[...e.values()]:[]}dispose(){this.items.clear(),this.path="",this._removeWatcher=En,this.items=al,Object.freeze(this)}},ll="stat",cl="lstat",gr=class{fsw;path;watchPath;fullWatchPath;dirParts;followSymlinks;statMethod;constructor(e,n,r){this.fsw=r;let s=e;this.path=e=e.replace(nl,""),this.watchPath=s,this.fullWatchPath=re.resolve(s),this.dirParts=[],this.dirParts.forEach(o=>{o.length>1&&o.pop()}),this.followSymlinks=n,this.statMethod=n?ll:cl}entryPath(e){return re.join(this.watchPath,re.relative(this.watchPath,e.fullPath))}filterPath(e){let{stats:n}=e;if(n&&n.isSymbolicLink())return this.filterDir(e);let r=this.entryPath(e);return this.fsw._isntIgnored(r,n)&&this.fsw._hasReadPermissions(n)}filterDir(e){return this.fsw._isntIgnored(this.entryPath(e),e.stats)}},xn=class extends Ya{closed;options;_closers;_ignoredPaths;_throttled;_streams;_symlinkPaths;_watched;_pendingWrites;_pendingUnlinks;_readyCount;_emitReady;_closePromise;_userIgnored;_readyEmitted;_emitRaw;_boundRemove;_nodeFsHandler;constructor(e={}){super(),this.closed=!1,this._closers=new Map,this._ignoredPaths=new Set,this._throttled=new Map,this._streams=new Set,this._symlinkPaths=new Map,this._watched=new Map,this._pendingWrites=new Map,this._pendingUnlinks=new Map,this._readyCount=0,this._readyEmitted=!1;let n=e.awaitWriteFinish,r={stabilityThreshold:2e3,pollInterval:100},s={persistent:!0,ignoreInitial:!1,ignorePermissionErrors:!1,interval:100,binaryInterval:300,followSymlinks:!0,usePolling:!1,atomic:!0,...e,ignored:e.ignored?Cn(e.ignored):Cn([]),awaitWriteFinish:n===!0?r:typeof n=="object"?{...r,...n}:!1};Gs&&(s.usePolling=!0),s.atomic===void 0&&(s.atomic=!s.usePolling);let o=process.env.CHOKIDAR_USEPOLLING;if(o!==void 0){let l=o.toLowerCase();l==="false"||l==="0"?s.usePolling=!1:l==="true"||l==="1"?s.usePolling=!0:s.usePolling=!!l}let i=process.env.CHOKIDAR_INTERVAL;i&&(s.interval=Number.parseInt(i,10));let a=0;this._emitReady=()=>{a++,a>=this._readyCount&&(this._emitReady=En,this._readyEmitted=!0,process.nextTick(()=>this.emit(ge.READY)))},this._emitRaw=(...l)=>this.emit(ge.RAW,...l),this._boundRemove=this._remove.bind(this),this.options=s,this._nodeFsHandler=new kn(this),Object.freeze(s)}_addIgnoredPath(e){if(pr(e)){for(let n of this._ignoredPaths)if(pr(n)&&n.path===e.path&&n.recursive===e.recursive)return}this._ignoredPaths.add(e)}_removeIgnoredPath(e){if(this._ignoredPaths.delete(e),typeof e=="string")for(let n of this._ignoredPaths)pr(n)&&n.path===e&&this._ignoredPaths.delete(n)}add(e,n,r){let{cwd:s}=this.options;this.closed=!1,this._closePromise=void 0;let o=Zs(e);return s&&(o=o.map(i=>il(i,s))),o.forEach(i=>{this._removeIgnoredPath(i)}),this._userIgnored=void 0,this._readyCount||(this._readyCount=0),this._readyCount+=o.length,Promise.all(o.map(async i=>{let a=await this._nodeFsHandler._addToNodeFs(i,!r,void 0,0,n);return a&&this._emitReady(),a})).then(i=>{this.closed||i.forEach(a=>{a&&this.add(re.dirname(a),re.basename(n||a))})}),this}unwatch(e){if(this.closed)return this;let n=Zs(e),{cwd:r}=this.options;return n.forEach(s=>{!re.isAbsolute(s)&&!this._closers.has(s)&&(r&&(s=re.join(r,s)),s=re.resolve(s)),this._closePath(s),this._addIgnoredPath(s),this._watched.has(s)&&this._addIgnoredPath({path:s,recursive:!0}),this._userIgnored=void 0}),this}close(){if(this._closePromise)return this._closePromise;this.closed=!0,this.removeAllListeners();let e=[];return this._closers.forEach(n=>n.forEach(r=>{let s=r();s instanceof Promise&&e.push(s)})),this._streams.forEach(n=>n.destroy()),this._userIgnored=void 0,this._readyCount=0,this._readyEmitted=!1,this._watched.forEach(n=>n.dispose()),this._closers.clear(),this._watched.clear(),this._streams.clear(),this._symlinkPaths.clear(),this._throttled.clear(),this._closePromise=e.length?Promise.all(e).then(()=>{}):Promise.resolve(),this._closePromise}getWatched(){let e={};return this._watched.forEach((n,r)=>{let o=(this.options.cwd?re.relative(this.options.cwd,r):r)||to;e[o]=n.getChildren().sort()}),e}emitWithAll(e,n){this.emit(e,...n),e!==ge.ERROR&&this.emit(ge.ALL,e,...n)}async _emit(e,n,r){if(this.closed)return;let s=this.options;fr&&(n=re.normalize(n)),s.cwd&&(n=re.relative(s.cwd,n));let o=[n];r!=null&&o.push(r);let i=s.awaitWriteFinish,a;if(i&&(a=this._pendingWrites.get(n)))return a.lastChange=new Date,this;if(s.atomic){if(e===ge.UNLINK)return this._pendingUnlinks.set(n,[e,...o]),setTimeout(()=>{this._pendingUnlinks.forEach((l,c)=>{this.emit(...l),this.emit(ge.ALL,...l),this._pendingUnlinks.delete(c)})},typeof s.atomic=="number"?s.atomic:100),this;e===ge.ADD&&this._pendingUnlinks.has(n)&&(e=ge.CHANGE,this._pendingUnlinks.delete(n))}if(i&&(e===ge.ADD||e===ge.CHANGE)&&this._readyEmitted){let l=(c,u)=>{c?(e=ge.ERROR,o[0]=c,this.emitWithAll(e,o)):u&&(o.length>1?o[1]=u:o.push(u),this.emitWithAll(e,o))};return this._awaitWriteFinish(n,i.stabilityThreshold,e,l),this}if(e===ge.CHANGE&&!this._throttle(ge.CHANGE,n,50))return this;if(s.alwaysStat&&r===void 0&&(e===ge.ADD||e===ge.ADD_DIR||e===ge.CHANGE)){let l=s.cwd?re.join(s.cwd,n):n,c;try{c=await Xa(l)}catch{}if(!c||this.closed)return;o.push(c)}return this.emitWithAll(e,o),this}_handleError(e){let n=e&&e.code;return e&&n!=="ENOENT"&&n!=="ENOTDIR"&&(!this.options.ignorePermissionErrors||n!=="EPERM"&&n!=="EACCES")&&this.emit(ge.ERROR,e),e||this.closed}_throttle(e,n,r){this._throttled.has(e)||this._throttled.set(e,new Map);let s=this._throttled.get(e);if(!s)throw new Error("invalid throttle");let o=s.get(n);if(o)return o.count++,!1;let i,a=()=>{let c=s.get(n),u=c?c.count:0;return s.delete(n),clearTimeout(i),c&&clearTimeout(c.timeoutObject),u};i=setTimeout(a,r);let l={timeoutObject:i,clear:a,count:0};return s.set(n,l),l}_incrReadyCount(){return this._readyCount++}_awaitWriteFinish(e,n,r,s){let o=this.options.awaitWriteFinish;if(typeof o!="object")return;let i=o.pollInterval,a,l=e;this.options.cwd&&!re.isAbsolute(e)&&(l=re.join(this.options.cwd,e));let c=new Date,u=this._pendingWrites;function f(m){Ja(l,(h,g)=>{if(h||!u.has(e)){h&&h.code!=="ENOENT"&&s(h);return}let p=Number(new Date);m&&g.size!==m.size&&(u.get(e).lastChange=p);let y=u.get(e);p-y.lastChange>=n?(u.delete(e),s(void 0,g)):a=setTimeout(f,i,g)})}u.has(e)||(u.set(e,{lastChange:c,cancelWait:()=>(u.delete(e),clearTimeout(a),r)}),a=setTimeout(f,i))}_isIgnored(e,n){if(this.options.atomic&&tl.test(e))return!0;if(!this._userIgnored){let{cwd:r}=this.options,o=(this.options.ignored||[]).map(eo(r)),a=[...[...this._ignoredPaths].map(eo(r)),...o];this._userIgnored=ol(a,void 0)}return this._userIgnored(e,n)}_isntIgnored(e,n){return!this._isIgnored(e,n)}_getWatchHelpers(e){return new gr(e,this.options.followSymlinks,this)}_getWatchedDir(e){let n=re.resolve(e);return this._watched.has(n)||this._watched.set(n,new mr(n,this._boundRemove)),this._watched.get(n)}_hasReadPermissions(e){return this.options.ignorePermissionErrors?!0:!!(Number(e.mode)&256)}_remove(e,n,r){let s=re.join(e,n),o=re.resolve(s);if(r=r??(this._watched.has(s)||this._watched.has(o)),!this._throttle("remove",s,100))return;!r&&this._watched.size===1&&this.add(e,n,!0),this._getWatchedDir(s).getChildren().forEach(m=>this._remove(s,m));let l=this._getWatchedDir(e),c=l.has(n);l.remove(n),this._symlinkPaths.has(o)&&this._symlinkPaths.delete(o);let u=s;if(this.options.cwd&&(u=re.relative(this.options.cwd,s)),this.options.awaitWriteFinish&&this._pendingWrites.has(u)&&this._pendingWrites.get(u).cancelWait()===ge.ADD)return;this._watched.delete(s),this._watched.delete(o);let f=r?ge.UNLINK_DIR:ge.UNLINK;c&&!this._isIgnored(s)&&this._emit(f,s),this._closePath(s)}_closePath(e){this._closeFile(e);let n=re.dirname(e);this._getWatchedDir(n).remove(re.basename(e))}_closeFile(e){let n=this._closers.get(e);n&&(n.forEach(r=>r()),this._closers.delete(e))}_addPathCloser(e,n){if(!n)return;let r=this._closers.get(e);r||(r=[],this._closers.set(e,r)),r.push(n)}_readdirp(e,n){if(this.closed)return;let r={type:ge.ALL,alwaysStat:!0,lstat:!0,...n,depth:0},s=Bs(e,r);return this._streams.add(s),s.once(Js,()=>{s=void 0}),s.once(dr,()=>{s&&(this._streams.delete(s),s=void 0)}),s}};function yr(t,e={}){let n=new xn(e);return n.add(t),n}var so={watch:yr,FSWatcher:xn};var oo={fs:fl,path:hl,sha256Hex:t=>ul("sha256").update(t).digest("hex"),tmpTag:()=>process.pid,existsSync:dl,watch(t,e,n){let r=so.watch(t,{ignoreInitial:!0,depth:e.depth,ignored:e.ignored});return r.on("change",n.change),r.on("add",n.add),r.on("unlink",n.unlink),r.on("unlinkDir",n.unlinkDir),r}};import{readdirSync as pl,lstatSync as ml,readFileSync as wr,writeFileSync as gl,realpathSync as io}from"node:fs";import{join as Sr,extname as yl,sep as wl}from"node:path";var br=300,ao=5*1024*1024,lo=20*1024*1024,bl=50*1024*1024,Sl=new Set(["node_modules"]),vl=new Set([".ts",".tsx",".jsx",".mts",".cts"]);function co(t,e){let n=[],r=0,s=(o,i)=>{for(let a of pl(o)){if(a.startsWith("."))continue;let l=Sr(o,a),c;try{c=ml(l)}catch{continue}if(c.isSymbolicLink())continue;let u=i?`${i}/${a}`:a;if(c.isDirectory()){Sl.has(a)||s(l,u);continue}if(!c.isFile()||a.endsWith(".d.ts"))continue;if(n.length>=br)throw new Error(`\u6587\u4EF6\u6570\u8D85\u8FC7 ${br}\uFF0C\u8BF7\u7CBE\u7B80\u9879\u76EE\uFF08node_modules \u4E0E\u9690\u85CF\u6587\u4EF6\u5DF2\u81EA\u52A8\u8DF3\u8FC7\uFF09`);let f=yl(a).toLowerCase(),m,h=e.mimeOf(f)??"application/octet-stream";if(vl.has(f)){let g=e.transpile(wr(l,"utf8"),f,u);m=Buffer.from(g??"","utf8"),h="text/javascript"}else m=wr(l);if(m.length>ao)throw new Error(`\u5355\u6587\u4EF6\u8D85\u8FC7 5MB\uFF1A${u}`);if(r+=m.length,r>lo)throw new Error("\u9879\u76EE\u603B\u5927\u5C0F\u8D85\u8FC7 20MB\uFF0C\u65E0\u6CD5\u53D1\u5E03");n.push({path:u,content_b64:m.toString("base64"),content_type:h,size:m.length})}};if(s(t,""),!n.length)throw new Error("\u9879\u76EE\u4E3A\u7A7A\uFF0C\u6CA1\u6709\u53EF\u53D1\u5E03\u7684\u6587\u4EF6");return{files:n,totalBytes:r}}var uo=".forsion-connect.json";function fo(t){try{return JSON.parse(wr(Sr(t,uo),"utf8"))}catch{return{}}}function ho(t,e){try{gl(Sr(t,uo),JSON.stringify(e,null,2)+`
|
|
2
|
-
`,"utf8")}catch{}}function
|
|
1
|
+
var vr=null;function ro(t){vr=t}function Ee(){if(!vr)throw new Error("core host not set (call setCoreHost first)");return vr}var so=new TextEncoder,pl=new TextDecoder("utf-8",{ignoreBOM:!0}),Bt=t=>so.encode(t),pt=t=>pl.decode(t),kr=t=>typeof t=="string"?so.encode(t).length:t.length;function oo(t){let e="";for(let n=0;n<t.length;n+=32768)e+=String.fromCharCode(...t.subarray(n,n+32768));return btoa(e)}function An(t){let e=t.replace(/-/g,"+").replace(/_/g,"/");return Uint8Array.from(atob(e.padEnd(Math.ceil(e.length/4)*4,"=")),n=>n.charCodeAt(0))}async function io(t){let e=new Blob([t]).stream().pipeThrough(new CompressionStream("gzip"));return new Uint8Array(await new Response(e).arrayBuffer())}function st(t,e){if(typeof e!="string"||!e.startsWith("/"))return null;let n=String(t||"").replace(/\/+$/,"").replace(/\/api$/,"");if(!n)return null;let r,s;try{r=new URL(n),s=new URL(n+"/api"+e)}catch{return null}return r.protocol!=="http:"&&r.protocol!=="https:"||s.origin!==r.origin||!s.pathname.startsWith("/api/")?null:s.toString()}function qt(t,e,n){return t.fetch?t.fetch(e,n):fetch(e,{...n,headers:{Authorization:`Bearer ${t.token}`,...n.headers}})}async function De(t,e,n,r,s=6e4){let o=await(t.fetch??fetch)(t.base+n,{method:e,headers:{"Content-Type":"application/json","X-Project-Source":"connect",...t.token&&!t.fetch?{Authorization:`Bearer ${t.token}`}:{}},body:r===void 0?void 0:JSON.stringify(r),signal:AbortSignal.timeout(s)}),i=await o.json().catch(()=>({}));return{status:o.status,json:i}}var hl=50*1024*1024,ml=new Set(["mode","type","source","name","summary","githubRepoUrl","npmPackage","version","readme","description","tags","minAppVersion","maxAppVersion","platforms"]);function gl(t){if(!t||typeof t!="object")return null;let e=t;if(e.id!==void 0&&(typeof e.id!="string"||!/^[a-zA-Z0-9_-]{1,128}$/.test(e.id))||!e.fields||typeof e.fields!="object"||Array.isArray(e.fields))return null;let n=new FormData,r=0;for(let[s,o]of Object.entries(e.fields)){if(!ml.has(s)||typeof o!="string"||(r+=o.length,r>25e4)||e.id&&!["mode","name","summary","version","readme","description","tags","minAppVersion","maxAppVersion","platforms"].includes(s))return null;n.append(s,o)}if(e.zip!==void 0){if(!e.zip||typeof e.zip.name!="string"||!/\.zip$/i.test(e.zip.name)||!(e.zip.data instanceof Uint8Array)||!e.zip.data.byteLength||e.zip.data.byteLength>hl)return null;n.append("zip",new Blob([new Uint8Array(e.zip.data)],{type:"application/zip"}),e.zip.name.replace(/[\\/]/g,"_").slice(-255))}return{path:`${e.id?`/market/mine/${e.id}/update`:"/market/submit"}${e.dryRun===!0?"?dryRun=1":""}`,body:n}}function ao(t){t.handle("cloud:marketSubmit",async(e,n)=>{if(!t.isTrustedSender(e))return{status:0,error:"untrusted"};let r=gl(n);if(!r)return{status:400,json:{error:"invalid_request"}};let s=await t.getCloud();if(!s.token)return{status:401,error:"not_signed_in"};let o=st(s.base,r.path);if(!o)return{status:0,error:"no_cloud_url"};try{let i=await qt(s,o,{method:"POST",body:r.body,redirect:"error",signal:AbortSignal.timeout(12e4)});return{status:i.status,json:await i.json().catch(()=>null)}}catch(i){return{status:0,error:String(i?.message||i)}}})}async function lo(t){if(!t.token)return"";try{let e=await De(t,"POST","/api/auth/handoff",{},5e3);if(e.status===200&&typeof e.json?.code=="string"&&e.json.code)return`code=${encodeURIComponent(e.json.code)}`;if((e.status===404||e.status===405)&&!t.fetch)return`token=${encodeURIComponent(t.token)}`}catch{}return""}var co=["membership","credits","storefront"],uo=["monthly","quarterly","yearly"],yl=/^[A-Za-z0-9_-]{1,64}$/;function fo(t){let e={status:0,error:"untrusted"},n={ok:!1,error:"untrusted"};t.handle("auth:openAccountCenter",async(s,o)=>{if(!t.isTrustedSender(s))return n;let i=await t.getCloud(),a=i.base;if(!a)return{ok:!1};let l=o&&/^[a-z0-9-]+$/i.test(o)?`#${o}`:"",c=await lo(i),u=`${a}/account${c?`?${c}`:""}${l}`;return i.signal?.throwIfAborted(),await t.openExternal(u),{ok:!0}}),t.handle("auth:openPayCenter",async(s,o,i,a)=>{if(!t.isTrustedSender(s))return n;if(o!==void 0&&!co.includes(o))return{ok:!1,error:"invalid_tab"};if(i!==void 0&&(typeof i!="string"||!yl.test(i)))return{ok:!1,error:"invalid_plan"};if(a!==void 0&&!uo.includes(a))return{ok:!1,error:"invalid_period"};let l=(o??"membership")==="membership"&&i?`&plan=${encodeURIComponent(i)}${a?`&period=${a}`:""}`:"",c=await t.getCloud(),u=c.base;if(!u)return{ok:!1};let f=await lo(c),p=`${u}/pay?tab=${o??"membership"}${l}${f?`&${f}`:""}&redirect=${encodeURIComponent(`${u}/account`)}`;return c.signal?.throwIfAborted(),await t.openExternal(p),{ok:!0}}),t.handle("profile:publicOrigin",async s=>{if(!t.isTrustedSender(s))return n;let{base:o}=await t.getCloud();if(!o)return{ok:!1};try{let i=await fetch(`${o}/account`,{redirect:"manual",signal:AbortSignal.timeout(4e3)});i.body?.cancel().catch(()=>{});let a=i.status>=300&&i.status<400?i.headers.get("location"):null;return a&&/^https?:\/\//i.test(a)?{ok:!0,origin:new URL(a).origin}:{ok:!1}}catch{return{ok:!1}}});let r=()=>t.getCloud();t.handle("account:quota",async s=>{if(!t.isTrustedSender(s))return e;let o=await r();if(!o.token)return{status:401,json:null};try{return await De(o,"GET","/api/token-quota/my",void 0,15e3)}catch(i){return{status:0,json:{detail:String(i?.message||i)}}}}),t.handle("account:useResetCard",async(s,o)=>{if(!t.isTrustedSender(s))return e;let i=await r();if(!i.token)return{status:401,json:null};if(o!==void 0&&o!=="both")return{status:400,json:{error:"invalid_type",detail:`invalid reset card type: ${o}`}};let a=o??"both";try{return await De(i,"POST","/api/token-quota/reset-card/use",{type:a},15e3)}catch(l){return{status:0,json:{detail:String(l?.message||l)}}}}),t.handle("account:bgConvert",async(s,o)=>{if(!t.isTrustedSender(s))return e;let i=await r();if(!i.token)return{status:401,json:null};if(!Number.isInteger(o)||o<1||o>100)return{status:400,json:{error:"invalid_percent"}};try{return await De(i,"POST","/api/token-quota/background/convert",{percent:o},15e3)}catch(a){return{status:0,json:{detail:String(a?.message||a)}}}}),t.handle("account:bgAutoMain",async(s,o)=>{if(!t.isTrustedSender(s))return e;let i=await r();if(!i.token)return{status:401,json:null};if(typeof o!="boolean")return{status:400,json:{error:"invalid_request"}};try{return await De(i,"POST","/api/token-quota/background/auto-main",{enabled:o},15e3)}catch(a){return{status:0,json:{detail:String(a?.message||a)}}}}),t.handle("feedback:submit",async(s,o)=>{if(!t.isTrustedSender(s))return n;let i=await t.getCloud();if(!i.base||!i.token)return{ok:!1,error:"not-logged-in"};let a=(o?.description||"").trim();if(!a)return{ok:!1,error:"empty"};if(a.length>1e4)return{ok:!1,error:"description-too-long"};let l=[],c=!1;if(o?.sessionLogJson){let u=Bt(o.sessionLogJson);if(u.length>5*1024*1024)return{ok:!1,error:"attachment-too-large"};l.push({filename:o.sessionLogName||"tangu-session.json",mime_type:"application/json",size:u.length,data_base64:oo(u)})}try{let u=await qt(i,`${i.base}/api/feedback`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({description:a,attachments:l}),signal:AbortSignal.timeout(2e4)});if(!u.ok){let p=`HTTP ${u.status}`;try{p=(await u.json())?.detail||p}catch{}return{ok:!1,error:p}}return{ok:!0,id:(await u.json().catch(()=>({})))?.id??null,attachmentSkipped:c}}catch(u){return{ok:!1,error:u?.message||String(u)}}}),t.handle("cloud:fetch",async(s,o)=>{if(!t.isTrustedSender(s))return{status:0,error:"untrusted"};let i=o??{},a=typeof i.path=="string"?i.path:"",l=i.projectSource===void 0?null:i.projectSource;if(l!==null&&(typeof l!="string"||!/^[a-z0-9][a-z0-9-]{0,63}$/.test(l)))return{status:0,error:"bad_project_source"};let c=Math.min(12e4,Math.max(1e3,Number(i.timeoutMs)||15e3)),u=typeof i.method=="string"?i.method.toUpperCase():"GET";if(!/^(GET|POST|PUT|PATCH|DELETE)$/.test(u))return{status:0,error:"bad_method"};if(!a.startsWith("/"))return{status:0,error:"bad_path"};let f=await t.getCloud();if(!String(f.base||""))return{status:0,error:"no_cloud_url"};let p=st(f.base,a);if(!p)return{status:0,error:"bad_path"};if(!f.token)return{status:401,error:"not_signed_in"};let h=i.body!==void 0&&u!=="GET"&&u!=="DELETE",g=new AbortController,m=setTimeout(()=>g.abort(),c);try{let w=await qt(f,p,{method:u,headers:{...h?{"Content-Type":"application/json"}:{},...l?{"X-Project-Source":l}:{}},body:h?JSON.stringify(i.body):void 0,signal:g.signal});return{status:w.status,json:await w.json().catch(()=>null)}}catch(w){return{status:0,error:String(w?.message||w)}}finally{clearTimeout(m)}}),ao(t)}import{createHash as Oo}from"node:crypto";import{existsSync as cc,promises as uc,readFileSync as dc,renameSync as fc}from"node:fs";import pc from"node:path";import{EventEmitter as Vl}from"node:events";import{stat as Jl}from"node:fs";import{readdir as Yl,stat as Gl}from"node:fs/promises";import*as ie from"node:path";import{lstat as po,readdir as wl,realpath as bl,stat as Sl}from"node:fs/promises";import{join as vl,resolve as kl,sep as ho}from"node:path";import{Readable as El}from"node:stream";var je={FILE_TYPE:"files",DIR_TYPE:"directories",FILE_DIR_TYPE:"files_directories",EVERYTHING_TYPE:"all"},Rt={root:".",fileFilter:t=>!0,directoryFilter:t=>!0,type:je.FILE_TYPE,lstat:!1,depth:2147483648,alwaysStat:!1,highWaterMark:256};Object.freeze(Rt);var wo="READDIRP_RECURSIVE_ERROR",_l=new Set(["ENOENT","EPERM","EACCES","ELOOP",wo]),mo=[je.DIR_TYPE,je.EVERYTHING_TYPE,je.FILE_DIR_TYPE,je.FILE_TYPE],Cl=new Set([je.DIR_TYPE,je.EVERYTHING_TYPE,je.FILE_DIR_TYPE]),xl=new Set([je.EVERYTHING_TYPE,je.FILE_DIR_TYPE,je.FILE_TYPE]),Tl=t=>_l.has(t.code),Al=process.platform==="win32",go=t=>!0,yo=t=>{if(t===void 0)return go;if(typeof t=="function")return t;if(typeof t=="string"){let e=t.trim();return n=>n.basename===e}if(Array.isArray(t)){let e=t.map(n=>n.trim());return n=>e.some(r=>n.basename===r)}return go},Er=class extends El{parents;reading;parent;_stat;_maxDepth;_wantsDir;_wantsFile;_wantsEverything;_root;_isDirent;_statsProp;_rdOptions;_fileFilter;_directoryFilter;_relStart;constructor(e={}){super({objectMode:!0,autoDestroy:!0,highWaterMark:e.highWaterMark??Rt.highWaterMark});let n={...Rt,...e},r=n.root??Rt.root,s=n.type??Rt.type;this._fileFilter=yo(n.fileFilter),this._directoryFilter=yo(n.directoryFilter);let o=n.lstat?po:Sl;Al?this._stat=a=>o(a,{bigint:!0}):this._stat=o,this._maxDepth=n.depth!=null&&Number.isSafeInteger(n.depth)?n.depth:Rt.depth,this._wantsDir=Cl.has(s),this._wantsFile=xl.has(s),this._wantsEverything=s===je.EVERYTHING_TYPE,this._root=kl(r),this._relStart=this._root.endsWith(ho)?this._root.length:this._root.length+1,this._isDirent=!n.alwaysStat,this._statsProp=this._isDirent?"dirent":"stats",this._rdOptions={encoding:"utf8",withFileTypes:this._isDirent};let i={path:this._root,depth:1};i.pending=this._exploreDir(this._root,1),this.parents=[i],this.reading=!1,this.parent=void 0}async _read(e){if(!this.reading){this.reading=!0;try{for(;!this.destroyed&&e>0;){let n=this.parent,r=n&&n.files;if(r&&r.length>0){let{path:s,depth:o}=n,i=r.splice(0,e).map(l=>this._formatEntry(l,s)),a=this._isDirent?i:await Promise.all(i);for(let l of a){if(!l)continue;if(this.destroyed)return;let c=this._getEntryType(l);typeof c!="string"&&(c=await c),c==="directory"&&this._directoryFilter(l)?(o<=this._maxDepth&&this.parents.push({path:l.fullPath,depth:o+1}),this._wantsDir&&(this.push(l),e--)):(c==="file"||this._includeAsFile(l))&&this._fileFilter(l)&&this._wantsFile&&(this.push(l),e--)}}else{let s=this.parents.pop();if(!s){this.push(null);break}let o=s.pending??this._exploreDir(s.path,s.depth),i=this.parents[this.parents.length-1];if(i&&!i.pending&&(i.pending=this._exploreDir(i.path,i.depth)),this.parent=await o,this.destroyed)return}}}catch(n){this.destroy(n)}finally{this.reading=!1}}}async _exploreDir(e,n){let r;try{r=await wl(e,this._rdOptions)}catch(s){this._onError(s)}return{files:r,depth:n,path:e}}_formatEntry(e,n){let r=this._isDirent?e.name:e,s=vl(n,r),o={path:s.slice(this._relStart),fullPath:s,basename:r};return this._isDirent?(o.dirent=e,o):this._stat(s).then(i=>(o.stats=i,o),i=>{this._onError(i)})}_onError(e){Tl(e)&&!this.destroyed?this.emit("warn",e):this.destroy(e)}_getEntryType(e){if(!e||!(this._statsProp in e))return"";let n=e[this._statsProp];return n.isFile()?"file":n.isDirectory()?"directory":n.isSymbolicLink()?this._getSymlinkEntryType(e):""}async _getSymlinkEntryType(e){let n=e.fullPath;try{let r=await bl(n),s=await po(r);if(s.isFile())return"file";if(s.isDirectory()){let o=r.length;if(n.startsWith(r)&&n[o]===ho){let i=new Error(`Circular symlink detected: "${n}" points to "${r}"`);return i.code=wo,this._onError(i),""}return"directory"}}catch(r){this._onError(r)}return""}_includeAsFile(e){let n=e&&e[this._statsProp];return n&&this._wantsEverything&&!n.isDirectory()}};function bo(t,e={}){let n=e.entryType||e.type;if(n==="both"&&(n=je.FILE_DIR_TYPE),t){if(typeof t!="string")throw new TypeError("readdirp: root argument must be a string. Usage: readdirp(root, options)");if(n&&!mo.includes(n))throw new Error(`readdirp: Invalid type passed. Use one of ${mo.join(", ")}`)}else throw new Error("readdirp: root argument is required. Usage: readdirp(root, options)");let r={...e,root:t};return n&&(r.type=n),new Er(r)}import{watch as Il,unwatchFile as So,watchFile as Rl}from"node:fs";import{realpath as _r,lstat as Pl,open as Dl,stat as ko}from"node:fs/promises";import{type as $l}from"node:os";import*as we from"node:path";var Ol="data",Tr="end",Eo="close",$n=()=>{};var On=process.platform,Ar=On==="win32",Ml=On==="darwin",Nl=On==="linux",jl=On==="freebsd",_o=$l()==="OS400",be={ALL:"all",READY:"ready",ADD:"add",CHANGE:"change",ADD_DIR:"addDir",UNLINK:"unlink",UNLINK_DIR:"unlinkDir",RAW:"raw",ERROR:"error"},Je=be,Fl="watch",Ul={lstat:Pl,stat:ko},Et="listeners",In="errHandlers",Pt="rawEmitters",Ll=[Et,In,Pt],zl=new Set(["3dm","3ds","3g2","3gp","7z","a","aac","adp","afdesign","afphoto","afpub","ai","aif","aiff","alz","ape","apk","appimage","ar","arj","asf","au","avi","bak","baml","bh","bin","bk","bmp","btif","bz2","bzip2","cab","caf","cgm","class","cmx","cpio","cr2","cur","dat","dcm","deb","dex","djvu","dll","dmg","dng","doc","docm","docx","dot","dotm","dra","DS_Store","dsk","dts","dtshd","dvb","dwg","dxf","ecelp4800","ecelp7470","ecelp9600","egg","eol","eot","epub","exe","f4v","fbs","fh","fla","flac","flatpak","fli","flv","fpx","fst","fvt","g3","gh","gif","graffle","gz","gzip","h261","h263","h264","icns","ico","ief","img","ipa","iso","jar","jpeg","jpg","jpgv","jpm","jxr","key","ktx","lha","lib","lvp","lz","lzh","lzma","lzo","m3u","m4a","m4v","mar","mdi","mht","mid","midi","mj2","mka","mkv","mmr","mng","mobi","mov","movie","mp3","mp4","mp4a","mpeg","mpg","mpga","mxu","nef","npx","numbers","nupkg","o","odp","ods","odt","oga","ogg","ogv","otf","ott","pages","pbm","pcx","pdb","pdf","pea","pgm","pic","png","pnm","pot","potm","potx","ppa","ppam","ppm","pps","ppsm","ppsx","ppt","pptm","pptx","psd","pya","pyc","pyo","pyv","qt","rar","ras","raw","resources","rgb","rip","rlc","rmf","rmvb","rpm","rtf","rz","s3m","s7z","scpt","sgi","shar","snap","sil","sketch","slk","smv","snk","so","stl","suo","sub","swf","tar","tbz","tbz2","tga","tgz","thmx","tif","tiff","tlz","ttc","ttf","txz","udf","uvh","uvi","uvm","uvp","uvs","uvu","viv","vob","war","wav","wax","wbmp","wdp","weba","webm","webp","whl","wim","wm","wma","wmv","wmx","woff","woff2","wrm","wvx","xbm","xif","xla","xlam","xls","xlsb","xlsm","xlsx","xlt","xltm","xltx","xm","xmind","xpi","xpm","xwd","xz","z","zip","zipx"]),Hl=t=>zl.has(we.extname(t).slice(1).toLowerCase()),xr=(t,e)=>{t instanceof Set?t.forEach(e):e(t)},Wt=(t,e,n)=>{let r=t[e];r instanceof Set||(t[e]=r=new Set([r])),r.add(n)},Bl=t=>e=>{let n=t[e];n instanceof Set?n.clear():delete t[e]},Vt=(t,e,n)=>{let r=t[e];r instanceof Set?r.delete(n):r===n&&delete t[e]},Co=t=>t instanceof Set?t.size===0:!t,Rn=new Map;function vo(t,e,n,r,s){let o=(i,a)=>{n(t),s(i,a,{watchedPath:t}),a&&t!==a&&Pn(we.resolve(t,a),Et,we.join(t,a))};try{return Il(t,{persistent:e.persistent},o)}catch(i){r(i);return}}var Pn=(t,e,n,r,s)=>{let o=Rn.get(t);o&&xr(o[e],i=>{i(n,r,s)})},ql=(t,e,n,r)=>{let{listener:s,errHandler:o,rawEmitter:i}=r,a=Rn.get(e),l;if(!n.persistent)return l=vo(t,n,s,o,i),l?l.close.bind(l):void 0;if(a)Wt(a,Et,s),Wt(a,In,o),Wt(a,Pt,i);else{if(l=vo(t,n,Pn.bind(null,e,Et),o,Pn.bind(null,e,Pt)),!l)return;l.on(Je.ERROR,async c=>{let u=Pn.bind(null,e,In);if(a&&(a.watcherUnusable=!0),Ar&&c.code==="EPERM")try{await(await Dl(t,"r")).close(),u(c)}catch{}else u(c)}),a={listeners:s,errHandlers:o,rawEmitters:i,watcher:l},Rn.set(e,a)}return()=>{Vt(a,Et,s),Vt(a,In,o),Vt(a,Pt,i),Co(a.listeners)&&(a.watcher.close(),Rn.delete(e),Ll.forEach(Bl(a)),a.watcher=void 0,Object.freeze(a))}},Cr=new Map,Wl=(t,e,n,r)=>{let{listener:s,rawEmitter:o}=r,i=Cr.get(e),a=i&&i.options;return a&&(a.persistent<n.persistent||a.interval>n.interval)&&(So(e),i=void 0),i?(Wt(i,Et,s),Wt(i,Pt,o)):(i={listeners:s,rawEmitters:o,options:n,watcher:Rl(e,n,(l,c)=>{xr(i.rawEmitters,f=>{f(Je.CHANGE,e,{curr:l,prev:c})});let u=l.mtimeMs;(l.size!==c.size||u>c.mtimeMs||u===0)&&xr(i.listeners,f=>f(t,l))})},Cr.set(e,i)),()=>{Vt(i,Et,s),Vt(i,Pt,o),Co(i.listeners)&&(Cr.delete(e),So(e),i.options=i.watcher=void 0,Object.freeze(i))}},Dn=class{fsw;_boundHandleError;constructor(e){this.fsw=e,this._boundHandleError=n=>e._handleError(n)}_watchWithNodeFs(e,n){let r=this.fsw.options,s=we.dirname(e),o=we.basename(e);this.fsw._getWatchedDir(s).add(o);let a=we.resolve(e),l={persistent:r.persistent};n||(n=$n);let c;if(r.usePolling){let u=r.interval!==r.binaryInterval;l.interval=u&&Hl(o)?r.binaryInterval:r.interval,c=Wl(e,a,l,{listener:n,rawEmitter:this.fsw._emitRaw})}else c=ql(e,a,l,{listener:n,errHandler:this._boundHandleError,rawEmitter:this.fsw._emitRaw});return c}_handleFile(e,n,r){if(this.fsw.closed)return;let s=we.dirname(e),o=we.basename(e),i=this.fsw._getWatchedDir(s),a=n;if(i.has(o))return;let l=async(u,f)=>{if(this.fsw._throttle(Fl,e,5)){if(!f||f.mtimeMs===0)try{let p=await ko(e);if(this.fsw.closed)return;let h=p.atimeMs,g=p.mtimeMs;if((!h||h<=g||g!==a.mtimeMs)&&this.fsw._emit(Je.CHANGE,e,p),(Ml||Nl||jl)&&a.ino!==p.ino){this.fsw._closeFile(u),a=p;let m=this._watchWithNodeFs(e,l);m&&this.fsw._addPathCloser(u,m)}else a=p}catch{this.fsw._remove(s,o)}else if(i.has(o)){let p=f.atimeMs,h=f.mtimeMs;(!p||p<=h||h!==a.mtimeMs)&&this.fsw._emit(Je.CHANGE,e,f),a=f}}},c=this._watchWithNodeFs(e,l);if(!(r&&this.fsw.options.ignoreInitial)&&this.fsw._isntIgnored(e)){if(!this.fsw._throttle(Je.ADD,e,0))return;this.fsw._emit(Je.ADD,e,n)}return c}async _handleSymlink(e,n,r,s){if(this.fsw.closed)return;let o=e.fullPath,i=this.fsw._getWatchedDir(n);if(!this.fsw.options.followSymlinks){this.fsw._incrReadyCount();let a;try{a=await _r(r)}catch{return this.fsw._emitReady(),!0}return this.fsw.closed?void 0:(i.has(s)?this.fsw._symlinkPaths.get(o)!==a&&(this.fsw._symlinkPaths.set(o,a),this.fsw._emit(Je.CHANGE,r,e.stats)):(i.add(s),this.fsw._symlinkPaths.set(o,a),this.fsw._emit(Je.ADD,r,e.stats)),this.fsw._emitReady(),!0)}if(this.fsw._symlinkPaths.has(o))return!0;this.fsw._symlinkPaths.set(o,!0)}_handleRead(e,n,r,s,o,i,a){e=we.join(e,"");let l=s?`${e}:${s}`:e;if(a=this.fsw._throttle("readdir",l,1e3),!a)return;let c=this.fsw._getWatchedDir(r.path),u=new Set,f=this.fsw._readdirp(e,{fileFilter:p=>r.filterPath(p),directoryFilter:p=>r.filterDir(p)});if(f)return f.on(Ol,async p=>{if(this.fsw.closed){f=void 0;return}let h=p.path,g=we.join(e,h);if(u.add(h),!(p.stats.isSymbolicLink()&&await this._handleSymlink(p,e,g,h))){if(this.fsw.closed){f=void 0;return}(h===s||!s&&!c.has(h))&&(this.fsw._incrReadyCount(),g=we.join(o,we.relative(o,g)),this._addToNodeFs(g,n,r,i+1))}}).on(Je.ERROR,this._boundHandleError),new Promise((p,h)=>{if(!f)return h();f.once(Tr,()=>{if(this.fsw.closed){f=void 0;return}let g=a?a.clear():!1;p(void 0),c.getChildren().filter(m=>m!==e&&!u.has(m)).forEach(m=>{this.fsw._remove(e,m)}),f=void 0,g&&this._handleRead(e,!1,r,s,o,i,a)})})}async _handleDir(e,n,r,s,o,i,a){let l=this.fsw._getWatchedDir(we.dirname(e)),c=l.has(we.basename(e));!(r&&this.fsw.options.ignoreInitial)&&!o&&!c&&this.fsw._emit(Je.ADD_DIR,e,n),l.add(we.basename(e)),this.fsw._getWatchedDir(e);let u,f,p=this.fsw.options.depth;if((p==null||s<=p)&&!this.fsw._symlinkPaths.has(a)){if(!o&&(await this._handleRead(e,r,i,o,e,s,u),this.fsw.closed))return;f=this._watchWithNodeFs(e,(h,g)=>{g&&g.mtimeMs===0||this._handleRead(h,!1,i,o,e,s,u)})}return f}async _addToNodeFs(e,n,r,s,o){let i=this.fsw._emitReady;if(this.fsw._isIgnored(e)||this.fsw.closed)return i(),!1;let a=this.fsw._getWatchHelpers(e);r&&(a.filterPath=l=>r.filterPath(l),a.filterDir=l=>r.filterDir(l));try{let l=await Ul[a.statMethod](a.watchPath);if(this.fsw.closed)return;if(this.fsw._isIgnored(a.watchPath,l))return i(),!1;let c=this.fsw.options.followSymlinks,u;if(l.isDirectory()){let f=we.resolve(e),p=c?await _r(e):e;if(this.fsw.closed||(u=await this._handleDir(a.watchPath,l,n,s,o,a,p),this.fsw.closed))return;f!==p&&p!==void 0&&this.fsw._symlinkPaths.set(f,p)}else if(l.isSymbolicLink()){let f=c?await _r(e):e;if(this.fsw.closed)return;let p=we.dirname(a.watchPath);if(this.fsw._getWatchedDir(p).add(a.watchPath),this.fsw._emit(Je.ADD,a.watchPath,l),u=await this._handleDir(p,l,n,s,e,a,f),this.fsw.closed)return;f!==void 0&&this.fsw._symlinkPaths.set(we.resolve(e),f)}else u=this._handleFile(a.watchPath,l,n);return i(),u&&this.fsw._addPathCloser(e,u),!1}catch(l){if(this.fsw._handleError(l))return i(),e}}};var Ir="/",Kl="//",Ro=".",Xl="..",Zl="string",Ql=/\\/g,Po=/\/\//g,ec=/\..*\.(sw[px])$|~$|\.subl.*\.tmp/,tc=/^\.[/\\]/;function Mn(t){return Array.isArray(t)?t:[t]}var Rr=t=>typeof t=="object"&&t!==null&&!(t instanceof RegExp);function nc(t){return typeof t=="function"?t:typeof t=="string"?e=>t===e:t instanceof RegExp?e=>t.test(e):typeof t=="object"&&t!==null?e=>{if(t.path===e)return!0;if(t.recursive){let n=ie.relative(t.path,e);return n?!n.startsWith("..")&&!ie.isAbsolute(n):!1}return!1}:()=>!1}function rc(t){if(typeof t!="string")throw new Error("string expected");t=ie.normalize(t),t=t.replace(/\\/g,"/");let e=!1;return t.startsWith("//")&&(e=!0),t=t.replace(Po,"/"),e&&(t="/"+t),t}function xo(t,e,n){let r=rc(e);for(let s=0;s<t.length;s++){let o=t[s];if(o(r,n))return!0}return!1}function sc(t,e){if(t==null)throw new TypeError("anymatch: specify first argument");let r=Mn(t).map(s=>nc(s));return e==null?(s,o)=>xo(r,s,o):xo(r,e)}var To=t=>{let e=Mn(t).flat();if(!e.every(n=>typeof n===Zl))throw new TypeError(`Non-string provided as watch path: ${e}`);return e.map(Do)},Ao=t=>{let e=t.replace(Ql,Ir),n=!1;return e.startsWith(Kl)&&(n=!0),e=e.replace(Po,Ir),n&&(e=Ir+e),e},Do=t=>Ao(ie.normalize(Ao(t))),Io=(t="")=>e=>typeof e=="string"?Do(ie.isAbsolute(e)?e:ie.join(t,e)):e,oc=(t,e)=>ie.isAbsolute(t)?t:ie.join(e,t),ic=Object.freeze(new Set),Pr=class{path;_removeWatcher;items;constructor(e,n){this.path=e,this._removeWatcher=n,this.items=new Set}add(e){let{items:n}=this;n&&e!==Ro&&e!==Xl&&n.add(e)}async remove(e){let{items:n}=this;if(!n||(n.delete(e),n.size>0))return;let r=this.path;try{await Yl(r)}catch{this._removeWatcher&&this._removeWatcher(ie.dirname(r),ie.basename(r))}}has(e){let{items:n}=this;if(n)return n.has(e)}getChildren(){let{items:e}=this;return e?[...e.values()]:[]}dispose(){this.items.clear(),this.path="",this._removeWatcher=$n,this.items=ic,Object.freeze(this)}},ac="stat",lc="lstat",Dr=class{fsw;path;watchPath;fullWatchPath;dirParts;followSymlinks;statMethod;constructor(e,n,r){this.fsw=r;let s=e;this.path=e=e.replace(tc,""),this.watchPath=s,this.fullWatchPath=ie.resolve(s),this.dirParts=[],this.dirParts.forEach(o=>{o.length>1&&o.pop()}),this.followSymlinks=n,this.statMethod=n?ac:lc}entryPath(e){return ie.join(this.watchPath,ie.relative(this.watchPath,e.fullPath))}filterPath(e){let{stats:n}=e;if(n&&n.isSymbolicLink())return this.filterDir(e);let r=this.entryPath(e);return this.fsw._isntIgnored(r,n)&&this.fsw._hasReadPermissions(n)}filterDir(e){return this.fsw._isntIgnored(this.entryPath(e),e.stats)}},Nn=class extends Vl{closed;options;_closers;_ignoredPaths;_throttled;_streams;_symlinkPaths;_watched;_pendingWrites;_pendingUnlinks;_readyCount;_emitReady;_closePromise;_userIgnored;_readyEmitted;_emitRaw;_boundRemove;_nodeFsHandler;constructor(e={}){super(),this.closed=!1,this._closers=new Map,this._ignoredPaths=new Set,this._throttled=new Map,this._streams=new Set,this._symlinkPaths=new Map,this._watched=new Map,this._pendingWrites=new Map,this._pendingUnlinks=new Map,this._readyCount=0,this._readyEmitted=!1;let n=e.awaitWriteFinish,r={stabilityThreshold:2e3,pollInterval:100},s={persistent:!0,ignoreInitial:!1,ignorePermissionErrors:!1,interval:100,binaryInterval:300,followSymlinks:!0,usePolling:!1,atomic:!0,...e,ignored:e.ignored?Mn(e.ignored):Mn([]),awaitWriteFinish:n===!0?r:typeof n=="object"?{...r,...n}:!1};_o&&(s.usePolling=!0),s.atomic===void 0&&(s.atomic=!s.usePolling);let o=process.env.CHOKIDAR_USEPOLLING;if(o!==void 0){let l=o.toLowerCase();l==="false"||l==="0"?s.usePolling=!1:l==="true"||l==="1"?s.usePolling=!0:s.usePolling=!!l}let i=process.env.CHOKIDAR_INTERVAL;i&&(s.interval=Number.parseInt(i,10));let a=0;this._emitReady=()=>{a++,a>=this._readyCount&&(this._emitReady=$n,this._readyEmitted=!0,process.nextTick(()=>this.emit(be.READY)))},this._emitRaw=(...l)=>this.emit(be.RAW,...l),this._boundRemove=this._remove.bind(this),this.options=s,this._nodeFsHandler=new Dn(this),Object.freeze(s)}_addIgnoredPath(e){if(Rr(e)){for(let n of this._ignoredPaths)if(Rr(n)&&n.path===e.path&&n.recursive===e.recursive)return}this._ignoredPaths.add(e)}_removeIgnoredPath(e){if(this._ignoredPaths.delete(e),typeof e=="string")for(let n of this._ignoredPaths)Rr(n)&&n.path===e&&this._ignoredPaths.delete(n)}add(e,n,r){let{cwd:s}=this.options;this.closed=!1,this._closePromise=void 0;let o=To(e);return s&&(o=o.map(i=>oc(i,s))),o.forEach(i=>{this._removeIgnoredPath(i)}),this._userIgnored=void 0,this._readyCount||(this._readyCount=0),this._readyCount+=o.length,Promise.all(o.map(async i=>{let a=await this._nodeFsHandler._addToNodeFs(i,!r,void 0,0,n);return a&&this._emitReady(),a})).then(i=>{this.closed||i.forEach(a=>{a&&this.add(ie.dirname(a),ie.basename(n||a))})}),this}unwatch(e){if(this.closed)return this;let n=To(e),{cwd:r}=this.options;return n.forEach(s=>{!ie.isAbsolute(s)&&!this._closers.has(s)&&(r&&(s=ie.join(r,s)),s=ie.resolve(s)),this._closePath(s),this._addIgnoredPath(s),this._watched.has(s)&&this._addIgnoredPath({path:s,recursive:!0}),this._userIgnored=void 0}),this}close(){if(this._closePromise)return this._closePromise;this.closed=!0,this.removeAllListeners();let e=[];return this._closers.forEach(n=>n.forEach(r=>{let s=r();s instanceof Promise&&e.push(s)})),this._streams.forEach(n=>n.destroy()),this._userIgnored=void 0,this._readyCount=0,this._readyEmitted=!1,this._watched.forEach(n=>n.dispose()),this._closers.clear(),this._watched.clear(),this._streams.clear(),this._symlinkPaths.clear(),this._throttled.clear(),this._closePromise=e.length?Promise.all(e).then(()=>{}):Promise.resolve(),this._closePromise}getWatched(){let e={};return this._watched.forEach((n,r)=>{let o=(this.options.cwd?ie.relative(this.options.cwd,r):r)||Ro;e[o]=n.getChildren().sort()}),e}emitWithAll(e,n){this.emit(e,...n),e!==be.ERROR&&this.emit(be.ALL,e,...n)}async _emit(e,n,r){if(this.closed)return;let s=this.options;Ar&&(n=ie.normalize(n)),s.cwd&&(n=ie.relative(s.cwd,n));let o=[n];r!=null&&o.push(r);let i=s.awaitWriteFinish,a;if(i&&(a=this._pendingWrites.get(n)))return a.lastChange=new Date,this;if(s.atomic){if(e===be.UNLINK)return this._pendingUnlinks.set(n,[e,...o]),setTimeout(()=>{this._pendingUnlinks.forEach((l,c)=>{this.emit(...l),this.emit(be.ALL,...l),this._pendingUnlinks.delete(c)})},typeof s.atomic=="number"?s.atomic:100),this;e===be.ADD&&this._pendingUnlinks.has(n)&&(e=be.CHANGE,this._pendingUnlinks.delete(n))}if(i&&(e===be.ADD||e===be.CHANGE)&&this._readyEmitted){let l=(c,u)=>{c?(e=be.ERROR,o[0]=c,this.emitWithAll(e,o)):u&&(o.length>1?o[1]=u:o.push(u),this.emitWithAll(e,o))};return this._awaitWriteFinish(n,i.stabilityThreshold,e,l),this}if(e===be.CHANGE&&!this._throttle(be.CHANGE,n,50))return this;if(s.alwaysStat&&r===void 0&&(e===be.ADD||e===be.ADD_DIR||e===be.CHANGE)){let l=s.cwd?ie.join(s.cwd,n):n,c;try{c=await Gl(l)}catch{}if(!c||this.closed)return;o.push(c)}return this.emitWithAll(e,o),this}_handleError(e){let n=e&&e.code;return e&&n!=="ENOENT"&&n!=="ENOTDIR"&&(!this.options.ignorePermissionErrors||n!=="EPERM"&&n!=="EACCES")&&this.emit(be.ERROR,e),e||this.closed}_throttle(e,n,r){this._throttled.has(e)||this._throttled.set(e,new Map);let s=this._throttled.get(e);if(!s)throw new Error("invalid throttle");let o=s.get(n);if(o)return o.count++,!1;let i,a=()=>{let c=s.get(n),u=c?c.count:0;return s.delete(n),clearTimeout(i),c&&clearTimeout(c.timeoutObject),u};i=setTimeout(a,r);let l={timeoutObject:i,clear:a,count:0};return s.set(n,l),l}_incrReadyCount(){return this._readyCount++}_awaitWriteFinish(e,n,r,s){let o=this.options.awaitWriteFinish;if(typeof o!="object")return;let i=o.pollInterval,a,l=e;this.options.cwd&&!ie.isAbsolute(e)&&(l=ie.join(this.options.cwd,e));let c=new Date,u=this._pendingWrites;function f(p){Jl(l,(h,g)=>{if(h||!u.has(e)){h&&h.code!=="ENOENT"&&s(h);return}let m=Number(new Date);p&&g.size!==p.size&&(u.get(e).lastChange=m);let w=u.get(e);m-w.lastChange>=n?(u.delete(e),s(void 0,g)):a=setTimeout(f,i,g)})}u.has(e)||(u.set(e,{lastChange:c,cancelWait:()=>(u.delete(e),clearTimeout(a),r)}),a=setTimeout(f,i))}_isIgnored(e,n){if(this.options.atomic&&ec.test(e))return!0;if(!this._userIgnored){let{cwd:r}=this.options,o=(this.options.ignored||[]).map(Io(r)),a=[...[...this._ignoredPaths].map(Io(r)),...o];this._userIgnored=sc(a,void 0)}return this._userIgnored(e,n)}_isntIgnored(e,n){return!this._isIgnored(e,n)}_getWatchHelpers(e){return new Dr(e,this.options.followSymlinks,this)}_getWatchedDir(e){let n=ie.resolve(e);return this._watched.has(n)||this._watched.set(n,new Pr(n,this._boundRemove)),this._watched.get(n)}_hasReadPermissions(e){return this.options.ignorePermissionErrors?!0:!!(Number(e.mode)&256)}_remove(e,n,r){let s=ie.join(e,n),o=ie.resolve(s);if(r=r??(this._watched.has(s)||this._watched.has(o)),!this._throttle("remove",s,100))return;!r&&this._watched.size===1&&this.add(e,n,!0),this._getWatchedDir(s).getChildren().forEach(p=>this._remove(s,p));let l=this._getWatchedDir(e),c=l.has(n);l.remove(n),this._symlinkPaths.has(o)&&this._symlinkPaths.delete(o);let u=s;if(this.options.cwd&&(u=ie.relative(this.options.cwd,s)),this.options.awaitWriteFinish&&this._pendingWrites.has(u)&&this._pendingWrites.get(u).cancelWait()===be.ADD)return;this._watched.delete(s),this._watched.delete(o);let f=r?be.UNLINK_DIR:be.UNLINK;c&&!this._isIgnored(s)&&this._emit(f,s),this._closePath(s)}_closePath(e){this._closeFile(e);let n=ie.dirname(e);this._getWatchedDir(n).remove(ie.basename(e))}_closeFile(e){let n=this._closers.get(e);n&&(n.forEach(r=>r()),this._closers.delete(e))}_addPathCloser(e,n){if(!n)return;let r=this._closers.get(e);r||(r=[],this._closers.set(e,r)),r.push(n)}_readdirp(e,n){if(this.closed)return;let r={type:be.ALL,alwaysStat:!0,lstat:!0,...n,depth:0},s=bo(e,r);return this._streams.add(s),s.once(Eo,()=>{s=void 0}),s.once(Tr,()=>{s&&(this._streams.delete(s),s=void 0)}),s}};function $r(t,e={}){let n=new Nn(e);return n.add(t),n}var $o={watch:$r,FSWatcher:Nn};var Or;function Mo(t){Or=t}var No={fs:uc,path:pc,sha256Hex:t=>Oo("sha256").update(t).digest("hex"),tmpTag:()=>process.pid,existsSync:cc,async compareAndReplace(t,e,n,r){if(!Or)throw new Error("This host needs the shared content write lock for safe cloud downloads");let s=!1;return await Or(e,()=>{if(!r())return;let o=null;try{o=Oo("sha256").update(dc(e)).digest("hex")}catch(i){if(i.code!=="ENOENT")throw i}o===n&&(fc(t,e),s=!0)}),s},watch(t,e,n){let r=$o.watch(t,{ignoreInitial:!0,depth:e.depth,ignored:e.ignored});return r.on("change",n.change),r.on("add",n.add),r.on("unlink",n.unlink),r.on("unlinkDir",n.unlinkDir),r}};import{readdirSync as hc,lstatSync as mc,readFileSync as Mr,writeFileSync as gc,realpathSync as jo}from"node:fs";import{join as jr,extname as yc,sep as wc}from"node:path";var Nr=300,Fo=5*1024*1024,Uo=20*1024*1024,bc=50*1024*1024,Sc=new Set(["node_modules"]),vc=new Set([".ts",".tsx",".jsx",".mts",".cts"]);function Lo(t,e){let n=[],r=0,s=(o,i)=>{for(let a of hc(o)){if(a.startsWith("."))continue;let l=jr(o,a),c;try{c=mc(l)}catch{continue}if(c.isSymbolicLink())continue;let u=i?`${i}/${a}`:a;if(c.isDirectory()){Sc.has(a)||s(l,u);continue}if(!c.isFile()||a.endsWith(".d.ts"))continue;if(n.length>=Nr)throw new Error(`\u6587\u4EF6\u6570\u8D85\u8FC7 ${Nr}\uFF0C\u8BF7\u7CBE\u7B80\u9879\u76EE\uFF08node_modules \u4E0E\u9690\u85CF\u6587\u4EF6\u5DF2\u81EA\u52A8\u8DF3\u8FC7\uFF09`);let f=yc(a).toLowerCase(),p,h=e.mimeOf(f)??"application/octet-stream";if(vc.has(f)){let g=e.transpile(Mr(l,"utf8"),f,u);p=Buffer.from(g??"","utf8"),h="text/javascript"}else p=Mr(l);if(p.length>Fo)throw new Error(`\u5355\u6587\u4EF6\u8D85\u8FC7 5MB\uFF1A${u}`);if(r+=p.length,r>Uo)throw new Error("\u9879\u76EE\u603B\u5927\u5C0F\u8D85\u8FC7 20MB\uFF0C\u65E0\u6CD5\u53D1\u5E03");n.push({path:u,content_b64:p.toString("base64"),content_type:h,size:p.length})}};if(s(t,""),!n.length)throw new Error("\u9879\u76EE\u4E3A\u7A7A\uFF0C\u6CA1\u6709\u53EF\u53D1\u5E03\u7684\u6587\u4EF6");return{files:n,totalBytes:r}}var zo=".forsion-connect.json";function Ho(t){try{return JSON.parse(Mr(jr(t,zo),"utf8"))}catch{return{}}}function Bo(t,e){try{gc(jr(t,zo),JSON.stringify(e,null,2)+`
|
|
2
|
+
`,"utf8")}catch{}}function qo(t){let e={"/__forsion/chat":{method:"POST",path:"/api/chat/completions",auth:!0},"/__forsion/images":{method:"POST",path:"/api/images/generations",auth:!0},"/__forsion/user":{method:"GET",path:"/api/brain/users/me",auth:!0},"/__forsion/models":{method:"GET",path:"/api/models",auth:!1},"/__forsion/config":{method:"GET",path:"/api/connect/config",auth:!1},"/__forsion/agent":{method:"POST",path:"/api/agent/runs",auth:!0,agentRun:!0}};function n(r){if(e[r])return e[r];let s="/__forsion/agent-events/";if(r.startsWith(s)){let o=r.slice(s.length);if(/^[A-Za-z0-9-]{1,64}$/.test(o))return{method:"GET",path:`/api/agent/runs/${o}/events`,auth:!0,timeoutMs:9e5}}}return async(r,s)=>{let[o,i]=(r.url||"").split("?"),a=(g,m)=>{s.headersSent||(s.statusCode=g,s.setHeader("Content-Type","application/json")),s.end(JSON.stringify({detail:m}))},l=n(o);if(!l)return a(404,"unknown connect endpoint");if((r.method||"GET")!==l.method)return a(405,"method not allowed");let c="",u="";try{({base:c,token:u}=await t())}catch{}if(!c)return a(502,"\u672A\u914D\u7F6E Forsion \u4E91\u7AEF\u5730\u5740");if(l.auth&&!u)return a(401,"\u8BF7\u5148\u5728 Forsion Desktop \u4E2D\u767B\u5F55 Forsion \u8D26\u53F7");let f;if(l.method==="POST"){let g=[],m=0;try{for await(let w of r){if(m+=w.length,m>bc)return r.destroy(),a(413,"\u8BF7\u6C42\u4F53\u8FC7\u5927");g.push(w)}}catch(w){return a(400,`\u8BF7\u6C42\u4F53\u8BFB\u53D6\u5931\u8D25\uFF1A${w?.message||String(w)}`)}f=Buffer.concat(g)}if(l.agentRun){let g;try{g=JSON.parse((f||Buffer.alloc(0)).toString("utf8")||"{}")}catch{return a(400,"agent \u8BF7\u6C42\u4F53\u5FC5\u987B\u662F JSON")}f=Buffer.from(JSON.stringify({session_id:typeof g.session_id=="string"?g.session_id:"",message:typeof g.message=="string"?g.message:"",app_id:"connect",agent_config:{}}))}let p=new AbortController,h=setTimeout(()=>p.abort(new Error("proxy timeout")),l.timeoutMs??3e5);r.on("close",()=>p.abort());try{let g=await fetch(c+l.path+(i?`?${i}`:""),{method:l.method,headers:{"Content-Type":"application/json","X-Project-Source":"connect",...u?{Authorization:`Bearer ${u}`}:{}},body:f&&f.length?new Uint8Array(f):void 0,signal:p.signal});if(s.statusCode=g.status,s.setHeader("Content-Type",g.headers.get("content-type")||"application/json"),s.setHeader("Cache-Control","no-store"),g.body)for await(let m of g.body)s.write(m);s.end()}catch(g){let m=`\u4E91\u7AEF\u8BF7\u6C42\u4E2D\u65AD\uFF1A${g?.message||String(g)}`;if(s.headersSent){try{s.write(`data: ${JSON.stringify({error:m})}
|
|
3
3
|
|
|
4
|
-
`)}catch{}s.end()}else a(502,
|
|
4
|
+
`)}catch{}s.end()}else a(502,m)}finally{clearTimeout(h)}}}var Wo=`
|
|
5
5
|
(function () {
|
|
6
6
|
'use strict';
|
|
7
7
|
if (window.forsion) return;
|
|
@@ -190,7 +190,7 @@ var or=null;function Is(t){or=t}function Se(){if(!or)throw new Error("core host
|
|
|
190
190
|
ai: { chat: chat, agent: agentRun, generateImage: generateImage }
|
|
191
191
|
};
|
|
192
192
|
})();
|
|
193
|
-
`,kl=t=>({transpile:(e,n,r)=>t.transpileForServe(e,n,r),mimeOf:e=>t.mimeOf(e)});function vr(t){let e=t;return typeof e.projectsRoot=="function"&&typeof e.transpileForServe=="function"&&typeof e.mimeOf=="function"&&typeof e.setPreviewHooks=="function"}function kr(t){t.setPreviewHooks({sdkJs:mo,proxy:po(()=>t.getCloud())}),t.handle("connect:meta",(e,n)=>typeof n=="string"&&n?fo(n):{}),t.handle("connect:list",async()=>{let e=await t.getCloud();if(!e.token)return{ok:!1,code:"not_logged_in",detail:"\u8BF7\u5148\u767B\u5F55 Forsion \u8D26\u53F7"};try{let{status:n,json:r}=await Ae(e,"GET","/api/connect/apps");return n===401||n===403?{ok:!1,code:"not_logged_in",detail:"\u767B\u5F55\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u767B\u5F55"}:n!==200?{ok:!1,code:"error",detail:r?.detail||`HTTP ${n}`}:{ok:!0,base:e.base,...r}}catch(n){return{ok:!1,code:"error",detail:n?.message||String(n)}}}),t.handle("connect:publish",async(e,n)=>{if(!n||typeof n.dir!="string"||!n.dir||!n.name||!n.slug||!n.entry)return{ok:!1,code:"error",detail:"\u53C2\u6570\u4E0D\u5B8C\u6574"};let r;try{let o=io(t.projectsRoot());if(r=io(n.dir),r!==o&&!r.startsWith(o+wl))return{ok:!1,code:"error",detail:"\u53EA\u80FD\u53D1\u5E03 Coding Space \u9879\u76EE\u76EE\u5F55"}}catch{return{ok:!1,code:"error",detail:"\u9879\u76EE\u76EE\u5F55\u4E0D\u5B58\u5728\u6216\u65E0\u6CD5\u8BBF\u95EE"}}let s=await t.getCloud();if(!s.token)return{ok:!1,code:"not_logged_in",detail:"\u8BF7\u5148\u767B\u5F55 Forsion \u8D26\u53F7"};try{let{files:o,totalBytes:i}=co(r,kl(t));if(!o.some(c=>c.path===n.entry))return{ok:!1,code:"error",detail:`\u5165\u53E3\u6587\u4EF6\u4E0D\u5B58\u5728:${n.entry}`};let{status:a,json:l}=await Ae(s,"POST","/api/connect/apps",{slug:n.slug,name:n.name,entry:n.entry,files:o},3e5);return a===401?{ok:!1,code:"not_logged_in",detail:"\u767B\u5F55\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u767B\u5F55"}:a!==200?{ok:!1,code:l?.code||"error",detail:l?.detail||`HTTP ${a}`,used:l?.used,limit:l?.limit}:(ho(r,{slug:String(l.slug)}),{ok:!0,slug:l.slug,handle:l.handle,url:`${s.base}${l.url}`,totalBytes:i})}catch(o){return{ok:!1,code:"error",detail:o?.message||String(o)}}}),t.handle("connect:unpublish",async(e,n)=>{if(!n||typeof n!="string")return{ok:!1,code:"error",detail:"\u53C2\u6570\u4E0D\u5B8C\u6574"};let r=await t.getCloud();if(!r.token)return{ok:!1,code:"not_logged_in",detail:"\u8BF7\u5148\u767B\u5F55 Forsion \u8D26\u53F7"};try{let{status:s,json:o}=await Ae(r,"DELETE",`/api/connect/apps/${encodeURIComponent(n)}`);return s===401||s===403?{ok:!1,code:"not_logged_in",detail:"\u767B\u5F55\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u767B\u5F55"}:s!==200&&s!==404?{ok:!1,code:"error",detail:o?.detail||`HTTP ${s}`}:{ok:!0}}catch(s){return{ok:!1,code:"error",detail:s?.message||String(s)}}}),t.handle("connect:listingApply",async(e,n)=>{if(!n||typeof n.slug!="string"||!n.slug||typeof n.summary!="string"||!n.summary.trim())return{ok:!1,code:"error",detail:"\u53C2\u6570\u4E0D\u5B8C\u6574"};let r=await t.getCloud();if(!r.token)return{ok:!1,code:"not_logged_in",detail:"\u8BF7\u5148\u767B\u5F55 Forsion \u8D26\u53F7"};try{let{status:s,json:o}=await Ae(r,"PUT",`/api/connect/apps/${encodeURIComponent(n.slug)}/listing`,{summary:n.summary});return s===401?{ok:!1,code:"not_logged_in",detail:"\u767B\u5F55\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u767B\u5F55"}:s!==200?{ok:!1,code:o?.code||"error",detail:o?.detail||`HTTP ${s}`}:{ok:!0,status:o.status}}catch(s){return{ok:!1,code:"error",detail:s?.message||String(s)}}}),t.handle("connect:listingWithdraw",async(e,n)=>{if(!n||typeof n!="string")return{ok:!1,code:"error",detail:"\u53C2\u6570\u4E0D\u5B8C\u6574"};let r=await t.getCloud();if(!r.token)return{ok:!1,code:"not_logged_in",detail:"\u8BF7\u5148\u767B\u5F55 Forsion \u8D26\u53F7"};try{let{status:s,json:o}=await Ae(r,"DELETE",`/api/connect/apps/${encodeURIComponent(n)}/listing`);return s===401?{ok:!1,code:"not_logged_in",detail:"\u767B\u5F55\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u767B\u5F55"}:s!==200&&s!==404?{ok:!1,code:"error",detail:o?.detail||`HTTP ${s}`}:{ok:!0}}catch(s){return{ok:!1,code:"error",detail:s?.message||String(s)}}}),t.handle("connect:store",async()=>{let e=await t.getCloud();try{let{status:n,json:r}=await Ae(e,"GET","/api/connect/store");return n!==200?{ok:!1,detail:r?.detail||`HTTP ${n}`}:{ok:!0,base:e.base,items:Array.isArray(r.items)?r.items:[]}}catch(n){return{ok:!1,detail:n?.message||String(n)}}}),t.log("[forsion-extend] connect handlers registered")}import{createHash as El}from"node:crypto";import{hostname as _l}from"node:os";async function zt(t,e){if(!t||!e)return{status:"offline"};let n=t.replace(/\/+$/,"");try{let r=await fetch(`${n}/api/brain/users/me`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(5e3)});if(r.status===401||r.status===403)return{status:(r.headers.get("content-type")||"").includes("application/json")?"expired":"offline"};if(!r.ok)return{status:"offline"};let s=await r.json();if(!s)return{status:"offline"};let o=s.avatar||s.avatarUrl||s.avatar_url||void 0;return o&&/^\/(?!\/)/.test(o)&&(o=n+o),{status:"ok",user:{username:s.username||s.nickname||void 0,nickname:s.nickname||void 0,avatar:o,membershipTier:s.membershipTier||s.membership_tier||void 0}}}catch{return{status:"offline"}}}var go=t=>`${t.seq}:${t.hash}`,Tn=(t=_l())=>{let e=t.replace(/\.local$/i,"").trim();return e?encodeURIComponent(e):null},Cl=t=>El("sha256").update(t).digest("hex");function Er(t){if(t===null)return{baseSeq:0,baseHash:null};if(typeof t!="string")return;let e=t.indexOf(":"),n=Number(e===-1?t:t.slice(0,e));if(!Number.isInteger(n)||n<=0)return;let r=e===-1?"":t.slice(e+1);return{baseSeq:n,baseHash:/^[0-9a-f]{64}$/.test(r)?r:null}}function An(t){let e=t.baseUrl.replace(/\/+$/,""),n=o=>`${e}/api/remotesync/vaults/${encodeURIComponent(t.vault)}${o}`,r=Tn(),s=async(o,i)=>{let a=t.getToken();if(!a)throw new Error("penzor-not-logged-in");let l=await fetch(o,{...i,headers:{...i.headers,Authorization:`Bearer ${a}`}});if(l.status===409){let c=await l.json().catch(()=>({}));throw new Error(`cas-conflict ${String(c.code??"")}: seq=${String(c.seq??"?")}`)}if(!l.ok){let c=await l.text().catch(()=>"");throw new Error(`penzor ${i.method??"GET"} ${l.status}: ${c.slice(0,200)}`)}return l};return{kind:"penzor",async walk(o){let i=await s(n("/manifest"),{method:"GET",signal:o}),{files:a}=await i.json();return a.map(l=>({key:l.path,size:l.size,mtimeMs:l.mtimeMs,id:go(l),hash:l.hash}))},async readFile(o,i){let l=await(await s(n(`/file?path=${encodeURIComponent(o)}`),{method:"GET",signal:i})).json(),c=await fetch(l.url,{signal:i});if(!c.ok)throw new Error(`penzor blob GET ${c.status}: ${o}`);let u=Buffer.from(await c.arrayBuffer());if(Cl(u)!==l.hash)throw new Error(`penzor hash mismatch: ${o}`);return u},async writeFile(o,i,a,l,c){let u=Er(c),f=new URLSearchParams({path:o,mtimeMs:String(Math.floor(a)||0)});u&&(f.set("baseSeq",String(u.baseSeq)),u.baseHash&&f.set("baseHash",u.baseHash));let h=await(await s(n(`/file?${f.toString()}`),{method:"PUT",body:new Uint8Array(i),headers:{"Content-Type":"application/octet-stream",...r?{"X-Forsion-Device":r}:{}},signal:l})).json();return{key:o,size:h.size,mtimeMs:h.mtimeMs,id:go(h)}},async rm(o,i,a){let l=Er(a),c=new URLSearchParams({path:o});l&&l.baseSeq>0&&(c.set("baseSeq",String(l.baseSeq)),l.baseHash&&c.set("baseHash",l.baseHash)),await s(n(`/file?${c.toString()}`),{method:"DELETE",signal:i})},async check(){try{return await s(n("/manifest"),{method:"GET"}),{ok:!0}}catch(o){return{ok:!1,error:String(o?.message||o)}}}}}var In="forsion-diagnostics",wo=50*1024*1024,yo=new Map;async function xl(t,e){let n=yo.get(e);if(n)return{id:n};let r=await zt(t,e);if(r.status==="offline")return{error:"penzor-offline"};if(r.status!=="ok")return{error:"penzor-not-logged-in"};let s=r.user?.username?.trim();return s?(yo.set(e,s),{id:s}):{error:"penzor-auth-unverified"}}var _r=t=>typeof t.registerRemoteSyncBackend=="function"&&typeof t.readCreds=="function";function Cr(t){t.registerRemoteSyncBackend("penzor",async e=>{let n=t.readCreds();if(!n.token||!n.cloudUrl)return{error:"penzor-not-logged-in"};let r=e?.vault,s=(typeof r=="string"?r:"default").trim()||"default";if(!/^[A-Za-z0-9_-]{1,64}$/.test(s)||s===In)return{error:"penzor-bad-vault"};let o=await xl(n.cloudUrl,n.token);if("error"in o)return o;let i=n.token;return{remote:An({baseUrl:n.cloudUrl,vault:s,getToken:()=>i}),fingerprint:`penzor:${n.cloudUrl.replace(/\/+$/,"")}|u:${o.id}|${s}`,maxFileBytes:wo}}),t.log('[forsion-extend] remote-sync backend "penzor" registered')}import{createReadStream as Al}from"node:fs";import{access as Il,link as Pl,lstat as Rl,mkdir as Dl,open as $l,readdir as Ol,rename as Ml,stat as Co,unlink as Ar}from"node:fs/promises";import{request as Nl}from"node:http";import{request as jl}from"node:https";import{homedir as Ul}from"node:os";import{basename as xo,extname as Fl,isAbsolute as Ll,join as qt}from"node:path";import{randomUUID as Rn}from"node:crypto";var Ht=52428800;var bo=["bytes","signed","text"],So=/^[A-Za-z0-9_-]{1,64}$/,vo=/^[a-z0-9][a-z0-9-]{0,63}$/;function Pn(t){if(typeof t!="string")return null;let n=(t.split(/[\\/]/).pop()??"").replace(/[\u0000-\u001f<>:"|?*]/g,"").trim().slice(0,200);return n&&n!=="."&&n!==".."?n:null}var Tl={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".heic":"image/heic",".svg":"image/svg+xml",".pdf":"application/pdf",".txt":"text/plain",".md":"text/markdown",".json":"application/json",".csv":"text/csv",".mp4":"video/mp4",".mov":"video/quicktime",".mp3":"audio/mpeg",".zip":"application/zip",".docx":"application/vnd.openxmlformats-officedocument.wordprocessingml.document",".xlsx":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",".pptx":"application/vnd.openxmlformats-officedocument.presentationml.presentation"};function ko(t){let e=t.lastIndexOf(".");return Tl[e>0?t.slice(e).toLowerCase():""]??"application/octet-stream"}function Eo(t,e,n,r){let s=n.replace(/[^\x20-\x7e]/g,"_").replace(/["\\]/g,"_")||"file",o=encodeURIComponent(n).replace(/['()*]/g,a=>`%${a.charCodeAt(0).toString(16).toUpperCase()}`),i="";for(let[a,l]of Object.entries(e))i+=`--${t}\r
|
|
193
|
+
`,kc=t=>({transpile:(e,n,r)=>t.transpileForServe(e,n,r),mimeOf:e=>t.mimeOf(e)});function Fr(t){let e=t;return typeof e.projectsRoot=="function"&&typeof e.transpileForServe=="function"&&typeof e.mimeOf=="function"&&typeof e.setPreviewHooks=="function"}function Ur(t){t.setPreviewHooks({sdkJs:Wo,proxy:qo(()=>t.getCloud())}),t.handle("connect:meta",(e,n)=>typeof n=="string"&&n?Ho(n):{}),t.handle("connect:list",async()=>{let e=await t.getCloud();if(!e.token)return{ok:!1,code:"not_logged_in",detail:"\u8BF7\u5148\u767B\u5F55 Forsion \u8D26\u53F7"};try{let{status:n,json:r}=await De(e,"GET","/api/connect/apps");return n===401||n===403?{ok:!1,code:"not_logged_in",detail:"\u767B\u5F55\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u767B\u5F55"}:n!==200?{ok:!1,code:"error",detail:r?.detail||`HTTP ${n}`}:{ok:!0,base:e.base,...r}}catch(n){return{ok:!1,code:"error",detail:n?.message||String(n)}}}),t.handle("connect:publish",async(e,n)=>{if(!n||typeof n.dir!="string"||!n.dir||!n.name||!n.slug||!n.entry)return{ok:!1,code:"error",detail:"\u53C2\u6570\u4E0D\u5B8C\u6574"};let r;try{let o=jo(t.projectsRoot());if(r=jo(n.dir),r!==o&&!r.startsWith(o+wc))return{ok:!1,code:"error",detail:"\u53EA\u80FD\u53D1\u5E03 Coding Space \u9879\u76EE\u76EE\u5F55"}}catch{return{ok:!1,code:"error",detail:"\u9879\u76EE\u76EE\u5F55\u4E0D\u5B58\u5728\u6216\u65E0\u6CD5\u8BBF\u95EE"}}let s=await t.getCloud();if(!s.token)return{ok:!1,code:"not_logged_in",detail:"\u8BF7\u5148\u767B\u5F55 Forsion \u8D26\u53F7"};try{let{files:o,totalBytes:i}=Lo(r,kc(t));if(!o.some(c=>c.path===n.entry))return{ok:!1,code:"error",detail:`\u5165\u53E3\u6587\u4EF6\u4E0D\u5B58\u5728:${n.entry}`};let{status:a,json:l}=await De(s,"POST","/api/connect/apps",{slug:n.slug,name:n.name,entry:n.entry,files:o},3e5);return a===401?{ok:!1,code:"not_logged_in",detail:"\u767B\u5F55\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u767B\u5F55"}:a!==200?{ok:!1,code:l?.code||"error",detail:l?.detail||`HTTP ${a}`,used:l?.used,limit:l?.limit}:(Bo(r,{slug:String(l.slug)}),{ok:!0,slug:l.slug,handle:l.handle,url:`${s.base}${l.url}`,totalBytes:i})}catch(o){return{ok:!1,code:"error",detail:o?.message||String(o)}}}),t.handle("connect:unpublish",async(e,n)=>{if(!n||typeof n!="string")return{ok:!1,code:"error",detail:"\u53C2\u6570\u4E0D\u5B8C\u6574"};let r=await t.getCloud();if(!r.token)return{ok:!1,code:"not_logged_in",detail:"\u8BF7\u5148\u767B\u5F55 Forsion \u8D26\u53F7"};try{let{status:s,json:o}=await De(r,"DELETE",`/api/connect/apps/${encodeURIComponent(n)}`);return s===401||s===403?{ok:!1,code:"not_logged_in",detail:"\u767B\u5F55\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u767B\u5F55"}:s!==200&&s!==404?{ok:!1,code:"error",detail:o?.detail||`HTTP ${s}`}:{ok:!0}}catch(s){return{ok:!1,code:"error",detail:s?.message||String(s)}}}),t.handle("connect:listingApply",async(e,n)=>{if(!n||typeof n.slug!="string"||!n.slug||typeof n.summary!="string"||!n.summary.trim())return{ok:!1,code:"error",detail:"\u53C2\u6570\u4E0D\u5B8C\u6574"};let r=await t.getCloud();if(!r.token)return{ok:!1,code:"not_logged_in",detail:"\u8BF7\u5148\u767B\u5F55 Forsion \u8D26\u53F7"};try{let{status:s,json:o}=await De(r,"PUT",`/api/connect/apps/${encodeURIComponent(n.slug)}/listing`,{summary:n.summary});return s===401?{ok:!1,code:"not_logged_in",detail:"\u767B\u5F55\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u767B\u5F55"}:s!==200?{ok:!1,code:o?.code||"error",detail:o?.detail||`HTTP ${s}`}:{ok:!0,status:o.status}}catch(s){return{ok:!1,code:"error",detail:s?.message||String(s)}}}),t.handle("connect:listingWithdraw",async(e,n)=>{if(!n||typeof n!="string")return{ok:!1,code:"error",detail:"\u53C2\u6570\u4E0D\u5B8C\u6574"};let r=await t.getCloud();if(!r.token)return{ok:!1,code:"not_logged_in",detail:"\u8BF7\u5148\u767B\u5F55 Forsion \u8D26\u53F7"};try{let{status:s,json:o}=await De(r,"DELETE",`/api/connect/apps/${encodeURIComponent(n)}/listing`);return s===401?{ok:!1,code:"not_logged_in",detail:"\u767B\u5F55\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u767B\u5F55"}:s!==200&&s!==404?{ok:!1,code:"error",detail:o?.detail||`HTTP ${s}`}:{ok:!0}}catch(s){return{ok:!1,code:"error",detail:s?.message||String(s)}}}),t.handle("connect:store",async()=>{let e=await t.getCloud();try{let{status:n,json:r}=await De(e,"GET","/api/connect/store");return n!==200?{ok:!1,detail:r?.detail||`HTTP ${n}`}:{ok:!0,base:e.base,items:Array.isArray(r.items)?r.items:[]}}catch(n){return{ok:!1,detail:n?.message||String(n)}}}),t.log("[forsion-extend] connect handlers registered")}import{createHash as Ec}from"node:crypto";import{hostname as _c}from"node:os";async function Jt(t,e){if(!t||!e)return{status:"offline"};let n=t.replace(/\/+$/,"");try{let r=await fetch(`${n}/api/brain/users/me`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(5e3)});if(r.status===401||r.status===403)return{status:(r.headers.get("content-type")||"").includes("application/json")?"expired":"offline"};if(!r.ok)return{status:"offline"};let s=await r.json();if(!s)return{status:"offline"};let o=s.avatar||s.avatarUrl||s.avatar_url||void 0;return o&&/^\/(?!\/)/.test(o)&&(o=n+o),{status:"ok",user:{username:s.username||s.nickname||void 0,nickname:s.nickname||void 0,avatar:o,membershipTier:s.membershipTier||s.membership_tier||void 0}}}catch{return{status:"offline"}}}var Vo=t=>`${t.seq}:${t.hash}`,jn=(t=_c())=>{let e=t.replace(/\.local$/i,"").trim();return e?encodeURIComponent(e):null},Cc=t=>Ec("sha256").update(t).digest("hex");function Lr(t){if(t===null)return{baseSeq:0,baseHash:null};if(typeof t!="string")return;let e=t.indexOf(":"),n=Number(e===-1?t:t.slice(0,e));if(!Number.isInteger(n)||n<=0)return;let r=e===-1?"":t.slice(e+1);return{baseSeq:n,baseHash:/^[0-9a-f]{64}$/.test(r)?r:null}}function Fn(t){let e=t.baseUrl.replace(/\/+$/,""),n=o=>`${e}/api/remotesync/vaults/${encodeURIComponent(t.vault)}${o}`,r=jn(),s=async(o,i)=>{let a=t.getToken();if(!a)throw new Error("penzor-not-logged-in");let l=await fetch(o,{...i,headers:{...i.headers,Authorization:`Bearer ${a}`}});if(l.status===409){let c=await l.json().catch(()=>({}));throw new Error(`cas-conflict ${String(c.code??"")}: seq=${String(c.seq??"?")}`)}if(!l.ok){let c=await l.text().catch(()=>"");throw new Error(`penzor ${i.method??"GET"} ${l.status}: ${c.slice(0,200)}`)}return l};return{kind:"penzor",async walk(o){let i=await s(n("/manifest"),{method:"GET",signal:o}),{files:a}=await i.json();return a.map(l=>({key:l.path,size:l.size,mtimeMs:l.mtimeMs,id:Vo(l),hash:l.hash}))},async readFile(o,i){let l=await(await s(n(`/file?path=${encodeURIComponent(o)}`),{method:"GET",signal:i})).json(),c=await fetch(l.url,{signal:i});if(!c.ok)throw new Error(`penzor blob GET ${c.status}: ${o}`);let u=Buffer.from(await c.arrayBuffer());if(Cc(u)!==l.hash)throw new Error(`penzor hash mismatch: ${o}`);return u},async writeFile(o,i,a,l,c){let u=Lr(c),f=new URLSearchParams({path:o,mtimeMs:String(Math.floor(a)||0)});u&&(f.set("baseSeq",String(u.baseSeq)),u.baseHash&&f.set("baseHash",u.baseHash));let h=await(await s(n(`/file?${f.toString()}`),{method:"PUT",body:new Uint8Array(i),headers:{"Content-Type":"application/octet-stream",...r?{"X-Forsion-Device":r}:{}},signal:l})).json();return{key:o,size:h.size,mtimeMs:h.mtimeMs,id:Vo(h)}},async rm(o,i,a){let l=Lr(a),c=new URLSearchParams({path:o});l&&l.baseSeq>0&&(c.set("baseSeq",String(l.baseSeq)),l.baseHash&&c.set("baseHash",l.baseHash)),await s(n(`/file?${c.toString()}`),{method:"DELETE",signal:i})},async check(){try{return await s(n("/manifest"),{method:"GET"}),{ok:!0}}catch(o){return{ok:!1,error:String(o?.message||o)}}}}}var Un="forsion-diagnostics",Yo=50*1024*1024,Jo=new Map;async function xc(t,e){let n=Jo.get(e);if(n)return{id:n};let r=await Jt(t,e);if(r.status==="offline")return{error:"penzor-offline"};if(r.status!=="ok")return{error:"penzor-not-logged-in"};let s=r.user?.username?.trim();return s?(Jo.set(e,s),{id:s}):{error:"penzor-auth-unverified"}}var zr=t=>typeof t.registerRemoteSyncBackend=="function"&&typeof t.readCreds=="function";function Hr(t){t.registerRemoteSyncBackend("penzor",async e=>{let n=t.readCreds();if(!n.token||!n.cloudUrl)return{error:"penzor-not-logged-in"};let r=e?.vault,s=(typeof r=="string"?r:"default").trim()||"default";if(!/^[A-Za-z0-9_-]{1,64}$/.test(s)||s===Un)return{error:"penzor-bad-vault"};let o=await xc(n.cloudUrl,n.token);if("error"in o)return o;let i=n.token;return{remote:Fn({baseUrl:n.cloudUrl,vault:s,getToken:()=>i}),fingerprint:`penzor:${n.cloudUrl.replace(/\/+$/,"")}|u:${o.id}|${s}`,maxFileBytes:Yo}}),t.log('[forsion-extend] remote-sync backend "penzor" registered')}import{createReadStream as Ac}from"node:fs";import{access as Ic,link as Rc,lstat as Pc,mkdir as Dc,open as $c,readdir as Oc,rename as Mc,stat as ti,unlink as Wr}from"node:fs/promises";import{request as Nc}from"node:http";import{request as jc}from"node:https";import{homedir as Fc}from"node:os";import{basename as ni,extname as Uc,isAbsolute as Lc,join as Gt}from"node:path";import{randomUUID as zn}from"node:crypto";var Yt=52428800;var Go=["bytes","signed","text"],Ko=/^[A-Za-z0-9_-]{1,64}$/,Xo=/^[a-z0-9][a-z0-9-]{0,63}$/;function Ln(t){if(typeof t!="string")return null;let n=(t.split(/[\\/]/).pop()??"").replace(/[\u0000-\u001f<>:"|?*]/g,"").trim().slice(0,200);return n&&n!=="."&&n!==".."?n:null}var Tc={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".heic":"image/heic",".svg":"image/svg+xml",".pdf":"application/pdf",".txt":"text/plain",".md":"text/markdown",".json":"application/json",".csv":"text/csv",".mp4":"video/mp4",".mov":"video/quicktime",".mp3":"audio/mpeg",".zip":"application/zip",".docx":"application/vnd.openxmlformats-officedocument.wordprocessingml.document",".xlsx":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",".pptx":"application/vnd.openxmlformats-officedocument.presentationml.presentation"};function Zo(t){let e=t.lastIndexOf(".");return Tc[e>0?t.slice(e).toLowerCase():""]??"application/octet-stream"}function Qo(t,e,n,r){let s=n.replace(/[^\x20-\x7e]/g,"_").replace(/["\\]/g,"_")||"file",o=encodeURIComponent(n).replace(/['()*]/g,a=>`%${a.charCodeAt(0).toString(16).toUpperCase()}`),i="";for(let[a,l]of Object.entries(e))i+=`--${t}\r
|
|
194
194
|
Content-Disposition: form-data; name="${a}"\r
|
|
195
195
|
\r
|
|
196
196
|
${l}\r
|
|
@@ -200,57 +200,68 @@ Content-Type: ${r}\r
|
|
|
200
200
|
\r
|
|
201
201
|
`,{head:i,tail:`\r
|
|
202
202
|
--${t}--\r
|
|
203
|
-
`}}function xr(t,e){let n=t.filter(([a])=>e-a<=3e3);if(n.length<2)return 0;let[r,s]=n[0],[o,i]=n[n.length-1];return o>r?Math.max(0,(i-s)/(o-r)*1e3):0}function Tr(t,e){let n=e??{};return t===401?"not_signed_in":n.code==="STORAGE_QUOTA_EXCEEDED"?"quota":n.code==="STORAGE_BUSY"||n.code==="STORAGE_RECONCILIATION_REQUIRED"?"storage_unavailable":n.code==="FILE_TOO_LARGE"||t===413?"too_large":typeof n.detail=="string"&&/quota exceeded/i.test(n.detail)?"quota":n.code==="STORAGE_NOT_CONFIGURED"?"storage_unavailable":`http_${t}`}var zl=3,Ir=6e4,Hl=200,ql=bo;function To(t,e,n,r){let{head:s,tail:o}=Eo(t,e,n,r);return{head:Buffer.from(s,"utf8"),tail:Buffer.from(o,"utf8")}}function Bl(t,e,n,r,s,o,i,a){return new Promise((l,c)=>{let u=new URL(t),f=(u.protocol==="https:"?jl:Nl)(u,{method:"POST",headers:{...e,"Content-Length":String(n.length+s+o.length)}},h=>{let g=[];h.on("data",p=>g.push(p)),h.on("end",()=>{let p=null;try{p=JSON.parse(Buffer.concat(g).toString("utf8"))}catch{}l({status:h.statusCode??0,body:p})}),h.on("error",c)}),m=()=>{f.destroy(new Error("aborted"))};if(a.aborted)return m();a.addEventListener("abort",m,{once:!0}),f.setTimeout(Ir,()=>f.destroy(new Error("timeout"))),f.on("error",h=>{a.removeEventListener("abort",m),c(h)}),(async()=>{try{f.write(n);let h=0;for await(let g of Al(r)){let p=g;if(h+=p.length,h>s)throw new Error("changed");f.write(p)||await new Promise(y=>f.once("drain",y)),i(h)}if(h!==s)throw new Error("changed");f.end(o)}catch(h){f.destroy(h)}})()})}function Pr(t,e={}){let n=e.downloadsDir??(()=>qt(Ul(),"Downloads")),r=e.post??Bl,s=e.now??Date.now,o=[],i=new Map,a=Promise.resolve(),l=async()=>{let w=await t.getCloud(),x=typeof t.accountId=="function"?t.accountId():null;return{...w,account:x||`${w.base}|${w.token}`}},c=w=>{let{account:x,attempt:b,relDir:I,abort:U,samples:B,dl:J,...se}=w;return{...se,speed:w.state==="active"?xr(B,s()):0}},u=(w,x,b=null)=>{w.state=x,w.error=b,w.abort=null,w.finishedAt=s(),w.samples=[];let I=o.filter(U=>U.state==="done"||U.state==="canceled");for(let U of I.slice(0,Math.max(0,I.length-Hl)))o.splice(o.indexOf(U),1);f()};function f(){for(let w of["up","down"]){let x=o.filter(b=>b.kind===w&&b.state==="active").length;for(let b of o){if(x>=zl)break;if(b.kind!==w||b.state!=="queued")continue;x++,b.state="active",b.startedAt=s(),b.done=0,b.samples=[[s(),0]],b.abort=new AbortController;let I=++b.attempt,U=()=>b.attempt===I&&b.state==="active";(w==="up"?_(b,U):C(b,U)).catch(B=>{U()&&u(b,"failed",m(B))})}}}let m=w=>{let x=String(w?.message||w);return x==="changed"||x==="too_large"||x==="quota"||x==="account_changed"||x==="not_signed_in"||x.startsWith("http_")||x==="bad_response"||x==="gone"?x:"network"},h=(w,x)=>{w.done=x;let b=s(),I=w.samples[w.samples.length-1];for((!I||b-I[0]>=200)&&w.samples.push([b,x]);w.samples.length>2&&b-w.samples[0][0]>3500;)w.samples.shift()};async function g(w){let x=await l();if(x.account!==w.account)throw new Error("account_changed");if(!x.token)throw new Error("not_signed_in");return x}async function p(w,x,b,I){let U=Xe(w,b);if(!U)throw new Error("bad_path");let B=await fetch(U,{method:I.method??"GET",headers:{Authorization:`Bearer ${x}`,...I.body!==void 0?{"Content-Type":"application/json"}:{},...I.projectSource?{"X-Project-Source":I.projectSource}:{}},body:I.body!==void 0?JSON.stringify(I.body):void 0,signal:AbortSignal.timeout(3e4)});return{status:B.status,json:await B.json().catch(()=>null)}}function y(w,x,b){if(!w.relDir.length)return Promise.resolve(w.targetId);let I=i.get(w.batch);I||i.set(w.batch,I=new Map);let U=I,B=J=>{if(J===0)return Promise.resolve(w.targetId);let se=w.relDir.slice(0,J).join("/"),pe=U.get(se);return pe||(pe=B(J-1).then(async X=>{let de=w.relDir[J-1],Z=await p(x,b,"/files",{method:"POST",body:{type:"directory",parentId:X,name:de},projectSource:w.projectSource});if(Z.status===201&&typeof Z.json?.id=="string")return Z.json.id;if(Z.status===409){let ke=await p(x,b,`/files${X==="ROOT"?"":`?parentId=${encodeURIComponent(X)}`}`,{projectSource:w.projectSource}),oe=Array.isArray(ke.json)?ke.json.find(Ee=>Ee?.fileType==="directory"&&Ee?.name===de):null;if(oe?.id)return String(oe.id)}throw new Error(Z.status===401?"not_signed_in":`http_${Z.status}`)}),pe.catch(()=>U.delete(se)),U.set(se,pe)),pe};return B(w.relDir.length)}async function _(w,x){let{base:b,token:I}=await g(w),U=await Co(w.localPath).catch(()=>null);if(!U?.isFile())throw new Error("gone");if(U.size>52428800)throw new Error("too_large");w.size=U.size;let B=await y(w,b,I);if(!x())return;w.parentId=B;let J=Xe(b,"/files/upload");if(!J)throw new Error("bad_path");let se=`----penzor${Rn().replace(/-/g,"")}`,{head:pe,tail:X}=To(se,{parentId:B,autoRename:"true"},w.name,ko(w.name)),de=await r(J,{Authorization:`Bearer ${I}`,"Content-Type":`multipart/form-data; boundary=${se}`,...w.projectSource?{"X-Project-Source":w.projectSource}:{}},pe,w.localPath,U.size,X,Z=>{x()&&h(w,Z)},w.abort.signal);x()&&(de.status===201||de.status===200?(w.fileId=typeof de.body?.id=="string"?de.body.id:null,h(w,w.size),u(w,"done")):u(w,"failed",Tr(de.status,de.body)))}function O(w,x,b,I){let U=async()=>{let J=Fl(b),se=J?b.slice(0,-J.length):b;for(let pe=0;pe<1e3;pe++){if(!I())throw new Error("aborted");let X=qt(x,pe===0?b:`${se} (${pe})${J}`);try{await Pl(w,X)}catch(de){let Z=de.code;if(Z==="EEXIST")continue;if(Z!=="EPERM"&&Z!=="ENOTSUP"&&Z!=="EOPNOTSUPP"&&Z!=="ENOSYS"&&Z!=="EXDEV")throw de;if(await Il(X).then(()=>!0,()=>!1))continue;await Ml(w,X)}if(!I())throw await Ar(X).catch(()=>{}),new Error("aborted");return await Ar(w).catch(()=>{}),X}throw new Error("too many duplicates")},B=a.then(U,U);return a=B.catch(()=>{}),B}async function C(w,x){let b=w.dl,{base:I,token:U}=await g(w);if(!x())return;let B=Xe(I,b.path);if(!B)throw new Error("bad_path");let J=w.abort.signal,se=b.subdir?qt(n(),b.subdir):n();await Dl(se,{recursive:!0});let pe=qt(se,`.${w.id}-${w.attempt}.penzor-part`),X=await $l(pe,"wx"),de=!1;try{let Z=new AbortController,ke=setTimeout(()=>Z.abort(),Ir),oe=()=>{clearTimeout(ke),ke=setTimeout(()=>Z.abort(),Ir)},Ee=AbortSignal.any([J,Z.signal]);try{let fe=await fetch(B,{headers:{Authorization:`Bearer ${U}`},signal:Ee});if(!fe.ok)throw new Error(fe.status===401?"not_signed_in":`http_${fe.status}`);let ye=fe.body,ae=Number(fe.headers.get("content-length"))||w.size;if(b.mode!=="bytes"){let be=await fe.json().catch(()=>null);if(b.mode==="text"){if(typeof be?.content!="string")throw new Error("bad_response");let E=Buffer.from(be.content,"utf8");await X.writeFile(E),w.size=E.length,h(w,E.length),ye=null}else{if(typeof be?.url!="string"||!/^https?:\/\//i.test(be.url))throw new Error("bad_response");let E=await fetch(be.url,{signal:Ee});if(!E.ok)throw new Error(`http_${E.status}`);ye=E.body,ae=Number(E.headers.get("content-length"))||w.size}}if(ye){w.size=ae;let be=0;for await(let E of ye){oe();for(let P=0;P<E.length;){let{bytesWritten:T}=await X.write(E,P,E.length-P);if(T<=0)throw new Error("short_write");P+=T}if(be+=E.length,!x())throw new Error("aborted");h(w,be)}be>w.size&&(w.size=be)}}finally{clearTimeout(ke)}if(await X.close(),!x()||(w.localPath=await O(pe,se,b.name,x),de=!0,!x()))return;u(w,"done")}finally{de||(await X.close().catch(()=>{}),await Ar(pe).catch(()=>{}))}}let M=(w,x)=>{let b={...w,id:Rn(),attempt:0,done:0,state:x?"failed":"queued",error:x??null,abort:null,samples:[],speed:0,startedAt:null,finishedAt:x?s():null};return o.push(b),b};async function H(w){let x=[],b=async(I,U)=>{if(U.length>32)return!0;let B=await(U.length?Rl(I):Co(I)).catch(()=>null);if(!B)return!0;if(B.isFile())return x.push({path:I,size:B.size,relDir:U}),x.length<=2e3;if(!B.isDirectory())return!0;let J=(await Ol(I).catch(()=>[])).filter(se=>!se.startsWith(".")).sort();for(let se of J)if(!await b(qt(I,se),[...U,xo(I)]))return!1;return!0};for(let I of w)if(!await b(I,[]))return"too_many";return x}return t.handle("penzor:device",w=>{if(!t.isTrustedSender(w))return{ok:!1,error:"untrusted"};let x=Tn();return{ok:!0,name:x?decodeURIComponent(x):null}}),t.handle("penzor:upload",async(w,x)=>{if(!t.isTrustedSender(w))return{ok:!1,error:"untrusted"};let b=x??{},I=Array.isArray(b.paths)?b.paths.filter(oe=>typeof oe=="string"&&Ll(oe)):[],U=typeof b.parentId=="string"&&So.test(b.parentId)?b.parentId:null,B=typeof b.projectSource=="string"&&vo.test(b.projectSource)?b.projectSource:null;if(!I.length)return{ok:!1,error:"no_files"};if(!U||!B)return{ok:!1,error:"bad_target"};let{base:J,token:se,account:pe}=await l();if(!se)return{ok:!1,error:"not_signed_in"};let X=await H(I);if(X==="too_many")return{ok:!1,error:"too_many",max:2e3};if(!X.length)return{ok:!1,error:"no_files"};let de=X.filter(oe=>oe.size<=52428800).reduce((oe,Ee)=>oe+Ee.size,0);try{let oe=await p(J,se,"/storage/quota",{}),Ee=Number(oe.json?.used),fe=Number(oe.json?.quota);if(oe.status===200&&fe>0&&Ee+de>fe)return{ok:!1,error:"quota",short:Ee+de-fe}}catch{}if((await l()).account!==pe)return{ok:!1,error:"account_changed"};let Z=Rn(),ke=X.map(oe=>M({kind:"up",name:xo(oe.path),size:oe.size,projectSource:B,parentId:oe.relDir.length?null:U,targetId:U,fileId:null,localPath:oe.path,batch:Z,account:pe,relDir:oe.relDir},oe.size>52428800?"too_large":void 0).id);return f(),{ok:!0,ids:ke,batch:Z}}),t.handle("penzor:download",async(w,x)=>{if(!t.isTrustedSender(w))return{ok:!1,error:"untrusted"};let b=x??{},I=ql.includes(b.mode)?b.mode:null,U=Pn(b.name);if(!I)return{ok:!1,error:"bad_mode"};if(!U)return{ok:!1,error:"bad_name"};let{base:B,token:J,account:se}=await l();if(typeof b.path!="string"||!Xe(B,b.path))return{ok:!1,error:"bad_path"};if(!J)return{ok:!1,error:"not_signed_in"};let pe=b.subdir==null?null:Pn(b.subdir),X=M({kind:"down",name:U,size:Math.max(0,Number(b.size)||0),localPath:null,batch:typeof b.batch=="string"&&b.batch.length<=64?b.batch:Rn(),account:se,relDir:[],dl:{path:b.path,mode:I,name:U,subdir:pe}});return f(),{ok:!0,id:X.id}}),t.handle("penzor:transfers",w=>t.isTrustedSender(w)?{ok:!0,items:o.map(c)}:{ok:!1,error:"untrusted"}),t.handle("penzor:transfer",(w,x)=>{if(!t.isTrustedSender(w))return{ok:!1,error:"untrusted"};let b=x??{},I=o.find(B=>B.id===b.id);if(!I)return{ok:!1,error:"not_found"};let U=()=>{I.abort?.abort(),I.abort=null,I.done=0,I.samples=[]};switch(b.op){case"pause":(I.state==="active"||I.state==="queued")&&(U(),I.state="paused",f());break;case"resume":I.state==="paused"&&(I.state="queued",f());break;case"cancel":(I.state==="active"||I.state==="queued"||I.state==="paused")&&(U(),u(I,"canceled"));break;case"retry":(I.state==="failed"||I.state==="canceled")&&(I.state="queued",I.error=null,I.finishedAt=null,I.done=0,f());break;case"dismiss":I.state!=="active"&&I.state!=="queued"&&o.splice(o.indexOf(I),1);break;default:return{ok:!1,error:"bad_op"}}return{ok:!0}}),t.handle("penzor:transfers:clear",(w,x)=>{if(!t.isTrustedSender(w))return{ok:!1,error:"untrusted"};let b=x?.which==="all";for(let I of[...o])(I.state==="done"||I.state==="canceled"||b&&I.state==="failed")&&o.splice(o.indexOf(I),1);return{ok:!0}}),t.addQuitGuard?.(w=>{let x=o.filter(b=>b.state==="active"||b.state==="queued"||b.state==="paused").length;return x?w==="zh"?{message:`\u8FD8\u6709 ${x} \u4E2A\u6587\u4EF6\u6CA1\u4F20\u5B8C`,detail:"\u73B0\u5728\u9000\u51FA\u4F1A\u4E2D\u65AD\uFF0C\u4E0B\u6B21\u6253\u5F00\u8981\u91CD\u65B0\u4F20\u3002"}:{message:x===1?"1 file hasn't finished transferring":`${x} files haven't finished transferring`,detail:"Quitting now stops them. You will need to start them again next time."}:null}),{list:()=>o.map(c)}}import{readFileSync as Yl,writeFileSync as Jl,mkdirSync as Gl,chmodSync as Xl,renameSync as Kl}from"node:fs";import{join as Zl}from"node:path";function Oe(t,e){try{let n=new URL(t);if(n.protocol!=="https:"&&n.protocol!=="http:")return null;let r=e.split(".")[1];if(!r)return null;let s=r.replace(/-/g,"+").replace(/_/g,"/"),o=Uint8Array.from(atob(s),l=>l.charCodeAt(0)),i=JSON.parse(new TextDecoder().decode(o)),a=i.userId??i.sub;return typeof a!="string"&&typeof a!="number"||!String(a).trim()?null:`${n.origin}${n.pathname.replace(/\/+$/,"")}::${String(a)}`}catch{return null}}function Rr(t){try{let e=t.split(".")[1];if(!e)return null;let n=JSON.parse(ot(wn(e)));return n&&typeof n=="object"?n:null}catch{return null}}function Dr(t,e=Date.now()){let n=Rr(t)?.iat;return typeof n=="number"?e-n*1e3:1/0}function Ao(t,e=Date.now()){let n=Rr(t)?.exp;return typeof n=="number"?n*1e3-e:1/0}var Wl=36e5;function Dn(t,e=Date.now()){return!!t&&Dr(t,e)>=Wl}async function $n(t,e,n=8e3,r){if(!t||!e)return null;let s=t.replace(/\/+$/,"");try{let o=await fetch(`${s}/api/auth/refresh`,{method:"POST",headers:{Authorization:`Bearer ${e}`,...r?{"X-Forsion-Client":r}:{}},signal:AbortSignal.timeout(n)});if(!o.ok)return null;let i=await o.json().catch(()=>null),a=typeof i?.token=="string"?i.token:"";return a&&a!==e?a:null}catch{return null}}var Bt=(t,e)=>`${t.replace(/\/+$/,"")}\0${e}`,Vl=(t,e)=>new Promise((n,r)=>{let s=()=>{clearTimeout(o),r(new Error("Sign-in cancelled."))},o=setTimeout(()=>{e.removeEventListener("abort",s),n()},t);e.aborted?s():e.addEventListener("abort",s,{once:!0})});function Io(t,e){let n=f=>e.write(JSON.stringify(f,null,2)),r=()=>{try{let f=JSON.parse(e.read()??"");return Array.isArray(f.accounts)?f.accounts.filter(m=>m&&typeof m.token=="string"&&m.id===Oe(m.cloudUrl,m.token)):[]}catch{return[]}},s=(f,m)=>{let h=Oe(f.cloudUrl||"",f.token||"");if(!h||!f.token||!f.cloudUrl)return;let g=r(),p=g.find(O=>O.id===h),y=Rr(f.token),_={...p,id:h,cloudUrl:f.cloudUrl.replace(/\/+$/,""),token:f.token,username:m?.username||p?.username||y?.username,nickname:m?.nickname||p?.nickname};JSON.stringify(p)!==JSON.stringify(_)&&n({version:1,accounts:[...g.filter(O=>O.id!==h),_]})},o=()=>{let f=t.readCreds();s(f);let m=Oe(f.cloudUrl,f.token);return r().map(({token:h,...g})=>({...g,active:g.id===m}))},i=f=>{let m=r().find(h=>h.id===f);if(!m)throw new Error("Account is no longer signed in. Sign in again.");return{cloudUrl:m.cloudUrl,token:m.token}},a=f=>{let m=Oe(f.cloudUrl||"",f.token||"");m&&n({version:1,accounts:r().filter(h=>h.id!==m)})},l=null;return{rememberForsionAccount:s,forsionAccounts:o,savedForsionAccount:i,forgetForsionAccount:a,cancelForsionLogin:()=>{l?.abort(),l=null},forsionDeviceLogin:async(f,m,h)=>{if(l)throw new Error("A sign-in is already in progress.");if(!f)throw new Error("\u8BF7\u5148\u586B\u5199 Forsion \u4E91\u7AEF\u5730\u5740(\u6216\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF TANGU_CLOUD_URL)");let g=new AbortController;l=g;let p=()=>{if(g.signal.aborted||l!==g)throw new Error("Sign-in cancelled.")};try{let y=f.replace(/\/+$/,""),_;try{_=await fetch(`${y}/api/auth/cli/start`,{method:"POST",headers:{"Content-Type":"application/json"},body:"{}",signal:AbortSignal.any([g.signal,AbortSignal.timeout(15e3)])}).then(x=>x.json())}catch(x){throw new Error(`\u65E0\u6CD5\u8FDE\u63A5 ${y}:${x?.message||x}`)}if(p(),!_?.device_code)throw new Error("\u4E91\u7AEF\u4E0D\u652F\u6301 CLI \u767B\u5F55(/api/auth/cli/start \u8FD4\u56DE\u5F02\u5E38)");let O=_.verification_uri_complete||`${_.verification_uri}?code=${_.user_code}`,C=new URL(`${y}/auth`);C.searchParams.set("logout","1"),C.searchParams.set("app","forsion-desktop"),C.searchParams.set("redirect",O);let M=C.toString();m?.({url:M,userCode:String(_.user_code||"")}),t.openExternal(M);let H=Date.now()+(_.expires_in||600)*1e3,w=(_.interval||2)*1e3;for(;Date.now()<H;){await Vl(w,g.signal),p();let x=null;try{x=await fetch(`${y}/api/auth/cli/poll`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({device_code:_.device_code}),signal:AbortSignal.any([g.signal,AbortSignal.timeout(15e3)])})}catch{p();continue}if(p(),x.status===410)throw new Error("\u767B\u5F55\u7801\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u53D1\u8D77\u767B\u5F55");let b=await x.json().catch(()=>({status:"pending"}));if(p(),b.status==="approved"&&b.token){let I={cloudUrl:y,token:b.token};return await h(I,p),p(),{token:b.token,cloudUrl:y}}}throw new Error("\u767B\u5F55\u8D85\u65F6,\u8BF7\u91CD\u8BD5")}finally{l===g&&(l=null)}},readAccounts:r}}function Ql(t){let e=()=>Zl(t(),"auth-accounts.json");return{read:()=>Yl(e(),"utf8"),write:n=>{Gl(t(),{recursive:!0});let r=`${e()}.tmp`;Jl(r,n,{encoding:"utf8",mode:384}),Xl(r,384),Kl(r,e())}}}var Ro=t=>Io(t,Ql(()=>t.homeDir())),Do=["homeDir","appVersion","broadcast","accountBackendState","accountTransition","accountCommit","accountClear","writeCreds","onExternalCredsChange","setTokenRefresher","readCreds"],$r=t=>Do.every(e=>typeof t[e]=="function");function Or(t){let e={ok:!1,error:"untrusted"},n={loggedIn:!1,error:"untrusted"},r=Ro(t),s=0,o=()=>{let a=t.readCreds();return Bt(a.cloudUrl,a.token)},i=null;t.handle("auth:status",async a=>{if(!t.isTrustedSender(a))return n;let l=s,c=o(),{base:u}=await t.getCloud(),f=t.readCreds().token,m=f?await zt(u,f):null,h=await t.accountBackendState(),{base:g}=await t.getCloud(),p=t.readCreds(),y=Bt(g,p.token)!==Bt(u,f),_=Bt(u,f);!y&&m?.status==="ok"&&m.user&&(i={key:_,user:m.user},r.rememberForsionAccount({...p,cloudUrl:u},m.user));let O=y?void 0:m?.status==="ok"?m.user:m?.status==="offline"&&i?.key===_?i.user:void 0;if(y)return{loggedIn:!!p.token,tokenValid:null,cloudUrl:g,accountId:Oe(g,p.token),username:null,nickname:null,avatar:null,membershipTier:null,tokenSource:p.token?"tangu-login":null,backendState:h};if(m?.status==="expired"){await t.accountTransition(async()=>{if(l!==s||o()!==c)return;let M=()=>{if(l!==s||o()!==c)throw Po};try{await t.accountClear(M,()=>{t.log("[auth] token \u5DF2\u5931\u6548(\u670D\u52A1\u7AEF 401/403),\u81EA\u52A8\u767B\u51FA"),++s,r.cancelForsionLogin(),r.forgetForsionAccount(t.readCreds()),i=null})}catch(H){if(H!==Po)throw H}});let C=t.readCreds();return{loggedIn:!!C.token,tokenValid:null,cloudUrl:C.cloudUrl||u,accountId:Oe(C.cloudUrl||u,C.token),username:null,nickname:null,avatar:null,membershipTier:null,tokenSource:C.token?"tangu-login":null,backendState:h}}return{loggedIn:!!f,tokenValid:m&&m.status==="ok"?!0:null,cloudUrl:u,accountId:Oe(u,f),username:O?.username||null,nickname:O?.nickname||null,avatar:O?.avatar||null,membershipTier:O?.membershipTier||null,tokenSource:f?"tangu-login":null,backendState:h}}),t.handle("auth:accounts",a=>t.isTrustedSender(a)?r.forsionAccounts():[]),t.handle("auth:switchAccount",async(a,l)=>{if(!t.isTrustedSender(a))return e;if(typeof l!="string")throw new Error("Invalid account.");let c=++s;return r.cancelForsionLogin(),t.accountTransition(async()=>{let u=r.savedForsionAccount(l);return await t.accountCommit(u,()=>{if(c!==s)throw new Error("Account switch cancelled.")},()=>{r.rememberForsionAccount(u),i=null}),{ok:!0,cloudUrl:u.cloudUrl||""}})}),t.handle("auth:forsionLogin",async(a,l)=>{if(!t.isTrustedSender(a))return e;let c=++s;r.cancelForsionLogin();let{base:u}=await t.getCloud();if(c!==s)throw new Error("Sign-in cancelled.");let f=(l||u||"").trim();return{ok:!0,cloudUrl:(await r.forsionDeviceLogin(f,h=>t.broadcast("auth:device",h),(h,g)=>t.accountTransition(()=>t.accountCommit(h,()=>{if(g(),c!==s)throw new Error("Sign-in cancelled.")},()=>{r.rememberForsionAccount(h),i=null})))).cloudUrl}}),t.handle("auth:logout",async a=>t.isTrustedSender(a)?(++s,r.cancelForsionLogin(),t.accountTransition(async()=>{let{base:l}=await t.getCloud(),c=t.readCreds();return await t.accountClear(void 0,()=>{r.forgetForsionAccount(c),i=null,l&&c.token&&fetch(`${l}/api/auth/logout`,{method:"POST",headers:{Authorization:`Bearer ${c.token}`},signal:AbortSignal.timeout(5e3)}).catch(()=>{})}),{ok:!0}})):e),t.onExternalCredsChange(({previous:a,current:l})=>{++s,r.cancelForsionLogin(),a.token&&!l.token&&r.forgetForsionAccount(a),i=null,r.rememberForsionAccount(l)}),t.setTokenRefresher(async a=>{let l=s,c=o(),u=t.readCreds().token;if(!Dn(u))return;let{base:f}=await t.getCloud(),m=await $n(f,u,a,`desktop/${t.appVersion()}`);if(!m){t.log("[auth] \u6ED1\u52A8\u7EED\u671F\u672A\u6210\u529F(\u79BB\u7EBF/\u8001\u7248\u672C server/\u8FD9\u679A\u5DF2\u5931\u6548),\u7EE7\u7EED\u7528\u65E7 token");return}l!==s||o()!==c||(r.rememberForsionAccount({cloudUrl:f,token:m}),t.writeCreds({cloudUrl:f,token:m}),t.log("[auth] \u767B\u5F55\u6001\u5DF2\u6ED1\u52A8\u7EED\u671F(\u6709\u6548\u671F\u91CD\u65B0\u8BA1\u6EE1 2 \u5468)"))}),t.log("[forsion-extend] account core registered")}var Po=Symbol("stale-auth-intent");import{promises as At}from"node:fs";import mt from"node:path";import{execFile as vc}from"node:child_process";import kc from"node:os";var Mr=null;function $o(t){Mr=t}function Ie(){if(!Mr)throw new Error("amadeus sync env not set (registerAmadeus factory has not run)");return Mr}var Te=()=>Ie().accountId();function Wt(t=Te()){return t?Se().sha256Hex(t):"signed-out"}var Me=(t=Te())=>Ie().readConfig(t),Ke=(t,e=Te())=>Ie().writeConfig(t,e),_t=(t,e=Te())=>Ie().updateConfig(t,e),it=(t=Te())=>Ie().cloudVaultDir(t),On=t=>Ie().isManagedCloudVault(t);function ec(t,e){let n=Object.create(null);for(let o=0;o<e.length;o++){let i=e[o];n[i]?n[i].push(o):n[i]=[o]}let s=[{buffer1index:-1,buffer2index:-1,chain:null}];for(let o=0;o<t.length;o++){let i=t[o],a=n[i]||[],l=0,c=s[0];for(let u of a){let f;for(f=l;f<s.length&&!(s[f].buffer2index<u&&(f===s.length-1||s[f+1].buffer2index>u));f++);if(f<s.length){let m={buffer1index:o,buffer2index:u,chain:s[f]};if(l===s.length?s.push(c):s[l]=c,l=f+1,c=m,l===s.length)break}}s[l]=c}return s[s.length-1]}function Oo(t,e){let n=ec(t,e),r=[],s=t.length,o=e.length;for(let i=n;i!==null;i=i.chain){let a=s-i.buffer1index-1,l=o-i.buffer2index-1;s=i.buffer1index,o=i.buffer2index,(a||l)&&r.push({buffer1:[s+1,a],buffer1Content:t.slice(s+1,s+1+a),buffer2:[o+1,l],buffer2Content:e.slice(o+1,o+1+l)})}return r.reverse(),r}function tc(t,e,n){let r=[];function s(l,c){r.push({ab:c,oStart:l.buffer1[0],oLength:l.buffer1[1],abStart:l.buffer2[0],abLength:l.buffer2[1]})}Oo(e,t).forEach(l=>s(l,"a")),Oo(e,n).forEach(l=>s(l,"b")),r.sort((l,c)=>l.oStart-c.oStart);let o=[],i=0;function a(l){l>i&&(o.push({stable:!0,buffer:"o",bufferStart:i,bufferLength:l-i,bufferContent:e.slice(i,l)}),i=l)}for(;r.length;){let l=r.shift(),c=l.oStart,u=l.oStart+l.oLength,f=[l];for(a(c);r.length;){let m=r[0],h=m.oStart;if(h>u)break;u=Math.max(u,h+m.oLength),f.push(r.shift())}if(f.length===1){if(l.abLength>0){let m=l.ab==="a"?t:n;o.push({stable:!0,buffer:l.ab,bufferStart:l.abStart,bufferLength:l.abLength,bufferContent:m.slice(l.abStart,l.abStart+l.abLength)})}}else{let m={a:[t.length,-1,e.length,-1],b:[n.length,-1,e.length,-1]};for(;f.length;){l=f.shift();let O=l.oStart,C=O+l.oLength,M=l.abStart,H=M+l.abLength,w=m[l.ab];w[0]=Math.min(M,w[0]),w[1]=Math.max(H,w[1]),w[2]=Math.min(O,w[2]),w[3]=Math.max(C,w[3])}let h=m.a[0]+(c-m.a[2]),g=m.a[1]+(u-m.a[3]),p=m.b[0]+(c-m.b[2]),y=m.b[1]+(u-m.b[3]),_={stable:!1,aStart:h,aLength:g-h,aContent:t.slice(h,g),oStart:c,oLength:u-c,oContent:e.slice(c,u),bStart:p,bLength:y-p,bContent:n.slice(p,y)};o.push(_)}i=u}return a(e.length),o}function Mo(t,e,n,r){r=Object.assign({excludeFalseConflicts:!0,stringSeparator:/\s+/},r),typeof t=="string"&&(t=t.split(r.stringSeparator)),typeof e=="string"&&(e=e.split(r.stringSeparator)),typeof n=="string"&&(n=n.split(r.stringSeparator));let o=[],i=tc(t,e,n),a=[];function l(){a.length&&o.push({ok:a}),a=[]}function c(u,f){if(u.length!==f.length)return!1;for(let m=0;m<u.length;m++)if(u[m]!==f[m])return!1;return!0}return i.forEach(u=>{u.stable?a.push(...u.bufferContent):r.excludeFalseConflicts&&c(u.aContent,u.bContent)?a.push(...u.aContent):(l(),o.push({conflict:{a:u.aContent,aIndex:u.aStart,o:u.oContent,oIndex:u.oStart,b:u.bContent,bIndex:u.bStart}}))}),l(),o}function Mn(t,e){let n=t.lastIndexOf("/"),r=n<0?"":t.slice(0,n+1),s=n<0?t:t.slice(n+1),o=s.lastIndexOf("."),i=o>0?s.slice(0,o):s,a=o>0?s.slice(o):"",l=u=>String(u).padStart(2,"0"),c=`${e.getFullYear()}-${l(e.getMonth()+1)}-${l(e.getDate())} ${l(e.getHours())}${l(e.getMinutes())}`;return`${r}${i} (conflict ${c})${a}`}function nc(t,e){if(e<2)return t;let n=t.lastIndexOf("."),r=n>t.lastIndexOf("/")&&n>t.lastIndexOf(")"),s=r?t.slice(0,n):t,o=r?t.slice(n):"";return`${s}-${e}${o}`}function rc(t){let e=3735928559,n=1103547991;for(let s=0;s<t.length;s++){let o=t.charCodeAt(s);e=Math.imul(e^o,2654435761),n=Math.imul(n^o,1597334677)}e=Math.imul(e^e>>>16,2246822507)^Math.imul(n^n>>>13,3266489909),n=Math.imul(n^n>>>16,2246822507)^Math.imul(e^e>>>13,3266489909);let r=4294967296*(2097151&n)+(e>>>0);return`${t.length.toString(36)}-${r.toString(36)}`}function Nn(t,e,n){if(t===null&&e===null&&n===null)return{kind:"none"};if(n===null)return t===null?e?{kind:"dropShadow"}:{kind:"none"}:e?t===e.hash?{kind:"deleteLocal"}:{kind:"pushCreate"}:{kind:"pushCreate"};if(t===null)return e?n.seq===e.seq?{kind:"pushDelete"}:{kind:"pull"}:{kind:"pull"};if(!e)return t===n.hash?{kind:"adopt"}:{kind:"conflict"};let r=t!==e.hash,s=n.seq!==e.seq;return!r&&!s?{kind:"none"}:r?s?t===n.hash?{kind:"adopt"}:n.hash===e.hash?{kind:"push",baseSeq:n.seq}:{kind:"conflict"}:{kind:"push",baseSeq:e.seq}:{kind:"pull"}}function No(t,e,n){let r=Mo(t.split(`
|
|
203
|
+
`}}function Br(t,e){let n=t.filter(([a])=>e-a<=3e3);if(n.length<2)return 0;let[r,s]=n[0],[o,i]=n[n.length-1];return o>r?Math.max(0,(i-s)/(o-r)*1e3):0}function qr(t,e){let n=e??{};return t===401?"not_signed_in":n.code==="STORAGE_QUOTA_EXCEEDED"?"quota":n.code==="STORAGE_BUSY"||n.code==="STORAGE_RECONCILIATION_REQUIRED"?"storage_unavailable":n.code==="FILE_TOO_LARGE"||t===413?"too_large":typeof n.detail=="string"&&/quota exceeded/i.test(n.detail)?"quota":n.code==="STORAGE_NOT_CONFIGURED"?"storage_unavailable":`http_${t}`}var zc=3,Vr=6e4,Hc=200,Bc=Go;function ri(t,e,n,r){let{head:s,tail:o}=Qo(t,e,n,r);return{head:Buffer.from(s,"utf8"),tail:Buffer.from(o,"utf8")}}function qc(t,e,n,r,s,o,i,a){return new Promise((l,c)=>{let u=new URL(t),f=(u.protocol==="https:"?jc:Nc)(u,{method:"POST",headers:{...e,"Content-Length":String(n.length+s+o.length)}},h=>{let g=[];h.on("data",m=>g.push(m)),h.on("end",()=>{let m=null;try{m=JSON.parse(Buffer.concat(g).toString("utf8"))}catch{}l({status:h.statusCode??0,body:m})}),h.on("error",c)}),p=()=>{f.destroy(new Error("aborted"))};if(a.aborted)return p();a.addEventListener("abort",p,{once:!0}),f.setTimeout(Vr,()=>f.destroy(new Error("timeout"))),f.on("error",h=>{a.removeEventListener("abort",p),c(h)}),(async()=>{try{f.write(n);let h=0;for await(let g of Ac(r)){let m=g;if(h+=m.length,h>s)throw new Error("changed");f.write(m)||await new Promise(w=>f.once("drain",w)),i(h)}if(h!==s)throw new Error("changed");f.end(o)}catch(h){f.destroy(h)}})()})}function Jr(t,e={}){let n=e.downloadsDir??(()=>Gt(Fc(),"Downloads")),r=e.post??qc,s=e.now??Date.now,o=[],i=new Map,a=Promise.resolve(),l=async()=>{let b=await t.getCloud(),C=typeof t.accountId=="function"?t.accountId():null;return{...b,account:C||`${b.base}|${b.token}`}},c=b=>{let{account:C,attempt:E,relDir:T,abort:L,samples:X,dl:ee,...te}=b;return{...te,speed:b.state==="active"?Br(X,s()):0}},u=(b,C,E=null)=>{b.state=C,b.error=E,b.abort=null,b.finishedAt=s(),b.samples=[];let T=o.filter(L=>L.state==="done"||L.state==="canceled");for(let L of T.slice(0,Math.max(0,T.length-Hc)))o.splice(o.indexOf(L),1);f()};function f(){for(let b of["up","down"]){let C=o.filter(E=>E.kind===b&&E.state==="active").length;for(let E of o){if(C>=zc)break;if(E.kind!==b||E.state!=="queued")continue;C++,E.state="active",E.startedAt=s(),E.done=0,E.samples=[[s(),0]],E.abort=new AbortController;let T=++E.attempt,L=()=>E.attempt===T&&E.state==="active";(b==="up"?k(E,L):O(E,L)).catch(X=>{L()&&u(E,"failed",p(X))})}}}let p=b=>{let C=String(b?.message||b);return C==="changed"||C==="too_large"||C==="quota"||C==="account_changed"||C==="not_signed_in"||C.startsWith("http_")||C==="bad_response"||C==="gone"?C:"network"},h=(b,C)=>{b.done=C;let E=s(),T=b.samples[b.samples.length-1];for((!T||E-T[0]>=200)&&b.samples.push([E,C]);b.samples.length>2&&E-b.samples[0][0]>3500;)b.samples.shift()};async function g(b){let C=await l();if(C.account!==b.account)throw new Error("account_changed");if(!C.token)throw new Error("not_signed_in");return C}async function m(b,C,E,T){let L=st(b,E);if(!L)throw new Error("bad_path");let X=await fetch(L,{method:T.method??"GET",headers:{Authorization:`Bearer ${C}`,...T.body!==void 0?{"Content-Type":"application/json"}:{},...T.projectSource?{"X-Project-Source":T.projectSource}:{}},body:T.body!==void 0?JSON.stringify(T.body):void 0,signal:AbortSignal.timeout(3e4)});return{status:X.status,json:await X.json().catch(()=>null)}}function w(b,C,E){if(!b.relDir.length)return Promise.resolve(b.targetId);let T=i.get(b.batch);T||i.set(b.batch,T=new Map);let L=T,X=ee=>{if(ee===0)return Promise.resolve(b.targetId);let te=b.relDir.slice(0,ee).join("/"),ae=L.get(te);return ae||(ae=X(ee-1).then(async le=>{let j=b.relDir[ee-1],q=await m(C,E,"/files",{method:"POST",body:{type:"directory",parentId:le,name:j},projectSource:b.projectSource});if(q.status===201&&typeof q.json?.id=="string")return q.json.id;if(q.status===409){let K=await m(C,E,`/files${le==="ROOT"?"":`?parentId=${encodeURIComponent(le)}`}`,{projectSource:b.projectSource}),Y=Array.isArray(K.json)?K.json.find(ce=>ce?.fileType==="directory"&&ce?.name===j):null;if(Y?.id)return String(Y.id)}throw new Error(q.status===401?"not_signed_in":`http_${q.status}`)}),ae.catch(()=>L.delete(te)),L.set(te,ae)),ae};return X(b.relDir.length)}async function k(b,C){let{base:E,token:T}=await g(b),L=await ti(b.localPath).catch(()=>null);if(!L?.isFile())throw new Error("gone");if(L.size>52428800)throw new Error("too_large");b.size=L.size;let X=await w(b,E,T);if(!C())return;b.parentId=X;let ee=st(E,"/files/upload");if(!ee)throw new Error("bad_path");let te=`----penzor${zn().replace(/-/g,"")}`,{head:ae,tail:le}=ri(te,{parentId:X,autoRename:"true"},b.name,Zo(b.name)),j=await r(ee,{Authorization:`Bearer ${T}`,"Content-Type":`multipart/form-data; boundary=${te}`,...b.projectSource?{"X-Project-Source":b.projectSource}:{}},ae,b.localPath,L.size,le,q=>{C()&&h(b,q)},b.abort.signal);C()&&(j.status===201||j.status===200?(b.fileId=typeof j.body?.id=="string"?j.body.id:null,h(b,b.size),u(b,"done")):u(b,"failed",qr(j.status,j.body)))}function P(b,C,E,T){let L=async()=>{let ee=Uc(E),te=ee?E.slice(0,-ee.length):E;for(let ae=0;ae<1e3;ae++){if(!T())throw new Error("aborted");let le=Gt(C,ae===0?E:`${te} (${ae})${ee}`);try{await Rc(b,le)}catch(j){let q=j.code;if(q==="EEXIST")continue;if(q!=="EPERM"&&q!=="ENOTSUP"&&q!=="EOPNOTSUPP"&&q!=="ENOSYS"&&q!=="EXDEV")throw j;if(await Ic(le).then(()=>!0,()=>!1))continue;await Mc(b,le)}if(!T())throw await Wr(le).catch(()=>{}),new Error("aborted");return await Wr(b).catch(()=>{}),le}throw new Error("too many duplicates")},X=a.then(L,L);return a=X.catch(()=>{}),X}async function O(b,C){let E=b.dl,{base:T,token:L}=await g(b);if(!C())return;let X=st(T,E.path);if(!X)throw new Error("bad_path");let ee=b.abort.signal,te=E.subdir?Gt(n(),E.subdir):n();await Dc(te,{recursive:!0});let ae=Gt(te,`.${b.id}-${b.attempt}.penzor-part`),le=await $c(ae,"wx"),j=!1;try{let q=new AbortController,K=setTimeout(()=>q.abort(),Vr),Y=()=>{clearTimeout(K),K=setTimeout(()=>q.abort(),Vr)},ce=AbortSignal.any([ee,q.signal]);try{let me=await fetch(X,{headers:{Authorization:`Bearer ${L}`},signal:ce});if(!me.ok)throw new Error(me.status===401?"not_signed_in":`http_${me.status}`);let Ce=me.body,pe=Number(me.headers.get("content-length"))||b.size;if(E.mode!=="bytes"){let fe=await me.json().catch(()=>null);if(E.mode==="text"){if(typeof fe?.content!="string")throw new Error("bad_response");let Q=Buffer.from(fe.content,"utf8");await le.writeFile(Q),b.size=Q.length,h(b,Q.length),Ce=null}else{if(typeof fe?.url!="string"||!/^https?:\/\//i.test(fe.url))throw new Error("bad_response");let Q=await fetch(fe.url,{signal:ce});if(!Q.ok)throw new Error(`http_${Q.status}`);Ce=Q.body,pe=Number(Q.headers.get("content-length"))||b.size}}if(Ce){b.size=pe;let fe=0;for await(let Q of Ce){Y();for(let x=0;x<Q.length;){let{bytesWritten:R}=await le.write(Q,x,Q.length-x);if(R<=0)throw new Error("short_write");x+=R}if(fe+=Q.length,!C())throw new Error("aborted");h(b,fe)}fe>b.size&&(b.size=fe)}}finally{clearTimeout(K)}if(await le.close(),!C()||(b.localPath=await P(ae,te,E.name,C),j=!0,!C()))return;u(b,"done")}finally{j||(await le.close().catch(()=>{}),await Wr(ae).catch(()=>{}))}}let A=(b,C)=>{let E={...b,id:zn(),attempt:0,done:0,state:C?"failed":"queued",error:C??null,abort:null,samples:[],speed:0,startedAt:null,finishedAt:C?s():null};return o.push(E),E};async function $(b){let C=[],E=async(T,L)=>{if(L.length>32)return!0;let X=await(L.length?Pc(T):ti(T)).catch(()=>null);if(!X)return!0;if(X.isFile())return C.push({path:T,size:X.size,relDir:L}),C.length<=2e3;if(!X.isDirectory())return!0;let ee=(await Oc(T).catch(()=>[])).filter(te=>!te.startsWith(".")).sort();for(let te of ee)if(!await E(Gt(T,te),[...L,ni(T)]))return!1;return!0};for(let T of b)if(!await E(T,[]))return"too_many";return C}return t.handle("penzor:device",b=>{if(!t.isTrustedSender(b))return{ok:!1,error:"untrusted"};let C=jn();return{ok:!0,name:C?decodeURIComponent(C):null}}),t.handle("penzor:upload",async(b,C)=>{if(!t.isTrustedSender(b))return{ok:!1,error:"untrusted"};let E=C??{},T=Array.isArray(E.paths)?E.paths.filter(Y=>typeof Y=="string"&&Lc(Y)):[],L=typeof E.parentId=="string"&&Ko.test(E.parentId)?E.parentId:null,X=typeof E.projectSource=="string"&&Xo.test(E.projectSource)?E.projectSource:null;if(!T.length)return{ok:!1,error:"no_files"};if(!L||!X)return{ok:!1,error:"bad_target"};let{base:ee,token:te,account:ae}=await l();if(!te)return{ok:!1,error:"not_signed_in"};let le=await $(T);if(le==="too_many")return{ok:!1,error:"too_many",max:2e3};if(!le.length)return{ok:!1,error:"no_files"};let j=le.filter(Y=>Y.size<=52428800).reduce((Y,ce)=>Y+ce.size,0);try{let Y=await m(ee,te,"/storage/quota",{}),ce=Number(Y.json?.used),me=Number(Y.json?.quota);if(Y.status===200&&me>0&&ce+j>me)return{ok:!1,error:"quota",short:ce+j-me}}catch{}if((await l()).account!==ae)return{ok:!1,error:"account_changed"};let q=zn(),K=le.map(Y=>A({kind:"up",name:ni(Y.path),size:Y.size,projectSource:X,parentId:Y.relDir.length?null:L,targetId:L,fileId:null,localPath:Y.path,batch:q,account:ae,relDir:Y.relDir},Y.size>52428800?"too_large":void 0).id);return f(),{ok:!0,ids:K,batch:q}}),t.handle("penzor:download",async(b,C)=>{if(!t.isTrustedSender(b))return{ok:!1,error:"untrusted"};let E=C??{},T=Bc.includes(E.mode)?E.mode:null,L=Ln(E.name);if(!T)return{ok:!1,error:"bad_mode"};if(!L)return{ok:!1,error:"bad_name"};let{base:X,token:ee,account:te}=await l();if(typeof E.path!="string"||!st(X,E.path))return{ok:!1,error:"bad_path"};if(!ee)return{ok:!1,error:"not_signed_in"};let ae=E.subdir==null?null:Ln(E.subdir),le=A({kind:"down",name:L,size:Math.max(0,Number(E.size)||0),localPath:null,batch:typeof E.batch=="string"&&E.batch.length<=64?E.batch:zn(),account:te,relDir:[],dl:{path:E.path,mode:T,name:L,subdir:ae}});return f(),{ok:!0,id:le.id}}),t.handle("penzor:transfers",b=>t.isTrustedSender(b)?{ok:!0,items:o.map(c)}:{ok:!1,error:"untrusted"}),t.handle("penzor:transfer",(b,C)=>{if(!t.isTrustedSender(b))return{ok:!1,error:"untrusted"};let E=C??{},T=o.find(X=>X.id===E.id);if(!T)return{ok:!1,error:"not_found"};let L=()=>{T.abort?.abort(),T.abort=null,T.done=0,T.samples=[]};switch(E.op){case"pause":(T.state==="active"||T.state==="queued")&&(L(),T.state="paused",f());break;case"resume":T.state==="paused"&&(T.state="queued",f());break;case"cancel":(T.state==="active"||T.state==="queued"||T.state==="paused")&&(L(),u(T,"canceled"));break;case"retry":(T.state==="failed"||T.state==="canceled")&&(T.state="queued",T.error=null,T.finishedAt=null,T.done=0,f());break;case"dismiss":T.state!=="active"&&T.state!=="queued"&&o.splice(o.indexOf(T),1);break;default:return{ok:!1,error:"bad_op"}}return{ok:!0}}),t.handle("penzor:transfers:clear",(b,C)=>{if(!t.isTrustedSender(b))return{ok:!1,error:"untrusted"};let E=C?.which==="all";for(let T of[...o])(T.state==="done"||T.state==="canceled"||E&&T.state==="failed")&&o.splice(o.indexOf(T),1);return{ok:!0}}),t.addQuitGuard?.(b=>{let C=o.filter(E=>E.state==="active"||E.state==="queued"||E.state==="paused").length;return C?b==="zh"?{message:`\u8FD8\u6709 ${C} \u4E2A\u6587\u4EF6\u6CA1\u4F20\u5B8C`,detail:"\u73B0\u5728\u9000\u51FA\u4F1A\u4E2D\u65AD\uFF0C\u4E0B\u6B21\u6253\u5F00\u8981\u91CD\u65B0\u4F20\u3002"}:{message:C===1?"1 file hasn't finished transferring":`${C} files haven't finished transferring`,detail:"Quitting now stops them. You will need to start them again next time."}:null}),{list:()=>o.map(c)}}import{readFileSync as Jc,writeFileSync as Yc,mkdirSync as Gc,chmodSync as Kc,renameSync as Xc}from"node:fs";import{join as Zc}from"node:path";function Fe(t,e){try{let n=new URL(t);if(n.protocol!=="https:"&&n.protocol!=="http:")return null;let r=e.split(".")[1];if(!r)return null;let s=r.replace(/-/g,"+").replace(/_/g,"/"),o=Uint8Array.from(atob(s),l=>l.charCodeAt(0)),i=JSON.parse(new TextDecoder().decode(o)),a=i.userId??i.sub;return typeof a!="string"&&typeof a!="number"||!String(a).trim()?null:`${n.origin}${n.pathname.replace(/\/+$/,"")}::${String(a)}`}catch{return null}}function Yr(t){try{let e=t.split(".")[1];if(!e)return null;let n=JSON.parse(pt(An(e)));return n&&typeof n=="object"?n:null}catch{return null}}function Gr(t,e=Date.now()){let n=Yr(t)?.iat;return typeof n=="number"?e-n*1e3:1/0}function si(t,e=Date.now()){let n=Yr(t)?.exp;return typeof n=="number"?n*1e3-e:1/0}var Wc=36e5;function Hn(t,e=Date.now()){return!!t&&Gr(t,e)>=Wc}async function Bn(t,e,n=8e3,r){if(!t||!e)return null;let s=t.replace(/\/+$/,"");try{let o=await fetch(`${s}/api/auth/refresh`,{method:"POST",headers:{Authorization:`Bearer ${e}`,...r?{"X-Forsion-Client":r}:{}},signal:AbortSignal.timeout(n)});if(!o.ok)return null;let i=await o.json().catch(()=>null),a=typeof i?.token=="string"?i.token:"";return a&&a!==e?a:null}catch{return null}}var Kt=(t,e)=>`${t.replace(/\/+$/,"")}\0${e}`,Vc=(t,e)=>new Promise((n,r)=>{let s=()=>{clearTimeout(o),r(new Error("Sign-in cancelled."))},o=setTimeout(()=>{e.removeEventListener("abort",s),n()},t);e.aborted?s():e.addEventListener("abort",s,{once:!0})});function oi(t,e){let n=f=>e.write(JSON.stringify(f,null,2)),r=()=>{let f;try{f=e.read()}catch(p){return p?.code==="ENOENT"?[]:null}if(f===null)return[];try{let p=JSON.parse(f);return Array.isArray(p.accounts)?p.accounts.filter(h=>h&&typeof h.token=="string"&&h.id===Fe(h.cloudUrl,h.token)):null}catch{return null}},s=(f,p)=>{let h=Fe(f.cloudUrl||"",f.token||"");if(!h||!f.token||!f.cloudUrl)return;let g=r();if(!g)return;let m=g.find(P=>P.id===h),w=Yr(f.token),k={...m,id:h,cloudUrl:f.cloudUrl.replace(/\/+$/,""),token:f.token,username:p?.username||m?.username||w?.username,nickname:p?.nickname||m?.nickname};JSON.stringify(m)!==JSON.stringify(k)&&n({version:1,accounts:[...g.filter(P=>P.id!==h),k]})},o=()=>{let f=t.readCreds();s(f);let p=Fe(f.cloudUrl,f.token);return(r()??[]).map(({token:h,...g})=>({...g,active:g.id===p}))},i=f=>{let p=r()?.find(h=>h.id===f);if(!p)throw new Error("Account is no longer signed in. Sign in again.");return{cloudUrl:p.cloudUrl,token:p.token}},a=f=>{let p=Fe(f.cloudUrl||"",f.token||""),h=r();p&&h&&n({version:1,accounts:h.filter(g=>g.id!==p)})},l=null;return{rememberForsionAccount:s,forsionAccounts:o,savedForsionAccount:i,forgetForsionAccount:a,cancelForsionLogin:()=>{l?.abort(),l=null},forsionDeviceLogin:async(f,p,h)=>{if(l)throw new Error("A sign-in is already in progress.");if(!f)throw new Error("\u8BF7\u5148\u586B\u5199 Forsion \u4E91\u7AEF\u5730\u5740(\u6216\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF TANGU_CLOUD_URL)");let g=new AbortController;l=g;let m=()=>{if(g.signal.aborted||l!==g)throw new Error("Sign-in cancelled.")};try{let w=f.replace(/\/+$/,""),k;try{k=await fetch(`${w}/api/auth/cli/start`,{method:"POST",headers:{"Content-Type":"application/json"},body:"{}",signal:AbortSignal.any([g.signal,AbortSignal.timeout(15e3)])}).then(C=>C.json())}catch(C){throw new Error(`\u65E0\u6CD5\u8FDE\u63A5 ${w}:${C?.message||C}`)}if(m(),!k?.device_code)throw new Error("\u4E91\u7AEF\u4E0D\u652F\u6301 CLI \u767B\u5F55(/api/auth/cli/start \u8FD4\u56DE\u5F02\u5E38)");let P=k.verification_uri_complete||`${k.verification_uri}?code=${k.user_code}`,O=new URL(`${w}/auth`);O.searchParams.set("logout","1"),O.searchParams.set("app","forsion-desktop"),O.searchParams.set("redirect",P);let A=O.toString();p?.({url:A,userCode:String(k.user_code||"")}),t.openExternal(A);let $=Date.now()+(k.expires_in||600)*1e3,b=(k.interval||2)*1e3;for(;Date.now()<$;){await Vc(b,g.signal),m();let C=null;try{C=await fetch(`${w}/api/auth/cli/poll`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({device_code:k.device_code}),signal:AbortSignal.any([g.signal,AbortSignal.timeout(15e3)])})}catch{m();continue}if(m(),C.status===410)throw new Error("\u767B\u5F55\u7801\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u53D1\u8D77\u767B\u5F55");let E=await C.json().catch(()=>({status:"pending"}));if(m(),E.status==="approved"&&E.token){let T={cloudUrl:w,token:E.token};return await h(T,m),m(),{token:E.token,cloudUrl:w}}}throw new Error("\u767B\u5F55\u8D85\u65F6,\u8BF7\u91CD\u8BD5")}finally{l===g&&(l=null)}},readAccounts:()=>r()??[]}}function Qc(t){let e=()=>Zc(t(),"auth-accounts.json");return{read:()=>Jc(e(),"utf8"),write:n=>{Gc(t(),{recursive:!0});let r=`${e()}.tmp`;Yc(r,n,{encoding:"utf8",mode:384}),Kc(r,384),Xc(r,e())}}}var ai=t=>oi(t,Qc(()=>t.homeDir())),li=["homeDir","appVersion","broadcast","accountBackendState","accountTransition","accountCommit","accountClear","writeCreds","onExternalCredsChange","setTokenRefresher","readCreds"],Kr=t=>li.every(e=>typeof t[e]=="function");function Xr(t){let e={ok:!1,error:"untrusted"},n={loggedIn:!1,error:"untrusted"},r=ai(t),s=0,o=()=>{let a=t.readCreds();return Kt(a.cloudUrl,a.token)},i=null;t.handle("auth:status",async a=>{if(!t.isTrustedSender(a))return n;let l=s,c=o(),{base:u}=await t.getCloud(),f=t.readCreds().token,p=f?await Jt(u,f):null,h=await t.accountBackendState(),{base:g}=await t.getCloud(),m=t.readCreds(),w=Kt(g,m.token)!==Kt(u,f),k=Kt(u,f);!w&&p?.status==="ok"&&p.user&&(i={key:k,user:p.user},r.rememberForsionAccount({...m,cloudUrl:u},p.user));let P=w?void 0:p?.status==="ok"?p.user:p?.status==="offline"&&i?.key===k?i.user:void 0;if(w)return{loggedIn:!!m.token,tokenValid:null,cloudUrl:g,accountId:Fe(g,m.token),username:null,nickname:null,avatar:null,membershipTier:null,tokenSource:m.token?"tangu-login":null,backendState:h};if(p?.status==="expired"){await t.accountTransition(async()=>{if(l!==s||o()!==c)return;let A=()=>{if(l!==s||o()!==c)throw ii};try{await t.accountClear(A,()=>{t.log("[auth] token \u5DF2\u5931\u6548(\u670D\u52A1\u7AEF 401/403),\u81EA\u52A8\u767B\u51FA"),++s,r.cancelForsionLogin(),r.forgetForsionAccount(t.readCreds()),i=null})}catch($){if($!==ii)throw $}});let O=t.readCreds();return{loggedIn:!!O.token,tokenValid:null,cloudUrl:O.cloudUrl||u,accountId:Fe(O.cloudUrl||u,O.token),username:null,nickname:null,avatar:null,membershipTier:null,tokenSource:O.token?"tangu-login":null,backendState:h}}return{loggedIn:!!f,tokenValid:p&&p.status==="ok"?!0:null,cloudUrl:u,accountId:Fe(u,f),username:P?.username||null,nickname:P?.nickname||null,avatar:P?.avatar||null,membershipTier:P?.membershipTier||null,tokenSource:f?"tangu-login":null,backendState:h}}),t.handle("auth:accounts",a=>t.isTrustedSender(a)?r.forsionAccounts():[]),t.handle("auth:switchAccount",async(a,l)=>{if(!t.isTrustedSender(a))return e;if(typeof l!="string")throw new Error("Invalid account.");let c=++s;return r.cancelForsionLogin(),t.accountTransition(async()=>{let u=r.savedForsionAccount(l);return await t.accountCommit(u,()=>{if(c!==s)throw new Error("Account switch cancelled.")},()=>{r.rememberForsionAccount(u),i=null}),{ok:!0,cloudUrl:u.cloudUrl||""}})}),t.handle("auth:forsionLogin",async(a,l)=>{if(!t.isTrustedSender(a))return e;let c=++s;r.cancelForsionLogin();let{base:u}=await t.getCloud();if(c!==s)throw new Error("Sign-in cancelled.");let f=(l||u||"").trim();return{ok:!0,cloudUrl:(await r.forsionDeviceLogin(f,h=>t.broadcast("auth:device",h),(h,g)=>t.accountTransition(()=>t.accountCommit(h,()=>{if(g(),c!==s)throw new Error("Sign-in cancelled.")},()=>{r.rememberForsionAccount(h),i=null})))).cloudUrl}}),t.handle("auth:logout",async a=>t.isTrustedSender(a)?(++s,r.cancelForsionLogin(),t.accountTransition(async()=>{let{base:l}=await t.getCloud(),c=t.readCreds();return await t.accountClear(void 0,()=>{r.forgetForsionAccount(c),i=null,l&&c.token&&fetch(`${l}/api/auth/logout`,{method:"POST",headers:{Authorization:`Bearer ${c.token}`},signal:AbortSignal.timeout(5e3)}).catch(()=>{})}),{ok:!0}})):e),t.onExternalCredsChange(({previous:a,current:l})=>{++s,r.cancelForsionLogin(),a.token&&!l.token&&r.forgetForsionAccount(a),i=null,r.rememberForsionAccount(l)}),t.setTokenRefresher(async a=>{let l=s,c=o(),u=t.readCreds().token;if(!Hn(u))return;let{base:f}=await t.getCloud(),p=await Bn(f,u,a,`desktop/${t.appVersion()}`);if(!p){t.log("[auth] \u6ED1\u52A8\u7EED\u671F\u672A\u6210\u529F(\u79BB\u7EBF/\u8001\u7248\u672C server/\u8FD9\u679A\u5DF2\u5931\u6548),\u7EE7\u7EED\u7528\u65E7 token");return}l!==s||o()!==c||(r.rememberForsionAccount({cloudUrl:f,token:p}),t.writeCreds({cloudUrl:f,token:p}),t.log("[auth] \u767B\u5F55\u6001\u5DF2\u6ED1\u52A8\u7EED\u671F(\u6709\u6548\u671F\u91CD\u65B0\u8BA1\u6EE1 2 \u5468)"))}),t.log("[forsion-extend] account core registered")}var ii=Symbol("stale-auth-intent");import{promises as Mt}from"node:fs";import _t from"node:path";import{execFile as Cu}from"node:child_process";import xu from"node:os";var Zr=null;function ci(t){Zr=t}function $e(){if(!Zr)throw new Error("amadeus sync env not set (registerAmadeus factory has not run)");return Zr}var Ae=()=>$e().accountId();function Xt(t=Ae()){return t?Ee().sha256Hex(t):"signed-out"}var Ue=(t=Ae())=>$e().readConfig(t),ot=(t,e=Ae())=>$e().writeConfig(t,e),Dt=(t,e=Ae())=>$e().updateConfig(t,e),ht=(t=Ae())=>$e().cloudVaultDir(t),qn=t=>$e().isManagedCloudVault(t);function eu(t,e){let n=Object.create(null);for(let o=0;o<e.length;o++){let i=e[o];n[i]?n[i].push(o):n[i]=[o]}let s=[{buffer1index:-1,buffer2index:-1,chain:null}];for(let o=0;o<t.length;o++){let i=t[o],a=n[i]||[],l=0,c=s[0];for(let u of a){let f;for(f=l;f<s.length&&!(s[f].buffer2index<u&&(f===s.length-1||s[f+1].buffer2index>u));f++);if(f<s.length){let p={buffer1index:o,buffer2index:u,chain:s[f]};if(l===s.length?s.push(c):s[l]=c,l=f+1,c=p,l===s.length)break}}s[l]=c}return s[s.length-1]}function ui(t,e){let n=eu(t,e),r=[],s=t.length,o=e.length;for(let i=n;i!==null;i=i.chain){let a=s-i.buffer1index-1,l=o-i.buffer2index-1;s=i.buffer1index,o=i.buffer2index,(a||l)&&r.push({buffer1:[s+1,a],buffer1Content:t.slice(s+1,s+1+a),buffer2:[o+1,l],buffer2Content:e.slice(o+1,o+1+l)})}return r.reverse(),r}function tu(t,e,n){let r=[];function s(l,c){r.push({ab:c,oStart:l.buffer1[0],oLength:l.buffer1[1],abStart:l.buffer2[0],abLength:l.buffer2[1]})}ui(e,t).forEach(l=>s(l,"a")),ui(e,n).forEach(l=>s(l,"b")),r.sort((l,c)=>l.oStart-c.oStart);let o=[],i=0;function a(l){l>i&&(o.push({stable:!0,buffer:"o",bufferStart:i,bufferLength:l-i,bufferContent:e.slice(i,l)}),i=l)}for(;r.length;){let l=r.shift(),c=l.oStart,u=l.oStart+l.oLength,f=[l];for(a(c);r.length;){let p=r[0],h=p.oStart;if(h>u)break;u=Math.max(u,h+p.oLength),f.push(r.shift())}if(f.length===1){if(l.abLength>0){let p=l.ab==="a"?t:n;o.push({stable:!0,buffer:l.ab,bufferStart:l.abStart,bufferLength:l.abLength,bufferContent:p.slice(l.abStart,l.abStart+l.abLength)})}}else{let p={a:[t.length,-1,e.length,-1],b:[n.length,-1,e.length,-1]};for(;f.length;){l=f.shift();let P=l.oStart,O=P+l.oLength,A=l.abStart,$=A+l.abLength,b=p[l.ab];b[0]=Math.min(A,b[0]),b[1]=Math.max($,b[1]),b[2]=Math.min(P,b[2]),b[3]=Math.max(O,b[3])}let h=p.a[0]+(c-p.a[2]),g=p.a[1]+(u-p.a[3]),m=p.b[0]+(c-p.b[2]),w=p.b[1]+(u-p.b[3]),k={stable:!1,aStart:h,aLength:g-h,aContent:t.slice(h,g),oStart:c,oLength:u-c,oContent:e.slice(c,u),bStart:m,bLength:w-m,bContent:n.slice(m,w)};o.push(k)}i=u}return a(e.length),o}function di(t,e,n,r){r=Object.assign({excludeFalseConflicts:!0,stringSeparator:/\s+/},r),typeof t=="string"&&(t=t.split(r.stringSeparator)),typeof e=="string"&&(e=e.split(r.stringSeparator)),typeof n=="string"&&(n=n.split(r.stringSeparator));let o=[],i=tu(t,e,n),a=[];function l(){a.length&&o.push({ok:a}),a=[]}function c(u,f){if(u.length!==f.length)return!1;for(let p=0;p<u.length;p++)if(u[p]!==f[p])return!1;return!0}return i.forEach(u=>{u.stable?a.push(...u.bufferContent):r.excludeFalseConflicts&&c(u.aContent,u.bContent)?a.push(...u.aContent):(l(),o.push({conflict:{a:u.aContent,aIndex:u.aStart,o:u.oContent,oIndex:u.oStart,b:u.bContent,bIndex:u.bStart}}))}),l(),o}function Wn(t,e){let n=t.lastIndexOf("/"),r=n<0?"":t.slice(0,n+1),s=n<0?t:t.slice(n+1),o=s.lastIndexOf("."),i=o>0?s.slice(0,o):s,a=o>0?s.slice(o):"",l=u=>String(u).padStart(2,"0"),c=`${e.getFullYear()}-${l(e.getMonth()+1)}-${l(e.getDate())} ${l(e.getHours())}${l(e.getMinutes())}`;return`${r}${i} (conflict ${c})${a}`}function nu(t,e){if(e<2)return t;let n=t.lastIndexOf("."),r=n>t.lastIndexOf("/")&&n>t.lastIndexOf(")"),s=r?t.slice(0,n):t,o=r?t.slice(n):"";return`${s}-${e}${o}`}function ru(t){let e=3735928559,n=1103547991;for(let s=0;s<t.length;s++){let o=t.charCodeAt(s);e=Math.imul(e^o,2654435761),n=Math.imul(n^o,1597334677)}e=Math.imul(e^e>>>16,2246822507)^Math.imul(n^n>>>13,3266489909),n=Math.imul(n^n>>>16,2246822507)^Math.imul(e^e>>>13,3266489909);let r=4294967296*(2097151&n)+(e>>>0);return`${t.length.toString(36)}-${r.toString(36)}`}function Vn(t,e,n){if(t===null&&e===null&&n===null)return{kind:"none"};if(n===null)return t===null?e?{kind:"dropShadow"}:{kind:"none"}:e?t===e.hash?{kind:"deleteLocal"}:{kind:"pushCreate"}:{kind:"pushCreate"};if(t===null)return e?n.seq===e.seq?{kind:"pushDelete"}:{kind:"pull"}:{kind:"pull"};if(!e)return t===n.hash?{kind:"adopt"}:{kind:"conflict"};let r=t!==e.hash,s=n.seq!==e.seq;return!r&&!s?{kind:"none"}:r?s?t===n.hash?{kind:"adopt"}:n.hash===e.hash?{kind:"push",baseSeq:n.seq}:{kind:"conflict"}:{kind:"push",baseSeq:e.seq}:{kind:"pull"}}function fi(t,e,n){let r=di(t.split(`
|
|
204
204
|
`),e.split(`
|
|
205
205
|
`),n.split(`
|
|
206
206
|
`),{excludeFalseConflicts:!0}),s=[];for(let o of r){if(o.conflict)return null;o.ok&&s.push(...o.ok)}return s.join(`
|
|
207
|
-
`)}function
|
|
208
|
-
`),
|
|
209
|
-
`);if(O<0)break;let C=m.slice(0,O).replace(/\r$/,"");if(m=m.slice(O+1),C==="")p();else{if(C.startsWith(":"))continue;C.startsWith("event:")?h=C.slice(6).trim():C.startsWith("data:")&&g.push(C.slice(5).replace(/^ /,""))}}}}catch(y){n||a(y);return}a(new Error("sse stream ended"))};return l(),{stop:()=>{n=!0,o&&clearTimeout(o),s?.abort()}}}var Yt=t=>Se().path.join(Ie().userDataDir(),Ie().isDevMode()?`${t}.dev.json`:`${t}.json`),Ur=Yt;async function Fr(t){try{let e=JSON.parse(await Se().fs.readFile(Ur(t),"utf8"));return!e||typeof e.vaultRoot!="string"||typeof e.vaultId!="string"?null:(e.files=e.files??{},e.cursor=Number(e.cursor??0),e.lastSyncAt=e.lastSyncAt??null,e)}catch{return null}}function zo(t){let e=null,n=null,r=Promise.resolve(),s=null,o=()=>{if(!e)return r;let i=e,a=JSON.stringify(e);return e=null,r=r.then(async()=>{try{let l=Ur(t),c=`${l}.tmp-${Se().tmpTag()}-${Date.now()}-0`;await Se().fs.writeFile(c,a,"utf8"),await Se().fs.rename(c,l),s=null}catch(l){e??=i,s=l}}),r};return{save(i){e=i,!n&&(n=setTimeout(()=>{n=null,o()},500))},async flush(i=!1){if(n&&(clearTimeout(n),n=null),await o(),i&&s)throw s}}}async function Ho(t){try{await Se().fs.unlink(Ur(t))}catch{}}var ic=5*1024*1024,ac=5*1024*1024,lc=3e4,cc=2500,uc=3e3,dc=5,fc=256*1024,hc=5,qo=1024*1024,Bo=200,pc=6e4,mc=50,gc=".sync-trash",xt=t=>Se().sha256Hex(t);function Jt(t,e={localRoot:it(),shadowName:`amadeus-sync-${Wt()}`,vaultId:"first",serverDir:"",excludePrefixes:["\u4E0E\u6211\u5171\u4EAB/"]}){let n=d=>{let S=jr(d,"");if(!S)return null;for(let v of e.excludePrefixes??[])if(S===v.replace(/\/$/,"")||S.startsWith(v))return null;if(e.ignoreNames?.length&&S.split("/").some(v=>e.ignoreNames.includes(v)))return null;let k=e.serverDir?`${e.serverDir}/${S}`:S;return e.inScope&&!e.inScope(k,ze(k))?null:k},r=d=>{let S;if(e.serverDir){if(!d.startsWith(`${e.serverDir}/`))return null;S=d.slice(e.serverDir.length+1)}else{for(let k of e.excludePrefixes??[])if(d.startsWith(k))return null;S=d}return S.split("/").some(k=>Vt(k)||!!e.ignoreNames?.includes(k))?null:S},s=(d,S)=>!e.inScope||e.inScope(d,S),o=e.accountId??Te(),{fs:i,path:a}=Se(),l=d=>i.access(d).then(()=>!0,()=>!1),c=!1,u=0,f=Promise.resolve(),m=new Set,h="disabled",g=null,p=null,y=null,_=null,O=null,C=null,M=0,H=new Map,w=null,x=zo(e.shadowName),b=new Map,I=!1,U=!1,B=[],J=()=>{p&&(p.pending=b.size?Object.fromEntries(b):void 0,x.save(p))},se=()=>{U=!1,B.length=0},pe=()=>{if(U)return!0;let d=Date.now();for(;B.length&&d-B[0]>pc;)B.shift();return B.length>=mc?(U=!0,!0):!1},X=[],de=new Set,Z=!1,ke=null,oe=null,Ee=null,fe=()=>{!c||Ee||(Ee=setTimeout(()=>{Ee=null,t.onStatus(ht())},200))},ye=(d,S)=>{h=d,S!==void 0&&(g=S),fe()},ae=(d,S=!1)=>{if(c){if(d.key){if(de.has(d.key))return;de.add(d.key)}S?X.unshift(d):X.push(d),z()}},be=new Map,E=d=>{if(!c)return;let S=(p?.files[d]?.size??0)>fc,k=(e.pushQuietMs??uc)*(S?hc:1),v=Date.now(),R=be.get(d);R&&clearTimeout(R.timer);let L=R?.since??v,q=Math.max(0,Math.min(k,L+k*dc-v)),F=setTimeout(()=>{be.delete(d),ae({key:d,run:()=>_e(d,!0)})},q);be.set(d,{timer:F,since:L}),fe()},P=()=>{for(let{timer:d}of be.values())clearTimeout(d);be.clear()},T=d=>!(d instanceof Ce)||d.status>=500||d.status===0,A=d=>d instanceof Ce&&(d.status===401||d.status===403),z=async()=>{if(!Z){Z=!0;try{for(;X.length;){(h==="idle"||h==="starting")&&ye("syncing");let d=X.shift();d.key&&de.delete(d.key);try{await d.run()}catch(S){if(!c)return;if(A(S)){X.length=0,de.clear(),mn(),ye("auth-required","login-expired");return}if(T(S)){ae(d,!0),mn(),ye("offline",S?.message||"network error"),D();return}let k=d.key??"(op)";H.set(k,S?.body?.code||`http ${S?.status}`),fe()}}c&&h==="syncing"&&(p&&(p.lastSyncAt=Date.now(),x.save(p)),ye("idle",null))}finally{Z=!1;for(let d of m)d();m.clear()}}},D=()=>{!c||ke||(ke=setTimeout(()=>{ke=null,Nt()},lc))},$=d=>{if(!C||!p)throw new Error("engine not bound");let S=r(d);if(S===null)throw new Error("path outside binding: "+d);let k=a.resolve(C,jo(S,p.folder)),v=a.relative(C,k);if(v.startsWith("..")||a.isAbsolute(v))throw new Error("path escapes vault: "+d);return k},N=d=>({size:d,mtimeMs:-1}),Y=async d=>{try{let S=await i.stat(d);return S.isFile()?{size:S.size,mtimeMs:Math.floor(S.mtimeMs)}:null}catch{return null}},W=0,G=async(d,S,k=()=>!0)=>{await i.mkdir(a.dirname(d),{recursive:!0});let v=`${d}.tmp-${Se().tmpTag()}-${Date.now()}-${W++}`;await i.writeFile(v,S);let R=await Y(v)??N(ir(S));return k()?(await i.rename(v,d),R):(await i.rm(v,{force:!0}),null)},le=async d=>{let S;try{S=await i.readdir(d,{withFileTypes:!0})}catch{return}for(let k of S)k.isDirectory()&&await le(a.join(d,k.name));try{await i.rmdir(d)}catch{}},ie=async d=>{let S=$(d),k=await Y(S),v;try{v=await i.readFile(S)}catch{return null}return{hash:at(ze(d))?xt(ot(v)):xt(v),size:k?.size??v.length,mtimeMs:k?.mtimeMs??-1,buf:v}},he=async(d,S,k,v)=>{p&&(p.files[d]={seq:S,hash:k,size:v.size,mtimeMs:v.mtimeMs},x.save(p))},ce=d=>{p&&d in p.files&&(delete p.files[d],x.save(p))},ue=async(d,S)=>{if(!y||!p||je(d))return;let k=we,v=ze(d),R,L,q;if(at(v)){let K;try{K=await y.getFile(p.vaultId,d)}catch(te){if(te instanceof Ce&&te.status===404){await Re(d);return}throw te}R=K.content,L=K.seq,q=K.hash??xt(K.content)}else{let K;try{K=await y.getAsset(p.vaultId,d)}catch(te){if(te instanceof Ce&&te.status===404){H.set(d,"ASSET_404"),fe();return}throw te}R=K,L=S??0,q=xt(K)}let F=await ie(d);if(k!==we||je(d))return;if(F&&F.hash===q){await he(d,L,q,F);return}let V=p.files[d];if(F&&V&&q===V.hash&&F.hash!==V.hash){await he(d,L,q,N(V.size)),ae({key:d,run:()=>_e(d)});return}if(F&&(!V||F.hash!==V.hash)&&(V&&v==="page"&&typeof R=="string"&&await Ue(d,V,F,R,L,q,()=>k===we&&!je(d))||k!==we||je(d)||!await wt(d,()=>k===we&&!je(d))))return;let j=await G($(d),R,()=>k===we&&!je(d));j&&await he(d,L,q,j)},Ue=async(d,S,k,v,R,L,q)=>{try{if(!y||!p||k.buf.length>qo||v.length>qo)return!1;let V=(await y.listVersions(p.vaultId,d)).find(te=>te.seq===S.seq);if(!V)return!1;let j=await y.getVersion(p.vaultId,V.id);if(xt(j)!==S.hash)return!1;let K=No(ot(k.buf),j,v);return K===null?!1:(await G($(d),K,q)&&(await he(d,R,L,N(ir(K))),ae({key:d,run:()=>_e(d)})),!0)}catch{return!1}},wt=async(d,S)=>{let k=Ct(Mn(d,new Date));if(!k)return!0;let v=k.lastIndexOf("."),R=v>k.lastIndexOf("/"),L=R?k.slice(0,v):k,q=R?k.slice(v):"",F=k,V=Se().existsSync;if(V)for(let j=2;V($(F));j++)F=`${L}-${j}${q}`;else for(let j=2;await l($(F));j++)F=`${L}-${j}${q}`;if(!S())return!1;try{await i.rename($(d),$(F))}catch(j){if(j?.code==="ENOENT")return!0;throw j}return M++,ae({key:F,run:()=>_e(F)}),fe(),!0},bt=async d=>{if(!C)return;let S=$(d),k=r(d)??d,v=a.join(C,gc,new Date().toISOString().slice(0,10),...k.split("/")),R=await l(v)?`${v}.${Date.now()}`:v;try{await i.mkdir(a.dirname(R),{recursive:!0}),await i.rename(S,R)}catch(L){if(L?.code==="ENOENT")return;throw new Error(`\u8F6F\u5220\u5931\u8D25,\u4FDD\u7559\u672C\u5730\u6587\u4EF6 ${S}: ${L?.message??String(L)}`)}},Re=async d=>{if(!p)return;let S=await ie(d);if(je(d))return;let k=p.files[d]??null,v=Nn(S?.hash??null,k,null);if(v.kind==="deleteLocal"){if(!I&&pe()){b.set(d,"local"),J(),fe();return}B.push(Date.now()),await bt(d),ce(d)}else v.kind==="pushCreate"?(ce(d),ae({key:d,run:()=>_e(d)})):ce(d)},Ss=(d,S)=>{if(p){for(let k of Object.keys(p.files))if(k===d||k.startsWith(`${d}/`)){let v=S+k.slice(d.length);p.files[v]=p.files[k],delete p.files[k]}x.save(p)}},vs=async d=>{if(!y||!p||d.seq<=p.cursor||!await fn())return;if(d.origin.client&&y.clientId===d.origin.client){p.cursor=d.seq,x.save(p);return}let S=d.type==="structure"?"folder":d.type,k=R=>r(R)!==null&&s(R,S);if(!k(d.path)&&!(d.newPath&&k(d.newPath))){p.cursor=d.seq,x.save(p);return}let v=d.path;switch(d.op){case"write":await ue(v,d.fileSeq);break;case"delete":await Re(v);break;case"move":{let R=d.newPath;if(!R)break;let L=p.files[v];if(await ie(v)&&L)try{await i.mkdir(a.dirname($(R)),{recursive:!0}),await i.rename($(v),$(R)),p.files[R]={...L,seq:d.fileSeq??L.seq},delete p.files[v],x.save(p)}catch{await ue(R,d.fileSeq)}else ce(v),await ue(R,d.fileSeq);break}case"mkdir":await i.mkdir($(v),{recursive:!0});break;case"rename-folder":case"move-folder":{let R=d.newPath;if(!R)break;try{await i.mkdir(a.dirname($(R)),{recursive:!0}),await i.rename($(v),$(R))}catch{}Ss(v,R);break}case"delete-folder":{let R=`${v}/`;for(let L of Object.keys(p.files))(L===v||L.startsWith(R))&&await Re(L);await le($(v));break}}if(p.cursor=d.seq,x.save(p),d.op==="move"||d.op==="rename-folder"||d.op==="move-folder"||d.op==="delete"||d.op==="delete-folder")try{await t.onRemoteApplied?.(d)}catch{}},aa=async(d,S,k)=>{let v=Number(S?.seq??0),R=S?.content??null;if(R!==null&&xt(R)===k.hash){await he(d,v,k.hash,k);return}if(R===null&&v===0){if(!p?.files[d]){H.set(d,S?.code||"EXISTS"),fe();return}ce(d),ae({key:d,run:()=>_e(d)});return}await ue(d,v)},un=async(d,S)=>{if(!y||!p)return;let k=await ie(d);if(!k){ae({key:d,run:()=>_e(d)});return}if(k.size>ic){H.set(d,"TOO_LARGE"),fe();return}let v=ot(k.buf);try{let R=await y.putFile(p.vaultId,d,v,S);H.delete(d),await he(d,R.seq,R.hash??k.hash,k)}catch(R){if(R instanceof Ce&&R.status===409){await aa(d,R.body,k);return}throw R}},dn=async(d,S)=>{if(!y||!p)return;let k=await ie(d);if(!k){ae({key:d,run:()=>_e(d)});return}if(k.size>(w??ac)){H.set(d,"TOO_LARGE"),fe();return}try{let v=await y.putBinary(p.vaultId,d,k.buf,{baseSeq:S});H.delete(d),await he(d,v.seq,k.hash,k)}catch(v){if(v instanceof Ce&&v.status===409){let R=Number(v.body?.seq??0),L=v.body?.hash??null;if(L!==null&&L===k.hash){await he(d,R,k.hash,k);return}if(R===0){if(!p.files[d]){H.set(d,v.body?.code||"EXISTS"),fe();return}ce(d),ae({key:d,run:()=>_e(d)});return}await ue(d,R);return}throw v}},ks=async d=>{if(!y||!p||je(d))return;let S=we,k=p.files[d];if(k){if(at(ze(d)))try{let v=await y.getFile(p.vaultId,d);if(v.seq!==k.seq){await ue(d,v.seq);return}}catch(v){if(v instanceof Ce&&v.status===404){ce(d);return}throw v}if(!(S!==we||je(d))){try{await y.deleteFile(p.vaultId,d,k.seq,{confirmed:I})}catch(v){if(v instanceof Ce&&v.status===409){await ue(d,Number(v.body?.seq??0)||null);return}if(v instanceof Ce&&v.status===429&&v.body?.code==="MASS_DELETE_BLOCKED"){b.set(d,"remote"),U=!0,J(),fe();return}throw v}ce(d)}}},fn=async()=>C?await i.stat(C).then(S=>S.isDirectory()).catch(()=>!1)||!e.requireRootExists&&!Object.keys(p?.files??{}).length?!0:(ye("error",`vault-missing: ${C}`),D(),!1):!1,we=0,hn=new Set,pn=new Map,De=d=>JSON.stringify([d.from,d.to]),st=(d,S)=>d===S||d.startsWith(`${S}/`),je=d=>[...p?.moves??[],...hn].some(S=>st(d,S.from)||st(d,S.to)),Ge=()=>!!(p?.moves?.length||hn.size),rr=async d=>{if(!y||!p)return;let{from:S,to:k,kind:v}=d;if(r(S)===null||r(k)===null)throw new Error("Invalid queued cloud move");d.hashes??=Object.fromEntries(Object.entries(p.files).filter(([F])=>st(F,S)).map(([F,V])=>[F.slice(S.length),V.hash])),x.save(p),await x.flush(!0);let R,L=!1;try{if(v==="folder"){let F=a.posix.dirname(S)==="."?"":a.posix.dirname(S),V=a.posix.dirname(k)==="."?"":a.posix.dirname(k);F===V?await y.renameFolder(p.vaultId,S,a.posix.basename(k)):await y.moveFolder(p.vaultId,S,V)}else{let F=await y.move(p.vaultId,S,k);R=Number(F.seq)}}catch(F){if(!(F instanceof Ce)||F.status!==404)throw F;let V=await y.tree(p.vaultId);if(V.entries.some(te=>st(te.path,S))||V.folders.some(te=>st(te,S)))throw F;let K=V.entries.find(te=>te.path===k);if(R=K?.seq,L=!K&&!V.entries.some(te=>st(te.path,k))&&!V.folders.some(te=>st(te,k)),!L){let te=Object.entries(d.hashes);if(!(te.length>0&&te.every(([Le,St])=>V.entries.some(vt=>vt.path===k+Le&&vt.hash===St))))throw new Ce(409,{code:"MOVE_DESTINATION_CHANGED"},"local-move")}}if(L)for(let F of Object.keys(p.files))st(F,S)&&delete p.files[F];else Ss(S,k),R!==void 0&&p.files[k]&&(p.files[k].seq=R);p.moves=(p.moves??[]).filter(F=>De(F)!==De(d)),x.save(p);try{await x.flush(!0)}catch(F){throw p.moves.unshift(d),x.save(p),F}let q=pn.get(De(d));pn.delete(De(d)),q?.(),je(k)||(v==="folder"?await sr():await _e(k))},_e=async(d,S=!1)=>{if(!p||je(d))return;if(!s(d,ze(d))){ce(d);return}if(!await fn())return;let k=await ie(d);if(je(d))return;let v=p.files[d]??null,R=Nn(k?.hash??null,v,v?{seq:v.seq,hash:v.hash}:null);switch(R.kind){case"push":at(ze(d))?await un(d,R.baseSeq):await dn(d,R.baseSeq);break;case"pushCreate":at(ze(d))?await un(d,0):await dn(d,0);break;case"pushDelete":if(S){yn();break}if(!I&&(b.has(d)||pe())){b.set(d,"remote"),J(),fe();break}B.push(Date.now()),await ks(d);break;case"dropShadow":ce(d);break;default:k&&v&&k.hash===v.hash&&k.mtimeMs>=0&&(v.size!==k.size||v.mtimeMs!==k.mtimeMs)&&await he(d,v.seq,v.hash,k);break}},Es=async()=>{let d=new Map;if(!C||!p)return d;let S=C,k=null,v=async R=>{if(k)return;let L;try{L=await i.readdir(R,{withFileTypes:!0})}catch(q){k=`${R}: ${q?.message??String(q)}`;return}for(let q of L){if(Vt(q.name)||q.isDirectory()&&e.ignoreNames?.includes(q.name))continue;let F=a.join(R,q.name);if(q.isDirectory())await v(F);else if(q.isFile()){let V=a.relative(S,F).split(a.sep).join("/"),j=n(V);if(!j)continue;try{let K=await i.stat(F);if(!K.isFile())continue;d.set(j,{size:K.size,mtimeMs:Math.floor(K.mtimeMs)})}catch(K){if(K?.code==="ENOENT")continue;k=`${F}: ${K?.message??String(K)}`;return}}}};return await v(S),k?(ye("error",`scan-failed: ${k}`),D(),null):d},sr=async()=>{let d=we;if(Ge()||d!==we||!p||!await fn())return;let S=await Es();if(!S||Ge()||d!==we)return;let k=!1;for(let[L,q]of[...b])(q==="remote"&&S.has(L)||q==="local"&&!S.has(L))&&(b.delete(L),k=!0);b.size||se();for(let[L,q]of S){let F=p.files[L];F&&F.size===q.size&&F.mtimeMs===q.mtimeMs||ae({key:L,run:()=>_e(L)})}let v=Object.keys(p.files),R=v.filter(L=>!S.has(L));if(R.length&&!I&&(U||Nr(R.length,v.length,Bo))){U=!0;for(let L of R)b.set(L,"remote");J(),fe();return}k&&(J(),fe());for(let L of R)b.has(L)||ae({key:L,run:()=>_e(L)})},Ot=async()=>{let d=we;if(Ge()||d!==we||!y||!p||!C||!await fn())return;let S=await y.tree(p.vaultId);if(S.maxFileBytes!==void 0&&S.maxFileBytes!==w&&(w=S.maxFileBytes,fe()),Ge()||d!==we)return;let k=new Map;for(let j of S.entries)r(j.path)===null||!s(j.path,j.kind)||k.set(j.path,j);let v=await Es();if(!v||Ge()||d!==we)return;let R=new Set([...k.keys(),...v.keys(),...Object.keys(p.files)]),L=Object.keys(p.files).length,q=[];for(let j of R){if(Ge()||d!==we)return;let K=p.files[j]??null,te=k.get(j)??null,xe=v.get(j)??null,Le=null,St=N(xe?.size??0);if(xe)if(K&&K.size===xe.size&&K.mtimeMs===xe.mtimeMs)Le=K.hash,St=xe;else{let vt=await ie(j);vt&&(Le=vt.hash,St=vt)}q.push({sp:j,d:Nn(Le,K,te?{seq:te.seq,hash:te.hash}:null),rSeq:te?.seq??null,localHash:Le,localStat:St})}if(Ge()||d!==we)return;let F=q.filter(j=>j.d.kind==="deleteLocal"||j.d.kind==="pushDelete").length,V=!I&&(U||Nr(F,L,Bo));V&&F&&(U=!0),b.clear();for(let{sp:j,d:K,rSeq:te,localHash:xe,localStat:Le}of q){if(Ge()||d!==we)return;if(V&&(K.kind==="deleteLocal"||K.kind==="pushDelete")){b.set(j,K.kind==="deleteLocal"?"local":"remote");continue}if((K.kind==="deleteLocal"||K.kind==="pushDelete")&&((await ie(j))?.hash??null)!==xe){ae({key:j,run:()=>_e(j)});continue}if(Ge()||d!==we)return;switch(K.kind){case"adopt":await he(j,te,xe,Le);break;case"pull":await ue(j,te);break;case"push":at(ze(j))?await un(j,K.baseSeq):await dn(j,K.baseSeq);break;case"pushCreate":at(ze(j))?await un(j,0):await dn(j,0);break;case"pushDelete":await ks(j);break;case"deleteLocal":await bt(j),ce(j);break;case"conflict":await ue(j,te);break;case"dropShadow":ce(j);break;case"none":break}}I&&(I=!1,B.length=0),b.size||se(),J(),V&&fe();for(let j of S.folders)if(!(r(j)===null||!s(j,"folder")))try{await i.mkdir($(j),{recursive:!0})}catch{}p.cursor=S.seq,p.lastSyncAt=Date.now(),x.save(p)},la=async()=>{if(!y||!p)return;let d=p.cursor,S=await y.changes(p.vaultId,d);if(S.changes.length===0&&S.seq>d||S.changes.length>0&&S.changes[0].seq!==d+1){await Ot();return}for(let v of S.changes)await vs(v)},Mt=null,_s=[],Cs=()=>{Mt&&_s.push(Mt.close()),Mt=null},ca=()=>{if(!c||Mt||!C)return;let d=Se();if(!d.watch)return;let S=k=>{if(!C)return;let v=a.relative(C,k);if(!v||v.startsWith(".."))return;let R=n(v);R&&E(R)};Mt=d.watch(C,{depth:12,ignored:k=>{let v=a.basename(k);return Vt(v)||!!e.ignoreNames?.includes(v)}},{change:S,add:S,unlink:()=>yn(),unlinkDir:()=>yn()})},mn=()=>{_?.stop(),_=null},ua=()=>{if(!c||!y||!p||_)return;let d=O;d&&(_=Lo({baseUrl:d.cloudUrl,vaultId:p.vaultId,token:d.token},{getSince:()=>p?.cursor??0,onHello:S=>{p&&S>p.cursor&&ae({run:la})},onChange:S=>{ae({run:()=>vs(S)})},onReset:()=>{ae({run:Ot})},onOpen:()=>{(h==="offline"||h==="starting")&&ye("idle",null),ae({run:sr})},onDown:()=>{(h==="idle"||h==="syncing")&&ye("offline")},onPresence:S=>t.onPresence?.(p?.vaultId??"",S),onPresenceRoster:S=>t.onPresenceRoster?.(p?.vaultId??"",S)}))},da=async()=>{let d=await Me(o);if(d.cloudSync?.deviceId)return d.cloudSync.deviceId;let S=`desk-${Math.random().toString(36).slice(2,10)}${Date.now().toString(36)}`;return await Ke({cloudSync:{...d.cloudSync??{},deviceId:S}},o),S},fa=async d=>{mn(),Cs(),X.length=0,de.clear(),b.clear(),I=!1,U=!1,B.length=0;let S=await Me(o);if(d!==u)return;let k=S.cloudSync;if(k?.enabled===!1){C=null,y=null,ye("disabled",null);return}if(!o||o!==Te()){ye("auth-required","not-logged-in");return}if(C=e.localRoot,e.requireRootExists){let q=await i.stat(C).then(F=>F.isDirectory()).catch(()=>!1);if(d!==u)return;if(!q){ye("error",`vault-missing: ${C}`),D();return}}if(d!==u)return;let v=t.loadCreds();if(!v.cloudUrl||!v.token){y=null,ye("auth-required","not-logged-in");return}ye("starting",null);let R=k?.deviceId??await da();if(d!==u)return;let L=e.clientIdSuffix?`${R}#${e.clientIdSuffix}`:R;O={cloudUrl:v.cloudUrl,token:v.token},y=Fo({baseUrl:v.cloudUrl,token:v.token,clientId:L});try{let q=e.vaultId==="first"?k?.vaultId:e.vaultId;if(!q){let V=await y.listVaults();if(d!==u)return;if(!V.length)throw new Error("\u4E91\u7AEF\u65E0\u53EF\u7528 vault");q=V[0].id,await Ke({cloudSync:{...k??{},vaultId:q}},o)}if(d!==u)return;let F=await Fr(e.shadowName);if(d!==u||(p=F&&F.vaultRoot===C&&F.vaultId===q&&F.folder===""?F:{vaultRoot:C,folder:"",vaultId:q,cursor:0,lastSyncAt:null,files:{}},d!==u))return;for(let[V,j]of Object.entries(p.pending??{}))b.set(V,j);if(b.size&&(U=!0),!e.requireRootExists){let V=await i.stat(C).then(j=>j.isDirectory()).catch(()=>!1);if(d!==u)return;if(!V){if(Object.keys(p.files).length){ye("error",`mirror-missing: ${C}`),D();return}if(await i.mkdir(C,{recursive:!0}),d!==u)return}}ca();for(let V of p.moves??[])ae({key:`move:${De(V)}`,run:()=>rr(V)});ae({run:Ot}),ae({run:async()=>{ua()}})}catch(q){if(d!==u)return;A(q)?ye("auth-required","login-expired"):(ye("offline",q?.message||String(q)),D())}},xs=()=>{c=!1,mn(),Cs(),X.length=0,de.clear(),P();for(let d of[ke,oe,Ee])d&&clearTimeout(d);ke=oe=Ee=null},Ts=async()=>{Z&&await new Promise(d=>m.add(d)),await Promise.all(_s.splice(0)),await x.flush(),p=null,y=null,O=null,C=null,M=0,H.clear(),w=null,b.clear(),I=!1,U=!1,B.length=0,h="disabled",g=null},ha=()=>{As()},gn=null,Nt=()=>{gn?.(),gn=Ie().onBeforeQuit(ha);let d=++u;xs();let S=f.catch(()=>{}).then(async()=>{await Ts(),d===u&&(c=!0,await fa(d))});return f=S,S},As=()=>{gn?.(),gn=null,++u,xs();let d=f.catch(()=>{}).then(Ts);return f=d,d},ht=()=>({enabled:h!=="disabled",state:h==="idle"&&be.size?"syncing":h,lastSyncAt:p?.lastSyncAt??null,pending:X.length+be.size,conflicts:M,skipped:[...H].map(([d,S])=>({path:d,reason:S})),error:g,pendingDeletions:b.size,maxFileBytes:w});return{getStatus:ht,start(){Nt()},notifyLocal(d,S,k){if(!p||h==="disabled"||h==="auth-required")return;let v=n(d),R=k?n(k):null;if(S==="write"&&v){Vt(v.split("/").pop()||"")||E(v);return}if(S==="remove"){if(!v)return;let L=`${v}/`,q=!1;for(let F of Object.keys(p.files))(F===v||F.startsWith(L))&&(q=!0,ae({key:F,run:()=>_e(F)}));!q&&v&&ae({key:v,run:()=>_e(v)})}},holdLocalMove(d,S){let k=R=>e.serverDir?`${e.serverDir}/${R.replace(/\\/g,"/").normalize("NFC")}`:R.replace(/\\/g,"/").normalize("NFC"),v={from:k(d),to:k(S)};return++we,hn.add(v),()=>{hn.delete(v)}},async notifyLocalMove(d,S,k,v){let R=n(d),L=n(S),q=p??await Fr(e.shadowName),F=jr(d,""),V=F&&(e.serverDir?`${e.serverDir}/${F}`:F);if(!R&&L&&V&&q&&Object.keys(q.files).some(j=>j===V||j.startsWith(`${V}/`))&&(R=V),!R&&!L){k?.();return}if(R&&L){let j=p??q;if(!j){k?.();return}let K=v??(Object.keys(j.files).some(xe=>xe.startsWith(`${R}/`))?"folder":"file"),te={from:R,to:L,kind:K};j.moves??=[],j.moves.some(xe=>De(xe)===De(te))||(j.moves.push(te),++we),k&&pn.set(De(te),k),x.save(j);try{await x.flush(!0)}catch(xe){throw j.moves=j.moves.filter(Le=>De(Le)!==De(te)),pn.delete(De(te)),x.save(j),xe}p===j&&c&&h!=="disabled"&&h!=="auth-required"&&ae({key:`move:${De(te)}`,run:()=>rr(te)});return}R&&this.notifyLocal(d,"remove"),L&&(ae({key:L,run:()=>_e(L)}),yn()),k?.()},async setEnabled(d){let S=await Me(o);return await Ke({cloudSync:{...S.cloudSync??{},enabled:d}},o),await Nt(),ht()},async restart(){return await Nt(),ht()},async syncNow(){if(H.clear(),h==="disabled"||h==="auth-required"||!y)await Nt();else{for(let d of p?.moves??[])ae({key:`move:${De(d)}`,run:()=>rr(d)});ae({run:Ot})}return ht()},confirmMassDeletions(){return b.size&&(I=!0,U=!1,b.clear(),B.length=0,J(),ae({run:Ot})),ht()},stop:As};function yn(){c&&(oe&&clearTimeout(oe),oe=setTimeout(()=>{oe=null,ae({run:sr})},cc))}}function Wo(t){let e=t.replace(/\.md$/i,""),n=t.lastIndexOf("/"),r=n<0?"":t.slice(0,n);return{root:t,fdPrefix:`${e}.fd/`,assetPrefix:r?`${r}/.amadeus/`:".amadeus/"}}function Vo(t,e,n){return!!(e===t.root||e.startsWith(t.fdPrefix)||`${e}/`===t.fdPrefix||n==="binary"&&e.startsWith(t.assetPrefix)||n==="folder"&&(`${e}/`===t.assetPrefix||e.startsWith(t.assetPrefix)))}var yc=t=>Se().sha256Hex(t).slice(0,8),wc=t=>t.replace(/[\\/:*?"<>|]/g," ").trim().slice(0,40)||"shared",jn="\u4E0E\u6211\u5171\u4EAB";function Lr(t){let e=yc(`${t.vaultId}:${t.path}`),n=Wo(t.path),r=t.path.includes("/")?t.path.slice(0,t.path.lastIndexOf("/")):"";return{key:e,vaultId:t.vaultId,rootPath:t.path,title:t.title,localRelDir:`${jn}/${wc(t.title)}-${e}`,serverDir:r,inScope:(s,o)=>Vo(n,s,o)}}function zr(){let t=Ie().readCreds(),e=Oe(t.cloudUrl??"",t.token??""),n=new AbortController,r=()=>{let f=Ie().readCreds();if(n.signal.aborted||!e||Oe(f.cloudUrl??"",f.token??"")!==e)throw Object.assign(new Error("Cloud account changed; retry from the current account"),{status:401});return f},s=()=>{let f=r();if(!f.cloudUrl||!f.token)throw Object.assign(new Error("\u672A\u767B\u5F55 Forsion \u8D26\u53F7"),{status:401});return f.cloudUrl.replace(/\/+$/,"")},o=async(f,m,h)=>{let g=r();if(!g.cloudUrl||!g.token)throw Object.assign(new Error("\u672A\u767B\u5F55 Forsion \u8D26\u53F7"),{status:401});let p=await fetch(`${g.cloudUrl.replace(/\/+$/,"")}/api/amadeus${m}`,{method:f,headers:{Authorization:`Bearer ${g.token}`,...h!==void 0?{"Content-Type":"application/json"}:{}},body:h!==void 0?JSON.stringify(h):void 0,signal:AbortSignal.any([n.signal,AbortSignal.timeout(2e4)])});if(!p.ok){let _=null;try{_=await p.json()}catch{}throw Object.assign(new Error(_?.detail||`http ${p.status}`),{status:p.status,code:_?.code})}let y=await p.json();return r(),y},i=null,a=async()=>(r(),i||(i=(await o("GET","/vaults")).vaults[0]?.id??"default",i)),l=()=>{try{let f=(r().token??"").split(".")[1],m=JSON.parse(ot(wn(f)));return typeof m.userId=="string"?m.userId:null}catch{return null}},c=async()=>(await o("GET","/shared-with-me")).items.map(m=>{let h=Lr(m),g=m.path.split("/").pop()??m.path;return{...m,localPath:`${h.localRelDir}/${g}`}}),u=null;return{stop:()=>n.abort(),call:o,ensureOwnVault:a,myUserId:l,sharedWithMe:c,linkBase:async()=>{if(r(),u)return u;try{u=((await o("GET","/collab/link-base")).webOrigin??"").trim().replace(/\/+$/,"")||s()}catch{u=s()}return u},async heartbeat(f,m){let h=(f??"").replace(/\\/g,"/"),g,p=null,y=m.find(_=>h.startsWith(`${_.localRelDir}/`));y?(g=y.vaultId,p=y.serverDir?`${y.serverDir}/${h.slice(y.localRelDir.length+1)}`:h.slice(y.localRelDir.length+1)):(g=await a(),p=h||null),await o("POST",`/vaults/${encodeURIComponent(g)}/presence`,{page:p})}}}import{promises as Go}from"node:fs";import bc from"node:path";var Hr=".forsion-vault.md",Yo=t=>`${t}/${Hr}`;function Un(t){let e=/^devices:\s*(\[.*\])\s*$/m.exec(t??"");if(!e)return null;try{let n=JSON.parse(e[1]);return Array.isArray(n)?n.filter(r=>!!r&&typeof r.id=="string"&&typeof r.name=="string").map(r=>({id:r.id,name:r.name,...typeof r.since=="string"?{since:r.since}:{}})):null}catch{return null}}var Jo=t=>`---
|
|
207
|
+
`)}function Qr(t,e,n=200){return t>=n||e>=5&&t>=Math.max(5,Math.ceil(e/2))}var su=/[\u0000-\u001f\u007f]/;function $t(t){let e=t.replace(/\\/g,"/").normalize("NFC").trim();if(e=e.replace(/\/+$/,""),!e||e.length>512||e.startsWith("/")||su.test(e))return null;let n=e.split("/");for(let r of n)if(!r||r==="."||r==="..")return null;return n.join("/")}function es(t,e){let n=t.replace(/\\/g,"/").normalize("NFC");return e===""?$t(n):n.startsWith(`${e}/`)?$t(n.slice(e.length+1)):null}function pi(t,e){return e===""?t:`${e}/${t}`}function Zt(t){return!!(t===".DS_Store"||t==="Icon\r"||t===".sync-trash"||/\.tmp-\d+-\d+-\d+$/.test(t)||/^\..+\.lock$/.test(t))}function We(t){return/\.md$/i.test(t)?"page":/\.db$/i.test(t)?"db":"binary"}var mt=t=>t==="page"||t==="db";var ou=1024,_e=class extends Error{status;body;constructor(e,n,r){super(`cloud http ${e} on ${r}`),this.status=e,this.body=n}},hi=t=>12e4+Math.ceil(t/256);function iu(t,e){let n=AbortSignal.timeout(t);if(!e)return n;let r=new AbortController;for(let s of[n,e])s.addEventListener("abort",()=>r.abort(s.reason),{once:!0});return r.signal}function mi(t){let e=`${t.baseUrl.replace(/\/+$/,"")}/api/amadeus`,n=()=>t.getToken?.()??t.token,r=async(i,a)=>{let l=n();for(let c=0;;c++){let u={...a.headers,Authorization:`Bearer ${l}`},f=await fetch(i,{...a,headers:u});if(n(),f.status!==401||f.redirected)return f;let p=await f.text(),h=n();if(h===l||c>0)return new Response(p,{status:f.status,statusText:f.statusText,headers:f.headers});l=h}},s=async(i,a,l)=>{let c={Authorization:`Bearer ${t.token}`,...l?.headers};i!=="GET"&&(c["X-Amadeus-Client"]=t.clientId);let u;l?.json!==void 0?(c["Content-Type"]="application/json",u=JSON.stringify(l.json),u.length>=ou&&(c["Content-Encoding"]="gzip",u=await io(u))):l?.form&&(u=l.form);let f=await r(a,{method:i,headers:c,body:u,signal:iu(l?.timeoutMs??3e4,l?.signal)});if(!f.ok){let h=null;try{h=await f.json()}catch{}throw n(),new _e(f.status,h,a)}let p=await f.json();return n(),p},o=i=>new URLSearchParams(i).toString();return{clientId:t.clientId,async listVaults(){return((await s("GET",`${e}/vaults`)).vaults??[]).map(a=>({id:String(a.id),name:String(a.name),lastChangeSeq:Number(a.lastChangeSeq??0)}))},async tree(i){let a=await s("GET",`${e}/vaults/${i}/tree`);if(!Array.isArray(a.entries))throw new Error("server too old: tree has no entries[] (deploy the amadeus microserver update)");return{folders:a.folders??[],seq:Number(a.seq??0),maxFileBytes:Number.isInteger(a.maxFileBytes)&&a.maxFileBytes>0?a.maxFileBytes:void 0,entries:a.entries.map(l=>({path:String(l.path),kind:l.kind,seq:Number(l.seq??0),hash:l.hash??null,size:Number(l.size??0)}))}},async getFile(i,a){let l=await s("GET",`${e}/vaults/${i}/file?${o({path:a})}`);return{content:String(l.content??""),seq:Number(l.seq??0),hash:l.hash??null}},putFile(i,a,l,c,u=!1){return s("PUT",`${e}/vaults/${i}/file`,{json:{path:a,content:l,baseSeq:c,...u?{force:!0}:{}}})},async deleteFile(i,a,l,c){let u={path:a};l!==void 0&&(u.baseSeq=String(l)),await s("DELETE",`${e}/vaults/${i}/file?${o(u)}`,c?.confirmed?{headers:{"X-Amadeus-Delete-Confirmed":"1"}}:void 0)},move(i,a,l){return s("POST",`${e}/vaults/${i}/move`,{json:{from:a,to:l}})},renameFolder(i,a,l){return s("POST",`${e}/vaults/${i}/folders/rename`,{json:{path:a,newName:l}})},moveFolder(i,a,l){return s("POST",`${e}/vaults/${i}/folders/move`,{json:{path:a,dest:l}})},async deleteFolder(i,a){await s("DELETE",`${e}/vaults/${i}/folders?${o({path:a})}`)},putBinary(i,a,l,c){let u=new FormData;return u.set("path",a),c?.ifAbsent&&u.set("ifAbsent","true"),c?.baseSeq!==void 0&&u.set("baseSeq",String(c.baseSeq)),u.set("file",new Blob([new Uint8Array(l)]),a.split("/").pop()||"file"),s("POST",`${e}/vaults/${i}/binary`,{form:u,timeoutMs:hi(l.length),signal:c?.signal})},async listVersions(i,a){return((await s("GET",`${e}/vaults/${i}/file/versions?${o({path:a})}`)).versions??[]).map(c=>({id:String(c.id),seq:Number(c.seq??0)}))},async getVersion(i,a){let l=await s("GET",`${e}/vaults/${i}/file/versions/${a}`);return String(l.content??"")},async getAsset(i,a,l){let c=new AbortController;l?.addEventListener("abort",()=>c.abort(l.reason),{once:!0});let u=()=>c.abort(new DOMException("Asset download timed out","TimeoutError")),f=setTimeout(u,12e4);try{let p=await r(`${e}/vaults/${i}/asset?${o({ref:a})}`,{headers:{Authorization:`Bearer ${t.token}`},signal:c.signal});if(!p.ok)throw new _e(p.redirected&&(p.status===401||p.status===403)?502:p.status,null,"asset:"+a);clearTimeout(f),f=setTimeout(u,hi(Number(p.headers.get("content-length"))||0));let h=new Uint8Array(await p.arrayBuffer());return n(),h}finally{clearTimeout(f)}},async changes(i,a){let l=await s("GET",`${e}/vaults/${i}/changes?${o({since:String(a)})}`);return{changes:l.changes??[],seq:Number(l.seq??0)}}}}function gi(t,e){let n=!1,r=0,s=null,o=null,i=()=>`${t.baseUrl.replace(/\/+$/,"")}/api/amadeus/vaults/${t.vaultId}/events?since=${e.getSince()}`,a=c=>{if(n)return;s?.abort(),e.onDown(c);let u=Math.min(3e4,1e3*2**r)*(.7+Math.random()*.6);r++,o=setTimeout(()=>void l(),u)},l=async()=>{if(n)return;s=new AbortController;let c;try{if(c=await fetch(i(),{headers:{Authorization:`Bearer ${t.getToken?.()??t.token}`,Accept:"text/event-stream"},signal:s.signal}),n){await c.body?.cancel();return}t.getToken?.()}catch(w){a(w);return}if(!c.ok||!c.body){a(new Error(`sse http ${c.status}`));return}r=0,e.onOpen();let u=c.body.getReader(),f=new TextDecoder,p="",h="",g=[],m=()=>{if(t.getToken?.(),!g.length&&!h)return;let w=g.join(`
|
|
208
|
+
`),k=h||"message";h="",g=[];let P=null;try{P=w?JSON.parse(w):null}catch{return}k==="hello"?e.onHello(Number(P?.seq??0)):k==="change"?e.onChange(P):k==="reset"?e.onReset():k==="presence"?e.onPresence?.(P):k==="presence-roster"&&e.onPresenceRoster?.(P)};try{for(;;){let{done:w,value:k}=await u.read();if(w)break;for(p+=f.decode(k,{stream:!0});;){let P=p.indexOf(`
|
|
209
|
+
`);if(P<0)break;let O=p.slice(0,P).replace(/\r$/,"");if(p=p.slice(P+1),O==="")m();else{if(O.startsWith(":"))continue;O.startsWith("event:")?h=O.slice(6).trim():O.startsWith("data:")&&g.push(O.slice(5).replace(/^ /,""))}}}}catch(w){n||a(w);return}a(new Error("sse stream ended"))};return l(),{stop:()=>{n=!0,o&&clearTimeout(o),s?.abort()}}}var Qt=t=>Ee().path.join($e().userDataDir(),$e().isDevMode()?`${t}.dev.json`:`${t}.json`),ts=Qt;async function ns(t){try{let e=JSON.parse(await Ee().fs.readFile(ts(t),"utf8"));return!e||typeof e.vaultRoot!="string"||typeof e.vaultId!="string"?null:(e.files=e.files??{},e.cursor=Number(e.cursor??0),e.lastSyncAt=e.lastSyncAt??null,e)}catch{return null}}function yi(t){let e=null,n=null,r=Promise.resolve(),s=null,o=()=>{if(!e)return r;let i=e,a=JSON.stringify(e);return e=null,r=r.then(async()=>{try{let l=ts(t),c=`${l}.tmp-${Ee().tmpTag()}-${Date.now()}-0`;await Ee().fs.writeFile(c,a,"utf8"),await Ee().fs.rename(c,l),s=null}catch(l){e??=i,s=l}}),r};return{save(i){e=i,!n&&(n=setTimeout(()=>{n=null,o()},500))},async flush(i=!1){if(n&&(clearTimeout(n),n=null),await o(),i&&s)throw s}}}async function wi(t){try{await Ee().fs.unlink(ts(t))}catch{}}var au=5*1024*1024,lu=5*1024*1024,cu=3e4,uu=5e3,du=5*6e4,fu=2500,pu=3e3,hu=5,mu=256*1024,gu=5,bi=1024*1024,Si=200,yu=6e4,wu=50,bu=".sync-trash",gt=t=>Ee().sha256Hex(t);function en(t,e={localRoot:ht(),shadowName:`amadeus-sync-${Xt()}`,vaultId:"first",serverDir:"",excludePrefixes:["\u4E0E\u6211\u5171\u4EAB/"]}){let n=d=>{let y=es(d,"");if(!y)return null;for(let v of e.excludePrefixes??[])if(y===v.replace(/\/$/,"")||y.startsWith(v))return null;if(e.ignoreNames?.length&&y.split("/").some(v=>e.ignoreNames.includes(v)))return null;let S=e.serverDir?`${e.serverDir}/${y}`:y;return e.inScope&&!e.inScope(S,We(S))?null:S},r=d=>{let y;if(e.serverDir){if(!d.startsWith(`${e.serverDir}/`))return null;y=d.slice(e.serverDir.length+1)}else{for(let S of e.excludePrefixes??[])if(d.startsWith(S))return null;y=d}return y.split("/").some(S=>Zt(S)||!!e.ignoreNames?.includes(S))?null:y},s=(d,y)=>!e.inScope||e.inScope(d,y),o=e.accountId??Ae(),{fs:i,path:a}=Ee(),l=d=>i.access(d).then(()=>!0,()=>!1),c=!1,u=0,f=Promise.resolve(),p=new Set,h="disabled",g=null,m=null,w=null,k=null,P=null,O=()=>{let d=t.loadCreds();if(!P||o!==Ae()||!d.token||d.cloudUrl?.replace(/\/+$/,"")!==P.cloudUrl.replace(/\/+$/,""))throw new _e(401,{code:"ACCOUNT_CHANGED"},"sync-session");return d.token},A=null,$=0,b=new Map,C=null,E=yi(e.shadowName),T=new Map,L=!1,X=!1,ee=[],te=()=>{m&&(m.pending=T.size?Object.fromEntries(T):void 0,E.save(m))},ae=()=>{X=!1,ee.length=0},le=()=>{if(X)return!0;let d=Date.now();for(;ee.length&&d-ee[0]>yu;)ee.shift();return ee.length>=wu?(X=!0,!0):!1},j=[],q=new Set,K=!1,Y=null,ce=null,me=null,Ce=null,pe=()=>{!c||Ce||(Ce=setTimeout(()=>{Ce=null,t.onStatus(kt())},200))},fe=(d,y)=>{h=d,y!==void 0&&(g=y),pe()},Q=(d,y=!1)=>{if(c){if(d.key){if(q.has(d.key))return;q.add(d.key)}y?j.unshift(d):j.push(d),U()}},x=new Map,R=d=>{if(!c)return;let y=(m?.files[d]?.size??0)>mu,S=(e.pushQuietMs??pu)*(y?gu:1),v=Date.now(),D=x.get(d);D&&clearTimeout(D.timer);let H=D?.since??v,B=Math.max(0,Math.min(S,H+S*hu-v)),M=setTimeout(()=>{x.delete(d),Q({key:d,run:()=>ke(d,!0)})},B);x.set(d,{timer:M,since:H}),pe()},_=()=>{for(let{timer:d}of x.values())clearTimeout(d);x.clear()},I=d=>!(d instanceof _e)||d.status>=500||d.status===0,z=d=>d instanceof _e&&(d.status===401||d.status===403),W=(d,y)=>{b.set(d,y?.body?.code||`http ${y?.status}`),pe()},U=async()=>{if(!K){K=!0;try{for(;j.length;){(h==="idle"||h==="starting")&&fe("syncing");let d=j.shift();d.key&&q.delete(d.key);try{await d.run()}catch(y){if(!c)return;if(z(y)){j.length=0,q.clear(),Cn(),fe("auth-required","login-expired");return}if(I(y)){Q(d,!0),Cn(),fe("offline",y?.message||"network error"),N();return}W(d.key??"(op)",y)}}c&&h==="syncing"&&(m&&(m.lastSyncAt=Date.now(),E.save(m)),fe("idle",null))}finally{K=!1;for(let d of p)d();p.clear()}}},N=()=>{!c||Y||(Y=setTimeout(()=>{Y=null,Ht()},cu))},V=new Map,Z=0,J=null,de=()=>!!ce||!!J||!c,he=d=>d instanceof _e&&d.status>=500||d?.name==="TimeoutError",Se=e.pushRetryMs??uu,ge=(d,y)=>{(y||!V.has(d))&&V.set(d,y)},ye=(d,y,S)=>{b.set(d,y instanceof _e?`http ${y.status}`:"timeout"),ge(d,S),Z=Math.min(Z*2||Se,du),ce=setTimeout(ut,Z),pe()},He=(d,y,S)=>{let v=new AbortController,D=y(v.signal).then(B=>()=>B,B=>()=>{throw B}),H={path:d,abort:v,after:[],settle:async()=>{let B=await D;if(J===H){J=null;try{await S(B)}catch(M){if(z(M)||I(M))throw M;W(d,M)}finally{for(let M of H.after)Q(M);Be(d)}}}};J=H,D.then(()=>Q({run:H.settle}))},Ve=(d,y)=>{for(let[S,v]of[...V])!v||!Me(S,d)||(V.delete(S),b.delete(S),y!==null&&V.set(y+S.slice(d.length),v));pe()},ut=()=>{ce=null;let[d]=V;if(d===void 0)return;let[y]=d;q.delete(y),Q({key:y,run:async()=>{if(J?.path===y)return;let S=V.get(y),v=!S&&V.delete(y);(S||v)&&b.delete(y);try{S?await Ye(y,S.seq):v&&await ke(y,!0)}finally{v&&Ne(y)&&ge(y),Be(y)}}})},Be=d=>{if(!de())if(V.has(d)){let y=V.get(d);V.delete(d),V.set(d,y),ce=setTimeout(ut,Z||Se)}else ut()},Te=d=>{if(!A||!m)throw new Error("engine not bound");let y=r(d);if(y===null)throw new Error("path outside binding: "+d);let S=a.resolve(A,pi(y,m.folder)),v=a.relative(A,S);if(v.startsWith("..")||a.isAbsolute(v))throw new Error("path escapes vault: "+d);return S},wn=d=>({size:d,mtimeMs:-1}),Bs=async d=>{try{let y=await i.stat(d);return y.isFile()?{size:y.size,mtimeMs:Math.floor(y.mtimeMs)}:null}catch{return null}},rl=0,qs=async(d,y,S,v)=>{await i.mkdir(a.dirname(d),{recursive:!0});let D=`${d}.tmp-${Ee().tmpTag()}-${Date.now()}-${rl++}`;await i.writeFile(D,y);let H=await Bs(D)??wn(kr(y));if(!v())return await i.rm(D,{force:!0}),null;try{let B=Ee().compareAndReplace;if(!B)throw new Error("Host does not support safe cloud download commits");return await B(D,d,S,v)?H:null}finally{await i.rm(D,{force:!0})}},Ws=async d=>{let y;try{y=await i.readdir(d,{withFileTypes:!0})}catch{return}for(let S of y)S.isDirectory()&&await Ws(a.join(d,S.name));try{await i.rmdir(d)}catch{}},dt=async d=>{let y=Te(d),S=await Bs(y),v;try{v=await i.readFile(y)}catch{return null}return{hash:mt(We(d))?gt(pt(v)):gt(v),size:S?.size??v.length,mtimeMs:S?.mtimeMs??-1,buf:v}},ft=async(d,y,S,v)=>{m&&(m.files[d]={seq:y,hash:S,size:v.size,mtimeMs:v.mtimeMs},E.save(m))},qe=d=>{m&&d in m.files&&(delete m.files[d],E.save(m))},Ye=async(d,y)=>{if(!w||!m||Ne(d))return;let S=ve,v=We(d);if(mt(v)){let M;try{M=await w.getFile(m.vaultId,d)}catch(G){if(G instanceof _e&&G.status===404){await br(d);return}throw G}await Vs(d,v,M.content,M.seq,M.hash??gt(M.content),S);return}if(de()){ge(d,{seq:y}),pe();return}let{vaultId:D}=m,H=w,B={seq:y};V.set(d,B),He(d,M=>H.getAsset(D,d,M),async M=>{let G=V.get(d)===B,F;try{F=M(),Z=0}catch(ne){if(!G)return;if(V.delete(d),ne instanceof _e&&ne.status===404){b.set(d,"ASSET_404"),pe();return}if(he(ne)){ye(d,ne,{seq:y});return}throw ne}G&&await Vs(d,v,F,y??0,gt(F),S)}),pe()},Vs=async(d,y,S,v,D,H)=>{if(!m)return;let B=async ue=>{await ft(d,v,D,ue),V.get(d)&&(V.delete(d),b.delete(d))},M=await dt(d);if(H!==ve||Ne(d))return;if(M&&M.hash===D){await B(M);return}let G=m.files[d];if(M&&G&&D===G.hash&&M.hash!==G.hash){await B(wn(G.size)),Q({key:d,run:()=>ke(d)});return}let F=M?gt(M.buf):null;if(M&&(!G||M.hash!==G.hash)){if(G&&y==="page"&&typeof S=="string"&&await sl(d,G,M,S,v,D,()=>H===ve&&!Ne(d))||H!==ve||Ne(d)||!await ol(d,()=>H===ve&&!Ne(d)))return;F=null}let ne=await qs(Te(d),S,F,()=>c&&H===ve&&!Ne(d));if(!ne){Q({key:d,run:()=>ke(d)});return}await B(ne)},sl=async(d,y,S,v,D,H,B)=>{try{if(!w||!m||S.buf.length>bi||v.length>bi)return!1;let G=(await w.listVersions(m.vaultId,d)).find(ue=>ue.seq===y.seq);if(!G)return!1;let F=await w.getVersion(m.vaultId,G.id);if(gt(F)!==y.hash)return!1;let ne=fi(pt(S.buf),F,v);return ne===null?!1:await qs(Te(d),ne,gt(S.buf),()=>c&&B())?(await ft(d,D,H,wn(kr(ne))),Q({key:d,run:()=>ke(d)}),!0):(Q({key:d,run:()=>ke(d)}),!0)}catch{return!1}},ol=async(d,y)=>{let S=$t(Wn(d,new Date));if(!S)return!0;let v=S.lastIndexOf("."),D=v>S.lastIndexOf("/"),H=D?S.slice(0,v):S,B=D?S.slice(v):"",M=S,G=Ee().existsSync;if(G)for(let F=2;G(Te(M));F++)M=`${H}-${F}${B}`;else for(let F=2;await l(Te(M));F++)M=`${H}-${F}${B}`;if(!y())return!1;try{await i.rename(Te(d),Te(M))}catch(F){if(F?.code==="ENOENT")return!0;throw F}return $++,Q({key:M,run:()=>ke(M)}),pe(),!0},Js=async d=>{if(!A)return;let y=Te(d),S=r(d)??d,v=a.join(A,bu,new Date().toISOString().slice(0,10),...S.split("/")),D=await l(v)?`${v}.${Date.now()}`:v;try{await i.mkdir(a.dirname(D),{recursive:!0}),await i.rename(y,D)}catch(H){if(H?.code==="ENOENT")return;throw new Error(`\u8F6F\u5220\u5931\u8D25,\u4FDD\u7559\u672C\u5730\u6587\u4EF6 ${y}: ${H?.message??String(H)}`)}},br=async d=>{if(!m)return;Ve(d,null);let y=await dt(d);if(Ne(d))return;let S=m.files[d]??null,v=Vn(y?.hash??null,S,null);if(v.kind==="deleteLocal"){if(!L&&le()){T.set(d,"local"),te(),pe();return}ee.push(Date.now()),await Js(d),qe(d)}else v.kind==="pushCreate"?(qe(d),Q({key:d,run:()=>ke(d)})):qe(d)},Ys=(d,y)=>{if(m){Ve(d,y);for(let S of Object.keys(m.files))if(S===d||S.startsWith(`${d}/`)){let v=y+S.slice(d.length);m.files[v]=m.files[S],delete m.files[S]}E.save(m)}},Gs=async d=>{if(!w||!m||d.seq<=m.cursor||!await vn())return;if(d.origin.client&&w.clientId===d.origin.client){m.cursor=d.seq,E.save(m);return}let y=d.type==="structure"?"folder":d.type,S=D=>r(D)!==null&&s(D,y);if(!S(d.path)&&!(d.newPath&&S(d.newPath))){m.cursor=d.seq,E.save(m);return}let v=d.path;if(d.op!=="write"&&d.op!=="mkdir"){for(;J&&(Me(J.path,v)||d.newPath&&Me(J.path,d.newPath));)await J.settle();if(!c)return}switch(d.op){case"write":await Ye(v,d.fileSeq);break;case"delete":await br(v);break;case"move":{let D=d.newPath;if(!D)break;let H=m.files[v],B=await dt(v),M=!!V.get(v);if(Ve(v,D),M&&ge(D,{seq:d.fileSeq}),B&&H)try{await i.mkdir(a.dirname(Te(D)),{recursive:!0}),await i.rename(Te(v),Te(D)),m.files[D]={...H,seq:M?H.seq:d.fileSeq??H.seq},delete m.files[v],E.save(m)}catch{await Ye(D,d.fileSeq)}else qe(v),await Ye(D,d.fileSeq);break}case"mkdir":await i.mkdir(Te(v),{recursive:!0});break;case"rename-folder":case"move-folder":{let D=d.newPath;if(!D)break;try{await i.mkdir(a.dirname(Te(D)),{recursive:!0}),await i.rename(Te(v),Te(D))}catch{}Ys(v,D);break}case"delete-folder":{let D=`${v}/`;for(let H of Object.keys(m.files))(H===v||H.startsWith(D))&&await br(H);Ve(v,null),await Ws(Te(v));break}}if(m.cursor=d.seq,E.save(m),d.op==="move"||d.op==="rename-folder"||d.op==="move-folder"||d.op==="delete"||d.op==="delete-folder")try{await t.onRemoteApplied?.(d)}catch{}},il=async(d,y,S)=>{let v=Number(y?.seq??0),D=y?.content??null;if(D!==null&>(D)===S.hash){await ft(d,v,S.hash,S);return}if(D===null&&v===0){if(!m?.files[d]){b.set(d,y?.code||"EXISTS"),pe();return}qe(d),Q({key:d,run:()=>ke(d)});return}await Ye(d,v)},bn=async(d,y)=>{if(!w||!m)return;let S=await dt(d);if(!S){Q({key:d,run:()=>ke(d)});return}if(S.size>au){b.set(d,"TOO_LARGE"),pe();return}let v=pt(S.buf);try{let D=await w.putFile(m.vaultId,d,v,y);b.delete(d),await ft(d,D.seq,D.hash??S.hash,S)}catch(D){if(D instanceof _e&&D.status===409){await il(d,D.body,S);return}throw D}},Sn=async(d,y)=>{if(!w||!m)return;let S=await dt(d);if(!S){Q({key:d,run:()=>ke(d)});return}if(S.size>(C??lu)){b.set(d,"TOO_LARGE"),pe();return}if(ge(d),pe(),de())return;let{vaultId:v}=m,D=w;He(d,H=>D.putBinary(v,d,S.buf,{baseSeq:y,signal:H}),async H=>{if(m){V.get(d)||V.delete(d);try{let B=H();Z=0,b.delete(d),await ft(d,B.seq,S.hash,S)}catch(B){if(he(B)){ye(d,B);return}if(!(B instanceof _e)||B.status!==409)throw B;let M=Number(B.body?.seq??0),G=B.body?.hash??null;if(G!==null&&G===S.hash){await ft(d,M,S.hash,S);return}if(M===0){if(!m.files[d]){b.set(d,B.body?.code||"EXISTS"),pe();return}qe(d),Q({key:d,run:()=>ke(d)});return}await Ye(d,M)}}})},Ks=async d=>{if(!w||!m||Ne(d))return;let y=ve,S=m.files[d];if(S){if(mt(We(d)))try{let v=await w.getFile(m.vaultId,d);if(v.seq!==S.seq){await Ye(d,v.seq);return}}catch(v){if(v instanceof _e&&v.status===404){qe(d);return}throw v}if(!(y!==ve||Ne(d))){try{await w.deleteFile(m.vaultId,d,S.seq,{confirmed:L})}catch(v){if(v instanceof _e&&v.status===409){await Ye(d,Number(v.body?.seq??0)||null);return}if(v instanceof _e&&v.status===429&&v.body?.code==="MASS_DELETE_BLOCKED"){T.set(d,"remote"),X=!0,te(),pe();return}throw v}qe(d)}}},vn=async()=>A?await i.stat(A).then(y=>y.isDirectory()).catch(()=>!1)||!e.requireRootExists&&!Object.keys(m?.files??{}).length?!0:(fe("error",`vault-missing: ${A}`),N(),!1):!1,ve=0,kn=new Set,En=new Map,Pe=d=>JSON.stringify([d.from,d.to]),Me=(d,y)=>d===y||d.startsWith(`${y}/`),Ne=d=>[...m?.moves??[],...kn].some(y=>Me(d,y.from)||Me(d,y.to)),rt=()=>!!(m?.moves?.length||kn.size),_n=async d=>{if(!w||!m)return;let{from:y,to:S,kind:v}=d;if(r(y)===null||r(S)===null)throw new Error("Invalid queued cloud move");if(J&&(Me(J.path,y)||Me(J.path,S))){J.after.push({key:`move:${Pe(d)}`,run:()=>_n(d)});return}d.hashes??=Object.fromEntries(Object.entries(m.files).filter(([M])=>Me(M,y)).map(([M,G])=>[M.slice(y.length),G.hash])),E.save(m),await E.flush(!0);let D,H=!1;try{if(v==="folder"){let M=a.posix.dirname(y)==="."?"":a.posix.dirname(y),G=a.posix.dirname(S)==="."?"":a.posix.dirname(S);M===G?await w.renameFolder(m.vaultId,y,a.posix.basename(S)):await w.moveFolder(m.vaultId,y,G)}else{let M=await w.move(m.vaultId,y,S);D=Number(M.seq)}}catch(M){if(!(M instanceof _e)||M.status!==404)throw M;let G=await w.tree(m.vaultId);if(G.entries.some(ue=>Me(ue.path,y))||G.folders.some(ue=>Me(ue,y)))throw M;let ne=G.entries.find(ue=>ue.path===S);if(D=ne?.seq,H=!ne&&!G.entries.some(ue=>Me(ue.path,S))&&!G.folders.some(ue=>Me(ue,S)),!H){let ue=Object.entries(d.hashes);if(!(ue.length>0&&ue.every(([Ge,At])=>G.entries.some(It=>It.path===S+Ge&&It.hash===At))))throw new _e(409,{code:"MOVE_DESTINATION_CHANGED"},"local-move")}}if(H){for(let M of Object.keys(m.files))Me(M,y)&&delete m.files[M];Ve(y,null)}else Ys(y,S),D!==void 0&&m.files[S]&&!V.get(S)&&(m.files[S].seq=D);m.moves=(m.moves??[]).filter(M=>Pe(M)!==Pe(d)),E.save(m);try{await E.flush(!0)}catch(M){throw m.moves.unshift(d),E.save(m),M}let B=En.get(Pe(d));En.delete(Pe(d)),B?.(),Ne(S)||(v==="folder"?await Sr():await ke(S))},ke=async(d,y=!1)=>{if(!m||Ne(d))return;if(J?.path===d){J.after.push({key:d,run:()=>ke(d,y)});return}if(!s(d,We(d))){qe(d);return}if(!await vn())return;let S=await dt(d);if(Ne(d))return;let v=m.files[d]??null,D=Vn(S?.hash??null,v,v?{seq:v.seq,hash:v.hash}:null);switch(D.kind){case"push":mt(We(d))?await bn(d,D.baseSeq):await Sn(d,D.baseSeq);break;case"pushCreate":mt(We(d))?await bn(d,0):await Sn(d,0);break;case"pushDelete":if(y){Tn();break}if(!L&&(T.has(d)||le())){T.set(d,"remote"),te(),pe();break}ee.push(Date.now()),await Ks(d);break;case"dropShadow":qe(d);break;default:S&&v&&S.hash===v.hash&&S.mtimeMs>=0&&(v.size!==S.size||v.mtimeMs!==S.mtimeMs)&&await ft(d,v.seq,v.hash,S);break}},Xs=async()=>{let d=new Map;if(!A||!m)return d;let y=A,S=null,v=async D=>{if(S)return;let H;try{H=await i.readdir(D,{withFileTypes:!0})}catch(B){S=`${D}: ${B?.message??String(B)}`;return}for(let B of H){if(Zt(B.name)||B.isDirectory()&&e.ignoreNames?.includes(B.name))continue;let M=a.join(D,B.name);if(B.isDirectory())await v(M);else if(B.isFile()){let G=a.relative(y,M).split(a.sep).join("/"),F=n(G);if(!F)continue;try{let ne=await i.stat(M);if(!ne.isFile())continue;d.set(F,{size:ne.size,mtimeMs:Math.floor(ne.mtimeMs)})}catch(ne){if(ne?.code==="ENOENT")continue;S=`${M}: ${ne?.message??String(ne)}`;return}}}};return await v(y),S?(fe("error",`scan-failed: ${S}`),N(),null):d},Sr=async()=>{let d=ve;if(rt()||d!==ve||!m||!await vn())return;let y=await Xs();if(!y||rt()||d!==ve)return;let S=!1;for(let[H,B]of[...T])(B==="remote"&&y.has(H)||B==="local"&&!y.has(H))&&(T.delete(H),S=!0);T.size||ae();for(let[H,B]of y){let M=m.files[H];M&&M.size===B.size&&M.mtimeMs===B.mtimeMs||Q({key:H,run:()=>ke(H)})}let v=Object.keys(m.files),D=v.filter(H=>!y.has(H));if(D.length&&!L&&(X||Qr(D.length,v.length,Si))){X=!0;for(let H of D)T.set(H,"remote");te(),pe();return}S&&(te(),pe());for(let H of D)T.has(H)||Q({key:H,run:()=>ke(H)})},Tt=async()=>{if(J){J.after.push({run:Tt});return}let d=ve;if(rt()||d!==ve||!w||!m||!A||!await vn())return;let y=await w.tree(m.vaultId);if(y.maxFileBytes!==void 0&&y.maxFileBytes!==C&&(C=y.maxFileBytes,pe()),rt()||d!==ve)return;let S=new Map;for(let F of y.entries)r(F.path)===null||!s(F.path,F.kind)||S.set(F.path,F);for(let[F,ne]of[...V])ne&&!S.has(F)&&Ve(F,null);let v=await Xs();if(!v||rt()||d!==ve)return;let D=new Set([...S.keys(),...v.keys(),...Object.keys(m.files)]),H=Object.keys(m.files).length,B=[];for(let F of D){if(rt()||d!==ve)return;let ne=m.files[F]??null,ue=S.get(F)??null,Ie=v.get(F)??null,Ge=null,At=wn(Ie?.size??0);if(Ie)if(ne&&ne.size===Ie.size&&ne.mtimeMs===Ie.mtimeMs)Ge=ne.hash,At=Ie;else{let It=await dt(F);It&&(Ge=It.hash,At=It)}B.push({sp:F,d:Vn(Ge,ne,ue?{seq:ue.seq,hash:ue.hash}:null),rSeq:ue?.seq??null,localHash:Ge,localStat:At})}if(rt()||d!==ve)return;let M=B.filter(F=>F.d.kind==="deleteLocal"||F.d.kind==="pushDelete").length,G=!L&&(X||Qr(M,H,Si));G&&M&&(X=!0),T.clear();for(let{sp:F,d:ne,rSeq:ue,localHash:Ie,localStat:Ge}of B){if(rt()||d!==ve)return;if(G&&(ne.kind==="deleteLocal"||ne.kind==="pushDelete")){T.set(F,ne.kind==="deleteLocal"?"local":"remote");continue}if((ne.kind==="deleteLocal"||ne.kind==="pushDelete")&&((await dt(F))?.hash??null)!==Ie){Q({key:F,run:()=>ke(F)});continue}if(rt()||d!==ve)return;switch(ne.kind){case"adopt":await ft(F,ue,Ie,Ge);break;case"pull":await Ye(F,ue);break;case"push":mt(We(F))?await bn(F,ne.baseSeq):await Sn(F,ne.baseSeq);break;case"pushCreate":mt(We(F))?await bn(F,0):await Sn(F,0);break;case"pushDelete":await Ks(F);break;case"deleteLocal":await Js(F),qe(F);break;case"conflict":await Ye(F,ue);break;case"dropShadow":qe(F);break;case"none":break}}L&&(L=!1,ee.length=0),T.size||ae(),te(),G&&pe();for(let F of y.folders)if(!(r(F)===null||!s(F,"folder")))try{await i.mkdir(Te(F),{recursive:!0})}catch{}m.cursor=y.seq,m.lastSyncAt=Date.now(),E.save(m)},al=async()=>{if(!w||!m)return;let d=m.cursor,y=await w.changes(m.vaultId,d);if(y.changes.length===0&&y.seq>d||y.changes.length>0&&y.changes[0].seq!==d+1){await Tt();return}for(let v of y.changes)await Gs(v)},zt=null,Zs=[],Qs=()=>{zt&&Zs.push(zt.close()),zt=null},ll=()=>{if(!c||zt||!A)return;let d=Ee();if(!d.watch)return;let y=S=>{if(!A)return;let v=a.relative(A,S);if(!v||v.startsWith(".."))return;let D=n(v);D&&R(D)};zt=d.watch(A,{depth:12,ignored:S=>{let v=a.basename(S);return Zt(v)||!!e.ignoreNames?.includes(v)}},{change:y,add:y,unlink:()=>Tn(),unlinkDir:()=>Tn()})},Cn=()=>{k?.stop(),k=null},cl=()=>{if(!c||!w||!m||k)return;let d=P;d&&(k=gi({baseUrl:d.cloudUrl,vaultId:m.vaultId,token:d.token,getToken:O},{getSince:()=>m?.cursor??0,onHello:y=>{m&&y>m.cursor&&Q({run:al})},onChange:y=>{Q({run:()=>Gs(y)})},onReset:()=>{Q({run:Tt})},onOpen:()=>{(h==="offline"||h==="starting")&&fe("idle",null),Q({run:Sr})},onDown:()=>{(h==="idle"||h==="syncing")&&fe("offline")},onPresence:y=>t.onPresence?.(m?.vaultId??"",y),onPresenceRoster:y=>t.onPresenceRoster?.(m?.vaultId??"",y)}))},ul=async()=>{let d=await Ue(o);if(d.cloudSync?.deviceId)return d.cloudSync.deviceId;let y=`desk-${Math.random().toString(36).slice(2,10)}${Date.now().toString(36)}`;return await ot({cloudSync:{...d.cloudSync??{},deviceId:y}},o),y},dl=async d=>{Cn(),Qs(),j.length=0,q.clear(),T.clear(),L=!1,X=!1,ee.length=0;let y=await Ue(o);if(d!==u)return;let S=y.cloudSync;if(S?.enabled===!1){A=null,w=null,fe("disabled",null);return}if(!o||o!==Ae()){fe("auth-required","not-logged-in");return}if(A=e.localRoot,e.requireRootExists){let B=await i.stat(A).then(M=>M.isDirectory()).catch(()=>!1);if(d!==u)return;if(!B){fe("error",`vault-missing: ${A}`),N();return}}if(d!==u)return;let v=t.loadCreds();if(!v.cloudUrl||!v.token){w=null,fe("auth-required","not-logged-in");return}fe("starting",null);let D=S?.deviceId??await ul();if(d!==u)return;let H=e.clientIdSuffix?`${D}#${e.clientIdSuffix}`:D;P={cloudUrl:v.cloudUrl,token:v.token},w=mi({baseUrl:v.cloudUrl,token:v.token,clientId:H,getToken:()=>{if(d!==u)throw new _e(401,{code:"ACCOUNT_CHANGED"},"sync-session");return O()}});try{let B=e.vaultId==="first"?S?.vaultId:e.vaultId;if(!B){let G=await w.listVaults();if(d!==u)return;if(!G.length)throw new Error("\u4E91\u7AEF\u65E0\u53EF\u7528 vault");B=G[0].id,await ot({cloudSync:{...S??{},vaultId:B}},o)}if(d!==u)return;let M=await ns(e.shadowName);if(d!==u||(m=M&&M.vaultRoot===A&&M.vaultId===B&&M.folder===""?M:{vaultRoot:A,folder:"",vaultId:B,cursor:0,lastSyncAt:null,files:{}},d!==u))return;for(let[G,F]of Object.entries(m.pending??{}))T.set(G,F);if(T.size&&(X=!0),!e.requireRootExists){let G=await i.stat(A).then(F=>F.isDirectory()).catch(()=>!1);if(d!==u)return;if(!G){if(Object.keys(m.files).length){fe("error",`mirror-missing: ${A}`),N();return}if(await i.mkdir(A,{recursive:!0}),d!==u)return}}ll();for(let G of m.moves??[])Q({key:`move:${Pe(G)}`,run:()=>_n(G)});Q({run:Tt}),Q({run:async()=>{cl()}})}catch(B){if(d!==u)return;z(B)?fe("auth-required","login-expired"):(fe("offline",B?.message||String(B)),N())}},eo=()=>{c=!1,Cn(),Qs(),j.length=0,q.clear(),_();for(let d of[Y,ce,me,Ce])d&&clearTimeout(d);Y=ce=me=Ce=null,J?.abort.abort(),J=null},to=async()=>{K&&await new Promise(d=>p.add(d)),await Promise.all(Zs.splice(0)),await E.flush(),m=null,w=null,P=null,A=null,$=0,b.clear(),V.clear(),Z=0,C=null,T.clear(),L=!1,X=!1,ee.length=0,h="disabled",g=null},fl=()=>{no()},xn=null,Ht=()=>{xn?.(),xn=$e().onBeforeQuit(fl);let d=++u;eo();let y=f.catch(()=>{}).then(async()=>{await to(),d===u&&(c=!0,await dl(d))});return f=y,y},no=()=>{xn?.(),xn=null,++u,eo();let d=f.catch(()=>{}).then(to);return f=d,d},kt=()=>({enabled:h!=="disabled",state:h==="idle"&&(x.size||V.size)?"syncing":h,lastSyncAt:m?.lastSyncAt??null,pending:j.length+x.size+V.size,conflicts:$,skipped:[...b].map(([d,y])=>({path:d,reason:y})),error:g,pendingDeletions:T.size,maxFileBytes:C});return{getStatus:kt,start(){Ht()},notifyLocal(d,y,S){if(!m||h==="disabled"||h==="auth-required")return;let v=n(d),D=S?n(S):null;if(y==="write"&&v){Zt(v.split("/").pop()||"")||R(v);return}if(y==="remove"){if(!v)return;let H=`${v}/`,B=!1;for(let M of Object.keys(m.files))(M===v||M.startsWith(H))&&(B=!0,Q({key:M,run:()=>ke(M)}));!B&&v&&Q({key:v,run:()=>ke(v)})}},holdLocalMove(d,y){let S=D=>e.serverDir?`${e.serverDir}/${D.replace(/\\/g,"/").normalize("NFC")}`:D.replace(/\\/g,"/").normalize("NFC"),v={from:S(d),to:S(y)};return++ve,kn.add(v),()=>{kn.delete(v)}},async notifyLocalMove(d,y,S,v){let D=n(d),H=n(y),B=m??await ns(e.shadowName),M=es(d,""),G=M&&(e.serverDir?`${e.serverDir}/${M}`:M);if(!D&&H&&G&&B&&Object.keys(B.files).some(F=>F===G||F.startsWith(`${G}/`))&&(D=G),!D&&!H){S?.();return}if(D&&H){let F=m??B;if(!F){S?.();return}let ne=v??(Object.keys(F.files).some(Ie=>Ie.startsWith(`${D}/`))?"folder":"file"),ue={from:D,to:H,kind:ne};F.moves??=[],F.moves.some(Ie=>Pe(Ie)===Pe(ue))||(F.moves.push(ue),++ve),S&&En.set(Pe(ue),S),E.save(F);try{await E.flush(!0)}catch(Ie){throw F.moves=F.moves.filter(Ge=>Pe(Ge)!==Pe(ue)),En.delete(Pe(ue)),E.save(F),Ie}m===F&&c&&h!=="disabled"&&h!=="auth-required"&&Q({key:`move:${Pe(ue)}`,run:()=>_n(ue)});return}D&&this.notifyLocal(d,"remove"),H&&(Q({key:H,run:()=>ke(H)}),Tn()),S?.()},async setEnabled(d){let y=await Ue(o);return await ot({cloudSync:{...y.cloudSync??{},enabled:d}},o),await Ht(),kt()},async restart(){return await Ht(),kt()},async syncNow(){if(b.clear(),h==="disabled"||h==="auth-required"||!w)await Ht();else{ce&&(clearTimeout(ce),ut());for(let d of m?.moves??[])Q({key:`move:${Pe(d)}`,run:()=>_n(d)});Q({run:Tt})}return kt()},confirmMassDeletions(){return T.size&&(L=!0,X=!1,T.clear(),ee.length=0,te(),Q({run:Tt})),kt()},stop:no};function Tn(){c&&(me&&clearTimeout(me),me=setTimeout(()=>{me=null,Q({run:Sr})},fu))}}function rs(t){let e=t.replace(/\.md$/i,""),n=t.lastIndexOf("/"),r=n<0?"":t.slice(0,n);return{root:t,fdPrefix:`${e}.fd/`,assetPrefix:r?`${r}/.amadeus/`:".amadeus/"}}function ss(t){return/\.md$/i.test(t)?rs(t):{root:t,fdPrefix:"\0",assetPrefix:"\0"}}function vi(t,e,n){return!!(e===t.root||e.startsWith(t.fdPrefix)||`${e}/`===t.fdPrefix||n==="binary"&&e.startsWith(t.assetPrefix)||n==="folder"&&(`${e}/`===t.assetPrefix||e.startsWith(t.assetPrefix)))}var Su=t=>Ee().sha256Hex(t).slice(0,8),vu=t=>t.replace(/[\\/:*?"<>|]/g," ").trim().slice(0,40)||"shared",Jn="\u4E0E\u6211\u5171\u4EAB";function ki(t,e){let n=Su(`${t.vaultId}:${t.path}`),r=t.path.includes("/")?t.path.slice(0,t.path.lastIndexOf("/")):"";return{key:n,vaultId:t.vaultId,rootPath:t.path,title:t.title,localRelDir:`${Jn}/${vu(t.title)}-${n}`,serverDir:r,inScope:(s,o)=>e.some(i=>vi(i,s,o)),scopeKey:e.map(s=>s.root).join("\0")}}function Ei(t){return ki(t,[rs(t.path),...(t.items??[]).map(ss)])}function _i(t){let e=t.map(Ei),n=t.flatMap((s,o)=>{let i=e[o].serverDir?`${e[o].serverDir}/`:"";return(s.items??[]).filter(a=>!a.startsWith(i)).map(a=>ki({vaultId:s.vaultId,path:a,title:(a.split("/").pop()??a).replace(/\.md$/i,"")},[ss(a)]))}),r=new Map;for(let s of[...e,...n])r.has(s.key)||r.set(s.key,s);return[...r.values()]}var ku=t=>{let e=[];for(let n of t.split("/"))!n||n==="."||(n===".."&&e.length&&e[e.length-1]!==".."?e.pop():e.push(n));return e.join("/")};function Ci(t,e){let n=l=>l.normalize("NFC"),r=n(e.replace(/\\/g,"/")),s=t.find(l=>r.startsWith(`${n(l.localRelDir)}/`));if(!s)return null;let o=r.slice(n(s.localRelDir).length+1),i=ku(s.serverDir?`${s.serverDir}/${o}`:o);if(!i||i===".."||i.startsWith("../"))return null;let a=[s,...t].find(l=>l.vaultId===s.vaultId&&(!l.serverDir||i.startsWith(`${l.serverDir}/`))&&l.inScope(i,We(i)));return a?`${a.localRelDir}/${a.serverDir?i.slice(a.serverDir.length+1):i}`:null}function os(){let t=$e().readCreds(),e=Fe(t.cloudUrl??"",t.token??""),n=new AbortController,r=()=>{let f=$e().readCreds();if(n.signal.aborted||!e||Fe(f.cloudUrl??"",f.token??"")!==e)throw Object.assign(new Error("Cloud account changed; retry from the current account"),{status:401});return f},s=()=>{let f=r();if(!f.cloudUrl||!f.token)throw Object.assign(new Error("\u672A\u767B\u5F55 Forsion \u8D26\u53F7"),{status:401});return f.cloudUrl.replace(/\/+$/,"")},o=async(f,p,h)=>{let g=r();if(!g.cloudUrl||!g.token)throw Object.assign(new Error("\u672A\u767B\u5F55 Forsion \u8D26\u53F7"),{status:401});let m=await fetch(`${g.cloudUrl.replace(/\/+$/,"")}/api/amadeus${p}`,{method:f,headers:{Authorization:`Bearer ${g.token}`,...h!==void 0?{"Content-Type":"application/json"}:{}},body:h!==void 0?JSON.stringify(h):void 0,signal:AbortSignal.any([n.signal,AbortSignal.timeout(2e4)])});if(!m.ok){let k=null;try{k=await m.json()}catch{}throw Object.assign(new Error(k?.detail||`http ${m.status}`),{status:m.status,code:k?.code})}let w=await m.json();return r(),w},i=null,a=async()=>(r(),i||(i=(await o("GET","/vaults")).vaults[0]?.id??"default",i)),l=()=>{try{let f=(r().token??"").split(".")[1],p=JSON.parse(pt(An(f)));return typeof p.userId=="string"?p.userId:null}catch{return null}},c=async()=>(await o("GET","/shared-with-me")).items.map(p=>{let h=Ei(p),g=p.path.split("/").pop()??p.path;return{...p,localPath:`${h.localRelDir}/${g}`}}),u=null;return{stop:()=>n.abort(),call:o,ensureOwnVault:a,myUserId:l,sharedWithMe:c,linkBase:async()=>{if(r(),u)return u;try{u=((await o("GET","/collab/link-base")).webOrigin??"").trim().replace(/\/+$/,"")||s()}catch{u=s()}return u},async heartbeat(f,p){let h=(f??"").replace(/\\/g,"/"),g,m=null,w=p.find(k=>h.startsWith(`${k.localRelDir}/`));w?(g=w.vaultId,m=w.serverDir?`${w.serverDir}/${h.slice(w.localRelDir.length+1)}`:h.slice(w.localRelDir.length+1)):(g=await a(),m=h||null),await o("POST",`/vaults/${encodeURIComponent(g)}/presence`,{page:m})}}}import{promises as Ai}from"node:fs";import Eu from"node:path";var is=".forsion-vault.md",xi=t=>`${t}/${is}`;function Yn(t){let e=/^devices:\s*(\[.*\])\s*$/m.exec(t??"");if(!e)return null;try{let n=JSON.parse(e[1]);return Array.isArray(n)?n.filter(r=>!!r&&typeof r.id=="string"&&typeof r.name=="string").map(r=>({id:r.id,name:r.name,...typeof r.since=="string"?{since:r.since}:{}})):null}catch{return null}}var Ti=t=>`---
|
|
210
210
|
devices: ${JSON.stringify(t.map(e=>({id:e.id,name:e.name,...e.since?{since:e.since}:{}})))}
|
|
211
211
|
---
|
|
212
|
-
`;var Ne=t=>t.replace(/\\/g,"/").normalize("NFC");function qr(t){let e=Ne(t.path);return e?t.kind==="folder"?`${e}/`:t.kind==="page"?`${e.replace(/\.md$/i,"")}.fd/`:null:null}function Tt(t,e,n){let r=Ne(n);if(!r)return!1;if(t.some(s=>Ne(s.path)===r))return!0;for(let s of e??[]){let o=Ne(s);if(!o)continue;let i=`${o.replace(/\.md$/i,"")}.fd`;if(r===o||r.startsWith(`${o}/`)||r===i||r.startsWith(`${i}/`))return!1}return t.some(s=>{let o=qr(s);return!!o&&r.startsWith(o)})}function Br(t,e,n){let r=Ne(t),s=Ne(e);return r===s?Ne(n):r.startsWith(`${s}/`)?Ne(n)+r.slice(s.length):null}function Gt(t,e,n){let r=!1,s=t.map(o=>{let i=Br(o,e,n);return i===null?o:(r=!0,i)});return{changed:r,next:s}}async function Xo(t){let e=await Go.readdir(t,{withFileTypes:!0}).catch(()=>[]),n=[],r=Object.create(null);for(let s of e){if(!s.isDirectory()||s.name.startsWith("."))continue;let o=await Go.readFile(bc.join(t,s.name,Hr),"utf8").catch(()=>null);if(o===null)continue;n.push(s.name);let i=Un(o);i?.length&&(r[s.name]=i)}return{names:n.sort(),devices:r}}var ve={get:"amadeus:sync:get",setEnabled:"amadeus:sync:set-enabled",syncNow:"amadeus:sync:now",confirmDeletions:"amadeus:sync:confirm-deletions",status:"amadeus:sync:status",switchSide:"amadeus:sync:switch-side",collabCall:"amadeus:collab:call",presence:"amadeus:collab:presence",entryGet:"amadeus:entry-sync:get",entryEnable:"amadeus:entry-sync:enable",entryDisable:"amadeus:entry-sync:disable",entryMark:"amadeus:entry-sync:mark",entryClosure:"amadeus:entry-sync:closure",entryChange:"amadeus:entry-sync:change",otherSideDbs:"amadeus:entry-sync:other-side-dbs"};var Fn=t=>Se().sha256Hex(t).slice(0,8);function Ko(t){return t.replace(/ \(conflict \d{4}-\d{2}-\d{2} \d{4}\)(?=(?:\.[^./]+)?$)/,"")}function lt(t,e=[]){let n=[],r=[];for(let s of t){let o=Ne(s.path);if(!o)continue;r.push(o);let i=qr(s);i&&n.push(i)}return{entries:t,exclude:e,prefixes:n,paths:r}}function Zo(t,e){let n=Ko(Ne(e));if(!n)return!1;if(Tt(t.entries,t.exclude,n))return!0;let r=`${n}/`;for(let s of t.paths)if(s.startsWith(r))return!0;for(let s of t.prefixes)if(s.startsWith(r))return!0;return!1}function Xt(t,e,n){let r=!1,s=t.map(o=>{let i=Br(o.path,e,n);return i===null?o:(r=!0,{...o,path:i})});return{changed:r,next:s}}function Qo(t,e,n,r){if(e==="delete"||e==="delete-folder"){let s=Ne(n),o=t.filter(i=>{let a=Ne(i.path);return!(a===s||e==="delete-folder"&&a.startsWith(`${s}/`))});return{changed:o.length!==t.length,next:o}}return r?Xt(t,n,r):{changed:!1,next:t}}function Wr(t,e){let n=Ct(t);return!n||n!==t.normalize("NFC").trim()?"\u540D\u79F0\u4E0D\u5408\u6CD5":n.includes("/")?"\u540D\u79F0\u4E0D\u80FD\u5305\u542B /":n===jn?`\u300C${jn}\u300D\u662F\u4FDD\u7559\u540D\u79F0`:e.includes(n)?"\u8BE5\u540D\u79F0\u5DF2\u88AB\u5176\u4ED6\u667A\u5E93\u7684\u4E91\u540C\u6B65\u5360\u7528":null}import{constants as Sc,promises as ei}from"node:fs";async function ti(t,e){try{await ei.copyFile(Yt(t),Yt(e),Sc.COPYFILE_EXCL)}catch(n){let r=n?.code;if(r==="EEXIST"||r==="ENOENT")return!1;throw n}return await ei.unlink(Yt(t)).catch(()=>{}),!0}var ni=["setAmadeusSyncFactory","readCreds","accountId","homeDir"],Vr=t=>ni.every(e=>typeof t[e]=="function"),Ec=()=>({enabled:!1,state:"disabled",lastSyncAt:null,pending:0,conflicts:0,skipped:[],error:null,pendingDeletions:0,maxFileBytes:null,side:"local"});function Yr(t){let e=null,n=()=>{if(!e)throw new Error("Cloud sync is not ready");return e};t.handle(ve.get,()=>e?e.get():Ec()),t.handle(ve.setEnabled,(r,s)=>n().setEnabled(s)),t.handle(ve.syncNow,()=>n().syncNow()),t.handle(ve.confirmDeletions,()=>n().confirmDeletions()),t.handle(ve.entryGet,()=>n().entryGet()),t.handle(ve.otherSideDbs,()=>n().otherSideDbs()),t.handle(ve.entryEnable,(r,s)=>n().entryEnable(s)),t.handle(ve.entryDisable,(r,s)=>n().entryDisable(s)),t.handle(ve.entryMark,(r,s,o)=>n().entryMark(s,o)),t.handle(ve.entryClosure,(r,s,o)=>n().entryClosure(s,o)),t.handle(ve.collabCall,(r,s,o)=>n().collabCall(s,o)),t.handle(ve.switchSide,(r,s)=>n().switchSide(r.sender.id,s)),t.setAmadeusSyncFactory(r=>{$o(r);let s=ri(r);return e=s.handlers,s.instance}),t.log("[forsion-extend] amadeus cloud sync registered")}function ri(t){let e=t.notifyAll,n=()=>t.vaultRoot(),r=0,s=!1,o=zr(),i=new Map,a=()=>{let E=Date.now();for(let[P,T]of i)E-T.at>7e4&&i.delete(P);e(ve.presence,[...i.values()])},l={loadCreds:()=>t.readCreds(),onStatus:E=>e(ve.status,{...E,pendingDeletions:ke(),side:g()?"cloud":"local"}),onPresence:(E,P)=>{let T=P;T?.userId&&(i.set(T.userId,{userId:T.userId,username:String(T.username??"user"),page:T.page??null,at:Number(T.at)||Date.now()}),a())},onPresenceRoster:(E,P)=>{if(Array.isArray(P)){for(let T of P){let A=T;A?.userId&&i.set(A.userId,{userId:A.userId,username:String(A.username??"user"),page:A.page??null,at:Number(A.at)||Date.now()})}a()}}},c=()=>{let E=r;return{...l,onStatus:P=>{E===r&&l.onStatus(P)},onPresence:(P,T)=>{E===r&&l.onPresence(P,T)},onPresenceRoster:(P,T)=>{E===r&&l.onPresenceRoster(P,T)}}},u=Jt(c()),f=new Map,m=[],h=async()=>{if(!s||!Te())return;let E=r,P=o,T;try{T=await P.sharedWithMe()}catch{return}if(E!==r||!s)return;let A=T.map(D=>Lr(D));m=A;let z=new Set(A.map(D=>D.key));for(let[D,$]of f)if(!z.has(D)){if(await $.engine.stop(),E!==r)return;f.delete(D)}for(let D of A){if(f.has(D.key))continue;let $=Jt(c(),{localRoot:mt.join(it(),...D.localRelDir.split("/")),shadowName:`amadeus-sync-${Wt()}-share-${D.key}`,vaultId:D.vaultId,serverDir:D.serverDir,inScope:D.inScope});f.set(D.key,{engine:$,plan:D}),$.start()}},g=()=>n()===it(),p=(E,P=E.base)=>{E.base=P;let T=[P,...E.pendingMoves];E.scope.current=lt(T.flatMap(A=>A.entries),T.flatMap(A=>A.exclude))},y=new Map,_=new Set,O=new Set,C=null,M=()=>C??=new Promise(E=>{let P=()=>kc.hostname().replace(/\.(local|lan|home)$/i,"")||"Desktop";if(process.platform!=="darwin")return E(P());vc("scutil",["--get","ComputerName"],{timeout:1500},(T,A)=>E(!T&&String(A).trim()||P()))}),H=async()=>{let E=(await Me()).cloudSync?.deviceId;return E?{id:E,name:await M()}:null},w=new Map,x=(E,P,T)=>{let A=r,z=(w.get(E)??Promise.resolve()).catch(()=>{}).then(async()=>{A!==r||T&&!await T()||A!==r||await b(E,P,A)});return w.set(E,z),z.finally(()=>{w.get(E)===z&&w.delete(E)}).catch(()=>{}),z},b=async(E,P,T)=>{let A=o,z=encodeURIComponent(await A.ensureOwnVault()),D=Yo(E);for(let $=0;$<3;$++){let N=null;try{N=await A.call("GET",`/vaults/${z}/file?path=${encodeURIComponent(D)}`)}catch(W){if(W?.status!==404)throw W}let Y=P(!!N,N?Un(N.content):null);if(Y===void 0||T!==r)return;try{if(Y===null){N&&await A.call("DELETE",`/vaults/${z}/file?path=${encodeURIComponent(D)}&baseSeq=${N.seq}`);return}await A.call("PUT",`/vaults/${z}/file`,{path:D,content:Jo(Y),baseSeq:N?.seq??0});return}catch(W){if(W?.status!==409)throw W}}throw Object.assign(new Error("marker write kept conflicting"),{status:409})},I=async E=>!!(await Me()).entrySync?.some(P=>P.cloudName===E&&P.entries.length>0),U=(E,P)=>x(E,(T,A)=>{let z=A?.find($=>$.id===P.id);if(z&&z.name===P.name)return;let D=z?.since??new Date().toISOString().slice(0,10);return[...(A??[]).filter($=>$.id!==P.id),{...P,since:D}]},()=>I(E)),B=(E,P)=>x(E,(T,A)=>{if(!T||!A?.some(D=>D.id===P))return;let z=A.filter(D=>D.id!==P);return z.length?z:null},async()=>!await I(E)),J=()=>{e(ve.entryChange)},se=async(E,P)=>{let T=y.get(E);if(!T)return;let A=$=>$&&$.startsWith(`${T.cloudName}/`)?$.slice(T.cloudName.length+1):null,z=A(P.path);if(!z)return;let D=!1;await _t($=>{if(y.get(E)!==T)return!1;let N=($.entrySync??[]).find(ie=>ie.vaultRoot===E);if(!N)return!1;let Y=P.op,W=A(P.newPath),G=Qo(N.entries,Y,z,W),le=W?Gt(N.exclude??[],z,W):{changed:!1,next:N.exclude??[]};if(!G.changed&&!le.changed)return!1;D=!0,N.entries=G.next,le.changed&&(N.exclude=le.next),p(T,lt(N.entries,N.exclude??[]))}),D&&y.get(E)===T&&J()},pe=E=>{let P=r;return{...c(),onStatus:T=>{P===r&&e(ve.status,{...T,pendingDeletions:ke(),side:"local",binding:E})},onRemoteApplied:async T=>{P===r&&await se(E,T)}}},X=async()=>{let E=Te();if(!s||!E)return;let P=r,T=o,A=Wt(E);await t.adoptLegacyCloudState(E,ti);let z=await Me(E),D=z.entrySync??[];if(P!==r||!s||E!==Te())return;let $=new Map(D.map(N=>[N.vaultRoot,N]));for(let[N,Y]of y){let W=$.get(N);if(!(W&&W.cloudName===Y.cloudName)&&(await Y.engine.stop(),P!==r||(y.delete(N),W&&await Ho(`amadeus-sync-${A}-entry-${Fn(N)}`),P!==r)))return}for(let N of D){let Y=y.get(N.vaultRoot);if(Y){p(Y,lt(N.entries,N.exclude??[]));continue}let W={current:lt(N.entries,N.exclude??[])},G=N.cloudName,le=Jt(pe(N.vaultRoot),{accountId:E,localRoot:N.vaultRoot,shadowName:`amadeus-sync-${A}-entry-${Fn(N.vaultRoot)}`,vaultId:"first",serverDir:G,clientIdSuffix:`entry-${Fn(N.vaultRoot)}`,requireRootExists:!0,ignoreNames:[".git","node_modules",".trash"],inScope:ie=>ie===G?!0:ie.startsWith(`${G}/`)?Zo(W.current,ie.slice(G.length+1)):!1});y.set(N.vaultRoot,{engine:le,scope:W,cloudName:G,base:W.current,pendingMoves:new Set}),le.start()}if(z.cloudSync?.enabled!==!1)for(let N of D){let Y=N.entries.length>0,W=Y?_:O;W.has(N.cloudName)||((Y?O:_).delete(N.cloudName),(async()=>{try{let G=await H();if(!G||P!==r||(await(Y?U(N.cloudName,G):B(N.cloudName,G.id)),P!==r))return;W.add(N.cloudName),(Y?O:_).delete(N.cloudName)}catch{}})())}},de=async(E,P,T,A,z)=>{let D=P.replace(/\\/g,"/").normalize("NFC"),$=T.replace(/\\/g,"/").normalize("NFC"),N=!1,Y,W,G,le=z??"file";try{await _t(async ie=>{if(y.get(E)!==A)return!1;let he=(ie.entrySync??[]).find(Re=>Re.vaultRoot===E);if(!he)return!1;let ce=Xt(he.entries,D,$),ue=Gt(he.exclude??[],D,$),Ue=Tt(he.entries,he.exclude,D);!z&&await At.stat(mt.join(E,...$.split("/"))).then(Re=>Re.isDirectory(),()=>!1)&&(le="folder");let wt=le==="folder"?"folder":/\.md$/i.test($)?"page":"asset";Ue&&!Tt(ce.next,ue.next,$)&&(ce.next.push({path:$,kind:wt}),ce.changed=!0),N=ce.changed||ue.changed;let bt=he.entries.filter(Re=>Xt([Re],D,$).changed);return Ue&&!bt.some(Re=>Re.path===D)&&bt.push({path:D,kind:wt}),Y=lt(bt,(he.exclude??[]).filter(Re=>Gt([Re],D,$).changed)),W=A.base,A.pendingMoves.add(Y),he.entries=ce.next,he.exclude=ue.next,G=lt(he.entries,he.exclude),p(A,G),N})}catch(ie){throw Y&&A.pendingMoves.delete(Y),p(A,A.base===G&&W?W:A.base),ie}try{Y&&await A.engine.notifyLocalMove(D,$,()=>{A.pendingMoves.delete(Y),p(A)},le)}catch(ie){throw Y&&A.pendingMoves.delete(Y),await _t(he=>{let ce=he.entrySync?.find(ue=>ue.vaultRoot===E);if(!ce)return!1;ce.entries=Xt(ce.entries,$,D).next,ce.exclude=Gt(ce.exclude??[],$,D).next,p(A,lt(ce.entries,ce.exclude))}),ie}N&&y.get(E)===A&&J()},Z=E=>{let P=E.replace(/\\/g,"/");for(let{engine:T,plan:A}of f.values())if(P.startsWith(`${A.localRelDir}/`))return{engine:T,rel:P.slice(A.localRelDir.length+1)};return{engine:u,rel:P}};t.setMutationHooks((E,P)=>{if(g()){let T=Z(E);T.engine.notifyLocal(T.rel,P);return}y.get(n()??"")?.engine.notifyLocal(E,P)},(E,P,T)=>{if(g()){let D=Z(E),$=Z(P);if(D.engine===$.engine)return D.engine.notifyLocalMove(D.rel,$.rel,void 0,T);D.engine.notifyLocal(D.rel,"remove"),$.engine.notifyLocal($.rel,"write");return}let A=n()??"",z=y.get(A);if(z)return de(A,E,P,z,T)},(E,P)=>{if(g()){let T=Z(E),A=Z(P),z=[T.engine.holdLocalMove(T.rel,A.rel)];return T.engine!==A.engine&&z.push(A.engine.holdLocalMove(T.rel,A.rel)),()=>{for(let D of z)D()}}return y.get(n()??"")?.engine.holdLocalMove(E,P)});let ke=()=>{let E=u.getStatus().pendingDeletions;for(let{engine:P}of f.values())E+=P.getStatus().pendingDeletions;for(let{engine:P}of y.values())E+=P.getStatus().pendingDeletions;return E},oe=E=>({...E,pendingDeletions:ke(),side:g()?"cloud":"local"}),Ee=()=>{if(!s)return Promise.resolve(u.getStatus());h();for(let{engine:E}of f.values())E.syncNow();for(let{engine:E}of y.values())E.syncNow();return u.syncNow()},fe=async()=>{++r,s=!1,o.stop();let E=[u.stop(),...[...f.values()].map(({engine:T})=>T.stop()),...[...y.values()].map(({engine:T})=>T.stop())];f.clear(),y.clear(),m=[],_.clear(),O.clear(),i.clear(),a(),await Promise.all(E),await t.awaitPendingVaultWrites();let P=n();if(P&&On(P)){let T=await Me(),A=T.localVault&&!On(T.localVault)?T.localVault:mt.join(t.workspaceDir(),"Amadeus");await At.mkdir(A,{recursive:!0}),await Ke({lastVault:A,localVault:A,lastPage:void 0}),await t.activateRoot(A,!1)}J()};return{handlers:{get:()=>oe(u.getStatus()),setEnabled:async E=>{if(!s)throw new Error("Cloud account is changing");let P=r;return await u.setEnabled(E),P!==r?u.getStatus():(await Promise.all([...f.values(),...y.values()].map(({engine:T})=>T.restart())),oe(u.getStatus()))},syncNow:()=>Ee(),confirmDeletions:()=>{for(let{engine:E}of f.values())E.confirmMassDeletions();for(let{engine:E}of y.values())E.confirmMassDeletions();return oe(u.confirmMassDeletions())},entryGet:async()=>{let E=await Me(),P=it(),T=await Xo(P);return{vaults:E.entrySync??[],activeRoot:n(),cloudRoot:P,mirrorVaults:T.names,mirrorVaultDevices:T.devices,deviceId:E.cloudSync?.deviceId??null}},otherSideDbs:async()=>{let E=n();if(!E)return null;let P=it(),T=await Me(),A=E===P?T.localVault&&T.localVault!==P?T.localVault:null:P;if(!A)return null;let z=[],D=500,$=async(N,Y)=>{if(z.length>=D)return;let W;try{W=await At.readdir(N,{withFileTypes:!0})}catch{return}for(let G of W){if(z.length>=D)break;if(G.name.startsWith(".")||G.isSymbolicLink())continue;let le=Y?`${Y}/${G.name}`:G.name;if(G.isDirectory())await $(mt.join(N,G.name),le);else if(G.isFile()&&/\.db$/i.test(G.name))try{z.push({rel:le,source:await At.readFile(mt.join(N,G.name),"utf8")})}catch{}}};return await $(A,""),{root:A,vaultName:A===P?"\u4E91\u7AEF":mt.basename(A),dbs:z}},entryEnable:async E=>{let P=r,T=o;if(!s||!Te())return{error:"Sign in to enable cloud sync"};let A=n();if(!A||g())return{error:"\u4EC5\u672C\u5730 vault \u53EF\u5F00\u542F\u4E91\u540C\u6B65"};let z=await Me(),D=z.entrySync??[],$=D.find(N=>N.vaultRoot===A);if(!$){let N=(E.cloudName??mt.basename(A)).normalize("NFC").trim(),Y=Wr(N,D.map(W=>W.cloudName));if(Y)return{error:Y};if(!E.merge)try{let W=await T.ensureOwnVault(),G=await T.call("GET",`/vaults/${encodeURIComponent(W)}/tree`);if((G.folders??[]).some(ie=>ie===N||ie.startsWith(`${N}/`))||(G.entries??[]).some(ie=>ie.path===N||ie.path.startsWith(`${N}/`)))return{conflict:N}}catch(W){return{error:W?.message||"\u65E0\u6CD5\u8FDE\u63A5\u4E91\u7AEF(\u9996\u6B21\u5F00\u542F\u9700\u8981\u5728\u7EBF)"}}$={vaultRoot:A,cloudName:N,entries:[]},D.push($)}return P!==r||!s?{error:"Cloud account changed; retry from the current account"}:(await _t(N=>{if(P!==r||!s)return!1;let Y=N.entrySync??[],W=Y.find(ue=>ue.vaultRoot===A);if(!W){let ue=Wr($.cloudName,Y.map(Ue=>Ue.cloudName));if(ue)throw new Error(ue);W={vaultRoot:A,cloudName:$.cloudName,entries:[]},Y.push(W)}let G=ue=>String(ue??"").replace(/\\/g,"/").normalize("NFC"),le=new Set;for(let ue of E.entries??[]){let Ue=G(ue.path);Ue&&(le.add(Ue),!W.entries.some(wt=>wt.path===Ue)&&W.entries.push({path:Ue,kind:ue.kind==="folder"||ue.kind==="asset"?ue.kind:"page"}))}let ie=(E.exclude??[]).map(G).filter(Boolean),he=new Set([...le,...(E.include??[]).map(G).filter(Boolean)]);W.exclude=[...new Set([...(W.exclude??[]).filter(ue=>!he.has(ue)),...ie])];let ce=new Set(ie);W.entries=W.entries.filter(ue=>!ce.has(ue.path)),N.entrySync=Y,$=W},z.cloudAccountId),P!==r?{error:"Cloud account changed; retry from the current account"}:(await X(),y.get(A)?.engine.syncNow(),J(),{ok:!0,cloudName:$.cloudName}))},entryDisable:async E=>{let P=n(),T=!1,A=r;return await _t(z=>{if(A!==r||!s)return!1;let D=(z.entrySync??[]).find(Y=>Y.vaultRoot===P);if(!P||!D)return!1;let $=String(E??"").replace(/\\/g,"/").normalize("NFC"),N=D.entries.length;if(D.entries=D.entries.filter(Y=>Y.path!==$),Tt(D.entries,D.exclude,$))D.exclude=[...new Set([...D.exclude??[],$])];else if(D.entries.length===N)return!1;T=!0}),!T||A!==r?{ok:!1}:(await X(),J(),{ok:!0})},entryMark:async(E,P)=>{let T=String(E??"").normalize("NFC");if(!T||T.includes("/")||T.startsWith("."))return{error:"invalid name"};if(!s||!Te())return{error:"Sign in first"};try{await x(T,A=>P?A?void 0:[]:A?null:void 0)}catch(A){return{error:A?.message||String(A)}}return u.syncNow(),{ok:!0}},entryClosure:(E,P)=>t.relatedClosure(String(E??""),P==="folder"?"folder":"page"),collabCall:async(E,P)=>{let T=o,A=async()=>T.ensureOwnVault(),z=$=>String((P??[])[$]??""),D=$=>(P??[])[$]??{};switch(E){case"listVaults":return(await T.call("GET","/vaults")).vaults;case"activeVaultId":return A();case"pageShare":return T.call("GET",`/vaults/${encodeURIComponent(await A())}/page-shares?path=${encodeURIComponent(z(0))}`);case"createPageShare":return T.call("POST",`/vaults/${encodeURIComponent(await A())}/page-shares`,{path:z(0),...D(1)});case"updatePageShare":return T.call("PATCH",`/vaults/${encodeURIComponent(await A())}/page-shares/${encodeURIComponent(z(0))}`,D(1));case"revokePageShare":return T.call("DELETE",`/vaults/${encodeURIComponent(await A())}/page-shares/${encodeURIComponent(z(0))}`);case"setParticipantRole":return T.call("PATCH",`/vaults/${encodeURIComponent(await A())}/page-shares/${encodeURIComponent(z(0))}/members/${encodeURIComponent(z(1))}`,{role:z(2)});case"removeParticipant":return T.call("DELETE",`/vaults/${encodeURIComponent(await A())}/page-shares/${encodeURIComponent(z(0))}/members/${encodeURIComponent(z(1))}`);case"sharedWithMe":{let $=await T.sharedWithMe();return h(),$}case"leaveShare":{let $=T.myUserId();if(!$)throw new Error("\u672A\u767B\u5F55");return T.call("DELETE",`/vaults/${encodeURIComponent(await A())}/page-shares/${encodeURIComponent(z(0))}/members/${encodeURIComponent($)}`)}case"publishes":return T.call("GET",`/vaults/${encodeURIComponent(await A())}/shares`);case"listAllShares":{let $=(await T.call("GET","/vaults")).vaults||[],N=T.myUserId(),Y=[],W=[];for(let G of $){try{let le=await T.call("GET",`/vaults/${encodeURIComponent(G.id)}/shares`);for(let ie of le.shares||[])Y.push({...ie,vaultId:G.id,vaultName:G.name||""})}catch(le){t.log(`[connect] listAllShares publishes vault ${G.id} failed: ${le?.message}`)}try{let le=await T.call("GET",`/vaults/${encodeURIComponent(G.id)}/page-shares`),ie=le?.shares||le?.pageShares||(Array.isArray(le)?le:[]);for(let he of ie){let ce=he.created_by??he.createdBy;(!N||!ce||ce===N)&&W.push({...he,vaultId:G.id,vaultName:G.name||""})}}catch(le){t.log(`[connect] listAllShares pageShares vault ${G.id} failed: ${le?.message}`)}}return{publishes:Y,pageShares:W,linkBase:await T.linkBase()}}case"createPublish":{let $=await T.call("POST",`/vaults/${encodeURIComponent(await A())}/shares`,{mode:z(0),path:z(1)});return{...$,url:`${await T.linkBase()}/share/${$.token}`}}case"revokePublish":return T.call("DELETE",`/vaults/${encodeURIComponent(await A())}/shares/${encodeURIComponent(z(0))}`);case"revokePublishIn":return T.call("DELETE",`/vaults/${encodeURIComponent(z(0))}/shares/${encodeURIComponent(z(1))}`);case"revokePageShareIn":return T.call("DELETE",`/vaults/${encodeURIComponent(z(0))}/page-shares/${encodeURIComponent(z(1))}`);case"myUserId":return T.myUserId();case"linkBase":return T.linkBase();case"heartbeat":return T.heartbeat((P??[])[0]??null,m);default:throw new Error(`unknown collab fn: ${E}`)}},switchSide:async(E,P)=>{let T=await Me();if(P==="cloud"){if(!s||!Te())throw new Error("Sign in to open cloud notes");let D=it();await At.mkdir(D,{recursive:!0}),T.lastVault&&!On(T.lastVault)&&await Ke({localVault:T.lastVault}),await Ke({lastVault:D});let $=await t.activateRoot(D,!1);return t.bindRenderer(E,D),{...$,side:"cloud"}}let A=T.localVault&&await At.stat(T.localVault).then(D=>D.isDirectory()).catch(()=>!1)?T.localVault:null;if(!A){let D=await t.ensureDefaultVault();return t.bindRenderer(E,D.root),{...D,side:"local"}}await Ke({lastVault:A});let z=await t.activateRoot(A,!1);return t.bindRenderer(E,A),{...z,side:"local"}}},instance:{start:()=>{s=!0,u.start(),h(),X()},stopAllSync:fe,restartAllSync:async()=>{await fe(),o=zr(),u=Jt(c()),s=!0,await Promise.all([u.restart(),h(),X()]),J(),e(ve.status,oe(u.getStatus()))}}}}import{hostname as _c}from"node:os";var Cc=256*1024;function si(t,e,n){if(n?.hasSecHeaders&&!n.gatewayStreamsSecHeaders)return!1;if(t.includes("text/event-stream"))return!0;let r=Number(e||NaN);return!Number.isFinite(r)||r>Cc}var Jr=45e3,xc=3e3,Tc=16*1024,Ac=6e4,Ln=t=>`${t.replace(/\/+$/,"")}/api`,Kt=class{deps;ctrl=null;conn=null;wake=null;redialNow=!1;inflight=new Map;connected=!1;lastError=null;hubCaps=new Set;constructor(e){this.deps=e}hubFetch(e,n){return(this.deps.hubFetch??fetch)(e,n)}get requestTimeoutMs(){return this.deps.requestTimeoutMs??Ac}status(){return{running:!!this.ctrl,connected:this.connected,unitId:this.deps.getPairing()?.unitId??null,lastError:this.lastError}}start(){if(this.ctrl)return;let e=new AbortController;this.ctrl=e,this.loop(e)}stop(){this.ctrl?.abort(),this.ctrl=null,this.markDown(),this.abortEnvelopes(),this.wake?.()}reconnect(e){this.ctrl&&(this.deps.log(`[unit-host] \u7ACB\u5373\u91CD\u8FDE\u901A\u9053(${e})`),this.redialNow=!0,this.conn?.abort(),this.wake?.())}markDown(){this.connected=!1,this.hook(this.deps.onChannelDown)}hook(e){try{e?.()}catch(n){this.deps.log(`[unit-host] \u901A\u9053\u56DE\u8C03\u51FA\u9519(\u5DF2\u5FFD\u7565): ${n?.message||n}`)}}abortEnvelope(e){let n=this.inflight.get(e);return n?(this.inflight.delete(e),n.ctrl.abort(),!0):!1}abortEnvelopes(e){for(let[n,r]of[...this.inflight])e&&r.conn!==e||(this.inflight.delete(n),r.ctrl.abort())}sleep(e){return new Promise(n=>{let r=setTimeout(s,e);function s(){clearTimeout(r),n()}this.wake=()=>{this.wake=null,s()}})}async loop(e){let n=1e3;for(;!e.signal.aborted;){let r=new AbortController,s=()=>r.abort();e.signal.addEventListener("abort",s,{once:!0}),this.conn=r;try{let{cloudUrl:o,token:i}=this.deps.getCreds();if(!i)throw new Error("\u672A\u767B\u5F55 Forsion \u8D26\u53F7");let a=this.deps.getPairing();if(!a){if(a=await this.register(o,i,r),r.signal.aborted)throw new Error("\u5165\u518C\u671F\u95F4\u901A\u9053\u5DF2\u88AB\u505C\u7528");await this.deps.savePairing(a),this.deps.log(`[unit-host] \u5DF2\u5165\u518C\u4E3A\u8BBE\u5907 ${a.unitId}`)}let l=this.deps.getLanUrl();this.hubCaps=new Set;let c=this.deps.readIdleMs??Jr,u=c?setTimeout(()=>{this.deps.log(`[unit-host] \u901A\u9053 ${Math.round(c/1e3)}s \u672A\u6536\u5230\u54CD\u5E94\u5934,\u5224\u5B9A\u5DF2\u65AD,\u91CD\u8FDE`),r.abort()},c):null,f;try{f=await this.hubFetch(`${Ln(o)}/units/${a.unitId}/channel`,{headers:{Authorization:`Bearer ${i}`,"X-Unit-Secret":a.secret,...l?{"X-Unit-Lan-Url":l}:{}},signal:r.signal})}finally{u&&clearTimeout(u)}if(f.status===403||f.status===404){let m=Number(f.headers.get("content-length"))>Tc,h=setTimeout(()=>r.abort(),m?0:xc),g=await f.json().then(p=>p?.code,()=>null);throw clearTimeout(h),g==="UNIT_NOT_FOUND"||g==="UNIT_SECRET_MISMATCH"?(await this.deps.clearPairing(),new Error(`\u901A\u9053\u88AB\u62D2(${f.status} ${g}),\u5DF2\u6E05\u9664\u914D\u5BF9\u5F85\u91CD\u65B0\u5165\u518C`)):new Error(`channel HTTP ${f.status} (not a hub verdict; keeping pairing and retrying)`)}if(!f.ok||!f.body)throw new Error(`channel HTTP ${f.status}`);this.connected=!0,this.lastError=null,n=1e3,this.deps.log("[unit-host] \u901A\u9053\u5DF2\u8FDE\u63A5"),await this.consume(f.body,r),this.markDown(),this.deps.log("[unit-host] \u901A\u9053\u65AD\u5F00,\u51C6\u5907\u91CD\u8FDE")}catch(o){if(this.markDown(),e.signal.aborted)return;this.lastError=r.signal.aborted?"\u901A\u9053\u88AB\u672C\u673A\u65AD\u5F00(\u770B\u95E8\u72D7 / \u91CD\u8FDE)":String(o?.message||o),this.deps.log(`[unit-host] ${this.lastError};${this.redialNow?"\u7ACB\u5373":`${Math.round(n/1e3)}s \u540E`}\u91CD\u8BD5`)}finally{e.signal.removeEventListener("abort",s),this.conn===r&&(this.conn=null),r.abort(),this.abortEnvelopes(r)}if(e.signal.aborted)return;if(this.redialNow){this.redialNow=!1,n=1e3;continue}if(await this.sleep(n),this.redialNow){this.redialNow=!1,n=1e3;continue}n=Math.min(n*2,3e4)}}async register(e,n,r){let s=this.deps.readIdleMs??Jr,o=s?setTimeout(()=>{this.deps.log(`[unit-host] \u8BBE\u5907\u5165\u518C ${Math.round(s/1e3)}s \u672A\u8FD4\u56DE,\u4E2D\u6B62\u91CD\u8BD5`),r.abort()},s):null;try{let i=await this.hubFetch(`${Ln(e)}/units/register`,{method:"POST",headers:{Authorization:`Bearer ${n}`,"Content-Type":"application/json"},body:JSON.stringify({name:_c(),platform:process.platform}),signal:r.signal});if(!i.ok)throw new Error(`\u8BBE\u5907\u5165\u518C\u5931\u8D25 HTTP ${i.status}`);let a=await i.json();if(!a.unitId||!a.secret)throw new Error("\u8BBE\u5907\u5165\u518C\u54CD\u5E94\u7F3A\u5B57\u6BB5");return{unitId:a.unitId,secret:a.secret}}finally{o&&clearTimeout(o)}}async consume(e,n){let r=e.getReader(),s=new TextDecoder,o="",i=this.deps.readIdleMs??Jr,a=null,l=()=>{i&&(a&&clearTimeout(a),a=setTimeout(()=>{this.deps.log(`[unit-host] \u901A\u9053 ${Math.round(i/1e3)}s \u65E0\u4EFB\u4F55\u5B57\u8282(\u7F51\u5173 15s \u4E00\u6B21\u5FC3\u8DF3),\u5224\u5B9A\u5DF2\u65AD,\u91CD\u8FDE`),n.abort(),r.cancel().catch(()=>{})},i))};l();try{for(;;){let{done:c,value:u}=await r.read();if(c||n.signal.aborted)return;l(),o=this.parseFrames(o+s.decode(u,{stream:!0}),n)}}finally{a&&clearTimeout(a)}}parseFrames(e,n){let r=e,s;for(;(s=r.indexOf(`
|
|
212
|
+
`;var Le=t=>t.replace(/\\/g,"/").normalize("NFC");function as(t){let e=Le(t.path);return e?t.kind==="folder"?`${e}/`:t.kind==="page"?`${e.replace(/\.md$/i,"")}.fd/`:null:null}function Ot(t,e,n){let r=Le(n);if(!r)return!1;if(t.some(s=>Le(s.path)===r))return!0;for(let s of e??[]){let o=Le(s);if(!o)continue;let i=`${o.replace(/\.md$/i,"")}.fd`;if(r===o||r.startsWith(`${o}/`)||r===i||r.startsWith(`${i}/`))return!1}return t.some(s=>{let o=as(s);return!!o&&r.startsWith(o)})}function ls(t,e,n){let r=Le(t),s=Le(e);return r===s?Le(n):r.startsWith(`${s}/`)?Le(n)+r.slice(s.length):null}function tn(t,e,n){let r=!1,s=t.map(o=>{let i=ls(o,e,n);return i===null?o:(r=!0,i)});return{changed:r,next:s}}async function Ii(t){let e=await Ai.readdir(t,{withFileTypes:!0}).catch(()=>[]),n=[],r=Object.create(null);for(let s of e){if(!s.isDirectory()||s.name.startsWith("."))continue;let o=await Ai.readFile(Eu.join(t,s.name,is),"utf8").catch(()=>null);if(o===null)continue;n.push(s.name);let i=Yn(o);i?.length&&(r[s.name]=i)}return{names:n.sort(),devices:r}}var xe={get:"amadeus:sync:get",setEnabled:"amadeus:sync:set-enabled",syncNow:"amadeus:sync:now",confirmDeletions:"amadeus:sync:confirm-deletions",status:"amadeus:sync:status",switchSide:"amadeus:sync:switch-side",collabCall:"amadeus:collab:call",presence:"amadeus:collab:presence",entryGet:"amadeus:entry-sync:get",entryEnable:"amadeus:entry-sync:enable",entryDisable:"amadeus:entry-sync:disable",entryMark:"amadeus:entry-sync:mark",entryClosure:"amadeus:entry-sync:closure",entryChange:"amadeus:entry-sync:change",otherSideDbs:"amadeus:entry-sync:other-side-dbs"};var Gn=t=>Ee().sha256Hex(t).slice(0,8);function Ri(t){return t.replace(/ \(conflict \d{4}-\d{2}-\d{2} \d{4}\)(?=(?:\.[^./]+)?$)/,"")}function yt(t,e=[]){let n=[],r=[];for(let s of t){let o=Le(s.path);if(!o)continue;r.push(o);let i=as(s);i&&n.push(i)}return{entries:t,exclude:e,prefixes:n,paths:r}}function Pi(t,e){let n=Ri(Le(e));if(!n)return!1;if(Ot(t.entries,t.exclude,n))return!0;let r=`${n}/`;for(let s of t.paths)if(s.startsWith(r))return!0;for(let s of t.prefixes)if(s.startsWith(r))return!0;return!1}function nn(t,e,n){let r=!1,s=t.map(o=>{let i=ls(o.path,e,n);return i===null?o:(r=!0,{...o,path:i})});return{changed:r,next:s}}function Di(t,e,n,r){if(e==="delete"||e==="delete-folder"){let s=Le(n),o=t.filter(i=>{let a=Le(i.path);return!(a===s||e==="delete-folder"&&a.startsWith(`${s}/`))});return{changed:o.length!==t.length,next:o}}return r?nn(t,n,r):{changed:!1,next:t}}function cs(t,e){let n=$t(t);return!n||n!==t.normalize("NFC").trim()?"\u540D\u79F0\u4E0D\u5408\u6CD5":n.includes("/")?"\u540D\u79F0\u4E0D\u80FD\u5305\u542B /":n===Jn?`\u300C${Jn}\u300D\u662F\u4FDD\u7559\u540D\u79F0`:e.includes(n)?"\u8BE5\u540D\u79F0\u5DF2\u88AB\u5176\u4ED6\u667A\u5E93\u7684\u4E91\u540C\u6B65\u5360\u7528":null}import{constants as _u,promises as $i}from"node:fs";async function Oi(t,e){try{await $i.copyFile(Qt(t),Qt(e),_u.COPYFILE_EXCL)}catch(n){let r=n?.code;if(r==="EEXIST"||r==="ENOENT")return!1;throw n}return await $i.unlink(Qt(t)).catch(()=>{}),!0}var Mi=["setAmadeusSyncFactory","readCreds","accountId","homeDir"],us=t=>Mi.every(e=>typeof t[e]=="function"),Tu=()=>({enabled:!1,state:"disabled",lastSyncAt:null,pending:0,conflicts:0,skipped:[],error:null,pendingDeletions:0,maxFileBytes:null,side:"local"});function ds(t){let e=null,n=()=>{if(!e)throw new Error("Cloud sync is not ready");return e};t.handle(xe.get,()=>e?e.get():Tu()),t.handle(xe.setEnabled,(r,s)=>n().setEnabled(s)),t.handle(xe.syncNow,()=>n().syncNow()),t.handle(xe.confirmDeletions,()=>n().confirmDeletions()),t.handle(xe.entryGet,()=>n().entryGet()),t.handle(xe.otherSideDbs,()=>n().otherSideDbs()),t.handle(xe.entryEnable,(r,s)=>n().entryEnable(s)),t.handle(xe.entryDisable,(r,s)=>n().entryDisable(s)),t.handle(xe.entryMark,(r,s,o)=>n().entryMark(s,o)),t.handle(xe.entryClosure,(r,s,o)=>n().entryClosure(s,o)),t.handle(xe.collabCall,(r,s,o)=>n().collabCall(s,o)),t.handle(xe.switchSide,(r,s)=>n().switchSide(r.sender.id,s)),t.setAmadeusSyncFactory(r=>{ci(r);let s=Ni(r);return e=s.handlers,s.instance}),t.log("[forsion-extend] amadeus cloud sync registered")}function Ni(t){let e=t.notifyAll,n=()=>t.vaultRoot(),r=0,s=!1,o=os(),i=new Map,a=()=>{let x=Date.now();for(let[R,_]of i)x-_.at>7e4&&i.delete(R);e(xe.presence,[...i.values()])},l={loadCreds:()=>t.readCreds(),onStatus:x=>e(xe.status,{...x,pendingDeletions:Y(),side:m()?"cloud":"local"}),onPresence:(x,R)=>{let _=R;_?.userId&&(i.set(_.userId,{userId:_.userId,username:String(_.username??"user"),page:_.page??null,at:Number(_.at)||Date.now()}),a())},onPresenceRoster:(x,R)=>{if(Array.isArray(R)){for(let _ of R){let I=_;I?.userId&&i.set(I.userId,{userId:I.userId,username:String(I.username??"user"),page:I.page??null,at:Number(I.at)||Date.now()})}a()}}},c=()=>{let x=r;return{...l,onStatus:R=>{x===r&&l.onStatus(R)},onPresence:(R,_)=>{x===r&&l.onPresence(R,_)},onPresenceRoster:(R,_)=>{x===r&&l.onPresenceRoster(R,_)}}},u=en(c()),f=new Map,p=[],h=0,g=async()=>{if(!s||!Ae())return;let x=r,R=++h,_=o,I;try{I=await _.sharedWithMe()}catch{return}if(x!==r||!s||R!==h)return;let z=_i(I);p=z;let W=new Map(z.map(U=>[U.key,U.scopeKey]));for(let[U,N]of f)if(W.get(U)!==N.plan.scopeKey){if(await N.engine.stop(),x!==r)return;f.delete(U)}for(let U of z){if(f.has(U.key))continue;let N=en(c(),{localRoot:_t.join(ht(),...U.localRelDir.split("/")),shadowName:`amadeus-sync-${Xt()}-share-${U.key}`,vaultId:U.vaultId,serverDir:U.serverDir,inScope:U.inScope});f.set(U.key,{engine:N,plan:U}),N.start()}},m=()=>n()===ht(),w=(x,R=x.base)=>{x.base=R;let _=[R,...x.pendingMoves];x.scope.current=yt(_.flatMap(I=>I.entries),_.flatMap(I=>I.exclude))},k=new Map,P=new Set,O=new Set,A=null,$=()=>A??=new Promise(x=>{let R=()=>xu.hostname().replace(/\.(local|lan|home)$/i,"")||"Desktop";if(process.platform!=="darwin")return x(R());Cu("scutil",["--get","ComputerName"],{timeout:1500},(_,I)=>x(!_&&String(I).trim()||R()))}),b=async()=>{let x=(await Ue()).cloudSync?.deviceId;return x?{id:x,name:await $()}:null},C=new Map,E=(x,R,_)=>{let I=r,z=(C.get(x)??Promise.resolve()).catch(()=>{}).then(async()=>{I!==r||_&&!await _()||I!==r||await T(x,R,I)});return C.set(x,z),z.finally(()=>{C.get(x)===z&&C.delete(x)}).catch(()=>{}),z},T=async(x,R,_)=>{let I=o,z=encodeURIComponent(await I.ensureOwnVault()),W=xi(x);for(let U=0;U<3;U++){let N=null;try{N=await I.call("GET",`/vaults/${z}/file?path=${encodeURIComponent(W)}`)}catch(Z){if(Z?.status!==404)throw Z}let V=R(!!N,N?Yn(N.content):null);if(V===void 0||_!==r)return;try{if(V===null){N&&await I.call("DELETE",`/vaults/${z}/file?path=${encodeURIComponent(W)}&baseSeq=${N.seq}`);return}await I.call("PUT",`/vaults/${z}/file`,{path:W,content:Ti(V),baseSeq:N?.seq??0});return}catch(Z){if(Z?.status!==409)throw Z}}throw Object.assign(new Error("marker write kept conflicting"),{status:409})},L=async x=>!!(await Ue()).entrySync?.some(R=>R.cloudName===x&&R.entries.length>0),X=(x,R)=>E(x,(_,I)=>{let z=I?.find(U=>U.id===R.id);if(z&&z.name===R.name)return;let W=z?.since??new Date().toISOString().slice(0,10);return[...(I??[]).filter(U=>U.id!==R.id),{...R,since:W}]},()=>L(x)),ee=(x,R)=>E(x,(_,I)=>{if(!_||!I?.some(W=>W.id===R))return;let z=I.filter(W=>W.id!==R);return z.length?z:null},async()=>!await L(x)),te=()=>{e(xe.entryChange)},ae=async(x,R)=>{let _=k.get(x);if(!_)return;let I=U=>U&&U.startsWith(`${_.cloudName}/`)?U.slice(_.cloudName.length+1):null,z=I(R.path);if(!z)return;let W=!1;await Dt(U=>{if(k.get(x)!==_)return!1;let N=(U.entrySync??[]).find(he=>he.vaultRoot===x);if(!N)return!1;let V=R.op,Z=I(R.newPath),J=Di(N.entries,V,z,Z),de=Z?tn(N.exclude??[],z,Z):{changed:!1,next:N.exclude??[]};if(!J.changed&&!de.changed)return!1;W=!0,N.entries=J.next,de.changed&&(N.exclude=de.next),w(_,yt(N.entries,N.exclude??[]))}),W&&k.get(x)===_&&te()},le=x=>{let R=r;return{...c(),onStatus:_=>{R===r&&e(xe.status,{..._,pendingDeletions:Y(),side:"local",binding:x})},onRemoteApplied:async _=>{R===r&&await ae(x,_)}}},j=async()=>{let x=Ae();if(!s||!x)return;let R=r,_=o,I=Xt(x);await t.adoptLegacyCloudState(x,Oi);let z=await Ue(x),W=z.entrySync??[];if(R!==r||!s||x!==Ae())return;let U=new Map(W.map(N=>[N.vaultRoot,N]));for(let[N,V]of k){let Z=U.get(N);if(!(Z&&Z.cloudName===V.cloudName)&&(await V.engine.stop(),R!==r||(k.delete(N),Z&&await wi(`amadeus-sync-${I}-entry-${Gn(N)}`),R!==r)))return}for(let N of W){let V=k.get(N.vaultRoot);if(V){w(V,yt(N.entries,N.exclude??[]));continue}let Z={current:yt(N.entries,N.exclude??[])},J=N.cloudName,de=en(le(N.vaultRoot),{accountId:x,localRoot:N.vaultRoot,shadowName:`amadeus-sync-${I}-entry-${Gn(N.vaultRoot)}`,vaultId:"first",serverDir:J,clientIdSuffix:`entry-${Gn(N.vaultRoot)}`,requireRootExists:!0,ignoreNames:[".git","node_modules",".trash"],inScope:he=>he===J?!0:he.startsWith(`${J}/`)?Pi(Z.current,he.slice(J.length+1)):!1});k.set(N.vaultRoot,{engine:de,scope:Z,cloudName:J,base:Z.current,pendingMoves:new Set}),de.start()}if(z.cloudSync?.enabled!==!1)for(let N of W){let V=N.entries.length>0,Z=V?P:O;Z.has(N.cloudName)||((V?O:P).delete(N.cloudName),(async()=>{try{let J=await b();if(!J||R!==r||(await(V?X(N.cloudName,J):ee(N.cloudName,J.id)),R!==r))return;Z.add(N.cloudName),(V?O:P).delete(N.cloudName)}catch{}})())}},q=async(x,R,_,I,z)=>{let W=R.replace(/\\/g,"/").normalize("NFC"),U=_.replace(/\\/g,"/").normalize("NFC"),N=!1,V,Z,J,de=z??"file";try{await Dt(async he=>{if(k.get(x)!==I)return!1;let Se=(he.entrySync??[]).find(Be=>Be.vaultRoot===x);if(!Se)return!1;let ge=nn(Se.entries,W,U),ye=tn(Se.exclude??[],W,U),He=Ot(Se.entries,Se.exclude,W);!z&&await Mt.stat(_t.join(x,...U.split("/"))).then(Be=>Be.isDirectory(),()=>!1)&&(de="folder");let Ve=de==="folder"?"folder":/\.md$/i.test(U)?"page":"asset";He&&!Ot(ge.next,ye.next,U)&&(ge.next.push({path:U,kind:Ve}),ge.changed=!0),N=ge.changed||ye.changed;let ut=Se.entries.filter(Be=>nn([Be],W,U).changed);return He&&!ut.some(Be=>Be.path===W)&&ut.push({path:W,kind:Ve}),V=yt(ut,(Se.exclude??[]).filter(Be=>tn([Be],W,U).changed)),Z=I.base,I.pendingMoves.add(V),Se.entries=ge.next,Se.exclude=ye.next,J=yt(Se.entries,Se.exclude),w(I,J),N})}catch(he){throw V&&I.pendingMoves.delete(V),w(I,I.base===J&&Z?Z:I.base),he}try{V&&await I.engine.notifyLocalMove(W,U,()=>{I.pendingMoves.delete(V),w(I)},de)}catch(he){throw V&&I.pendingMoves.delete(V),await Dt(Se=>{let ge=Se.entrySync?.find(ye=>ye.vaultRoot===x);if(!ge)return!1;ge.entries=nn(ge.entries,U,W).next,ge.exclude=tn(ge.exclude??[],U,W).next,w(I,yt(ge.entries,ge.exclude))}),he}N&&k.get(x)===I&&te()},K=x=>{let R=x.replace(/\\/g,"/");for(let{engine:_,plan:I}of f.values())if(R.startsWith(`${I.localRelDir}/`))return{engine:_,rel:R.slice(I.localRelDir.length+1)};return{engine:u,rel:R}};t.setMutationHooks((x,R)=>{if(m()){let _=K(x);_.engine.notifyLocal(_.rel,R);return}k.get(n()??"")?.engine.notifyLocal(x,R)},(x,R,_)=>{if(m()){let W=K(x),U=K(R);if(W.engine===U.engine)return W.engine.notifyLocalMove(W.rel,U.rel,void 0,_);W.engine.notifyLocal(W.rel,"remove"),U.engine.notifyLocal(U.rel,"write");return}let I=n()??"",z=k.get(I);if(z)return q(I,x,R,z,_)},(x,R)=>{if(m()){let _=K(x),I=K(R),z=[_.engine.holdLocalMove(_.rel,I.rel)];return _.engine!==I.engine&&z.push(I.engine.holdLocalMove(_.rel,I.rel)),()=>{for(let W of z)W()}}return k.get(n()??"")?.engine.holdLocalMove(x,R)});let Y=()=>{let x=u.getStatus().pendingDeletions;for(let{engine:R}of f.values())x+=R.getStatus().pendingDeletions;for(let{engine:R}of k.values())x+=R.getStatus().pendingDeletions;return x},ce=x=>({...x,pendingDeletions:Y(),side:m()?"cloud":"local"}),me=()=>{if(!s)return Promise.resolve(u.getStatus());g();for(let{engine:x}of f.values())x.syncNow();for(let{engine:x}of k.values())x.syncNow();return u.syncNow()},Ce=async()=>{++r,s=!1,o.stop();let x=[u.stop(),...[...f.values()].map(({engine:_})=>_.stop()),...[...k.values()].map(({engine:_})=>_.stop())];f.clear(),k.clear(),p=[],P.clear(),O.clear(),i.clear(),a(),await Promise.all(x),await t.awaitPendingVaultWrites();let R=n();if(R&&qn(R)){let _=await Ue(),I=_.localVault&&!qn(_.localVault)?_.localVault:_t.join(t.workspaceDir(),"Amadeus");await Mt.mkdir(I,{recursive:!0}),await ot({lastVault:I,localVault:I,lastPage:void 0}),await t.activateRoot(I,!1)}te()};return{handlers:{get:()=>ce(u.getStatus()),setEnabled:async x=>{if(!s)throw new Error("Cloud account is changing");let R=r;return await u.setEnabled(x),R!==r?u.getStatus():(await Promise.all([...f.values(),...k.values()].map(({engine:_})=>_.restart())),ce(u.getStatus()))},syncNow:()=>me(),confirmDeletions:()=>{for(let{engine:x}of f.values())x.confirmMassDeletions();for(let{engine:x}of k.values())x.confirmMassDeletions();return ce(u.confirmMassDeletions())},entryGet:async()=>{let x=await Ue(),R=ht(),_=await Ii(R);return{vaults:x.entrySync??[],activeRoot:n(),cloudRoot:R,mirrorVaults:_.names,mirrorVaultDevices:_.devices,deviceId:x.cloudSync?.deviceId??null}},otherSideDbs:async()=>{let x=n();if(!x)return null;let R=ht(),_=await Ue(),I=x===R?_.localVault&&_.localVault!==R?_.localVault:null:R;if(!I)return null;let z=[],W=500,U=async(N,V)=>{if(z.length>=W)return;let Z;try{Z=await Mt.readdir(N,{withFileTypes:!0})}catch{return}for(let J of Z){if(z.length>=W)break;if(J.name.startsWith(".")||J.isSymbolicLink())continue;let de=V?`${V}/${J.name}`:J.name;if(J.isDirectory())await U(_t.join(N,J.name),de);else if(J.isFile()&&/\.db$/i.test(J.name))try{z.push({rel:de,source:await Mt.readFile(_t.join(N,J.name),"utf8")})}catch{}}};return await U(I,""),{root:I,vaultName:I===R?"\u4E91\u7AEF":_t.basename(I),dbs:z}},entryEnable:async x=>{let R=r,_=o;if(!s||!Ae())return{error:"Sign in to enable cloud sync"};let I=n();if(!I||m())return{error:"\u4EC5\u672C\u5730 vault \u53EF\u5F00\u542F\u4E91\u540C\u6B65"};let z=await Ue(),W=z.entrySync??[],U=W.find(N=>N.vaultRoot===I);if(!U){let N=(x.cloudName??_t.basename(I)).normalize("NFC").trim(),V=cs(N,W.map(Z=>Z.cloudName));if(V)return{error:V};if(!x.merge)try{let Z=await _.ensureOwnVault(),J=await _.call("GET",`/vaults/${encodeURIComponent(Z)}/tree`);if((J.folders??[]).some(he=>he===N||he.startsWith(`${N}/`))||(J.entries??[]).some(he=>he.path===N||he.path.startsWith(`${N}/`)))return{conflict:N}}catch(Z){return{error:Z?.message||"\u65E0\u6CD5\u8FDE\u63A5\u4E91\u7AEF(\u9996\u6B21\u5F00\u542F\u9700\u8981\u5728\u7EBF)"}}U={vaultRoot:I,cloudName:N,entries:[]},W.push(U)}return R!==r||!s?{error:"Cloud account changed; retry from the current account"}:(await Dt(N=>{if(R!==r||!s)return!1;let V=N.entrySync??[],Z=V.find(ye=>ye.vaultRoot===I);if(!Z){let ye=cs(U.cloudName,V.map(He=>He.cloudName));if(ye)throw new Error(ye);Z={vaultRoot:I,cloudName:U.cloudName,entries:[]},V.push(Z)}let J=ye=>String(ye??"").replace(/\\/g,"/").normalize("NFC"),de=new Set;for(let ye of x.entries??[]){let He=J(ye.path);He&&(de.add(He),!Z.entries.some(Ve=>Ve.path===He)&&Z.entries.push({path:He,kind:ye.kind==="folder"||ye.kind==="asset"?ye.kind:"page"}))}let he=(x.exclude??[]).map(J).filter(Boolean),Se=new Set([...de,...(x.include??[]).map(J).filter(Boolean)]);Z.exclude=[...new Set([...(Z.exclude??[]).filter(ye=>!Se.has(ye)),...he])];let ge=new Set(he);Z.entries=Z.entries.filter(ye=>!ge.has(ye.path)),N.entrySync=V,U=Z},z.cloudAccountId),R!==r?{error:"Cloud account changed; retry from the current account"}:(await j(),k.get(I)?.engine.syncNow(),te(),{ok:!0,cloudName:U.cloudName}))},entryDisable:async x=>{let R=n(),_=!1,I=r;return await Dt(z=>{if(I!==r||!s)return!1;let W=(z.entrySync??[]).find(V=>V.vaultRoot===R);if(!R||!W)return!1;let U=String(x??"").replace(/\\/g,"/").normalize("NFC"),N=W.entries.length;if(W.entries=W.entries.filter(V=>V.path!==U),Ot(W.entries,W.exclude,U))W.exclude=[...new Set([...W.exclude??[],U])];else if(W.entries.length===N)return!1;_=!0}),!_||I!==r?{ok:!1}:(await j(),te(),{ok:!0})},entryMark:async(x,R)=>{let _=String(x??"").normalize("NFC");if(!_||_.includes("/")||_.startsWith("."))return{error:"invalid name"};if(!s||!Ae())return{error:"Sign in first"};try{await E(_,I=>R?I?void 0:[]:I?null:void 0)}catch(I){return{error:I?.message||String(I)}}return u.syncNow(),{ok:!0}},entryClosure:(x,R)=>t.relatedClosure(String(x??""),R==="folder"?"folder":"page"),collabCall:async(x,R)=>{let _=o,I=async()=>_.ensureOwnVault(),z=U=>String((R??[])[U]??""),W=U=>(R??[])[U]??{};switch(x){case"listVaults":return(await _.call("GET","/vaults")).vaults;case"activeVaultId":return I();case"pageShare":return _.call("GET",`/vaults/${encodeURIComponent(await I())}/page-shares?path=${encodeURIComponent(z(0))}`);case"relatedItems":return _.call("GET",`/vaults/${encodeURIComponent(await I())}/page-shares/${encodeURIComponent(z(0))}/related`);case"setShareItem":return _.call("POST",`/vaults/${encodeURIComponent(await I())}/page-shares/${encodeURIComponent(z(0))}/items`,{path:z(1),included:(R??[])[2]===!0});case"createPageShare":return _.call("POST",`/vaults/${encodeURIComponent(await I())}/page-shares`,{path:z(0),...W(1)});case"updatePageShare":return _.call("PATCH",`/vaults/${encodeURIComponent(z(2)||await I())}/page-shares/${encodeURIComponent(z(0))}`,W(1));case"revokePageShare":return _.call("DELETE",`/vaults/${encodeURIComponent(await I())}/page-shares/${encodeURIComponent(z(0))}`);case"setParticipantRole":return _.call("PATCH",`/vaults/${encodeURIComponent(z(3)||await I())}/page-shares/${encodeURIComponent(z(0))}/members/${encodeURIComponent(z(1))}`,{role:z(2)});case"removeParticipant":return _.call("DELETE",`/vaults/${encodeURIComponent(z(2)||await I())}/page-shares/${encodeURIComponent(z(0))}/members/${encodeURIComponent(z(1))}`);case"sharedWithMe":{let U=await _.sharedWithMe();return g(),U}case"leaveShare":{let U=_.myUserId();if(!U)throw new Error("\u672A\u767B\u5F55");let N=await _.call("DELETE",`/vaults/${encodeURIComponent(z(1)||await I())}/page-shares/${encodeURIComponent(z(0))}/members/${encodeURIComponent(U)}`);return g(),N}case"publishes":return _.call("GET",`/vaults/${encodeURIComponent(await I())}/shares`);case"listAllShares":{let U=(await _.call("GET","/vaults")).vaults||[],N=_.myUserId(),V=[],Z=[];for(let J of U){try{let de=await _.call("GET",`/vaults/${encodeURIComponent(J.id)}/shares`);for(let he of de.shares||[])V.push({...he,vaultId:J.id,vaultName:J.name||""})}catch(de){t.log(`[connect] listAllShares publishes vault ${J.id} failed: ${de?.message}`)}try{let de=await _.call("GET",`/vaults/${encodeURIComponent(J.id)}/page-shares?expired=1`),he=de?.shares||de?.pageShares||(Array.isArray(de)?de:[]);for(let Se of he){let ge=Se.created_by??Se.createdBy;(!N||!ge||ge===N)&&Z.push({...Se,vaultId:J.id,vaultName:J.name||""})}}catch(de){t.log(`[connect] listAllShares pageShares vault ${J.id} failed: ${de?.message}`)}}return{publishes:V,pageShares:Z,linkBase:await _.linkBase()}}case"createPublish":{let U=await _.call("POST",`/vaults/${encodeURIComponent(await I())}/shares`,{mode:z(0),path:z(1)});return{...U,url:`${await _.linkBase()}/share/${U.token}`}}case"revokePublish":return _.call("DELETE",`/vaults/${encodeURIComponent(await I())}/shares/${encodeURIComponent(z(0))}`);case"revokePublishIn":return _.call("DELETE",`/vaults/${encodeURIComponent(z(0))}/shares/${encodeURIComponent(z(1))}`);case"revokePageShareIn":return _.call("DELETE",`/vaults/${encodeURIComponent(z(0))}/page-shares/${encodeURIComponent(z(1))}`);case"myUserId":return _.myUserId();case"linkBase":return _.linkBase();case"heartbeat":return _.heartbeat((R??[])[0]??null,p);default:throw new Error(`unknown collab fn: ${x}`)}},switchSide:async(x,R)=>{let _=await Ue();if(R==="cloud"){if(!s||!Ae())throw new Error("Sign in to open cloud notes");let W=ht();await Mt.mkdir(W,{recursive:!0}),_.lastVault&&!qn(_.lastVault)&&await ot({localVault:_.lastVault}),await ot({lastVault:W});let U=await t.activateRoot(W,!1);return t.bindRenderer(x,W),{...U,side:"cloud"}}let I=_.localVault&&await Mt.stat(_.localVault).then(W=>W.isDirectory()).catch(()=>!1)?_.localVault:null;if(!I){let W=await t.ensureDefaultVault();return t.bindRenderer(x,W.root),{...W,side:"local"}}await ot({lastVault:I});let z=await t.activateRoot(I,!1);return t.bindRenderer(x,I),{...z,side:"local"}}},instance:{start:()=>{s=!0,u.start(),g(),j()},stopAllSync:Ce,restartAllSync:async()=>{await Ce(),o=os(),u=en(c()),s=!0,await Promise.all([u.restart(),g(),j()]),te(),e(xe.status,ce(u.getStatus()))},resolveSharedAsset:x=>Ci(p,x)}}}import{hostname as Au}from"node:os";var Iu=256*1024;function ji(t,e,n){if(n?.hasSecHeaders&&!n.gatewayStreamsSecHeaders)return!1;if(t.includes("text/event-stream"))return!0;let r=Number(e||NaN);return!Number.isFinite(r)||r>Iu}var fs=45e3,Ru=3e3,Pu=16*1024,Du=6e4,Kn=t=>`${t.replace(/\/+$/,"")}/api`,rn=class{deps;ctrl=null;conn=null;wake=null;redialNow=!1;inflight=new Map;connected=!1;lastError=null;hubCaps=new Set;constructor(e){this.deps=e}hubFetch(e,n){return(this.deps.hubFetch??fetch)(e,n)}get requestTimeoutMs(){return this.deps.requestTimeoutMs??Du}status(){return{running:!!this.ctrl,connected:this.connected,unitId:this.deps.getPairing()?.unitId??null,lastError:this.lastError}}start(){if(this.ctrl)return;let e=new AbortController;this.ctrl=e,this.loop(e)}stop(){this.ctrl?.abort(),this.ctrl=null,this.markDown(),this.abortEnvelopes(),this.wake?.()}reconnect(e){this.ctrl&&(this.deps.log(`[unit-host] \u7ACB\u5373\u91CD\u8FDE\u901A\u9053(${e})`),this.redialNow=!0,this.conn?.abort(),this.wake?.())}markDown(){this.connected=!1,this.hook(this.deps.onChannelDown)}hook(e){try{e?.()}catch(n){this.deps.log(`[unit-host] \u901A\u9053\u56DE\u8C03\u51FA\u9519(\u5DF2\u5FFD\u7565): ${n?.message||n}`)}}abortEnvelope(e){let n=this.inflight.get(e);return n?(this.inflight.delete(e),n.ctrl.abort(),!0):!1}abortEnvelopes(e){for(let[n,r]of[...this.inflight])e&&r.conn!==e||(this.inflight.delete(n),r.ctrl.abort())}sleep(e){return new Promise(n=>{let r=setTimeout(s,e);function s(){clearTimeout(r),n()}this.wake=()=>{this.wake=null,s()}})}async loop(e){let n=1e3;for(;!e.signal.aborted;){let r=new AbortController,s=()=>r.abort();e.signal.addEventListener("abort",s,{once:!0}),this.conn=r;try{let{cloudUrl:o,token:i}=this.deps.getCreds();if(!i)throw new Error("\u672A\u767B\u5F55 Forsion \u8D26\u53F7");let a=this.deps.getPairing();if(!a){if(a=await this.register(o,i,r),r.signal.aborted)throw new Error("\u5165\u518C\u671F\u95F4\u901A\u9053\u5DF2\u88AB\u505C\u7528");await this.deps.savePairing(a),this.deps.log(`[unit-host] \u5DF2\u5165\u518C\u4E3A\u8BBE\u5907 ${a.unitId}`)}let l=this.deps.getLanUrl();this.hubCaps=new Set;let c=this.deps.readIdleMs??fs,u=c?setTimeout(()=>{this.deps.log(`[unit-host] \u901A\u9053 ${Math.round(c/1e3)}s \u672A\u6536\u5230\u54CD\u5E94\u5934,\u5224\u5B9A\u5DF2\u65AD,\u91CD\u8FDE`),r.abort()},c):null,f;try{f=await this.hubFetch(`${Kn(o)}/units/${a.unitId}/channel`,{headers:{Authorization:`Bearer ${i}`,"X-Unit-Secret":a.secret,...l?{"X-Unit-Lan-Url":l}:{}},signal:r.signal})}finally{u&&clearTimeout(u)}if(f.status===403||f.status===404){let p=Number(f.headers.get("content-length"))>Pu,h=setTimeout(()=>r.abort(),p?0:Ru),g=await f.json().then(m=>m?.code,()=>null);throw clearTimeout(h),g==="UNIT_NOT_FOUND"||g==="UNIT_SECRET_MISMATCH"?(await this.deps.clearPairing(),new Error(`\u901A\u9053\u88AB\u62D2(${f.status} ${g}),\u5DF2\u6E05\u9664\u914D\u5BF9\u5F85\u91CD\u65B0\u5165\u518C`)):new Error(`channel HTTP ${f.status} (not a hub verdict; keeping pairing and retrying)`)}if(!f.ok||!f.body)throw new Error(`channel HTTP ${f.status}`);this.connected=!0,this.lastError=null,n=1e3,this.deps.log("[unit-host] \u901A\u9053\u5DF2\u8FDE\u63A5"),await this.consume(f.body,r),this.markDown(),this.deps.log("[unit-host] \u901A\u9053\u65AD\u5F00,\u51C6\u5907\u91CD\u8FDE")}catch(o){if(this.markDown(),e.signal.aborted)return;this.lastError=r.signal.aborted?"\u901A\u9053\u88AB\u672C\u673A\u65AD\u5F00(\u770B\u95E8\u72D7 / \u91CD\u8FDE)":String(o?.message||o),this.deps.log(`[unit-host] ${this.lastError};${this.redialNow?"\u7ACB\u5373":`${Math.round(n/1e3)}s \u540E`}\u91CD\u8BD5`)}finally{e.signal.removeEventListener("abort",s),this.conn===r&&(this.conn=null),r.abort(),this.abortEnvelopes(r)}if(e.signal.aborted)return;if(this.redialNow){this.redialNow=!1,n=1e3;continue}if(await this.sleep(n),this.redialNow){this.redialNow=!1,n=1e3;continue}n=Math.min(n*2,3e4)}}async register(e,n,r){let s=this.deps.readIdleMs??fs,o=s?setTimeout(()=>{this.deps.log(`[unit-host] \u8BBE\u5907\u5165\u518C ${Math.round(s/1e3)}s \u672A\u8FD4\u56DE,\u4E2D\u6B62\u91CD\u8BD5`),r.abort()},s):null;try{let i=await this.hubFetch(`${Kn(e)}/units/register`,{method:"POST",headers:{Authorization:`Bearer ${n}`,"Content-Type":"application/json"},body:JSON.stringify({name:Au(),platform:process.platform}),signal:r.signal});if(!i.ok)throw new Error(`\u8BBE\u5907\u5165\u518C\u5931\u8D25 HTTP ${i.status}`);let a=await i.json();if(!a.unitId||!a.secret)throw new Error("\u8BBE\u5907\u5165\u518C\u54CD\u5E94\u7F3A\u5B57\u6BB5");return{unitId:a.unitId,secret:a.secret}}finally{o&&clearTimeout(o)}}async consume(e,n){let r=e.getReader(),s=new TextDecoder,o="",i=this.deps.readIdleMs??fs,a=null,l=()=>{i&&(a&&clearTimeout(a),a=setTimeout(()=>{this.deps.log(`[unit-host] \u901A\u9053 ${Math.round(i/1e3)}s \u65E0\u4EFB\u4F55\u5B57\u8282(\u7F51\u5173 15s \u4E00\u6B21\u5FC3\u8DF3),\u5224\u5B9A\u5DF2\u65AD,\u91CD\u8FDE`),n.abort(),r.cancel().catch(()=>{})},i))};l();try{for(;;){let{done:c,value:u}=await r.read();if(c||n.signal.aborted)return;l(),o=this.parseFrames(o+s.decode(u,{stream:!0}),n)}}finally{a&&clearTimeout(a)}}parseFrames(e,n){let r=e,s;for(;(s=r.indexOf(`
|
|
213
213
|
|
|
214
214
|
`))>=0;){let o=r.slice(0,s);if(r=r.slice(s+2),o.includes("event: ready")){let a=o.split(`
|
|
215
215
|
`).find(l=>l.startsWith("data: "))?.slice(6);try{let l=JSON.parse(a||"{}").caps;this.hubCaps=new Set(Array.isArray(l)?l.map(String):[])}catch{this.hubCaps=new Set}n.signal.aborted||this.hook(this.deps.onChannelReady);continue}if(!o.includes("event: dispatch"))continue;let i=o.split(`
|
|
216
|
-
`).find(a=>a.startsWith("data: "))?.slice(6);if(i)try{let a=JSON.parse(i);this.dispatch(a,n).catch(l=>this.deps.log(`[unit-host] \u6D3E\u53D1\u5904\u7406\u5931\u8D25: ${l?.message||l}`))}catch{}}return r}async dispatch(e,n){let r=new AbortController;if(n.signal.aborted)return;this.inflight.get(e.id)?.ctrl.abort();let s={ctrl:r,conn:n};this.inflight.set(e.id,s);try{await this.handle(e,r)}finally{this.inflight.get(e.id)===s&&this.inflight.delete(e.id)}}async handle(e,n){let r=this.deps.getUnitWeb();if(!r.url){await this.respond(e.id,503,"application/json",Buffer.from(JSON.stringify({detail:"\u672C\u673A\u4E92\u8054\u670D\u52A1\u672A\u5C31\u7EEA",code:"UNIT_WEB_NOT_READY"})),void 0,n.signal);return}let s={"x-unit-internal":r.internalSecret};e.ct&&(s["Content-Type"]=e.ct),e.accept&&(s.Accept=e.accept);let o;try{let u=new URL(`${r.url}${e.path}`);Object.assign(s,this.deps.callerHeaders({dispatchId:e.id,method:e.method,target:u,proxyCaller:e.proxyCaller})),o=await fetch(u,{method:e.method,headers:s,body:e.body??void 0,signal:n.signal})}catch(u){if(n.signal.aborted)return;await this.respond(e.id,502,"application/json",Buffer.from(JSON.stringify({detail:`\u672C\u673A\u4E92\u8054\u670D\u52A1\u4E0D\u53EF\u8FBE: ${u?.message||u}`})),void 0,n.signal);return}let i=o.headers.get("content-type")||"",a={};for(let u of["content-security-policy","x-content-type-options"]){let f=o.headers.get(u);f&&(a[u]=f)}let l=i||"application/octet-stream";o.body&&
|
|
216
|
+
`).find(a=>a.startsWith("data: "))?.slice(6);if(i)try{let a=JSON.parse(i);this.dispatch(a,n).catch(l=>this.deps.log(`[unit-host] \u6D3E\u53D1\u5904\u7406\u5931\u8D25: ${l?.message||l}`))}catch{}}return r}async dispatch(e,n){let r=new AbortController;if(n.signal.aborted)return;this.inflight.get(e.id)?.ctrl.abort();let s={ctrl:r,conn:n};this.inflight.set(e.id,s);try{await this.handle(e,r)}finally{this.inflight.get(e.id)===s&&this.inflight.delete(e.id)}}async handle(e,n){let r=this.deps.getUnitWeb();if(!r.url){await this.respond(e.id,503,"application/json",Buffer.from(JSON.stringify({detail:"\u672C\u673A\u4E92\u8054\u670D\u52A1\u672A\u5C31\u7EEA",code:"UNIT_WEB_NOT_READY"})),void 0,n.signal);return}let s={"x-unit-internal":r.internalSecret};e.ct&&(s["Content-Type"]=e.ct),e.accept&&(s.Accept=e.accept);let o;try{let u=new URL(`${r.url}${e.path}`);Object.assign(s,this.deps.callerHeaders({dispatchId:e.id,method:e.method,target:u,proxyCaller:e.proxyCaller})),o=await fetch(u,{method:e.method,headers:s,body:e.body??void 0,signal:n.signal})}catch(u){if(n.signal.aborted)return;await this.respond(e.id,502,"application/json",Buffer.from(JSON.stringify({detail:`\u672C\u673A\u4E92\u8054\u670D\u52A1\u4E0D\u53EF\u8FBE: ${u?.message||u}`})),void 0,n.signal);return}let i=o.headers.get("content-type")||"",a={};for(let u of["content-security-policy","x-content-type-options"]){let f=o.headers.get(u);f&&(a[u]=f)}let l=i||"application/octet-stream";o.body&&ji(i,o.headers.get("content-length"),{hasSecHeaders:Object.keys(a).length>0,gatewayStreamsSecHeaders:this.hubCaps.has("stream-sec-headers")})?await this.streamBack(e.id,o,n,l,a):await this.respond(e.id,o.status,l,Buffer.from(await o.arrayBuffer()),a,n.signal)}async respond(e,n,r,s,o,i){if(i?.aborted)return;let{cloudUrl:a,token:l}=this.deps.getCreds(),c=this.deps.getPairing();if(!c)return;let u=this.requestTimeoutMs*2,f=[...u?[AbortSignal.timeout(u)]:[],...i?[i]:[]],p=f.length>1?AbortSignal.any(f):f[0];await this.hubFetch(`${Kn(a)}/units/${c.unitId}/resp/${e}`,{method:"POST",headers:{Authorization:`Bearer ${l}`,"X-Unit-Secret":c.secret,"Content-Type":"application/json"},body:JSON.stringify({status:n,headers:{"content-type":r,...o},bodyB64:s.toString("base64")}),...p?{signal:p}:{}}).then(h=>{h.body?.cancel().catch(()=>{})}).catch(h=>{i?.aborted||this.deps.log(`[unit-host] \u56DE\u5305\u5931\u8D25: ${h?.name==="TimeoutError"?`${Math.round(u/1e3)}s \u672A\u5B8C\u6210`:h?.message||h}`)})}async streamBack(e,n,r,s,o){let{cloudUrl:i,token:a}=this.deps.getCreds(),l=this.deps.getPairing();if(!l)return;let c=o?.["content-security-policy"],u=o?.["x-content-type-options"],f=`${Kn(i)}/units/${l.unitId}/stream/${e}?status=${n.status}&ct=${encodeURIComponent(s)}`+(c?`&csp=${encodeURIComponent(c)}`:"")+(u?`&xcto=${encodeURIComponent(u)}`:""),p=n.body;if(!p)return;let h=p.getReader(),g=0,m=this.requestTimeoutMs,w=m?setTimeout(()=>{g>=2||(this.deps.log(`[unit-host] \u6D41\u5F0F\u56DE\u4F20 ${Math.round(m/1e3)}s \u672A\u628A\u9996\u5757\u5199\u7ED9\u7F51\u5173,\u4E2D\u6B62\u672C\u6B21\u6D3E\u53D1`),r.abort())},m):null,k=new ReadableStream({async pull(P){++g===2&&w&&clearTimeout(w);let{done:O,value:A}=await h.read();O?P.close():P.enqueue(A)},cancel(P){return h.cancel(P)}},{highWaterMark:0});try{await this.hubFetch(f,{method:"POST",headers:{Authorization:`Bearer ${a}`,"X-Unit-Secret":l.secret,"Content-Type":"application/octet-stream"},body:k,signal:r.signal,duplex:"half"})}catch(P){this.deps.log(`[unit-host] \u6D41\u5F0F\u56DE\u4F20\u4E2D\u65AD: ${P?.message||P}`);try{await h.cancel()}catch{}}finally{w&&clearTimeout(w)}}};var sn=class{d;up=!1;gen=0;lastSent=null;disabled=!1;inflight=!1;again=!1;timer=null;warned=new Set;constructor(e){this.d=e}channelReady(){this.gen++,this.up=!0,this.lastSent=null,this.disabled=!1,this.clearTimer(),this.again=!1,this.flush()}channelDown(){this.gen++,this.up=!1,this.lastSent=null,this.again=!1,this.clearTimer()}engineChanged(){!this.up||this.disabled||(this.clearTimer(),this.timer=setTimeout(()=>{this.timer=null,this.flush()},this.d.debounceMs??500))}clearTimer(){this.timer&&(clearTimeout(this.timer),this.timer=null)}async flush(){if(!this.up||this.disabled)return;if(this.inflight){this.again=!0;return}let e;try{e=this.d.current()}catch(a){this.d.log(`[unit-caps] \u8BFB\u5F15\u64CE\u6001\u5931\u8D25:${a?.message||a}`);return}if(e===this.lastSent)return;let n=this.d.getPairing(),r;try{r=this.d.getCreds()}catch{return}if(!n||!r.token||!r.cloudUrl)return;let s=this.gen;this.inflight=!0;let o=new AbortController,i=setTimeout(()=>o.abort(),this.d.timeoutMs??1e4);try{let a=`${r.cloudUrl.replace(/\/+$/,"")}/api/units/${encodeURIComponent(n.unitId)}/caps`,l=await(this.d.hubFetch??fetch)(a,{method:"POST",headers:{Authorization:`Bearer ${r.token}`,"X-Unit-Secret":n.secret,"Content-Type":"application/json"},body:JSON.stringify({engine:e,tools:[]}),signal:o.signal});try{await l.text()}catch{}if(s!==this.gen)return;l.ok?(this.lastSent=e,this.d.log(`[unit-caps] \u5DF2\u4E0A\u62A5\u5F15\u64CE\u6001 ${e}`)):l.status===404||l.status===405?(this.disabled=!0,this.d.log(`[unit-caps] \u7F51\u5173\u4E0D\u6536 caps(HTTP ${l.status},\u8001\u7248\u672C),\u672C\u8FDE\u63A5\u5185\u4E0D\u518D\u4E0A\u62A5`)):l.status===400||l.status===401||l.status===403?this.warned.has(l.status)||(this.warned.add(l.status),this.d.log(`[unit-caps] \u4E0A\u62A5\u88AB\u62D2 HTTP ${l.status}`)):this.d.log(`[unit-caps] \u4E0A\u62A5\u5931\u8D25 HTTP ${l.status},\u7B49\u4E0B\u6B21\u53D8\u5316 / \u91CD\u8FDE\u518D\u62A5`)}catch(a){s===this.gen&&this.d.log(`[unit-caps] \u4E0A\u62A5\u5931\u8D25:${o.signal.aborted?"\u8D85\u65F6":a?.message||a}`)}finally{clearTimeout(i),this.inflight=!1,this.again&&this.up&&!this.disabled&&(this.again=!1,this.flush())}}};var Fi=["setUnitHubFactory"],ps=t=>Fi.every(e=>typeof t[e]=="function");function Ui(t){let e=new sn({getCreds:()=>t.getCreds(),getPairing:()=>t.getPairing(),current:()=>t.engineCaps(),log:r=>t.log(r)}),n=new rn({onChannelReady:()=>e.channelReady(),onChannelDown:()=>e.channelDown(),getCreds:()=>t.getCreds(),getUnitWeb:()=>t.getUnitWeb(),callerHeaders:r=>t.callerHeaders(r),getLanUrl:()=>t.getLanUrl(),getPairing:()=>t.getPairing(),savePairing:r=>t.savePairing(r),clearPairing:()=>t.clearPairing(),log:r=>t.log(r)});return{start:()=>n.start(),stop:()=>n.stop(),reconnect:r=>n.reconnect(r),status:()=>n.status(),engineChanged:()=>e.engineChanged()}}function hs(t){let e=async(n,r,s)=>{let{base:o,token:i}=await t.getCloud();if(!i)return{status:401,json:{detail:"\u672A\u767B\u5F55 Forsion \u8D26\u53F7"}};try{let a=await fetch(`${o}/api${r}`,{method:n,headers:{Authorization:`Bearer ${i}`,...s!==void 0?{"Content-Type":"application/json"}:{}},body:s!==void 0?JSON.stringify(s):void 0});return{status:a.status,json:await a.json().catch(()=>null)}}catch(a){return{status:0,json:{detail:String(a?.message||a)}}}};t.handle("units:list",()=>e("GET","/units")),t.handle("units:update",(n,r,s)=>e("PATCH",`/units/${encodeURIComponent(String(r))}`,{name:s?.name,icon:s?.icon})),t.handle("units:remove",(n,r)=>e("DELETE",`/units/${encodeURIComponent(String(r))}`)),t.handle("units:openInBrowser",async(n,r)=>{if(typeof r!="string"||!/^[0-9a-zA-Z-]{8,64}$/.test(r))throw new Error("\u53C2\u6570\u4E0D\u5B8C\u6574");let{base:s,token:o}=await t.getCloud();await t.openExternal(`${s}/api/units/${r}/open${o?`#token=${encodeURIComponent(o)}`:""}`)}),t.setUnitHubFactory(Ui),t.log("[forsion-extend] unit hub registered")}import{createHash as Wu}from"node:crypto";import{constants as Ji,mkdirSync as Vu,readFileSync as Ju,renameSync as Yu,writeFileSync as Gu}from"node:fs";import{lstat as lt,open as ia,readFile as Ku,readdir as aa,statfs as Xu}from"node:fs/promises";import{cpus as Zu,freemem as Qu,homedir as Yi,hostname as la,release as ed,totalmem as td}from"node:os";import{basename as ca,join as oe}from"node:path";var $u=/^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i,on=class t extends Date{#t=!1;#n=!1;#e=null;constructor(e){let n=!0,r=!0,s="Z";if(typeof e=="string"){let o=e.match($u);o?(o[1]||(n=!1,e=`0000-01-01T${e}`),r=!!o[2],r&&e[10]===" "&&(e=e.replace(" ","T")),o[2]&&+o[2]>23?e="":(s=o[3]||null,e=e.toUpperCase(),!s&&r&&(e+="Z"))):e=""}super(e),isNaN(this.getTime())||(this.#t=n,this.#n=r,this.#e=s)}isDateTime(){return this.#t&&this.#n}isLocal(){return!this.#t||!this.#n||!this.#e}isDate(){return this.#t&&!this.#n}isTime(){return this.#n&&!this.#t}isValid(){return this.#t||this.#n}toISOString(){let e=super.toISOString();if(this.isDate())return e.slice(0,10);if(this.isTime())return e.slice(11,23);if(this.#e===null)return e.slice(0,-1);if(this.#e==="Z")return e;let n=+this.#e.slice(1,3)*60+ +this.#e.slice(4,6);return n=this.#e[0]==="-"?n:-n,new Date(this.getTime()-n*6e4).toISOString().slice(0,-1)+this.#e}static wrapAsOffsetDateTime(e,n="Z"){let r=new t(e);return r.#e=n,r}static wrapAsLocalDateTime(e){let n=new t(e);return n.#e=null,n}static wrapAsLocalDate(e){let n=new t(e);return n.#n=!1,n.#e=null,n}static wrapAsLocalTime(e){let n=new t(e);return n.#t=!1,n.#e=null,n}};function Ou(t,e){let n=t.slice(0,e).split(/\r\n|\n|\r/g);return[n.length,n.pop().length+1]}function Mu(t,e,n){let r=t.split(/\r\n|\n|\r/g),s="",o=(Math.log10(e+1)|0)+1;for(let i=e-1;i<=e+1;i++){let a=r[i-1];a&&(s+=i.toString().padEnd(o," "),s+=": ",s+=a,s+=`
|
|
217
217
|
`,i===e&&(s+=" ".repeat(o+n+2),s+=`^
|
|
218
|
-
`))}return s}var
|
|
218
|
+
`))}return s}var re=class extends Error{line;column;codeblock;constructor(e,n){let[r,s]=Ou(n.toml,n.ptr),o=Mu(n.toml,r,s);super(`Invalid TOML document: ${e}
|
|
219
219
|
|
|
220
|
-
${o}`,n),this.line=r,this.column=s,this.codeblock=o}};var
|
|
220
|
+
${o}`,n),this.line=r,this.column=s,this.codeblock=o}};var Nu=/^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/,ju=/^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/,Fu=/^[+-]?0[0-9_]/;function Xn(t,e){let n=t[e++],r=n,s=n==="'",o=n===t[e]&&n===t[e+1];o&&(t[e+=2]===`
|
|
221
221
|
`?e++:t[e]==="\r"&&t[e+1]===`
|
|
222
222
|
`&&(e+=2));let i="",a=e,l=0;for(let c=e;c<t.length;c++)if(n=t[c],o&&(n===`
|
|
223
223
|
`||n==="\r"&&t[c+1]===`
|
|
224
|
-
`))l=l&&3;else{if(n<" "&&n!==" "||n==="\x7F")throw new
|
|
225
|
-
`;else if(n==="f")i+="\f";else if(n==="r")i+="\r";else if(n==="e")i+="\x1B";else if(n==='"')i+='"';else if(n==="\\")i+="\\";else throw new
|
|
226
|
-
`,e);return t[r-1]==="\r"&&r--,r<=n?r:-1}function
|
|
224
|
+
`))l=l&&3;else{if(n<" "&&n!==" "||n==="\x7F")throw new re("control characters are not allowed in strings",{toml:t,ptr:c});if((!l||l===3)&&n===r&&(!o||t[c+1]===r&&t[c+2]===r))return o&&(t[c+3]===r&&c++,t[c+3]===r&&c++),[l?i:i+t.slice(a,c),c+(o?3:1)];if(!l)!s&&n==="\\"&&(i+=t.slice(a,a=c),l=1);else if(l===1)if(n==="x"||n==="u"||n==="U"){let u=0,f=n==="x"?2:n==="u"?4:8;for(let p=0;p<f;p++,c++){let h=t.charCodeAt(c+1),g=h>=48&&h<=57?h-48:h>=65&&h<=70?h-65+10:h>=97&&h<=102?h-97+10:-1;if(g<0)throw new re("invalid non-hex character in unicode escape",{toml:t,ptr:c+1});u=u<<4|g}if(u<0||u>1114111||u>=55296&&u<=57343)throw new re("invalid unicode escape",{toml:t,ptr:c});i+=String.fromCodePoint(u),a=c+1,l=0}else if(n===" "||n===" ")l=2;else{if(n==="b")i+="\b";else if(n==="t")i+=" ";else if(n==="n")i+=`
|
|
225
|
+
`;else if(n==="f")i+="\f";else if(n==="r")i+="\r";else if(n==="e")i+="\x1B";else if(n==='"')i+='"';else if(n==="\\")i+="\\";else throw new re("unrecognized escape sequence",{toml:t,ptr:c});a=c+1,l=0}else if(n!==" "&&n!==" "){if(l===2)throw new re("invalid escape: only line-ending whitespace may be escaped",{toml:t,ptr:a});l=!s&&n==="\\"?1:0,a=c}}throw new re("unfinished string",{toml:t,ptr:e})}function Li(t,e,n,r){if(t==="true")return!0;if(t==="false")return!1;if(t==="-inf")return-1/0;if(t==="inf"||t==="+inf")return 1/0;if(t==="nan"||t==="+nan"||t==="-nan")return NaN;if(t==="-0")return r?0n:0;let s=Nu.test(t);if(s||ju.test(t)){if(Fu.test(t))throw new re("leading zeroes are not allowed",{toml:e,ptr:n});t=t.replace(/_/g,"");let i=+t;if(isNaN(i))throw new re("invalid number",{toml:e,ptr:n});if(s){if((s=!Number.isSafeInteger(i))&&!r)throw new re("integer value cannot be represented losslessly",{toml:e,ptr:n});(s||r===!0)&&(i=BigInt(t))}return i}let o=new on(t);if(!o.isValid())throw new re("invalid value",{toml:e,ptr:n});return o}function Zn(t,e=0,n=t.length){let r=t.indexOf(`
|
|
226
|
+
`,e);return t[r-1]==="\r"&&r--,r<=n?r:-1}function Nt(t,e){for(let n=e;n<t.length;n++){let r=t[n];if(r===`
|
|
227
227
|
`)return n;if(r==="\r"&&t[n+1]===`
|
|
228
|
-
`)return n+1;if(r<" "&&r!==" "||r==="\x7F")throw new
|
|
228
|
+
`)return n+1;if(r<" "&&r!==" "||r==="\x7F")throw new re("control characters are not allowed in comments",{toml:t,ptr:e})}return t.length}function Ke(t,e,n,r){let s;for(;;){for(;(s=t[e])===" "||s===" "||!n&&(s===`
|
|
229
229
|
`||s==="\r"&&t[e+1]===`
|
|
230
|
-
`);)e++;if(r||s!=="#")break;e=
|
|
230
|
+
`);)e++;if(r||s!=="#")break;e=Nt(t,e)}return e}function zi(t,e,n,r,s=!1){if(!r)return e=Zn(t,e),e<0?t.length:e;for(let o=e;o<t.length;o++){let i=t[o];if(i==="#")o=Zn(t,o);else{if(i===n)return o+1;if(i===r||s&&(i===`
|
|
231
231
|
`||i==="\r"&&t[o+1]===`
|
|
232
|
-
`))return o}}throw new
|
|
233
|
-
`&&t[c]!=="\r")throw new
|
|
234
|
-
`&&i!=="\r"){let a,l=s,c=!1,[u,f]=
|
|
235
|
-
`&&o!=="\r"){let i=
|
|
236
|
-
`&&t[a]!=="\r")throw new
|
|
237
|
-
`)}catch{return`[unparsed:${t.length}]`}}var
|
|
238
|
-
`)+1):i}finally{await n.close()}}function
|
|
239
|
-
`).filter(
|
|
240
|
-
`)})}}catch(
|
|
232
|
+
`))return o}}throw new re("cannot find end of structure",{toml:t,ptr:e})}function Uu(t,e,n){let r=t.slice(e,n),s=r.indexOf("#");return s>-1&&(Nt(t,s),r=r.slice(0,s)),[r.trimEnd(),s]}function an(t,e,n,r,s){if(r===0)throw new re("document contains excessively nested structures. aborting.",{toml:t,ptr:e});let o=t[e];if(o==="["||o==="{"){let[l,c]=o==="["?Bi(t,e,r,s):Hi(t,e,r,s);if(n){if(c=Ke(t,c),t[c]===",")c++;else if(t[c]!==n)throw new re("expected comma or end of structure",{toml:t,ptr:c})}return[l,c]}if(o==='"'||o==="'"){let[l,c]=Xn(t,e);if(n){if(c=Ke(t,c),t[c]&&t[c]!==","&&t[c]!==n&&t[c]!==`
|
|
233
|
+
`&&t[c]!=="\r")throw new re("unexpected character encountered",{toml:t,ptr:c});t[c]===","&&c++}return[l,c]}let i=zi(t,e,",",n),a=Uu(t,e,i-(t[i-1]===","?1:0));if(!a[0])throw new re("incomplete key-value declaration: no value specified",{toml:t,ptr:e});return n&&a[1]>-1&&(i=Ke(t,e+a[1]),t[i]===","&&i++),[Li(a[0],t,e,s),i]}var Lu=/^[a-zA-Z0-9-_]+[ \t]*$/;function Qn(t,e,n="="){let r=e-1,s=[],o=t.indexOf(n,e);if(o<0)throw new re("incomplete key-value: cannot find end of key",{toml:t,ptr:e});do{let i=t[e=++r];if(i!==" "&&i!==" ")if(i==='"'||i==="'"){if(i===t[e+1]&&i===t[e+2])throw new re("multiline strings are not allowed in keys",{toml:t,ptr:e});let[a,l]=Xn(t,e);r=t.indexOf(".",l);let c=t.slice(l,r<0||r>o?o:r),u=Zn(c);if(u>-1)throw new re("newlines are not allowed in keys",{toml:t,ptr:e+r+u});if(c.trimStart())throw new re("found extra tokens after the string part",{toml:t,ptr:l});if(o<l&&(o=t.indexOf(n,l),o<0))throw new re("incomplete key-value: cannot find end of key",{toml:t,ptr:e});s.push(a)}else{r=t.indexOf(".",e);let a=t.slice(e,r<0||r>o?o:r);if(!Lu.test(a))throw new re("only letter, numbers, dashes and underscores are allowed in keys",{toml:t,ptr:e});s.push(a.trimEnd())}}while(r+1&&r<o);return[s,Ke(t,o+1,!0,!0)]}function Hi(t,e,n,r){let s={},o=new Set,i;for(e++;(i=t[e++])!=="}"&&i;){if(i===",")throw new re("expected value, found comma",{toml:t,ptr:e-1});if(i==="#")e=Nt(t,e);else if(i!==" "&&i!==" "&&i!==`
|
|
234
|
+
`&&i!=="\r"){let a,l=s,c=!1,[u,f]=Qn(t,e-1);for(let g=0;g<u.length;g++){if(g&&(l=c?l[a]:l[a]={}),a=u[g],(c=Object.hasOwn(l,a))&&(typeof l[a]!="object"||o.has(l[a])))throw new re("trying to redefine an already defined value",{toml:t,ptr:e});!c&&a==="__proto__"&&Object.defineProperty(l,a,{enumerable:!0,configurable:!0,writable:!0})}if(c)throw new re("trying to redefine an already defined value",{toml:t,ptr:e});let[p,h]=an(t,f,"}",n-1,r);o.add(p),l[a]=p,e=h}}if(!i)throw new re("unfinished table encountered",{toml:t,ptr:e});return[s,e]}function Bi(t,e,n,r){let s=[],o;for(e++;(o=t[e++])!=="]"&&o;){if(o===",")throw new re("expected value, found comma",{toml:t,ptr:e-1});if(o==="#")e=Nt(t,e);else if(o!==" "&&o!==" "&&o!==`
|
|
235
|
+
`&&o!=="\r"){let i=an(t,e-1,"]",n-1,r);s.push(i[0]),e=i[1]}}if(!o)throw new re("unfinished array encountered",{toml:t,ptr:e});return[s,e]}function qi(t,e,n,r){let s=e,o=n,i,a=!1,l;for(let c=0;c<t.length;c++){if(c){if(s=a?s[i]:s[i]={},o=(l=o[i]).c,r===0&&(l.t===1||l.t===2))return null;if(l.t===2){let u=s.length-1;s=s[u],o=o[u].c}}if(i=t[c],(a=Object.hasOwn(s,i))&&o[i]?.t===0&&o[i]?.d)return null;a||(i==="__proto__"&&(Object.defineProperty(s,i,{enumerable:!0,configurable:!0,writable:!0}),Object.defineProperty(o,i,{enumerable:!0,configurable:!0,writable:!0})),o[i]={t:c<t.length-1&&r===2?3:r,d:!1,i:0,c:{}})}if(l=o[i],l.t!==r&&!(r===1&&l.t===3)||(r===2&&(l.d||(l.d=!0,s[i]=[]),s[i].push(s={}),l.c[l.i++]=l={t:1,d:!1,i:0,c:{}}),l.d))return null;if(l.d=!0,r===1)s=a?s[i]:s[i]={};else if(r===0&&a)return null;return[i,s,l.c]}function er(t,{maxDepth:e=1e3,integersAsBigInt:n}={}){let r={},s={},o=r,i=s;for(let a=Ke(t,0);a<t.length;){if(t[a]==="["){let l=t[++a]==="[",c=Qn(t,a+=+l,"]");if(l){if(t[c[1]-1]!=="]")throw new re("expected end of table declaration",{toml:t,ptr:c[1]-1});c[1]++}let u=qi(c[0],r,s,l?2:1);if(!u)throw new re("trying to redefine an already defined table or value",{toml:t,ptr:a});i=u[2],o=u[1],a=c[1]}else{let l=Qn(t,a),c=qi(l[0],o,i,0);if(!c)throw new re("trying to redefine an already defined table or value",{toml:t,ptr:a});let u=an(t,l[1],void 0,e,n);c[1][c[0]]=u[0],a=u[1]}if(a=Ke(t,a,!0),t[a]&&t[a]!==`
|
|
236
|
+
`&&t[a]!=="\r")throw new re("each key-value declaration must be followed by an end-of-line",{toml:t,ptr:a});a=Ke(t,a)}return r}var nr=14,zu=1440*6e4,Hu=12e4,Bu=15e3,ms=1792*1024,qu=7,it=t=>t.toISOString().slice(0,10),Xe=t=>Date.parse(it(t))-(qu-1)*zu,Wi=["sessions","activity"],tr=t=>typeof t=="number"&&Number.isFinite(t)?t:void 0;function gs(t,e,n){let r=t?.day===it(n)?t:void 0;return Object.fromEntries(Wi.map(s=>[s,tr(r?.[s])??Math.min(Math.max(tr(e[s])??0,Xe(n)),n.getTime())]))}function ys(t,e,n,r,s,o){let i=e?.day===it(r)?e:void 0,a={sent:{...t},file:{day:it(r)}};for(let l of Wi){let c=l in s&&!o.includes(l)&&!(`${l}Error`in s),u=tr(i?.[l]);c?(a.file[l]=n[l],a.sent[l]=r.getTime()):u!==void 0&&(a.sent[l]=Math.min(tr(t[l])??u,u))}return a}function Vi(t,e=[]){let n={...t},r=Bt(JSON.stringify(n));for(let s of["activity","sessions","memory","runs","engine"]){if(r.length<=ms)break;s in n&&(delete n[s],e.push(s),r=Bt(JSON.stringify({...n,truncated:e})))}return r.length>ms?null:r}async function ws(t,e,n,r=new Date){let s=AbortSignal.timeout(Hu);await t.writeFile(`${e}/${it(r)}.json`,n,r.getTime(),s);try{let o=it(new Date(r.getTime()-nr*24*60*6e4));for(let i of await t.walk(s)){let a=/^([^/]+)\/(\d{4}-\d{2}-\d{2})\.json$/.exec(i.key);a&&a[1]===e&&a[2]<o&&await t.rm(i.key,s)}}catch{}}var bs={mode:"scheduled",intervalHours:24,requestedAt:0};function ln(t){let e=t&&typeof t=="object"?t:{},n=Number(e.intervalHours),r=Number(e.requestedAt);return{mode:e.mode==="manual"?"manual":"scheduled",intervalHours:Number.isInteger(n)&&n>=1&&n<=720?n:bs.intervalHours,requestedAt:Number.isFinite(r)&&r>0?r:0}}async function Ss(t){try{let e=await fetch(`${t.cloudUrl.replace(/\/+$/,"")}/api/remotesync/diagnostics/policy`,{headers:{Authorization:`Bearer ${t.token}`},signal:AbortSignal.timeout(Bu)});return e.status===404?{...bs}:e.ok?ln(await e.json()):null}catch{return null}}var nd=(t,e=[])=>{let n=Vi(t,e);return n&&Buffer.from(n.buffer,n.byteOffset,n.byteLength)},ua=60*6e4,rd=2*6e4,sd=10*6e4,Gi=ua,od=4*1024*1024,id=256*1024,Ki=["user","teamwork","discussion","delegate"],ad=/^(?:New remarks in the team chat:|You are activated now \()/,da={totalBytes:1024*1024,sessionBytes:256*1024,textChars:8e3,sessions:300,messages:400},ld=t=>t.replace(/\b[a-z][a-z0-9+.-]*:\/\/[^\s"'`<>]+|(?:~|\b[A-Za-z]:|\\)?(?:[\\/][^\s"'`<>:*?|\\/()[\]{},;]+){2,}[\\/]?/gi,e=>/^(?:[a-z][a-z0-9+.-]*:\/\/|\/(?:v\d+|api)\/)/i.test(e)?e:"[path]"),dn=4e3,rr=(t,e)=>typeof t=="string"&&t?at(ld(wt(t.slice(0,dn))),e):void 0,cd={runs:200,totalBytes:128*1024,errorChars:300,events:2e3,tools:40},ud=64*1024,vs=500,dd={totalBytes:256*1024,fileChars:24e3,logChars:12e3,activity:300,detailChars:300},fd=256*1024,Xi=["SOUL.md","MEMORY.md",".memory-raw.md","HARNESS.md",".harness-raw.md",".harness-refinements.jsonl","HUMAN.md"],pd=["description","developer_instructions"],hd=["memory","harness","project_memory","human","dream","log_appended"],md=["homeDir","readCreds","accountId","appVersion"],ks=t=>md.every(e=>typeof t[e]=="function"),Zi=Yi().length>3?Yi():null;function wt(t){return typeof t=="string"?(Zi?t.split(Zi).join("~"):t).replace(/\bBearer\s+[A-Za-z0-9._~+\/-]+=*/gi,"Bearer [redacted]").replace(/\b(sk-[a-zA-Z0-9_-]{12,})\b/g,"[redacted]").replace(/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}/g,"[redacted]").replace(/\b(?:gh[pousr]_[A-Za-z0-9]{20,}|github_pat_[A-Za-z0-9_]{20,}|AKIA[0-9A-Z]{16}|LTAI[0-9A-Za-z]{12,}|xox[abeprs]-[A-Za-z0-9-]{10,}|AIza[0-9A-Za-z_-]{30,})/g,"[redacted]").replace(/-{5}BEGIN [A-Z ]*PRIVATE KEY-{5}[\s\S]*?(?:-{5}END [A-Z ]*PRIVATE KEY-{5}|$)/g,"[redacted]").replace(/\b[a-fA-F0-9]{32,}\b/g,(e,n,r)=>/^[a-f0-9]{48}$/.test(e)&&/(?:^|[^\w-])pr-$/.test(r.slice(Math.max(0,n-4),n))?e:`[hex:${e.length}]`).replace(/((?:["']?)(?:api[_-]?key|access[_-]?token|refresh[_-]?token|token|password|secret|authorization|cookie)(?:["']?)\s*[:=]\s*)("[^"\n]*"|'[^'\n]*'|\[[^\]\n]*\]|[^\s,"';&}]+)/gi,"$1[redacted]"):Array.isArray(t)?t.map(wt):t&&typeof t=="object"?Object.fromEntries(Object.entries(t).map(([e,n])=>[e,/^(?:token|.*api[_-]?key|access[_-]?token|refresh[_-]?token|password|secret|authorization|cookie|set-cookie)$/i.test(e)?"[redacted]":wt(n)])):t}var gd=/^(?:model|modelId|voice|mode|backend|notify|escalateTo|realtimeModel|realtimeVoice|vision|background)$/,se=(t,e=120)=>typeof t=="string"&&t.length<=e?t:void 0,yd=(t,e)=>/^[A-Za-z_][\w.-]{0,63}$/.test(t)?t:`[key:${e}]`;function jt(t,e=0){if(typeof t=="boolean"||typeof t=="number"||t===null||t===void 0)return t??null;if(typeof t=="string")return`[string:${t.length}]`;if(Array.isArray(t))return`[array:${t.length}]`;if(typeof t!="object"||e>=4)return"[object]";let n={};for(let[r,[s,o]]of Object.entries(t).slice(0,100).entries())n[yd(s,r)]=gd.test(s)&&se(o,80)!==void 0?o:jt(o,e+1);return n}var wd={"":/^(?:name|version|description|model|model_reasoning_effort|approval_mode|max_iterations|tools|enabled_skill_ids|enabled_mcp_servers|library_order|apps|avatar|share_default_memory|cloud_sync|activity_access|tools_strict|tools_mode|tools_list|created_by|created_at|developer_instructions|compaction|lead|slug|members|mode|max_rounds)$/,compaction:/^(?:enabled|reserveTokens|thresholdPercent|keepRecentTokens|summaryMaxTokens|thinking|model|instructions|prompt)$/,members:/^(?:slug|role)$/},Qi={"":/^(?:name|version|model|model_reasoning_effort|approval_mode|created_by|created_at|avatar|lead|slug)$/,compaction:/^model$/,members:/^slug$/},bd=/^(?:apps|enabled_skill_ids)$/,ea=t=>!!t&&typeof t=="object"&&!Array.isArray(t)&&!(t instanceof Date);function Sd(t){try{let e=er(t),n=[],r=[],s=8192,o=(l,c)=>s<=0?!1:(s-=c.length+1,l.push(c),!0),i=(l,c,u)=>{let f=wd[l].test(c)?c:`[key:${c.length}]`,p=Qi[l].test(c),h;return typeof u=="boolean"||typeof u=="number"?h=String(u):p&&typeof u=="string"&&!/[\r\n]/.test(u)&&JSON.stringify(u).length<=120?h=JSON.stringify(u):p&&u instanceof Date?h=u.toISOString():l===""&&bd.test(c)&&Array.isArray(u)&&u.every(g=>typeof g=="string"&&!/[\r\n]/.test(g))&&JSON.stringify(u).length<=2e3&&(h=`[${u.map(g=>JSON.stringify(g)).join(", ")}]`),`${f} = ${h??`"[text:${typeof u=="string"?u.length:JSON.stringify(u).length}]"`}`},a=(l,c,u)=>{if(o(r,c)){for(let[f,p]of Object.entries(u))if(!o(r,i(l,f,p)))return}};for(let[l,c]of Object.entries(e)){let u=l!==""&&Object.hasOwn(Qi,l);if(u&&ea(c))a(l,`[${l}]`,c);else if(u&&Array.isArray(c)&&c.length>0&&c.every(ea))for(let f of c)a(l,`[[${l}]]`,f);else o(n,i("",l,c));if(s<=0)break}return[...n,...r].join(`
|
|
237
|
+
`)}catch{return`[unparsed:${t.length}]`}}var fa=async t=>{try{return(await lt(t)).isFile()?await Ku(t,"utf8"):null}catch{return null}},un=t=>lt(t).then(e=>e.isDirectory(),()=>!1),Ft=async t=>{try{return JSON.parse(await fa(t)??"null")}catch{return null}},Ze=async(t,e=200)=>{try{return(await aa(t)).filter(n=>!n.startsWith(".")&&n.length<=120).sort().slice(0,e)}catch{return[]}};async function vd(t,e){if(!(await lt(t)).isFile())return"";let n=await ia(t,"r");try{let{size:r}=await n.stat(),s=Math.max(0,r-e),o=Buffer.alloc(r-s);await n.read(o,0,o.length,s);let i=o.toString("utf8");return s>0?i.slice(i.indexOf(`
|
|
238
|
+
`)+1):i}finally{await n.close()}}function kd(t){if(!t||typeof t!="object")return{};let e=n=>n&&typeof n=="object"?Object.entries(n).slice(0,100):[];return{defaultModel:se(t.cloud?.defaultModel)??null,models:jt(t.models),tts:jt(t.tts),asr:jt(t.asr),specialAgents:jt(t.specialAgents),pluginSettings:jt(t.plugins?.global),providers:(Array.isArray(t.providers)?t.providers:[]).slice(0,50).map(n=>({providerId:se(n?.providerId)??null,models:(Array.isArray(n?.modelIds)?n.modelIds:[]).filter(r=>se(r)!==void 0).slice(0,100)})),mcpServers:e(t.mcp?.mcpServers).map(([n,r])=>({name:se(n,64)??"[name]",enabled:r?.enabled!==!1})),channels:e(t.channels).map(([n,r])=>({name:se(n,64)??"[name]",enabled:r?.enabled===!0}))}}var Ed=new Set(["config.toml","SOUL.md","MEMORY.md","HARNESS.md","HUMAN.md","Library","LOG","skills","plugins","Space","SCHEDULE.db","triggers.json"]);async function ta(t){let e=[];for(let n of await Ze(t,100)){let r=oe(t,n);if(!await un(r))continue;let s=await fa(oe(r,"config.toml"));e.push({id:n,config:s===null?null:Sd(s).slice(0,4096),files:(await Ze(r,400)).filter(o=>Ed.has(o))})}return e}async function na(t){let e=[];for(let n of await Ze(t,300)){let r=await Ft(oe(t,n,"manifest.json"));r&&e.push({id:se(r.id)??n,version:se(r.version,40)??null,name:se(r.nameEn)??se(r.name)??null})}return e}var Ct=t=>String(t?.code||t?.message||t).slice(0,120);async function _d(t,e,n,r=id){let s=p=>String(p).padStart(2,"0"),o=p=>{let h=new Date(p);return`${h.getFullYear()}${s(h.getMonth()+1)}${s(h.getDate())}${s(h.getHours())}${s(h.getMinutes())}`},i=p=>`${p.slice(0,4)}-${p.slice(4,6)}-${p.slice(6,8)}.log`,a=o(n),l=o(e.getTime()),c=[],u=r,f=!1;try{let p=(await aa(t)).filter(h=>/^\d{4}-\d{2}-\d{2}\.log$/.test(h)&&h>=i(a)&&h<=i(l)).sort().reverse();for(let h of p){if(f)break;let m=(await vd(oe(t,h),od).catch(k=>{if(k?.code==="ENOENT")return"";throw k})).split(`
|
|
239
|
+
`).filter(k=>/^\d{12} /.test(k)&&k.slice(0,12)>=a&&k.slice(0,12)<l),w=m.length;for(;w>0&&Buffer.byteLength(m[w-1])+1<=u;)u-=Buffer.byteLength(m[--w])+1;w>0&&(f=!0),w<m.length&&c.push({date:h.slice(0,10),log:m.slice(w).join(`
|
|
240
|
+
`)})}}catch(p){return p?.code==="ENOENT"?{activity:[]}:{activity:[],activityError:Ct(p)}}return{activity:c.reverse(),...f?{activityTruncated:!0}:{}}}var at=(t,e)=>{if(!(typeof t!="string"||!t))return t.length>e?`${t.slice(0,e)}\u2026[+${t.length-e}]`:t},ra=t=>{try{let e=typeof t=="string"?JSON.parse(t):t;return Array.isArray(e)?e:[]}catch{return[]}},Ut=t=>new Date(t).toISOString().slice(0,19).replace("T"," ");async function Cd(t,e,n=da,r=Xe(e)){let s=oe(t,"tangu","state.db"),o=await lt(s).then(a=>a.isFile(),a=>a?.code==="ENOENT"?!1:Ct(a));if(o!==!0)return o===!1?{sessions:[]}:{sessions:[],sessionsError:o};let i;try{let{DatabaseSync:a}=await import("node:sqlite");i=new a(s,{readOnly:!0}),i.exec("PRAGMA busy_timeout = 1500");let c="m.updated_at >= ? AND m.updated_at < ? AND m.timestamp >= ?",u=[Ut(r),Ut(e.getTime()),Xe(e)],f=i.prepare(`SELECT s.id, s.kind, s.parent_session_id, s.app_id, s.title, s.model_id, s.project_name, s.archived, s.created_at, s.updated_at, MAX(m.updated_at) AS changed_at
|
|
241
241
|
FROM chat_messages m JOIN chat_sessions s ON s.id = m.session_id
|
|
242
|
-
WHERE s.kind IN (${
|
|
243
|
-
FROM chat_messages m WHERE m.session_id = ? AND ${c} ORDER BY m.timestamp DESC, m.created_at DESC LIMIT ?`),h=[],g=0,
|
|
242
|
+
WHERE s.kind IN (${Ki.map(()=>"?").join(", ")}) AND ${c} GROUP BY s.id ORDER BY changed_at DESC, s.id LIMIT ?`).all(...Ki,...u,n.sessions+1),p=i.prepare(`SELECT m.role, m.content, m.reasoning, m.timestamp, m.model_id, m.is_error, m.tool_calls, length(m.tool_results) AS tool_result_chars, m.attachments, m.agent_slug
|
|
243
|
+
FROM chat_messages m WHERE m.session_id = ? AND ${c} ORDER BY m.timestamp DESC, m.created_at DESC LIMIT ?`),h=[],g=0,m=f.length>n.sessions;for(let w of f.slice(0,n.sessions)){let k=p.all(w.id,...u,n.messages+1),P=k.length>n.messages,O=[],A=0;for(let C of k.slice(0,n.messages)){let E=ra(C.tool_calls),T=w.kind==="teamwork"&&C.role==="user"&&ad.test(String(C.content??"")),L={role:se(C.role,16)??null,at:Number(C.timestamp)||null,agent:se(C.agent_slug,64),model:se(C.model_id,128),error:C.is_error?!0:void 0,text:T?void 0:at(C.content,n.textChars),relayChars:T?String(C.content??"").length:void 0,reasoning:at(C.reasoning,n.textChars),tools:E.length?E.map(ee=>se(ee?.function?.name??ee?.name,80)??"?"):void 0,toolArgChars:E.length?E.reduce((ee,te)=>ee+String(te?.function?.arguments??"").length,0):void 0,toolResultChars:Number(C.tool_result_chars)||void 0,attachments:ra(C.attachments).length||void 0},X=Buffer.byteLength(JSON.stringify(L));if(A+X>n.sessionBytes){P=!0;break}A+=X,O.push(L)}let $={id:se(w.id,64)??null,kind:se(w.kind,16)??null,parent:se(w.parent_session_id,64),app:se(w.app_id,50)??null,title:at(w.title,200)??null,model:se(w.model_id,128)??null,project:at(w.project_name,120),archived:w.archived?!0:void 0,createdAt:se(w.created_at,40)??null,updatedAt:se(w.updated_at,40)??null,messages:O.reverse(),...P?{olderMessagesDropped:!0}:{}},b=Buffer.byteLength(JSON.stringify($));if(g+b>n.totalBytes){m=!0;break}g+=b,h.push($)}return{sessions:h,...m?{sessionsTruncated:!0}:{}}}catch(a){return{sessions:[],sessionsError:Ct(a)}}finally{try{i?.close()}catch{}}}async function xd(t,e,n=cd){let r=oe(t,"tangu","state.db"),s=await lt(r).then(i=>i.isFile(),i=>i?.code==="ENOENT"?!1:Ct(i));if(s!==!0)return s===!1?{runs:[]}:{runs:[],runsError:s};let o;try{let{DatabaseSync:i}=await import("node:sqlite");o=new i(r,{readOnly:!0}),o.exec("PRAGMA busy_timeout = 1500");let l=o.prepare(`SELECT r.id, r.session_id, r.app_id, r.status, r.current_step, r.model_id, substr(r.error, 1, ${dn}) AS error, r.tokens_total, r.created_at, r.updated_at, s.kind
|
|
244
244
|
FROM agent_runs r LEFT JOIN chat_sessions s ON s.id = r.session_id
|
|
245
|
-
WHERE r.updated_at >= ? AND r.updated_at < ? ORDER BY r.updated_at DESC, r.id LIMIT ?`).all(
|
|
245
|
+
WHERE r.updated_at >= ? AND r.updated_at < ? ORDER BY r.updated_at DESC, r.id LIMIT ?`).all(Ut(Xe(e)),Ut(e.getTime()),n.runs+1),c=o.prepare(`SELECT e.type, json_extract(e.payload, '$.name') AS name, json_extract(e.payload, '$.isError') AS failed, json_extract(e.payload, '$.elapsedMs') AS ms,
|
|
246
246
|
json_extract(e.payload, '$.prompt') AS prompt, json_extract(e.payload, '$.completion') AS completion, json_extract(e.payload, '$.cached') AS cached,
|
|
247
247
|
json_extract(e.payload, '$.reasoningTokens') AS reasoning, json_extract(e.payload, '$.llmMs') AS llm_ms, json_extract(e.payload, '$.ttftMs') AS ttft_ms,
|
|
248
|
-
json_extract(e.payload, '$.requestBytes') AS request_bytes, json_extract(e.payload, '$.phase') AS phase, substr(json_extract(e.payload, '$.error'), 1, ${
|
|
249
|
-
FROM agent_run_events e WHERE e.run_id = ? AND e.type IN ('usage', 'tool_result', 'error', 'status') AND json_valid(e.payload) ORDER BY e.seq LIMIT ?`),u=
|
|
250
|
-
`),...o?{logTruncated:!0}:{}}}function
|
|
251
|
-
WHERE created_at >= ? AND created_at < ? AND (${
|
|
252
|
-
ORDER BY created_at DESC, rowid DESC LIMIT ?`).all(Dt(qe(e)),Dt(e.getTime()),n.activity+1);y.length>n.activity&&(i.truncated=!0);for(let _ of y.slice(0,n.activity))if(!l(i.activity,{at:ee(_.created_at,40)??null,agent:ee(_.agent,64)??null,action:ee(_.action,64)??null,detail:typeof _.detail=="string"&&_.detail?Qe(ct(_.detail),n.detailChars):void 0,session:ee(_.session_ref,64)}))break}catch(g){i.activityError=gt(g)}finally{try{h?.close()}catch{}}}for(let h of await Be(ne(r,"project-memory"),100)){let g=ne(r,"project-memory",h);if(!await rn(g))continue;let p=await nn(ne(g,"MEMORY.md"),n.fileChars),y=await xi(g);if(!p&&!y)continue;let _=(await Rt(ne(g,"PROJECT.json")))?.project;if(!l(i.projects,{id:ee(h,64)??null,name:typeof _=="string"?ee(Pi(_.replace(/[\\/]+$/,"").replace(/\\/g,"/"))):void 0,state:y,memory:p}))break}for(let h of await Be(ne(r,"teams"),100)){if(!await rn(ne(r,"teams",h)))continue;let g=await nn(ne(r,"teams",h,"TEAM.md"),n.fileChars);if(g&&!l(i.teams,{id:h,files:{"TEAM.md":g}}))break}let m=[];for(let h of await Be(ne(r,"agents"),100)){let g=ne(r,"agents",h);await rn(g)&&m.push({id:h,dir:g,at:Math.max(0,...await Promise.all([...wi,".memory-state.json"].map(p=>s(ne(g,p)))))})}for(let{id:h,dir:g,at:p}of m.sort((y,_)=>_.at-y.at||y.id.localeCompare(_.id))){let y={};for(let H of wi){let w=await nn(ne(g,H),n.fileChars);w&&(y[H]=w)}let _=[];if(await rn(ne(g,"LOG")))for(let H of(await Be(ne(g,"LOG"),400)).filter(w=>/^\d{4}-\d{2}-\d{2}\.md$/.test(w)&&w.slice(0,10)>=o&&w.slice(0,10)<=Ze(e))){let w=await nn(ne(g,"LOG",H),n.logChars);w&&_.push({date:H.slice(0,10),text:w})}let O=(await Rt(ne(g,".memory-dream.json")))?.last,C=await xi(g),M=await xu(g,n.fileChars);!Object.keys(y).length&&!_.length&&!C&&!M||l(i.agents,{id:h,updatedAt:p?new Date(p).toISOString():null,config:M,state:C,dream:O&&typeof O=="object"?{state:ee(O.state,32),startedAt:ee(O.startedAt,40),finishedAt:ee(O.finishedAt,40),calls:typeof O.calls=="number"?O.calls:void 0,detail:typeof O.detail=="string"?Qe(ct(O.detail),n.detailChars):void 0}:void 0,files:Object.keys(y).length?y:void 0,log:_.length?_:void 0})}return i}async function Ni(t){let e=(await Rt(ne(t,"tangu","device.json")))?.deviceId;return typeof e=="string"&&/^[A-Za-z0-9_-]{1,64}$/.test(e)?e:`h${zc("sha256").update(Ii()).digest("hex").slice(0,8)}`}async function Au(t){let{home:e}=t,n=ne(e,"tangu"),r=t.now??new Date,s=i=>t.since?.[i]??qe(r),o=_u(t.engineLogs);return ct({schema:3,collectedAt:r.toISOString(),app:{version:t.appVersion,platform:process.platform,arch:process.arch,os:Xc(),electron:process.versions.electron??null,node:process.versions.node,locale:Intl.DateTimeFormat().resolvedOptions().locale,timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,home:Pi(e),cloudUrl:t.cloudUrl},device:{id:await Ni(e),name:Ii()},system:await Eu(e),config:wu(await Rt(ne(e,"config.json"))),agents:await ki(ne(n,"agents")),teams:await ki(ne(n,"teams")),plugins:{desktop:await Ei(ne(e,"plugins")),engine:await Ei(ne(n,"plugins"))},inventory:{skills:await Be(ne(n,"skills")),spaces:await Be(ne(e,"spaces")),themes:await Be(ne(e,"themes"))},...t.activity?{...await Su(ne(e,"activity"),r,s("activity")),activitySince:new Date(s("activity")).toISOString()}:{},...t.sessions?{...await vu(e,r,Di,s("sessions")),sessionsSince:new Date(s("sessions")).toISOString()}:{},...(typeof t.memory=="function"?t.memory():t.memory)===!0?{memory:await Tu(e,r)}:{},...await ku(e,r),runsSince:new Date(qe(r)).toISOString(),...o?{engine:o}:{}})}function ji(t,e={}){let n=e.now??(()=>new Date),r=e.remoteFor??(C=>An({baseUrl:C.cloudUrl,vault:In,getToken:()=>C.token})),s=e.policyFor??ns,o=()=>ne(t.homeDir(),"extend-diagnostics.json"),i=()=>{let C=M=>M&&typeof M=="object"?M:{};try{let M=JSON.parse(qc(o(),"utf8"));return{accounts:C(M?.accounts),sent:C(M?.sent)}}catch{return{accounts:{},sent:{}}}},a=()=>i().accounts,l=(C,M,H)=>{let w=i();w.accounts[C]={...w.accounts[C],...M},Object.assign(w.sent,H),Hc(t.homeDir(),{recursive:!0});let x=`${o()}.${process.pid}.tmp`;Wc(x,JSON.stringify(w,null,2),{encoding:"utf8",mode:384}),Bc(x,o())},c=()=>{let C=t.readCreds();return C.token&&C.cloudUrl?t.accountId():null},u=()=>{let C=c(),M=C?a()[C]??{}:{},H=tn(M.policy);return{signedIn:!!C,enabled:M.enabled===!0,activity:M.activity!==!1,sessions:M.sessions??M.enabled!==!0,memory:M.memory??M.enabled!==!0,lastUploadAt:M.lastUploadAt??null,lastError:M.lastError??null,retainDays:Vn,mode:H.mode,intervalHours:H.intervalHours}},f=()=>{try{return Ci(t)?t.diagnosticLogs():null}catch{return null}},m=null,h=new Map,g=async()=>{let C=c();if(!C)return!1;if(m)return m.id===C?m.done:(await m.done,g());let M={...t.readCreds()},H=n(),w=i(),x=w.accounts[C],b=M.cloudUrl.replace(/\/+$/,""),I=Zr(x?.file,w.sent[b]??{},H),U=(async()=>{try{let B=await Au({home:t.homeDir(),appVersion:t.appVersion(),cloudUrl:M.cloudUrl,activity:x?.activity!==!1,sessions:x?.sessions===!0,now:H,since:I,engineLogs:f(),memory:()=>{let Z=c()===C?a()[C]:void 0;return Z?.enabled===!0&&Z.memory===!0}}),J=await Ni(t.homeDir()),se=a()[C];if(c()!==C||se?.enabled!==!0)return!1;if(se.activity===!1)for(let Z of["activity","activityTruncated","activityError","activitySince"])delete B[Z];if(se.sessions!==!0)for(let Z of["sessions","sessionsTruncated","sessionsError","sessionsSince"])delete B[Z];se.memory!==!0&&delete B.memory;let pe=[],X=Zc(B,pe);if(!X)throw new Error("snapshot too large");await es(r(M),J,X,H),h.delete(C);let de=Qr(i().sent[b]??{},x?.file,I,H,B,pe);return l(C,{lastUploadAt:n().getTime(),lastError:void 0,file:de.file},{[b]:de.sent}),t.log(`[forsion-extend] diagnostics uploaded (${X.length} bytes)`),!0}catch(B){h.set(C,n().getTime());let J=String(B?.message||B).slice(0,300);try{l(C,{lastError:J})}catch{}return t.log(`[forsion-extend] diagnostics upload failed: ${J}`),!1}finally{m=null}})();return m={id:C,done:U},U},p=async()=>{try{let C=c();if(!C||a()[C]?.enabled!==!0)return;let M=await s({...t.readCreds()}),H=c()===C?a()[C]:void 0;if(H?.enabled!==!0)return;M&&(M.mode!==H.policy?.mode||M.intervalHours!==H.policy?.intervalHours)&&l(C,{policy:{mode:M.mode,intervalHours:M.intervalHours}}),M&&H.requestSeen===void 0&&l(C,{requestSeen:M.requestedAt});let w=M??{...tn(H.policy),requestedAt:0},x=w.requestedAt>(H.requestSeen??w.requestedAt),b=H.lastUploadAt??0,I=!b||w.mode==="scheduled"&&n().getTime()-b>=w.intervalHours*Ri;if(!x&&!I||n().getTime()-(h.get(C)??-gi)<gi)return;await g()&&x&&l(C,{requestSeen:w.requestedAt})}catch(C){t.log(`[forsion-extend] diagnostics tick failed: ${String(C?.message||C)}`)}},y={ok:!1,error:"untrusted"};t.handle("diagnostics:get",C=>t.isTrustedSender(C)?u():y),t.handle("diagnostics:set",(C,M)=>{if(!t.isTrustedSender(C))return y;let H=c();if(!H)return u();let w={};typeof M?.enabled=="boolean"&&(w.enabled=M.enabled),w.enabled&&(w.requestSeen=void 0),typeof M?.activity=="boolean"&&(w.activity=M.activity),typeof M?.sessions=="boolean"&&(w.sessions=M.sessions),typeof M?.memory=="boolean"&&(w.memory=M.memory);let x=a()[H];for(let b of["sessions","memory"])w[b]!==void 0||x?.[b]!==void 0||(x?.enabled===!0?w[b]=!1:w.enabled&&(w[b]=!0));return l(H,w),w.enabled&&(h.delete(H),p()),u()}),t.handle("diagnostics:uploadNow",async C=>t.isTrustedSender(C)?(u().enabled&&await g(),u()):y);let _=setTimeout(()=>void p(),Qc),O=setInterval(()=>void p(),eu);return _.unref?.(),O.unref?.(),t.log(`[forsion-extend] diagnostics registered${Ci(t)?"":" (host has no diagnosticLogs: snapshots carry no engine log)"}`),Object.assign(()=>{clearTimeout(_),clearInterval(O)},{tick:p})}import{readFileSync as on,lstatSync as oa,renameSync as Wu,linkSync as Vu,unlinkSync as ea,readdirSync as Yu,rmdirSync as Ju,writeFileSync as Gu,mkdirSync as Xu,copyFileSync as Ku,constants as Zu}from"node:fs";import{readFile as ps,writeFile as ms,mkdir as ta,rename as na,readdir as Qu,lstat as gs,stat as tr,unlink as ra}from"node:fs/promises";import{join as Ye,dirname as nr,relative as ys,sep as ws}from"node:path";import{hostname as ed}from"node:os";import{randomUUID as nt}from"node:crypto";import{Readable as sa}from"node:stream";var Ui={version:1,revision:0,enabled:!1,rules:[{id:"default",source:"",target:"default"}]};function ut(t,e=!1){if(typeof t!="string"||!t&&!e||t.length>512||t.startsWith("/")||/[\\\u0000-\u001f\u007f]/.test(t)||t&&t.split("/").some(n=>!n||n==="."||n===".."||n.endsWith(".")||n.endsWith(" ")||n.startsWith(".forsion-sync")))throw Error("Invalid content path");return t}function Iu(t){if(t==="default"||t==="off"||typeof t=="string"&&/^device-[A-Za-z0-9_-]{1,64}$/.test(t))return t;throw Error("Invalid content target")}function ss(t,e){let n=t;if(!n||n.version!==1||typeof n.enabled!="boolean"||!Array.isArray(n.rules)||n.rules.length>512)throw Error("Invalid content sync configuration");let r=new Set,s=new Set,o=n.rules.map(i=>{let a=ut(i.source,!0),l=Iu(i.target);if(typeof i.id!="string"||!/^[A-Za-z0-9_-]{1,80}$/.test(i.id)||s.has(i.id)||r.has(a))throw Error("Duplicate or invalid sync rule");return s.add(i.id),r.add(a),{id:i.id,source:a,target:l,...i.sourceId&&/^[a-f0-9-]{36}$/i.test(i.sourceId)?{sourceId:i.sourceId}:{}}});return{version:1,revision:e,enabled:n.enabled,rules:o}}function Jn(t,e){let n=null;for(let r of e)(!r.source||t===r.source||t.startsWith(r.source+"/"))&&(!n||r.source.length>n.source.length)&&(n=r);return n}var tt={get:"penzor:sync:get",preview:"penzor:sync:preview",apply:"penzor:sync:apply",run:"penzor:sync:run",pause:"penzor:sync:pause",retry:"penzor:sync:retry",rename:"penzor:sync:rename",setup:"penzor:sync:setup"},Fi=t=>t.replace(/\.local$/i,"").replace(/[-_]+/g," ").trim()||t,Li=["Amadeus","agents","human","Plugins"];var $t=[{id:"notes",path:"Amadeus"},{id:"agents",path:"agents"},{id:"profile",path:"human"},{id:"plugins",path:"Plugins"}];var Gn=(t,e)=>Jn(e,t)?.target??"off",zi=(t,e)=>t===e||t.startsWith(e+"/"),Pu=t=>$t.some(e=>zi(t,e.path)),os=t=>t.some(e=>e.id==="default")?as():"default";function Hi(t,e,n){n==="off"&&(t=t.filter(o=>e?!o.source.startsWith(e+"/"):!o.source||Pu(o.source)));let r=t.find(o=>o.source===e),s=t.filter(o=>o!==r);return e&&Gn(s,e)===n?s:r?t.map(o=>o===r?{...o,target:n}:o):[...t,{id:e?as():os(t),source:e,target:n}]}function is(t,e,n,r=!1){let s=t.rules;if(!t.enabled){let o=s.find(a=>!a.source),i=e?s.filter(a=>a.source&&zi(a.source,e)):[];s=[{id:o?.id??os(i),source:"",target:"off"},...i]}if(!e)for(let o of $t)s.some(i=>i.source===o.path)||(s=[...s,{id:as(),source:o.path,target:Gn(s,o.path)}]);return Ru({...t,rules:Hi(s,e,n)},r)}function Ru(t,e=!1){let n=r=>Gn(t.rules,r)!=="off";return{...t,enabled:$t.some(r=>n(r.path))||t.rules.some(r=>r.source&&r.target!=="off")||e&&n("")}}function qi(t){let e=t.rules.some(n=>n.source==="")?t.rules:[{id:os(t.rules),source:"",target:"default"},...t.rules];for(let n of $t)Gn(e,n.path)==="off"&&(e=Hi(e,n.path,"default"));return{...t,enabled:!0,rules:e}}var Du=0,as=()=>`rule-${Date.now().toString(36)}-${(Du++).toString(36)}`;import{constants as Bi,lstatSync as Xn,readFileSync as $u,renameSync as ls,unlinkSync as Ou,linkSync as Mu,mkdirSync as Kn,realpathSync as Nu,rmdirSync as ju}from"node:fs";import{open as Wi,lstat as cs,readdir as Uu,realpath as Vi,readFile as us,writeFile as Fu,mkdir as Yi,unlink as Lu}from"node:fs/promises";import{join as yt,dirname as Ji,relative as ds,sep as Zn}from"node:path";import{randomUUID as Gi,createHash as zu}from"node:crypto";var Xi=".forsion-sync-id.json",Hu=new Set([".git","node_modules",".DS_Store",".Trash",".trash","__pycache__",".cache"]),qu=t=>!Hu.has(t)&&!t.startsWith(".forsion-sync")&&!/\.tmp-[0-9]|\.lock$|-(wal|shm)$/.test(t)&&(!t.startsWith(".")||t===".memory-tombstones.json"),Pe=t=>zu("sha256").update(t).digest("hex");function Ki(t){if(process.platform==="win32"&&t.split("/").some(e=>/[:*?"<>|]/.test(e)||/^(con|prn|aux|nul|com[1-9¹²³]|lpt[1-9¹²³])(?:\..*)?$/i.test(e)))throw Error("This name is not a safe Windows file destination")}async function We(t,e,n=!1){if(n){if(e.split("/").some(a=>a===".."||a==="."||!a)||e.startsWith("/")||e.includes("\\"))throw Error("Invalid internal content path")}else ut(e,!0);Ki(e);let r=await Vi(t),s=yt(r,...e.split("/").filter(Boolean)),o=ds(r,s);if(o===".."||o.startsWith(".."+Zn))throw Error("Content path escapes root");let i=r;for(let a of o.split(Zn).filter(Boolean)){i=yt(i,a);try{if((await cs(i)).isSymbolicLink())throw Error("Content symlinks are not synchronized")}catch(l){if(l.code!=="ENOENT")throw l}}return s}function Ve(t,e,n=!1){if(n||ut(e,!0),Ki(e),e.split("/").some(o=>o===".."||o===".")||e.startsWith("/")||e.includes("\\"))throw Error("Unsafe sync path");let s=Nu(t);for(let o of e.split("/").filter(Boolean)){s=yt(s,o);try{if(Xn(s).isSymbolicLink())throw Error("Content symlinks are not synchronized")}catch(i){if(i.code!=="ENOENT")throw i}}return s}async function Qn(t){let e=new Map,n=t.filter(s=>s.prefix).map(s=>s.prefix),r=[];for(let s of t)try{r.push({...s,root:await Vi(s.root)})}catch(o){if(o.code!=="ENOENT")throw o}if(new Set(r.map(s=>s.root)).size!==r.length)throw Error("Managed roots refer to the same directory; choose a separate vault folder");for(let s of r){let o=s.root;if(!(await cs(o)).isDirectory())throw Error(`Sync root is not a directory: ${s.prefix||"Forsion"}`);let i=async(a,l)=>{let c=await cs(a);if(!c.isSymbolicLink()&&!(a!==o&&r.some(u=>u!==s&&u.root===a))&&!(l&&s.prefix===""&&n.some(u=>l===u||l.startsWith(u+"/")))){if(l){ut(l);let u;if(c.isDirectory())try{let f=JSON.parse(await us(yt(a,Xi),"utf8"));/^[a-f0-9-]{36}$/i.test(f.id)&&(u=f.id)}catch(f){if(f.code!=="ENOENT"&&!(f instanceof SyntaxError))throw f}e.set(l,{path:l,physical:a,root:o,kind:c.isDirectory()?"folder":"file",localId:u,size:c.isFile()?c.size:0,mtime:c.mtimeMs,inode:`${c.dev}:${c.ino}:${c.birthtimeMs}`})}if(c.isDirectory())for(let u of await Uu(a,{withFileTypes:!0}))!qu(u.name)||!u.isDirectory()&&!u.isFile()||await i(yt(a,u.name),l?`${l}/${u.name}`:u.name)}};await i(o,s.prefix)}return[...e.values()].sort((s,o)=>s.path.split("/").length-o.path.split("/").length||s.path.localeCompare(o.path))}async function fs(t){if(t.kind!=="folder")throw Error("Folder identity required");if(t.localId)return t.localId;let e=await We(t.root,ds(t.root,yt(t.physical,Xi)).split(Zn).join("/"),!0),n=Gi();try{let r=await Wi(e,"wx",384);try{await r.writeFile(JSON.stringify({version:1,id:n})+`
|
|
253
|
-
`)}finally{await r.close()}return t.localId=n,n}catch(r){if(r.code!=="EEXIST")throw r;let s=JSON.parse(await us(e,"utf8"));if(!/^[a-f0-9-]{36}$/i.test(s.id))throw Error("Invalid folder sync identity");return t.localId=s.id,s.id}}async function er(t){let e=await We(t.root,ds(t.root,t.physical).split(Zn).join("/")),n=await Wi(e,Bi.O_RDONLY|(Bi.O_NOFOLLOW||0));try{if((await n.stat()).size>50*1024*1024)throw Error("File exceeds 50 MB content limit");return await n.readFile()}finally{await n.close()}}function dt(t,e){ut(e);let n=[...t].sort((r,s)=>s.prefix.length-r.prefix.length).find(r=>!r.prefix||e===r.prefix||e.startsWith(r.prefix+"/"));if(!n)throw Error("Content root unavailable");return{root:n.root,relative:n.prefix?e.slice(n.prefix.length).replace(/^\//,""):e}}async function Zi(t,e,n,r,s=async(o,i)=>i()){let o=dt(t,e);await Yi(o.root,{recursive:!0});let i=await We(o.root,o.relative),a=await us(i).catch(c=>{if(c.code==="ENOENT")return null;throw c});if((a?Pe(a):null)!==r)throw Error("Local file changed during download");let l=yt(o.root,`.forsion-sync-${Gi()}.tmp`);try{await Fu(l,n,{flag:"wx",mode:384}),await We(o.root,o.relative),await s(i,()=>{Ve(o.root,o.relative),Kn(Ji(i),{recursive:!0}),Ve(o.root,o.relative);let c=null;try{c=$u(i)}catch(u){if(u.code!=="ENOENT")throw u}if((c?Pe(c):null)!==r)throw Error("Local file changed during download");ls(l,i)})}finally{await Lu(l).catch(()=>{})}}async function Qi(t,e,n=async(r,s)=>s()){let r=dt(t,e);await Yi(r.root,{recursive:!0});let s=await We(r.root,r.relative);await n([s],()=>{Ve(r.root,r.relative),Kn(s,{recursive:!0})})}async function hs(t,e,n,r=async(s,o)=>o()){let s=dt(t,e),o=dt(t,n);if(s.root!==o.root)throw Error("Folder move crosses a managed source");let i=await We(s.root,s.relative),a=await We(o.root,o.relative);await r([i,a],()=>{if(Ve(s.root,s.relative),Ve(o.root,o.relative),Bu(a))throw Error("Local rename destination exists");Kn(Ji(a),{recursive:!0});let l=Xn(i);if(l.isDirectory()){if(process.platform==="win32"){ls(i,a);return}Kn(a,{mode:448});try{ls(i,a)}catch(c){try{ju(a)}catch{}throw c}}else{Mu(i,a);let c=Xn(i);if(c.ino!==l.ino||c.dev!==l.dev)throw Error("Source changed during rename");Ou(i)}})}function Bu(t){try{return Xn(t),!0}catch(e){if(e.code==="ENOENT")return!1;throw e}}var td=()=>({config:structuredClone(Ui),owned:!1,paused:!1,folders:{},files:{},jobs:[]}),an=50*1024*1024,rt=(t,e)=>`${t}:${e}`,ln=t=>t.includes("/")?t.slice(0,t.lastIndexOf("/")):"",cn=t=>t.slice(t.lastIndexOf("/")+1),ft=t=>t.split("/").length,Je=t=>t instanceof Error?t.message:String(t);function ia(t){if(!t.contentSync)return;let e=new bs(t);for(let[n,r]of Object.entries({[tt.get]:()=>e.snapshot(),[tt.preview]:s=>e.preview(s),[tt.apply]:s=>e.apply(typeof s=="string"?s:""),[tt.run]:()=>e.run(),[tt.pause]:s=>e.pause(s===!0),[tt.retry]:()=>e.run(),[tt.rename]:s=>e.rename(s),[tt.setup]:s=>e.setup(s)}))t.handle(n,async(s,...o)=>{if(!t.isTrustedSender(s))return{ok:!1,error:"untrusted"};try{return{ok:!0,value:await r(...o)}}catch(i){return{ok:!1,error:Je(i)}}});t.addQuitGuard?.(n=>e.running?{message:n==="zh"?"\u8FD8\u6709\u5185\u5BB9\u6B63\u5728\u540C\u6B65":"Content is still syncing"}:null),e.start()}var bs=class{session=null;initializing=null;previewValue=null;watcher=null;sources=[];devices=[];others;deviceId="";customName="";serial=Promise.resolve();scheduled=null;tick=null;first=null;blocked=new Map;phase="idle";error;closed=!1;runFinished=Promise.resolve();running=!1;host;options;constructor(e,n={}){this.host=e,this.options=n}start(){(this.tick=setInterval(()=>{this.getSession().then(r=>{r.stored.config.enabled&&!r.stored.paused&&this.run()}).catch(r=>{this.error=Je(r)})},3e4)).unref?.(),(this.first=setTimeout(()=>{this.getSession().then(r=>{r.stored.config.enabled&&this.run()}).catch(r=>{this.error=Je(r)})},5e3)).unref?.()}async close(){this.closed=!0,this.tick&&clearInterval(this.tick),this.first&&clearTimeout(this.first),this.scheduled&&clearTimeout(this.scheduled),this.session?.abort.abort(),await this.watcher?.close(),await this.runFinished}guard(e,n=!0){if(this.closed)throw Error("content_sync_closed");if(this.host.accountId()!==e.account||this.session!==e)throw Error("account_changed");n&&e.abort.signal.throwIfAborted()}async persist(e){let n=e.writes.catch(()=>{}).then(async()=>{this.guard(e,!1),await ta(nr(e.file),{recursive:!0,mode:448});let r=e.file+".tmp-"+nt();try{await ms(r,JSON.stringify(e.stored),{mode:384,flag:"wx"}),this.guard(e,!1),await na(r,e.file)}finally{await ra(r).catch(()=>{})}});return e.writes=n,n}async getSession(){let e=this.host.accountId();if(!e)throw this.session?.abort.abort(),this.session=null,Error("not_signed_in");return this.session?.account===e?this.session:this.initializing?this.initializing.then(n=>(this.guard(n),n)):(this.session?.abort.abort(new Error("account_changed")),await this.watcher?.close(),this.watcher=null,this.previewValue=null,this.sources=[],this.devices=[],this.initializing=(async()=>{let n=Ye(this.host.homeDir(),"content-sync"),r=Ye(n,Pe(e)+".json"),s=td();try{let c=JSON.parse(await ps(r,"utf8"));s={...s,...c,config:ss(c.config,c.config.revision)},s.jobs=Array.isArray(c.jobs)?c.jobs.slice(-200):[]}catch(c){if(c.code!=="ENOENT")throw Error("Invalid content sync state; original data was retained")}let o,i=Ye(this.host.homeDir(),"content-sync-device.json");try{if(o=JSON.parse(await ps(i,"utf8")),!/^[A-Za-z0-9_-]{1,64}$/.test(o.id))throw Error("Invalid device sync ID")}catch(c){if(c.code!=="ENOENT")throw c;o={id:nt()},await ta(nr(i),{recursive:!0});try{await ms(i,JSON.stringify(o),{flag:"wx",mode:384})}catch(u){if(u.code!=="EEXIST")throw u;o=JSON.parse(await ps(i,"utf8"))}}if(this.host.accountId()!==e)throw Error("account_changed");this.deviceId=o.id,this.customName=typeof o.name=="string"?o.name:"";let a=await this.host.contentSync.roots();if(this.host.accountId()!==e)throw Error("account_changed");let l={account:e,file:r,stored:s,roots:a,abort:new AbortController,writes:Promise.resolve()};return this.session=l,await this.recoverTrash(l),s.owned&&await this.host.contentSync.claim(!0),this.setSources(await this.scan(l,a).catch(c=>(this.error=Je(c),[]))),await this.json(l,"devices",`/${encodeURIComponent(this.deviceId)}`,"PUT",{name:this.deviceName()}),this.devices=(await this.json(l,"devices")).devices,await this.watchRoots(l),l})().catch(n=>{throw this.session?.account===e&&(this.session.abort.abort(),this.session=null),n}).finally(()=>{this.initializing=null}),this.initializing)}async scan(e,n=e.roots){for(let r of e.stored.roots??[]){let s=n.find(i=>i.prefix===r.prefix);if(!s||s.root!==r.root)throw Error("content_roots_changed_preview_required");let o=await tr(r.root).catch(()=>{throw Error(`Sync root unavailable: ${r.prefix||"Forsion"}`)});if(!o.isDirectory()||r.dev!==void 0&&(o.dev!==r.dev||o.ino!==r.ino))throw Error("Sync root changed; preview before rebinding")}return Qn(n)}async write(e,n,r,s){this.guard(e),await Zi(e.roots,n,r,s,(o,i)=>this.lock(e,o,i)),await this.recordRoots(e)}async recordRoots(e){this.guard(e);let n=!1;for(let r of e.roots){if(e.stored.roots?.some(o=>o.prefix===r.prefix&&o.root===r.root))continue;let s=await tr(r.root).catch(o=>{if(o.code==="ENOENT")return null;throw o});if(s){if(!s.isDirectory())throw Error("Sync root is not a directory");(e.stored.roots??=[]).push({...r,dev:s.dev,ino:s.ino}),n=!0}}n&&await this.persist(e)}lock(e,n,r,s=!1){let o=()=>{if(this.guard(e),e.stored.paused&&!s)throw Error("paused");r()};return this.host.contentSync.withWriteLock?.(n,o)??Promise.resolve().then(o)}async previewScan(e,n){for(let r of e.stored.roots??[])n.some(s=>s.prefix===r.prefix&&s.root===r.root)&&await gs(r.root).catch(()=>{throw Error(`Sync root unavailable: ${r.prefix||"Forsion"}`)});return Qn(n)}async watchRoots(e){this.options.watch!==!1&&(this.guard(e),await this.watcher?.close(),this.watcher=yr(e.roots.map(n=>n.root),{ignoreInitial:!0,ignored:n=>{let r=n.split(/[\\/]/).at(-1)??"";return r.startsWith(".")&&r!==".memory-tombstones.json"||r==="node_modules"||r==="__pycache__"}}),this.watcher.on("all",()=>{this.scheduled&&clearTimeout(this.scheduled),this.scheduled=setTimeout(()=>{e.stored.config.enabled&&!e.stored.paused&&this.run()},1500),this.scheduled.unref?.()}))}async request(e,n,r="",s="GET",o,i){this.guard(e);let a=this.host.readCreds();if(!a.token)throw Error("not_signed_in");let l=a.cloudUrl.replace(/\/+$/,"")+`/api/remotesync/content/${encodeURIComponent(n)}${r}`,c={Authorization:`Bearer ${a.token}`},u;if(o instanceof Buffer){c["Content-Type"]="application/octet-stream",c["Content-Length"]=String(o.length);let h=async function*(){for(let g=0;g<o.length;g+=64*1024)e.abort.signal.throwIfAborted(),yield o.subarray(g,g+64*1024),i?.(Math.min(o.length,g+64*1024))};u=sa.from(h())}else o!==void 0&&(c["Content-Type"]="application/json",u=JSON.stringify(o));let f={method:s,headers:c,body:u,signal:AbortSignal.any([e.abort.signal,AbortSignal.timeout(12e4)]),...o instanceof Buffer?{duplex:"half"}:{}},m=await fetch(l,f);if(this.guard(e),!m.ok){let h=await m.json().catch(()=>({}));throw Object.assign(new Error(typeof h.detail=="string"?h.detail:`content_http_${m.status}`),{status:m.status})}return m}async json(e,n,r="",s="GET",o){return await(await this.request(e,n,r,s,o)).json()}async manifests(e,n){let r=new Map;for(let s of new Set(n.rules.filter(o=>o.target!=="off").map(o=>o.target))){let o=await this.json(e,s);if(o.schemaVersion!==1||o.namespace!==s||!Array.isArray(o.nodes))throw Error("Incomplete cloud content manifest");let i=new Set;for(let a of o.nodes){if(ut(a.path),i.has(a.id))throw Error("Duplicate cloud content identity");i.add(a.id)}r.set(s,o)}return r}route(e,n){let r=Jn(e,n.rules);return r&&r.target!=="off"?r.target:null}effective(e,n){let r=new Map(n.filter(s=>s.localId).map(s=>[s.localId,s.path]));return{...e,rules:e.rules.map(s=>s.sourceId&&r.has(s.sourceId)?{...s,source:r.get(s.sourceId)}:s)}}deviceName(){return this.customName||Fi(ed())}setSources(e){let n=new Map,r={files:0,size:0};for(let s of e)s.kind==="folder"&&n.set(s.path,{size:0,files:0});for(let s of e)if(s.kind==="file"){Li.some(o=>s.path.startsWith(o+"/"))||(r.files++,r.size+=s.size);for(let o=ln(s.path);o;o=ln(o)){let i=n.get(o);i&&(i.size+=s.size,i.files++)}}this.others=r,this.sources=[...n].sort(([s],[o])=>ft(s)-ft(o)||(s<o?-1:1)).slice(0,2e3).map(([s,o])=>({path:s,kind:"folder",size:o.size,files:o.files}))}async rename(e){let n=typeof e=="string"?e.trim():"";if(n.length>64||/[\u0000-\u001f\u007f]/.test(n))throw Error("Invalid device name");let r=await this.getSession(),s=Ye(this.host.homeDir(),"content-sync-device.json"),o=s+".tmp-"+nt();try{await ms(o,JSON.stringify({id:this.deviceId,...n?{name:n}:{}}),{mode:384,flag:"wx"}),await na(o,s)}finally{await ra(o).catch(()=>{})}return this.customName=n,await this.json(r,"devices",`/${encodeURIComponent(this.deviceId)}`,"PUT",{name:this.deviceName()}),this.devices=(await this.json(r,"devices")).devices,this.deviceName()}async setup(e){let n=await this.getSession(),r=e&&typeof e=="object"?e:{};if(n.stored.config.enabled||n.stored.config.revision>0)return null;let s=is(qi(n.stored.config),"","off");for(let o of $t)r[o.id]===!1&&(s=is(s,o.path,"off"));return this.preview(s)}async snapshot(){let e=await this.getSession();return{available:!0,account:Pe(e.account),deviceId:this.deviceId,deviceName:this.deviceName(),config:structuredClone(e.stored.config),running:this.running,paused:e.stored.paused,phase:this.phase,jobs:structuredClone(e.stored.jobs),devices:this.devices,sources:this.sources,...this.others?{others:this.others}:{},...this.error?{error:this.error}:{}}}async preview(e){let n=await this.getSession();if(e?.revision!==n.stored.config.revision)throw Error("config_changed");let s=ss(e,n.stored.config.revision+1),o=await this.host.contentSync.roots();this.guard(n),n.roots=o;let i=await this.previewScan(n,o),a=this.effective(s,i),l=await this.manifests(n,a);this.guard(n),this.setSources(i);let c=0,u=0,f=0,m=0;for(let p of i.filter(y=>y.kind==="file")){let y=this.route(p.path,a);if(!y)continue;let _=l.get(y)?.nodes.find(C=>!C.deleted&&C.kind==="file"&&C.path===p.path);if(p.size>an){c++,m+=p.size;continue}let O=Pe(await er(p));this.guard(n),O!==_?.hash&&(c++,m+=p.size,_?.version&&f++)}for(let[p,y]of l)for(let _ of y.nodes)!_.deleted&&_.kind==="file"&&_.version&&this.route(_.path,a)===p&&!i.some(O=>O.path===_.path)&&u++;let h=this.signature(i,l,o),g={token:nt(),config:a,upload:s.enabled?c:0,download:s.enabled?u:0,conflicts:s.enabled?f:0,bytes:s.enabled?m:0,oldTargetsRetained:!0,expiresAt:Date.now()+5*6e4};return this.previewValue={value:g,account:n.account,signature:h},g}signature(e,n,r){return Pe(JSON.stringify([r,e.map(s=>[s.path,s.size,s.mtime,s.inode]),[...n].map(([s,o])=>[s,o.nodes.map(i=>[i.id,i.revision,i.version,i.deleted])])]))}async apply(e){let n=this.serial,r;this.serial=new Promise(s=>{r=s}),await n;try{let s=await this.getSession(),o=this.previewValue;if(!o||o.value.token!==e||o.account!==s.account||o.value.expiresAt<Date.now()||o.value.config.revision!==s.stored.config.revision+1)throw Error("preview_expired");if(this.running)throw Error("sync_in_progress");let i=await this.host.contentSync.roots(),a=await this.previewScan(s,i),l=await this.manifests(s,o.value.config);if(this.signature(a,l,i)!==o.signature)throw Error("preview_changed");let c=[];for(let f of i){let m=await tr(f.root).catch(h=>{if(h.code==="ENOENT")return null;throw h});m&&c.push({...f,dev:m.dev,ino:m.ino})}this.guard(s);let u=structuredClone(s.stored);s.stored.config=o.value.config,s.stored.owned=!0,s.stored.paused=!1;for(let f of s.stored.config.rules){let m=a.find(h=>h.kind==="folder"&&h.path===f.source);m&&(f.sourceId=await fs(m))}for(let[f,m]of Object.entries(s.stored.files))(u.config.enabled!==s.stored.config.enabled||JSON.stringify(u.roots??c)!==JSON.stringify(c)||this.route(m.path,u.config)!==this.route(m.path,s.stored.config))&&delete s.stored.files[f];for(let[f,m]of Object.entries(s.stored.folders))(u.config.enabled!==s.stored.config.enabled||JSON.stringify(u.roots??c)!==JSON.stringify(c)||this.route(m.path,u.config)!==this.route(m.path,s.stored.config))&&delete s.stored.folders[f];s.stored.roots=c,await this.persist(s);try{await this.host.contentSync.claim(!0),this.guard(s)}catch(f){throw s.stored=u,await this.persist(s),await this.host.contentSync.claim(u.owned).catch(()=>{}),f}this.previewValue=null,s.roots=i,await this.watchRoots(s)}finally{r()}this.run()}async pause(e){let n=await this.getSession();n.stored.paused=e,e?(n.abort.abort(new Error("paused")),this.phase="paused"):this.running||(n.abort=new AbortController),await this.persist(n),e||this.run()}job(e,n,r,s,o){let i=e.stored.jobs.findLast(l=>l.path===n&&l.target===r&&l.direction===s&&["failed","paused","queued"].includes(l.state));if(i)return Object.assign(i,{state:"active",done:0,size:o,at:Date.now(),error:void 0,finishedAt:void 0}),i;let a={id:nt(),path:n,target:r,direction:s,state:"active",done:0,size:o,at:Date.now()};return e.stored.jobs.push(a),e.stored.jobs=e.stored.jobs.slice(-200),a}done(e){e.state="done",e.done=e.size??e.done,e.finishedAt=Date.now()}async operation(e,n,r,s,o,i){if(this.guard(e),e.stored.paused)throw Error("paused");let a=this.job(e,n,r,s,o);try{let l=await i(a);if(this.guard(e),e.stored.paused)throw Error("paused");return this.done(a),l}catch(l){throw a.state=e.stored.paused?"paused":"failed",a.error=Je(l),a.finishedAt=Date.now(),l}}async run(){if(this.running||this.closed)return;this.running=!0;let e;this.runFinished=new Promise(r=>{e=r});let n;try{if(n=await this.getSession(),!n.stored.config.enabled||n.stored.paused)return;n.abort.signal.aborted&&(n.abort=new AbortController),this.blocked.clear(),this.phase="scanning",this.error=void 0;let r=await this.host.contentSync.roots();this.guard(n),n.roots=r;let s=await this.scan(n,r);await this.recordRoots(n);let o=this.effective(n.stored.config,s),i=await this.manifests(n,o);this.guard(n),await this.json(n,"devices",`/${encodeURIComponent(this.deviceId)}`,"PUT",{name:this.deviceName()}),this.devices=(await this.json(n,"devices")).devices,await this.folders(n,o,s,i),await this.recordRoots(n),await this.fileRenames(n,o,s,i),s=await this.scan(n,r),o=this.effective(o,s),n.stored.config=o,this.setSources(s),this.phase="syncing";for(let a of s.filter(l=>l.kind==="file")){if(this.guard(n),n.stored.paused)throw Error("paused");let l=this.route(a.path,o);if(!(!l||this.isBlocked(l,a.path)))try{await this.file(n,o,a,l,i.get(l))}catch(c){this.error=Je(c)}}for(let[a,l]of i)for(let c of l.nodes.filter(u=>u.kind==="file"&&!u.busy)){if(this.guard(n),n.stored.paused)throw Error("paused");if(!(this.isBlocked(a,c.path)||this.route(c.path,o)!==a||s.some(u=>u.path===c.path)))try{await this.missing(n,c,a)}catch(u){this.error=Je(u)}}await this.cleanupFolders(n,o,i),await this.host.contentSync.changed(),this.guard(n),await this.persist(n)}catch(r){this.error=Je(r)}finally{this.running=!1,this.phase=n?.stored.paused?"paused":"idle",n&&this.host.accountId()===n.account&&(await this.persist(n).catch(()=>{}),!this.closed&&n.abort.signal.aborted&&!n.stored.paused&&n.stored.config.enabled&&(n.abort=new AbortController,queueMicrotask(()=>void this.run()))),e()}}isBlocked(e,n){return(this.blocked.get(e)??[]).some(r=>n===r||n.startsWith(r+"/"))}block(e,n,r){this.blocked.set(e,[...this.blocked.get(e)??[],n]),this.error=Je(r)}async folders(e,n,r,s){let o=r.filter(a=>a.kind==="folder"),i=new Map;for(let a of o)if(a.localId){if(i.has(a.localId))throw Error(`Duplicate folder sync identity: ${a.path}`);i.set(a.localId,a.path)}for(let[a,l]of s){for(let c of l.nodes.filter(u=>u.kind==="folder"&&!u.deleted&&!u.busy).sort((u,f)=>ft(u.path)-ft(f.path)))if(!this.isBlocked(a,c.path))try{let u=Object.entries(e.stored.folders).find(([m,h])=>m.startsWith(a+":")&&h.id===c.id)?.[1],f=(u?o.find(m=>m.localId===u.localId):null)??o.find(m=>m.path===c.path);if(u&&f&&c.path!==u.path&&f.path!==u.path&&c.path!==f.path)throw Error(`Concurrent folder rename: ${f.path}`);if(u&&f&&c.path!==u.path&&f.path===u.path){if(this.route(f.path,n)!==a)continue;if(this.route(c.path,n)!==a)throw Error("Remote rename crosses a sync rule; review the destination");await this.operation(e,f.path,a,"rename",null,()=>hs(e.roots,f.path,c.path,(h,g)=>this.lock(e,h,g)));let m=f.path;for(let h of r)if(h.path===m||h.path.startsWith(m+"/")){let g=h.path;h.path=c.path+g.slice(m.length);let p=dt(e.roots,h.path);h.physical=Ye(p.root,p.relative)}for(let[h,g]of Object.entries(e.stored.files))h.startsWith(a+":")&&g.path.startsWith(u.path+"/")&&(g.path=c.path+g.path.slice(u.path.length));for(let h of n.rules)(h.source===u.path||h.source.startsWith(u.path+"/"))&&(h.source=c.path+h.source.slice(u.path.length))}if(!f&&this.route(c.path,n)===a&&!u){await Qi(e.roots,c.path,(h,g)=>this.lock(e,h,g));let m=(await this.scan(e)).find(h=>h.path===c.path);m&&(r.push(m),o.push(m))}}catch(u){this.block(a,c.path,u);let f=Object.entries(e.stored.folders).find(([m,h])=>m.startsWith(a+":")&&h.id===c.id)?.[1];f&&this.block(a,f.path,u)}for(let c of o.sort((u,f)=>ft(u.path)-ft(f.path)))if(!this.isBlocked(a,c.path))try{let u=this.route(c.path,n),f=n.rules.some(_=>_.target===a&&_.source.startsWith(c.path+"/"));if(u!==a&&!f)continue;let m=await fs(c),h=e.stored.folders[rt(a,m)],g=h?l.nodes.find(_=>_.id===h.id):l.nodes.find(_=>_.path===c.path&&!_.deleted);if(g?.deleted){if(h){let _=!1;for(let O of r.filter(C=>C.kind==="file"&&C.path.startsWith(c.path+"/")&&this.route(C.path,n)===a)){let C=Object.entries(e.stored.files).find(([M,H])=>M.startsWith(a+":")&&H.path===O.path)?.[1];if(!C||Pe(await er(O))!==C.hash){_=!0;break}}if(!_)continue}g=void 0}let p=ln(c.path),y=p?l.nodes.find(_=>_.path===p&&_.kind==="folder"&&!_.deleted)?.id:"";if(p&&!y)throw Error("Cloud parent is unavailable");if(!g)g=await this.json(e,a,"/nodes","POST",{id:h?nt():m,parentId:y,name:cn(c.path),kind:"folder"}),l.nodes.push(g);else if(h&&g.path!==c.path){if(g.revision!==h.revision)throw Error(`Concurrent folder rename: ${c.path}`);let _=g.path,O=await this.operation(e,c.path,a,"rename",null,()=>this.json(e,a,`/nodes/${g.id}`,"PATCH",{parentId:y,name:cn(c.path),revision:g.revision}));for(let C of l.nodes)C.path.startsWith(_+"/")&&(C.path=c.path+C.path.slice(_.length));Object.assign(g,O);for(let[C,M]of Object.entries(e.stored.files))C.startsWith(a+":")&&M.path.startsWith(_+"/")&&(M.path=c.path+M.path.slice(_.length))}e.stored.folders[rt(a,m)]={id:g.id,localId:m,path:c.path,revision:g.revision,parentId:g.parentId,name:g.name}}catch(u){this.block(a,c.path,u);let f=this.job(e,c.path,a,"rename",null);f.state="conflict",f.error=Je(u),f.finishedAt=Date.now()}}}async cleanupFolders(e,n,r){let s=await this.scan(e);for(let[o,i]of r)for(let a of i.nodes.filter(l=>l.kind==="folder"&&!l.busy).sort((l,c)=>ft(c.path)-ft(l.path))){if(this.isBlocked(o,a.path)||this.route(a.path,n)!==o)continue;let l=Object.entries(e.stored.folders).find(([u,f])=>u.startsWith(o+":")&&f.id===a.id);if(!l)continue;let c=s.find(u=>u.path===a.path&&u.kind==="folder");if(a.deleted&&c){if(s.some(f=>f.path.startsWith(a.path+"/"))||(await Qu(c.physical)).some(f=>f!==".forsion-sync-id.json"))continue;await this.operation(e,a.path,o,"delete",null,()=>this.lock(e,c.physical,()=>{Ve(c.root,ys(c.root,c.physical).split(ws).join("/"));let f=Yu(c.physical);if(f.some(g=>g!==".forsion-sync-id.json"))throw Error("Folder changed before deletion");let m=Ye(c.physical,".forsion-sync-id.json"),h=f.length?on(m):null;h&&ea(m);try{Ju(c.physical)}catch(g){if(h)try{Gu(m,h,{flag:"wx",mode:384})}catch{}throw g}})),delete e.stored.folders[l[0]]}else if(!a.deleted&&!c){if(i.nodes.some(u=>u.parentId===a.id&&!u.deleted))continue;await this.operation(e,a.path,o,"delete",null,()=>this.json(e,o,`/nodes/${a.id}`,"DELETE",{revision:a.revision,version:null})),a.deleted=!0,delete e.stored.folders[l[0]]}}}async download(e,n,r,s){if(n.size!==void 0&&n.size>an)throw Error("File exceeds 50 MB content limit");let o=await this.request(e,r,`/nodes/${n.id}/content`),i=[],a=0;if(o.body){let c=o.body.getReader();for(;;){let u=await c.read();if(u.done)break;if(this.guard(e),a+=u.value.length,a>an)throw await c.cancel(),Error("Content too large");i.push(u.value),s.done=a}}let l=Buffer.concat(i);if(n.hash&&Pe(l)!==n.hash)throw Error("Cloud file changed during download");return l}async fileRenames(e,n,r,s){for(let[o,i]of s)for(let a of i.nodes.filter(l=>l.kind==="file"&&!l.deleted&&!l.busy)){let l=e.stored.files[rt(o,a.id)];if(!l||l.path===a.path)continue;let c=r.find(u=>u.kind==="file"&&u.path===l.path);if(!(!c||this.route(c.path,n)!==o))try{if(this.route(a.path,n)!==o)throw Error("Remote rename crosses a sync rule; review the destination");await this.operation(e,c.path,o,"rename",null,()=>hs(e.roots,c.path,a.path,(u,f)=>this.lock(e,u,f))),l.path=a.path}catch(u){this.block(o,c.path,u),this.block(o,a.path,u)}}}async upload(e,n,r,s,o){if(s.length>an)throw Error("File exceeds 50 MB content limit");this.guard(e);let i=this.host.readCreds(),a=sa.from((async function*(){for(let c=0;c<s.length;c+=64*1024)e.abort.signal.throwIfAborted(),yield s.subarray(c,c+64*1024),o.done=Math.min(s.length,c+64*1024)})()),l=await fetch(i.cloudUrl.replace(/\/+$/,"")+`/api/remotesync/content/${encodeURIComponent(r)}/nodes/${n.id}/content`,{method:"PUT",headers:{Authorization:`Bearer ${i.token}`,"Content-Type":"application/octet-stream","Content-Length":String(s.length),"X-Content-Version":n.version??"create"},body:a,duplex:"half",signal:AbortSignal.any([e.abort.signal,AbortSignal.timeout(12e4)])});if(this.guard(e),!l.ok){let c=await l.json().catch(()=>({}));throw Error(c.detail??`content_http_${l.status}`)}return await l.json()}shadow(e,n,r,s,o){for(let i of e.stored.jobs)i.path===r.path&&i.target===n&&["failed","paused","active"].includes(i.state)&&["upload","download","merge"].includes(i.direction)&&this.done(i);e.stored.files[rt(n,r.id)]={id:r.id,path:r.path,version:r.version,hash:Pe(s),...s.length<1024*1024&&Buffer.from(s.toString("utf8")).equals(s)?{base:s.toString("utf8")}:{},...o?{inode:o.inode}:{}}}async file(e,n,r,s,o){if(r.size>an){await this.operation(e,r.path,s,"upload",r.size,async()=>{throw Error("File exceeds 50 MB content limit")});return}let i=await er(r),a=Pe(i);this.guard(e);let l=o.nodes.find(h=>h.kind==="file"&&!h.deleted&&h.path===r.path);if(!l){let h=Object.entries(e.stored.files).find(([g,p])=>g.startsWith(s+":")&&p.inode===r.inode&&p.path!==r.path)?.[1];if(h){let g=dt(e.roots,h.path),p=await gs(Ye(g.root,g.relative)).then(()=>!0,_=>_.code==="ENOENT"?!1:Promise.reject(_)),y=o.nodes.find(_=>_.id===h.id&&!_.deleted);if(!p&&y){if(y.path!==h.path)throw Error(`Concurrent file rename: ${r.path}`);let _=ln(r.path),O=_?o.nodes.find(M=>M.path===_&&M.kind==="folder"&&!M.deleted)?.id:"";if(_&&!O)throw Error("Rename parent unavailable");let C=await this.operation(e,r.path,s,"rename",null,()=>this.json(e,s,`/nodes/${y.id}`,"PATCH",{name:cn(r.path),parentId:O,revision:y.revision}));Object.assign(y,C),h.path=r.path,l=y}}}let c=l?e.stored.files[rt(s,l.id)]:Object.entries(e.stored.files).find(([h,g])=>h.startsWith(s+":")&&g.path===r.path)?.[1];if(!l){if((c?o.nodes.find(y=>y.id===c.id&&y.deleted):null)&&c?.hash===a){await this.operation(e,r.path,s,"delete",r.size,()=>this.trashFile(e,r,a)),delete e.stored.files[rt(s,c.id)];return}let g=ln(r.path),p=g?o.nodes.find(y=>y.path===g&&!y.deleted&&y.kind==="folder")?.id:"";if(g&&!p)throw Error("Parent folder is unavailable");l=await this.json(e,s,"/nodes","POST",{id:nt(),parentId:p,name:cn(r.path),kind:"file"}),o.nodes.push(l),c=void 0}if(l.busy)return;if(l.hash===a){this.shadow(e,s,l,i,r);return}if(!l.version||c&&l.version===c.version){let h=await this.operation(e,r.path,s,"upload",i.length,g=>this.upload(e,l,s,i,g));Object.assign(l,h),this.shadow(e,s,l,i,r);return}let u=await this.operation(e,r.path,s,"download",l.size??null,h=>this.download(e,l,s,h)),f=u,m=!1;if(!c||c.hash!==a){let h=i.toString("utf8"),g=u.toString("utf8"),p=Buffer.from(h).equals(i)&&Buffer.from(g).equals(u)?this.host.contentSync.merge(r.path,h,c?.base??null,g):null;if(p?(f=Buffer.from(p.content),m=p.conflict):m=!0,m){let y=r.path.lastIndexOf("."),_=` (conflict ${this.deviceId.slice(0,8)} ${Date.now()})`,O=y>r.path.lastIndexOf("/")?r.path.slice(0,y)+_+r.path.slice(y):r.path+_;await this.write(e,O,i,null);let C=this.job(e,r.path,s,"merge",i.length);C.state="conflict",C.error="Both versions preserved",C.finishedAt=Date.now()}if(!f.equals(u)){let y=await this.operation(e,r.path,s,"merge",f.length,_=>this.upload(e,l,s,f,_));Object.assign(l,y)}}await this.write(e,r.path,f,a),this.shadow(e,s,l,f,r)}async missing(e,n,r){let s=e.stored.files[rt(r,n.id)];if(n.deleted){s&&delete e.stored.files[rt(r,n.id)];return}if(!n.version)return;if(s&&s.version===n.version){await this.operation(e,n.path,r,"delete",n.size??null,()=>this.json(e,r,`/nodes/${n.id}`,"DELETE",{revision:n.revision,version:n.version})),delete e.stored.files[rt(r,n.id)],n.deleted=!0;return}let o=await this.operation(e,n.path,r,"download",n.size??null,i=>this.download(e,n,r,i));await this.write(e,n.path,o,null),this.shadow(e,r,n,o)}async recoverTrash(e){for(let n of[...e.stored.trash??[]]){if(n.parentId){let l=(await Qn(e.roots)).find(c=>c.kind==="folder"&&c.localId===n.parentId);l&&(n.path=l.path+"/"+cn(n.path))}let r=dt(e.roots,n.path),s=await We(r.root,r.relative);if(!/^\.forsion-sync-trash-[a-f0-9-]+$/.test(n.stage))throw Error("Invalid sync recovery journal");let o=n.stageRoot??r.root,i=await tr(o);if(n.stageDev!==void 0&&(i.dev!==n.stageDev||i.ino!==n.stageIno))throw Error("Sync recovery root changed; journal retained");let a=Ye(o,n.stage);await gs(a).then(()=>!0,l=>l.code==="ENOENT"?!1:Promise.reject(l))&&await this.lock(e,s,()=>{if(Ve(o,n.stage,!0),Pe(on(a))!==n.hash)throw Error("Sync recovery content changed");Ve(r.root,r.relative),Xu(nr(s),{recursive:!0});let l=nd(s)?s+` (sync recovery ${nt().slice(0,8)})`:s;try{Vu(a,l)}catch(c){if(c.code!=="EXDEV")throw c;if(Ku(a,l,Zu.COPYFILE_EXCL),Pe(on(l))!==n.hash)throw Error("Sync recovery copy incomplete; original retained")}ea(a)},!0),e.stored.trash=e.stored.trash.filter(l=>l!==n)}}async trashFile(e,n,r){this.guard(e);let s=await We(n.root,ys(n.root,n.physical).split(ws).join("/")),o={path:n.path,stage:".forsion-sync-trash-"+nt(),hash:r},i=Ye(n.root,o.stage),a=oa(n.root);o.stageRoot=n.root,o.stageDev=a.dev,o.stageIno=a.ino;try{let l=JSON.parse(on(Ye(nr(s),".forsion-sync-id.json"),"utf8")).id;/^[a-f0-9-]{36}$/i.test(l)&&(o.parentId=l)}catch{}(e.stored.trash??=[]).push(o),await this.persist(e);try{await this.lock(e,s,()=>{if(Ve(n.root,ys(n.root,s).split(ws).join("/")),Pe(on(s))!==r)throw Error("Local file changed before deletion");Wu(s,i)}),await this.host.contentSync.trash(i),e.stored.trash=e.stored.trash.filter(l=>l!==o)}catch(l){throw this.host.accountId()===e.account&&!e.abort.signal.aborted&&await this.recoverTrash(e),l}}};function nd(t){try{return oa(t),!0}catch(e){if(e.code==="ENOENT")return!1;throw e}}Is(oo);function zp(t){js(t),Pr(t),ia(t),t.log("[forsion-extend] cloud account handlers registered"),vr(t)?kr(t):t.log("[forsion-extend] host has no Connect seam (projectsRoot / transpileForServe / mimeOf / setPreviewHooks); Connect stays with the host"),_r(t)?Cr(t):t.log("[forsion-extend] host has no remote-sync seam (registerRemoteSyncBackend / readCreds); penzor stays with the host"),$r(t)?Or(t):t.log("[forsion-extend] host has no account seam (accountCommit / accountClear / \u2026); account core stays with the host"),Vr(t)?Yr(t):t.log("[forsion-extend] host has no amadeus seam (setAmadeusSyncFactory); cloud sync stays with the host"),Gr(t)?Xr(t):t.log("[forsion-extend] host has no unit seam (setUnitHubFactory); the device channel stays with the host"),$i(t)?ji(t):t.log("[forsion-extend] host has no diagnostics seam (homeDir / readCreds / accountId / appVersion); diagnostics upload is off")}export{Do as ACCOUNT_SEAM,ni as AMADEUS_SEAM,br as CONNECT_MAX_FILES,ao as CONNECT_MAX_FILE_BYTES,lo as CONNECT_MAX_TOTAL_BYTES,In as DIAGNOSTICS_VAULT,mo as FORSION_CONNECT_LOCAL_SDK,Ns as PAY_PERIODS,Ms as PAY_TABS,wo as PENZOR_MAX_FILE,ve as SYNC_IPC,oi as UNIT_SEAM,Ht as UPLOAD_MAX_FILE,Zt as UnitCapsReporter,Kt as UnitHost,Ae as cloudJson,co as collectProjectFiles,Mn as conflictCopyPath,nc as conflictCopyVariant,Ro as createAccountCloud,ri as createAmadeusCloud,An as createPenzorRemote,ii as createUnitHub,Tn as deviceHeader,Er as expectedPartsOf,Oe as forsionAccountId,$n as forsionRefreshToken,zt as forsionWhoami,$r as hasAccountHost,Vr as hasAmadeusHost,vr as hasConnectHost,_r as hasRemoteSyncHost,Gr as hasUnitHost,po as makePreviewProxy,To as multipartFrame,fo as readConnectMeta,Or as registerAccount,Yr as registerAmadeus,zp as registerCloud,kr as registerConnect,Cr as registerPenzor,Pr as registerPenzorTransfers,Xr as registerUnit,Pn as safeDownloadName,Dn as shouldRefreshToken,xr as speedOf,si as streamWorthy,Ko as stripConflictSuffix,rc as textFingerprint,Dr as tokenAgeMs,Ao as tokenRemainingMs,Tr as uploadError,ho as writeConnectMeta};
|
|
248
|
+
json_extract(e.payload, '$.requestBytes') AS request_bytes, json_extract(e.payload, '$.phase') AS phase, substr(json_extract(e.payload, '$.error'), 1, ${dn}) AS error
|
|
249
|
+
FROM agent_run_events e WHERE e.run_id = ? AND e.type IN ('usage', 'tool_result', 'error', 'status') AND json_valid(e.payload) ORDER BY e.seq LIMIT ?`),u=m=>typeof m=="number"&&Number.isFinite(m)&&m>0?m:0,f=m=>m||void 0,p=[],h=0,g=l.length>n.runs;for(let m of l.slice(0,n.runs)){let w={llmCalls:0,prompt:0,completion:0,cached:0,reasoning:0,llmMs:0,ttftMaxMs:0,requestMaxBytes:0},k=new Map,P=[],O=0,A=c.all(m.id,n.events+1),$=A.length>n.events;for(let E of A.slice(0,n.events))if(E.type==="usage")w.llmCalls++,w.prompt+=u(E.prompt),w.completion+=u(E.completion),w.cached+=u(E.cached),w.reasoning+=u(E.reasoning),w.llmMs+=u(E.llm_ms),w.ttftMaxMs=Math.max(w.ttftMaxMs,u(E.ttft_ms)),w.requestMaxBytes=Math.max(w.requestMaxBytes,u(E.request_bytes));else if(E.type==="tool_result"){let T=se(E.name,80)??"?",L=k.get(T)??(k.size<n.tools?{name:T,n:0,ms:0,maxMs:0}:void 0);if(!L){$=!0;continue}k.set(T,L),L.n++,E.failed&&(L.errors=(L.errors??0)+1),L.ms+=u(E.ms),L.maxMs=Math.max(L.maxMs,u(E.ms))}else if(E.type==="error"){let T=rr(E.error,n.errorChars);T&&!P.includes(T)&&P.length<3&&P.push(T)}else E.phase==="llm_retry"&&O++;let b={id:se(m.id,64)??null,session:se(m.session_id,64)??null,kind:se(m.kind,16),app:se(m.app_id,50),model:se(m.model_id,128),status:se(m.status,16)??null,error:rr(m.error,n.errorChars),createdAt:se(m.created_at,40)??null,updatedAt:se(m.updated_at,40)??null,steps:f(u(m.current_step)),tokens:f(u(m.tokens_total)),retries:f(O),...Object.fromEntries(Object.entries(w).map(([E,T])=>[E,f(T)])),errors:P.length?P:void 0,tools:k.size?[...k.values()]:void 0,partial:$||void 0},C=Buffer.byteLength(JSON.stringify(b));if(h+C>n.totalBytes){g=!0;break}h+=C,p.push(b)}return{runs:p,...g?{runsTruncated:!0}:{}}}catch(i){return{runs:[],runsError:Ct(i)}}finally{try{o?.close()}catch{}}}async function Td(t){let e=s=>Math.round(s/1048576),n=s=>lt(s).then(o=>o.isFile()?o.size:0,()=>0),r=oe(t,"tangu","state.db");return{cpus:Zu().length,memTotalMB:e(td()),memFreeMB:e(Qu()),diskFreeMB:await Xu(t).then(s=>e(s.bavail*s.bsize),()=>null),stateDbMB:e(await n(r)+await n(`${r}-wal`)),uptimeMin:Math.round(process.uptime()/60)}}var sa=t=>typeof t.diagnosticLogs=="function";function Ad(t,e=ud){let n=t?.engine;if(!n||typeof n!="object")return null;let r=(Array.isArray(n.lines)?n.lines:[]).filter(l=>typeof l=="string"&&!!l),s=r.map(l=>rr(l,vs)??""),o=s.some((l,c)=>l.length>vs||r[c].length>dn),i=s.length,a=e;for(;i>0&&Buffer.byteLength(s[i-1])+1<=a;)a-=Buffer.byteLength(s[--i])+1;return i>0&&(o=!0),{state:se(n.state,32)??null,lastError:rr(n.lastError,vs)??null,log:s.slice(i).join(`
|
|
250
|
+
`),...o?{logTruncated:!0}:{}}}function Id(t,e=pd){let n;try{n=er(t)}catch{return{}}return Object.fromEntries(e.flatMap(r=>typeof n[r]=="string"&&n[r]?[[r,n[r]]]:[]))}async function pa(t,e=fd){try{if(!(await lt(t)).isFile())return null;let n=await ia(t,Ji.O_RDONLY|(Ji.O_NOFOLLOW??0));try{let r=await n.stat();if(!r.isFile())return null;let s=Buffer.alloc(Math.min(e,r.size)),{bytesRead:o}=await n.read(s,0,s.length,0);return s.subarray(0,o).toString("utf8")}finally{await n.close()}}catch{return null}}var cn=async(t,e)=>{let n=await pa(t);return n?at(wt(n),e):void 0};async function Rd(t,e){let n=await pa(oe(t,"config.toml")),r=Object.entries(n?Id(n):{}).map(([s,o])=>[s,at(wt(o),e)??""]);return r.length?Object.fromEntries(r):void 0}async function oa(t){let e=await Ft(oe(t,".memory-state.json"));if(!e||typeof e!="object")return;let n=r=>Array.isArray(r)?r.length:0;return{entries:n(e.entries),tombstones:n(e.tombstones),revisions:n(e.revisions),processedCandidates:n(e.processedCandidateIds),updatedAt:typeof e.updatedAt=="number"?e.updatedAt:null,projectionPending:e.projectionPending===!0?!0:void 0}}async function Pd(t,e,n=dd){let r=oe(t,"tangu"),s=h=>lt(h).then(g=>g.isFile()?g.mtimeMs:0,()=>0),o=it(new Date(Xe(e))),i={agents:[],teams:[],projects:[],activity:[]},a=n.totalBytes,l=(h,g)=>{let m=Buffer.byteLength(JSON.stringify(g))+1;return m>a?(i.truncated=!0,!1):(a-=m,h.push(g),!0)},c=await cn(oe(r,"USER.md"),n.fileChars);c&&l([],c)&&(i.user=c);let u=oe(r,"state.db"),f=await lt(u).then(h=>h.isFile(),h=>h?.code==="ENOENT"?!1:Ct(h));if(typeof f=="string")i.activityError=f;else if(f){let h;try{let{DatabaseSync:g}=await import("node:sqlite");h=new g(u,{readOnly:!0}),h.exec("PRAGMA busy_timeout = 1500");let w=h.prepare(`SELECT agent, action, substr(detail, 1, ${dn}) AS detail, session_ref, created_at FROM special_agent_log
|
|
251
|
+
WHERE created_at >= ? AND created_at < ? AND (${hd.map(k=>`action GLOB '${k}*'`).join(" OR ")})
|
|
252
|
+
ORDER BY created_at DESC, rowid DESC LIMIT ?`).all(Ut(Xe(e)),Ut(e.getTime()),n.activity+1);w.length>n.activity&&(i.truncated=!0);for(let k of w.slice(0,n.activity))if(!l(i.activity,{at:se(k.created_at,40)??null,agent:se(k.agent,64)??null,action:se(k.action,64)??null,detail:typeof k.detail=="string"&&k.detail?at(wt(k.detail),n.detailChars):void 0,session:se(k.session_ref,64)}))break}catch(g){i.activityError=Ct(g)}finally{try{h?.close()}catch{}}}for(let h of await Ze(oe(r,"project-memory"),100)){let g=oe(r,"project-memory",h);if(!await un(g))continue;let m=await cn(oe(g,"MEMORY.md"),n.fileChars),w=await oa(g);if(!m&&!w)continue;let k=(await Ft(oe(g,"PROJECT.json")))?.project;if(!l(i.projects,{id:se(h,64)??null,name:typeof k=="string"?se(ca(k.replace(/[\\/]+$/,"").replace(/\\/g,"/"))):void 0,state:w,memory:m}))break}for(let h of await Ze(oe(r,"teams"),100)){if(!await un(oe(r,"teams",h)))continue;let g=await cn(oe(r,"teams",h,"TEAM.md"),n.fileChars);if(g&&!l(i.teams,{id:h,files:{"TEAM.md":g}}))break}let p=[];for(let h of await Ze(oe(r,"agents"),100)){let g=oe(r,"agents",h);await un(g)&&p.push({id:h,dir:g,at:Math.max(0,...await Promise.all([...Xi,".memory-state.json"].map(m=>s(oe(g,m)))))})}for(let{id:h,dir:g,at:m}of p.sort((w,k)=>k.at-w.at||w.id.localeCompare(k.id))){let w={};for(let $ of Xi){let b=await cn(oe(g,$),n.fileChars);b&&(w[$]=b)}let k=[];if(await un(oe(g,"LOG")))for(let $ of(await Ze(oe(g,"LOG"),400)).filter(b=>/^\d{4}-\d{2}-\d{2}\.md$/.test(b)&&b.slice(0,10)>=o&&b.slice(0,10)<=it(e))){let b=await cn(oe(g,"LOG",$),n.logChars);b&&k.push({date:$.slice(0,10),text:b})}let P=(await Ft(oe(g,".memory-dream.json")))?.last,O=await oa(g),A=await Rd(g,n.fileChars);!Object.keys(w).length&&!k.length&&!O&&!A||l(i.agents,{id:h,updatedAt:m?new Date(m).toISOString():null,config:A,state:O,dream:P&&typeof P=="object"?{state:se(P.state,32),startedAt:se(P.startedAt,40),finishedAt:se(P.finishedAt,40),calls:typeof P.calls=="number"?P.calls:void 0,detail:typeof P.detail=="string"?at(wt(P.detail),n.detailChars):void 0}:void 0,files:Object.keys(w).length?w:void 0,log:k.length?k:void 0})}return i}async function ha(t){let e=(await Ft(oe(t,"tangu","device.json")))?.deviceId;return typeof e=="string"&&/^[A-Za-z0-9_-]{1,64}$/.test(e)?e:`h${Wu("sha256").update(la()).digest("hex").slice(0,8)}`}async function Dd(t){let{home:e}=t,n=oe(e,"tangu"),r=t.now??new Date,s=i=>t.since?.[i]??Xe(r),o=Ad(t.engineLogs);return wt({schema:3,collectedAt:r.toISOString(),app:{version:t.appVersion,platform:process.platform,arch:process.arch,os:ed(),electron:process.versions.electron??null,node:process.versions.node,locale:Intl.DateTimeFormat().resolvedOptions().locale,timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,home:ca(e),cloudUrl:t.cloudUrl},device:{id:await ha(e),name:la()},system:await Td(e),config:kd(await Ft(oe(e,"config.json"))),agents:await ta(oe(n,"agents")),teams:await ta(oe(n,"teams")),plugins:{desktop:await na(oe(e,"plugins")),engine:await na(oe(n,"plugins"))},inventory:{skills:await Ze(oe(n,"skills")),spaces:await Ze(oe(e,"spaces")),themes:await Ze(oe(e,"themes"))},...t.activity?{...await _d(oe(e,"activity"),r,s("activity")),activitySince:new Date(s("activity")).toISOString()}:{},...t.sessions?{...await Cd(e,r,da,s("sessions")),sessionsSince:new Date(s("sessions")).toISOString()}:{},...(typeof t.memory=="function"?t.memory():t.memory)===!0?{memory:await Pd(e,r)}:{},...await xd(e,r),runsSince:new Date(Xe(r)).toISOString(),...o?{engine:o}:{}})}function ma(t,e={}){let n=e.now??(()=>new Date),r=e.remoteFor??(A=>Fn({baseUrl:A.cloudUrl,vault:Un,getToken:()=>A.token})),s=e.policyFor??Ss,o=()=>oe(t.homeDir(),"extend-diagnostics.json"),i=()=>{let A=$=>$&&typeof $=="object"?$:{};try{let $=JSON.parse(Ju(o(),"utf8"));return{accounts:A($?.accounts),sent:A($?.sent)}}catch{return{accounts:{},sent:{}}}},a=()=>i().accounts,l=(A,$,b)=>{let C=i();C.accounts[A]={...C.accounts[A],...$},Object.assign(C.sent,b),Vu(t.homeDir(),{recursive:!0});let E=`${o()}.${process.pid}.tmp`;Gu(E,JSON.stringify(C,null,2),{encoding:"utf8",mode:384}),Yu(E,o())},c=()=>{let A=t.readCreds();return A.token&&A.cloudUrl?t.accountId():null},u=()=>{let A=c(),$=A?a()[A]??{}:{},b=ln($.policy);return{signedIn:!!A,enabled:$.enabled===!0,activity:$.activity!==!1,sessions:$.sessions??$.enabled!==!0,memory:$.memory??$.enabled!==!0,lastUploadAt:$.lastUploadAt??null,lastError:$.lastError??null,retainDays:nr,mode:b.mode,intervalHours:b.intervalHours}},f=()=>{try{return sa(t)?t.diagnosticLogs():null}catch{return null}},p=null,h=new Map,g=async()=>{let A=c();if(!A)return!1;if(p)return p.id===A?p.done:(await p.done,g());let $={...t.readCreds()},b=n(),C=i(),E=C.accounts[A],T=$.cloudUrl.replace(/\/+$/,""),L=gs(E?.file,C.sent[T]??{},b),X=(async()=>{try{let ee=await Dd({home:t.homeDir(),appVersion:t.appVersion(),cloudUrl:$.cloudUrl,activity:E?.activity!==!1,sessions:E?.sessions===!0,now:b,since:L,engineLogs:f(),memory:()=>{let K=c()===A?a()[A]:void 0;return K?.enabled===!0&&K.memory===!0}}),te=await ha(t.homeDir()),ae=a()[A];if(c()!==A||ae?.enabled!==!0)return!1;if(ae.activity===!1)for(let K of["activity","activityTruncated","activityError","activitySince"])delete ee[K];if(ae.sessions!==!0)for(let K of["sessions","sessionsTruncated","sessionsError","sessionsSince"])delete ee[K];ae.memory!==!0&&delete ee.memory;let le=[],j=nd(ee,le);if(!j)throw new Error("snapshot too large");await ws(r($),te,j,b),h.delete(A);let q=ys(i().sent[T]??{},E?.file,L,b,ee,le);return l(A,{lastUploadAt:n().getTime(),lastError:void 0,file:q.file},{[T]:q.sent}),t.log(`[forsion-extend] diagnostics uploaded (${j.length} bytes)`),!0}catch(ee){h.set(A,n().getTime());let te=String(ee?.message||ee).slice(0,300);try{l(A,{lastError:te})}catch{}return t.log(`[forsion-extend] diagnostics upload failed: ${te}`),!1}finally{p=null}})();return p={id:A,done:X},X},m=async()=>{try{let A=c();if(!A||a()[A]?.enabled!==!0)return;let $=await s({...t.readCreds()}),b=c()===A?a()[A]:void 0;if(b?.enabled!==!0)return;$&&($.mode!==b.policy?.mode||$.intervalHours!==b.policy?.intervalHours)&&l(A,{policy:{mode:$.mode,intervalHours:$.intervalHours}}),$&&b.requestSeen===void 0&&l(A,{requestSeen:$.requestedAt});let C=$??{...ln(b.policy),requestedAt:0},E=C.requestedAt>(b.requestSeen??C.requestedAt),T=b.lastUploadAt??0,L=!T||C.mode==="scheduled"&&n().getTime()-T>=C.intervalHours*ua;if(!E&&!L||n().getTime()-(h.get(A)??-Gi)<Gi)return;await g()&&E&&l(A,{requestSeen:C.requestedAt})}catch(A){t.log(`[forsion-extend] diagnostics tick failed: ${String(A?.message||A)}`)}},w=Promise.resolve(),k={ok:!1,error:"untrusted"};t.handle("diagnostics:get",A=>t.isTrustedSender(A)?u():k),t.handle("diagnostics:set",(A,$)=>{if(!t.isTrustedSender(A))return k;let b=c();if(!b)return u();let C={};typeof $?.enabled=="boolean"&&(C.enabled=$.enabled),C.enabled&&(C.requestSeen=void 0),typeof $?.activity=="boolean"&&(C.activity=$.activity),typeof $?.sessions=="boolean"&&(C.sessions=$.sessions),typeof $?.memory=="boolean"&&(C.memory=$.memory);let E=a()[b];for(let T of["sessions","memory"])C[T]!==void 0||E?.[T]!==void 0||(E?.enabled===!0?C[T]=!1:C.enabled&&(C[T]=!0));return l(b,C),C.enabled&&(h.delete(b),w=Promise.all([w,m()]).then(()=>{})),u()}),t.handle("diagnostics:uploadNow",async A=>t.isTrustedSender(A)?(u().enabled&&await g(),u()):k);let P=setTimeout(()=>void m(),rd),O=setInterval(()=>void m(),sd);return P.unref?.(),O.unref?.(),t.log(`[forsion-extend] diagnostics registered${sa(t)?"":" (host has no diagnosticLogs: snapshots carry no engine log)"}`),Object.assign(()=>{clearTimeout(P),clearInterval(O)},{tick:m,settled:()=>w})}import{randomUUID as xa}from"node:crypto";import{appendFileSync as Bd,existsSync as qd,mkdirSync as Cs,readFileSync as Ta,renameSync as Aa,rmSync as xs,statSync as Wd,writeFileSync as Ia}from"node:fs";import{lstat as Vd}from"node:fs/promises";import{homedir as Jd,release as Yd}from"node:os";import{join as pn}from"node:path";var fn={$comment:"\u5E2E\u52A9\u6539\u8FDB Forsion(\u533F\u540D\u9065\u6D4B)\u4E8B\u4EF6\u767D\u540D\u5355 v1\u3002\u6B63\u5178\u5728\u4ED3\u6839 docs/ToBeImproved/\u9ED8\u8BA4\u6570\u636E\u91C7\u96C6\u65B9\u6848_2026-10-28/telemetry-schema.json;server(src/config/telemetry-schema.json)\u4E0E Forsion-Extend(src/core/telemetry-schema.json)\u5404\u5B58\u4E00\u4EFD\u539F\u6837\u526F\u672C,\u6539\u4E00\u5904\u4E09\u5904\u540C\u6539,\u5E76\u540C\u6B65\u9690\u79C1\u653F\u7B56\u300C\u6539\u8FDB\u6570\u636E\u300D\u4E00\u8282\u3002\u7C7B\u578B:int = 0..2147483647 \u7684\u6574\u6570;bool;enum = \u53EA\u80FD\u53D6\u5217\u51FA\u7684\u503C;id = \u5339\u914D ^[A-Za-z0-9._:/@+-]{1,max}$ \u7684\u77ED\u4E32;text = \u81EA\u7531\u6587\u672C,\u5FC5\u987B\u5148\u8FC7 sanitize \u518D\u622A\u5230 max\u3002\u4E0D\u5728\u8868\u91CC\u7684\u4E8B\u4EF6\u4E0E\u5B57\u6BB5\u4E00\u5F8B\u4E22\u3002",version:1,limits:{maxBatchBytes:65536,maxEvents:200},envelope:{installId:{type:"uuid"},app:{type:"enum",values:["desktop","web","mobile"]},appVersion:{type:"id",max:40},coreVersion:{type:"id",max:40},channel:{type:"enum",values:["stable","beta"]},os:{type:"enum",values:["darwin","win32","linux","android","ios","other"]},osVersion:{type:"id",max:40},arch:{type:"enum",values:["arm64","x64","ia32","other"]},locale:{type:"enum",values:["zh","en"]},region:{type:"enum",values:["CN","other"]}},eventFields:{event:{type:"enum",values:["crash","agent_run","tool_call","perf","feature"]},ts:{type:"iso-time"},sessionId:{type:"uuid"}},events:{crash:{process:{type:"enum",values:["main","renderer","engine","plugin-host","extend","other"]},errorName:{type:"id",max:60},stack:{type:"stack",max:4e3},uptimeS:{type:"int"},exitCode:{type:"int"},reason:{type:"enum",values:["exception","rejection","crashed","oom","killed","abnormal-exit","launch-failed","integrity-failure","other"]},pluginId:{type:"id",max:64}},agent_run:{modelId:{type:"id",max:80},providerKind:{type:"enum",values:["forsion","codex","byok","local","other"]},mode:{type:"enum",values:["chat","agent","muse","historian","team","task","other"]},steps:{type:"int"},llmCalls:{type:"int"},tokensIn:{type:"int"},tokensOut:{type:"int"},tokensCached:{type:"int"},retries:{type:"int"},durationMs:{type:"int"},outcome:{type:"enum",values:["done","error","aborted","other"]},errorClass:{type:"enum",values:["timeout","rate_limit","auth","network","context_length","upstream","tool","aborted","other"]}},tool_call:{tool:{type:"id",max:80},calls:{type:"int"},failures:{type:"int"},totalMs:{type:"int"},maxMs:{type:"int"},runOutcome:{type:"enum",values:["done","error","aborted","other"]}},perf:{kind:{type:"enum",values:["startup","hourly"]},startupMs:{type:"int"},engineReadyMs:{type:"int"},rssMb:{type:"int"},heapMb:{type:"int"},longTasks:{type:"int"}},feature:{name:{type:"enum",values:["space_open","view_open","plugin_open","setting_change"]},kind:{type:"id",max:60},id:{type:"id",max:80},key:{type:"id",max:80},value:{type:"id",max:40}}}};var Od=fn.events,Md=fn.envelope,_s=fn.limits,wa=fn.version,Nd=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,jd=/^[A-Za-z0-9._:/@+-]+$/,ba=t=>typeof t=="string"&&Nd.test(t),ga=/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g,Fd=[[/\/Users\/[^/\s]+\//gi,"~/"],[/\/home\/[^/\s]+\//gi,"~/"],[/[a-z]:\\Users\\[^\\\s]+\\/gi,"~\\"],[/~([/\\])[^\s"'`」:()]+/g,"~$1\u2026"],[/\/Volumes\/[^\s"'`」:()]+/g,"/Volumes/\u2026"],[/\b([d-z]):\\[^\s"'`」:()]+/gi,"$1:\\\u2026"],[/forsion-agent-space\/[^/\s]+\//g,"forsion-agent-space/\u2026/"],[/"[^"]{1,200}"/g,'"\u2026"'],[/'[^']{1,200}'/g,"'\u2026'"],[/`[^`]{1,200}`/g,"`\u2026`"],[/「[^「」]{1,200}」/g,"\u300C\u2026\u300D"],[/(https?:\/\/[^\s?#"'`」]+)[?#][^\s"'`」]*/gi,"$1"],[/sk-[A-Za-z0-9_-]{10,}/g,"[redacted]"],[/Bearer\s+\S+/gi,"[redacted]"],[/[0-9a-f]{32,}/gi,"[redacted]"],[/[A-Za-z0-9+/]{40,}={0,2}/g,"[redacted]"],[/[A-Za-z0-9_-]{40,}/g,"[redacted]"],[/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g,"[email]"]],Sa=t=>Fd.reduce((e,[n,r])=>e.replace(n,r),t);function ya(t,e,n){let r=t.slice(0,2e4).replace(/\u0000/g,"").replace(ga,"\uFFFD");return n&&n.length>3&&(r=r.split(n).join("~")),r=Sa(r),(r.length>e?r.slice(0,e):r).replace(ga,"\uFFFD")}var Ud=/^pr-[a-f0-9]{48}$/,Ld=/^market-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,zd=t=>Ud.test(t)||Ld.test(t)||Sa(t)===t;function Hd(t){if(typeof t!="string")return"";let e=t.search(/^\s+at /m);return e<0?"":t.slice(e)}function Es(t,e,n){switch(t.type){case"enum":return typeof e=="string"&&t.values.includes(e)?e:void 0;case"int":return typeof e=="number"&&Number.isFinite(e)&&e>=0?Math.min(Math.round(e),2147483647):void 0;case"bool":return typeof e=="boolean"?e:void 0;case"uuid":return ba(e)?e.toLowerCase():void 0;case"iso-time":return typeof e=="string"&&!Number.isNaN(Date.parse(e))?new Date(e).toISOString():void 0;case"id":return typeof e=="string"&&e.length<=t.max&&jd.test(e)&&zd(e)?e:void 0;case"text":return typeof e=="string"&&e?ya(e,t.max,n):void 0;case"stack":{let r=Hd(e);return r?ya(r,t.max,n):void 0}}}function sr(t,e){let n=typeof t?.event=="string"?Od[t.event]:void 0;if(!n)return null;let r={},s=t.props&&typeof t.props=="object"?t.props:{};for(let[i,a]of Object.entries(n)){let l=Es(a,s[i],e);l!==void 0&&(r[i]=l)}let o=Es({type:"iso-time"},t.ts);return{event:t.event,ts:o??new Date().toISOString(),...ba(t.sessionId)?{sessionId:t.sessionId.toLowerCase()}:{},props:r}}function va(t){let e={};for(let[n,r]of Object.entries(Md)){if(n==="installId")continue;let s=Es(r,t[n]);e[n]=typeof s=="string"?s:null}return e}function ka(t,e){if(e==="aborted")return"aborted";if(!t)return;let n=t.toLowerCase();return/abort|cancel/.test(n)?"aborted":/timeout|timed out|etimedout/.test(n)?"timeout":/\b429\b|rate.?limit|too many requests|quota/.test(n)?"rate_limit":/\b40[13]\b|unauthori[sz]ed|forbidden|invalid api key|authentication/.test(n)?"auth":/context.{0,20}(length|window|too long)|maximum context|too many tokens|prompt is too long/.test(n)?"context_length":/econn|enotfound|eai_again|socket|network|fetch failed|getaddrinfo/.test(n)?"network":/\b5\d\d\b|upstream|bad gateway|overloaded|service unavailable/.test(n)?"upstream":/tool/.test(n)?"tool":"other"}function Ea(t){return t==="done"?"done":t==="failed"?"error":t==="aborted"?"aborted":"other"}function _a(t){return t?/^pr-/.test(t)?"forsion":/^codex\//.test(t)?"codex":/^(?:ollama|lmstudio|local)[/:]/i.test(t)?"local":"byok":"other"}function Ca(t){return{user:"chat",agent:"agent",muse:"muse",historian:"historian",teamwork:"team",discussion:"team",subagent:"task"}[t||"user"]??"other"}var Gd=10*6e4,Kd=6e4,Xd=50,Ra=1024*1024,Zd=168*36e5,Pa=15e3,Qd=200,ef=2e3,$a=t=>new Date(t).toISOString().slice(0,19).replace("T"," "),Da=t=>({at:$a(t),id:"~"}),or=t=>typeof t=="string"?Date.parse(`${t.replace(" ","T")}Z`):NaN;async function tf(t,e,n,r){let s=pn(t,"tangu","state.db");if(!await Vd(s).then(i=>i.isFile(),()=>!1))return{events:[],cursor:e};let o;try{let{DatabaseSync:i}=await import("node:sqlite");o=new i(s,{readOnly:!0}),o.exec("PRAGMA busy_timeout = 1500");let a=o.prepare(`SELECT r.id, r.status, r.current_step, r.model_id, substr(r.error, 1, 2000) AS error, r.created_at, r.updated_at, s.kind
|
|
253
|
+
FROM agent_runs r LEFT JOIN chat_sessions s ON s.id = r.session_id
|
|
254
|
+
WHERE r.status IN ('done', 'failed', 'aborted') AND (r.updated_at > ? OR (r.updated_at = ? AND r.id > ?)) AND r.updated_at < ?
|
|
255
|
+
ORDER BY r.updated_at, r.id LIMIT ?`).all(e.at,e.at,e.id,r??"9999-12-31 23:59:59",Qd),l=o.prepare(`SELECT e.type, json_extract(e.payload, '$.name') AS name, json_extract(e.payload, '$.isError') AS failed, json_extract(e.payload, '$.elapsedMs') AS ms,
|
|
256
|
+
json_extract(e.payload, '$.prompt') AS prompt, json_extract(e.payload, '$.completion') AS completion, json_extract(e.payload, '$.cached') AS cached,
|
|
257
|
+
json_extract(e.payload, '$.phase') AS phase
|
|
258
|
+
FROM agent_run_events e WHERE e.run_id = ? AND e.type IN ('usage', 'tool_result', 'status') AND json_valid(e.payload) ORDER BY e.seq LIMIT ?`),c=p=>typeof p=="number"&&Number.isFinite(p)&&p>0?p:0,u=[],f=e;for(let p of a){f={at:String(p.updated_at),id:String(p.id)};let h={llmCalls:0,tokensIn:0,tokensOut:0,tokensCached:0,retries:0},g=new Map;for(let O of l.all(p.id,ef))if(O.type==="usage")h.llmCalls++,h.tokensIn+=c(O.prompt),h.tokensOut+=c(O.completion),h.tokensCached+=c(O.cached);else if(O.type==="tool_result"&&typeof O.name=="string"){let A=O.name.startsWith("mcp__")?"mcp":O.name,$=g.get(A)??{calls:0,failures:0,totalMs:0,maxMs:0};g.set(A,$),$.calls++,O.failed&&$.failures++,$.totalMs+=c(O.ms),$.maxMs=Math.max($.maxMs,c(O.ms))}else O.phase==="llm_retry"&&h.retries++;let m=Ea(p.status),w=or(p.updated_at)-or(p.created_at),k=new Date(Number.isNaN(or(p.updated_at))?Date.now():or(p.updated_at)).toISOString(),P=sr({event:"agent_run",ts:k,sessionId:n,props:{modelId:p.model_id,providerKind:_a(p.model_id),mode:Ca(p.kind),steps:c(p.current_step),...h,durationMs:Number.isFinite(w)&&w>=0?w:void 0,outcome:m,errorClass:m==="done"?void 0:ka(p.error,p.status)}});P&&u.push(P);for(let[O,A]of g){let $=sr({event:"tool_call",ts:k,sessionId:n,props:{tool:O,...A,runOutcome:m}});$&&$.props.tool&&u.push($)}}return{events:u,cursor:f}}catch{return{events:[],cursor:e}}finally{try{o?.close()}catch{}}}var nf=t=>["darwin","win32","linux"].includes(t)?t:"other",rf=t=>["arm64","x64","ia32"].includes(t)?t:"other",sf=()=>/^zh\b/i.test(Intl.DateTimeFormat().resolvedOptions().locale)?"zh":"en";function Oa(t,e={}){let n=e.now??(()=>new Date),r=e.fetch??fetch,s=()=>t.homeDir(),o=()=>pn(s(),"extend-telemetry.json"),i=()=>pn(s(),"telemetry"),a=()=>pn(i(),"queue.jsonl"),l=()=>pn(i(),"sent.jsonl"),c=t.telemetry,u=()=>{try{let j=JSON.parse(Ta(o(),"utf8"));return j&&typeof j=="object"?j:{}}catch{return{}}},f=j=>{let q={...u(),...j};Cs(s(),{recursive:!0});let K=`${o()}.${process.pid}.tmp`;return Ia(K,JSON.stringify(q,null,2),{encoding:"utf8",mode:384}),Aa(K,o()),q},p=()=>u().installId??f({installId:xa()}).installId,h=(j=u())=>j.enabled!==!1&&j.noticeSeen===!0&&c?.packaged===!0,g=j=>{try{return Ta(j,"utf8").split(`
|
|
259
|
+
`).filter(Boolean)}catch{return[]}},m=()=>g(a()).flatMap(j=>{try{return[JSON.parse(j)]}catch{return[]}}),w=(j,q)=>{if(Cs(i(),{recursive:!0}),!q.length){xs(j,{force:!0});return}let K=`${j}.${process.pid}.tmp`;Ia(K,q.map(Y=>JSON.stringify(Y)).join(`
|
|
260
|
+
`)+`
|
|
261
|
+
`,{encoding:"utf8",mode:384}),Aa(K,j)},k=()=>{xs(a(),{force:!0}),xs(l(),{force:!0})},P=()=>{let j=n().getTime(),q=g(l()).flatMap(Y=>{try{return[JSON.parse(Y)]}catch{return[]}}),K=q.filter(Y=>j-Y.at<Zd);return K.length!==q.length&&w(l(),K),K},O=0,A=!1,$=0,b=j=>{if(!(!j.length||!h())){Cs(i(),{recursive:!0}),Bd(a(),j.map(q=>JSON.stringify(q)).join(`
|
|
262
|
+
`)+`
|
|
263
|
+
`,{encoding:"utf8",mode:384});try{if(Wd(a()).size>Ra){let q=m(),K=q.length,Y=0;for(;K>0&&Y+Buffer.byteLength(JSON.stringify(q[K-1]))+1<=Ra/2;)Y+=Buffer.byteLength(JSON.stringify(q[--K]))+1;w(a(),q.slice(K))}}catch{}m().length>=Xd&&L()}},C=()=>{let j=u();return{available:!!c,enabled:j.enabled!==!1,noticeSeen:j.noticeSeen===!0,active:h(j),packaged:c?.packaged===!0,installId:p(),queued:qd(a())?m().length:0,lastSentAt:j.lastSentAt??null,lastError:j.lastError??null}},E=()=>va({app:"desktop",appVersion:t.appVersion(),coreVersion:c?.coreVersion()??void 0,channel:c?.channel(),os:nf(process.platform),osVersion:Yd(),arch:rf(process.arch),locale:sf()}),T=null,L=()=>{if(T)return T;if(A||n().getTime()<$)return Promise.resolve();let j=O,q=(async()=>{try{for(let K=0;K<5;K++){let Y=m();if(!Y.length)return;let ce=p(),me={v:wa,installId:ce,...E()},Ce=[],pe=Buffer.byteLength(JSON.stringify({...me,events:[]}));for(let _ of Y){let I=Buffer.byteLength(JSON.stringify(_))+1;if(Ce.length>=_s.maxEvents||pe+I>_s.maxBatchBytes)break;Ce.push(_),pe+=I}if(!Ce.length){w(a(),Y.slice(1));continue}let{base:fe}=await t.getCloud(),Q={...me,events:Ce};if(!h()||j!==O)return;let x=await r(`${fe.replace(/\/+$/,"")}/api/telemetry/batch`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(Q),signal:AbortSignal.timeout(Pa)}).catch(_=>({ok:!1,status:0,error:String(_?.message||_)})),R=x.status;if(R>=200&&R<300||R===400||R===413){let _=new Set(Ce.map(I=>JSON.stringify(I)));w(a(),m().filter(I=>!_.has(JSON.stringify(I))))}if(R>=200&&R<300){let _=n().getTime();h()&&j===O&&w(l(),[...P(),{at:_,body:Q}]),f({lastSentAt:_,lastError:void 0});continue}if(R!==400&&R!==413){let _=Number(x.headers?.get?.("retry-after"));$=n().getTime()+(Number.isFinite(_)&&_>0?Math.min(_,3600)*1e3:5*6e4)}f({lastError:R?`HTTP ${R}`:String(x.error??"network error").slice(0,200)});return}}catch(K){try{f({lastError:String(K?.message||K).slice(0,200)})}catch{}}})();return T=q,q.finally(()=>{T===q&&(T=null)}),q},X=async()=>{try{P();let j=u();if(!h(j))return;let q=O,K=j.cursor??Da(n().getTime()),Y=await tf(s(),K,c?.sessionId,$a(n().getTime()));if(!h()||q!==O)return;b(Y.events),Y.cursor!==K&&f({cursor:Y.cursor}),await L()}catch(j){t.log(`[forsion-extend] telemetry tick failed: ${String(j?.message||j)}`)}},ee=c?.subscribe(j=>{try{if(!h())return;let q=sr({...j,sessionId:c.sessionId},Jd());q&&b([q])}catch(q){t.log(`[forsion-extend] telemetry event dropped: ${String(q?.message||q)}`)}}),te={ok:!1,error:"untrusted"};t.handle("telemetry:get",j=>t.isTrustedSender(j)?C():te),t.handle("telemetry:set",(j,q)=>{if(!t.isTrustedSender(j))return te;let K=u(),Y={};typeof q?.enabled=="boolean"&&(Y.enabled=q.enabled),q?.noticeSeen===!0&&(Y.noticeSeen=!0);let ce={...K,...Y};return!h(K)&&h(ce)&&(Y.cursor=Da(n().getTime())),h(K)&&!h(ce)&&O++,f(Y),Y.enabled===!1&&k(),C()}),t.handle("telemetry:sent",j=>t.isTrustedSender(j)?{batches:P()}:te),t.handle("telemetry:delete",async j=>{if(!t.isTrustedSender(j))return te;A=!0,O++;try{await T?.catch(()=>{});let q=p(),{base:K}=await t.getCloud(),ce=(await r(`${K.replace(/\/+$/,"")}/api/telemetry/install/${q}`,{method:"DELETE",signal:AbortSignal.timeout(Pa)}).catch(me=>({ok:!1,status:0,error:String(me?.message||me)}))).status;return ce>=200&&ce<300?(k(),f({installId:xa(),lastSentAt:void 0,lastError:void 0}),C()):{ok:!1,error:ce?`HTTP ${ce}`:"network error"}}finally{A=!1}});let ae=setTimeout(()=>void X(),Kd),le=setInterval(()=>void X(),Gd);return ae.unref?.(),le.unref?.(),t.log(`[forsion-extend] telemetry registered (${c?c.packaged?"packaged":"dev build: never sends":"host has no telemetry seam: never sends"})`),Object.assign(()=>{clearTimeout(ae),clearInterval(le),ee?.()},{tick:X,flush:L})}import{readFileSync as hn,lstatSync as tl,renameSync as kf,linkSync as Ef,unlinkSync as Xa,readdirSync as _f,rmdirSync as Cf,writeFileSync as xf,mkdirSync as Tf,copyFileSync as Af,constants as If}from"node:fs";import{readFile as pr,writeFile as hr,mkdir as js,rename as Fs,readdir as Za,lstat as mr,stat as gr,unlink as yr}from"node:fs/promises";import{join as ze,dirname as wr,relative as Us,sep as Ls}from"node:path";import{hostname as Rf}from"node:os";import{randomUUID as tt}from"node:crypto";import{isUtf8 as Pf}from"node:buffer";import{Readable as Qa}from"node:stream";var Ma={version:1,revision:0,enabled:!1,rules:[{id:"default",source:"",target:"default"}]};function bt(t,e=!1){if(typeof t!="string"||!t&&!e||t.length>512||t.startsWith("/")||/[\\\u0000-\u001f\u007f]/.test(t)||t&&t.split("/").some(n=>!n||n==="."||n===".."||n.endsWith(".")||n.endsWith(" ")||n.startsWith(".forsion-sync")))throw Error("Invalid content path");return t}function of(t){if(t==="default"||t==="off"||typeof t=="string"&&/^device-[A-Za-z0-9_-]{1,64}$/.test(t))return t;throw Error("Invalid content target")}function Ts(t,e){let n=t;if(!n||n.version!==1||typeof n.enabled!="boolean"||!Array.isArray(n.rules)||n.rules.length>512)throw Error("Invalid content sync configuration");let r=new Set,s=new Set,o=n.rules.map(i=>{let a=bt(i.source,!0),l=of(i.target);if(typeof i.id!="string"||!/^[A-Za-z0-9_-]{1,80}$/.test(i.id)||s.has(i.id)||r.has(a))throw Error("Duplicate or invalid sync rule");return s.add(i.id),r.add(a),{id:i.id,source:a,target:l,...i.sourceId&&/^[a-f0-9-]{36}$/i.test(i.sourceId)?{sourceId:i.sourceId}:{}}});return{version:1,revision:e,enabled:n.enabled,rules:o}}function ir(t,e){let n=null;for(let r of e)(!r.source||t===r.source||t.startsWith(r.source+"/"))&&(!n||r.source.length>n.source.length)&&(n=r);return n}var ct={get:"penzor:sync:get",preview:"penzor:sync:preview",apply:"penzor:sync:apply",run:"penzor:sync:run",pause:"penzor:sync:pause",retry:"penzor:sync:retry",rename:"penzor:sync:rename",setup:"penzor:sync:setup"},Na=t=>t.replace(/\.local$/i,"").replace(/[-_]+/g," ").trim()||t,ja=["Amadeus","agents","human","Plugins"];var Lt=[{id:"notes",path:"Amadeus"},{id:"agents",path:"agents"},{id:"profile",path:"human"},{id:"plugins",path:"Plugins"}];var ar=(t,e)=>ir(e,t)?.target??"off",Fa=(t,e)=>t===e||t.startsWith(e+"/"),af=t=>Lt.some(e=>Fa(t,e.path)),As=t=>t.some(e=>e.id==="default")?Rs():"default";function Ua(t,e,n){n==="off"&&(t=t.filter(o=>e?!o.source.startsWith(e+"/"):!o.source||af(o.source)));let r=t.find(o=>o.source===e),s=t.filter(o=>o!==r);return e&&ar(s,e)===n?s:r?t.map(o=>o===r?{...o,target:n}:o):[...t,{id:e?Rs():As(t),source:e,target:n}]}function Is(t,e,n,r=!1){let s=t.rules;if(!t.enabled){let o=s.find(a=>!a.source),i=e?s.filter(a=>a.source&&Fa(a.source,e)):[];s=[{id:o?.id??As(i),source:"",target:"off"},...i]}if(!e)for(let o of Lt)s.some(i=>i.source===o.path)||(s=[...s,{id:Rs(),source:o.path,target:ar(s,o.path)}]);return lf({...t,rules:Ua(s,e,n)},r)}function lf(t,e=!1){let n=r=>ar(t.rules,r)!=="off";return{...t,enabled:Lt.some(r=>n(r.path))||t.rules.some(r=>r.source&&r.target!=="off")||e&&n("")}}function La(t){let e=t.rules.some(n=>n.source==="")?t.rules:[{id:As(t.rules),source:"",target:"default"},...t.rules];for(let n of Lt)ar(e,n.path)==="off"&&(e=Ua(e,n.path,"default"));return{...t,enabled:!0,rules:e}}var cf=0,Rs=()=>`rule-${Date.now().toString(36)}-${(cf++).toString(36)}`;import{constants as za,lstatSync as lr,readFileSync as uf,renameSync as Ps,unlinkSync as df,linkSync as ff,mkdirSync as cr,realpathSync as pf,rmdirSync as hf}from"node:fs";import{open as Ha,lstat as Ds,readdir as mf,realpath as Ba,readFile as $s,writeFile as gf,mkdir as qa,unlink as yf}from"node:fs/promises";import{join as xt,dirname as Wa,relative as Os,sep as ur}from"node:path";import{randomUUID as Va,createHash as wf}from"node:crypto";var Ja=".forsion-sync-id.json",bf=new Set([".git","node_modules",".DS_Store",".Trash",".trash","__pycache__",".cache"]),Sf=t=>!bf.has(t)&&!t.startsWith(".forsion-sync")&&!/\.tmp-[0-9]|\.lock$|-(wal|shm)$/.test(t)&&(!t.startsWith(".")||t===".memory-tombstones.json"),Re=t=>wf("sha256").update(t).digest("hex");function Ya(t){if(process.platform==="win32"&&t.split("/").some(e=>/[:*?"<>|]/.test(e)||/^(con|prn|aux|nul|com[1-9¹²³]|lpt[1-9¹²³])(?:\..*)?$/i.test(e)))throw Error("This name is not a safe Windows file destination")}async function Qe(t,e,n=!1){if(n){if(e.split("/").some(a=>a===".."||a==="."||!a)||e.startsWith("/")||e.includes("\\"))throw Error("Invalid internal content path")}else bt(e,!0);Ya(e);let r=await Ba(t),s=xt(r,...e.split("/").filter(Boolean)),o=Os(r,s);if(o===".."||o.startsWith(".."+ur))throw Error("Content path escapes root");let i=r;for(let a of o.split(ur).filter(Boolean)){i=xt(i,a);try{if((await Ds(i)).isSymbolicLink())throw Error("Content symlinks are not synchronized")}catch(l){if(l.code!=="ENOENT")throw l}}return s}function et(t,e,n=!1){if(n||bt(e,!0),Ya(e),e.split("/").some(o=>o===".."||o===".")||e.startsWith("/")||e.includes("\\"))throw Error("Unsafe sync path");let s=pf(t);for(let o of e.split("/").filter(Boolean)){s=xt(s,o);try{if(lr(s).isSymbolicLink())throw Error("Content symlinks are not synchronized")}catch(i){if(i.code!=="ENOENT")throw i}}return s}async function dr(t){let e=new Map,n=t.filter(s=>s.prefix).map(s=>s.prefix),r=[];for(let s of t)try{r.push({...s,root:await Ba(s.root)})}catch(o){if(o.code!=="ENOENT")throw o}if(new Set(r.map(s=>s.root)).size!==r.length)throw Error("Managed roots refer to the same directory; choose a separate vault folder");for(let s of r){let o=s.root;if(!(await Ds(o)).isDirectory())throw Error(`Sync root is not a directory: ${s.prefix||"Forsion"}`);let i=async(a,l)=>{let c=await Ds(a);if(!c.isSymbolicLink()&&!(a!==o&&r.some(u=>u!==s&&u.root===a))&&!(l&&s.prefix===""&&n.some(u=>l===u||l.startsWith(u+"/")))){if(l){bt(l);let u;if(c.isDirectory())try{let f=JSON.parse(await $s(xt(a,Ja),"utf8"));/^[a-f0-9-]{36}$/i.test(f.id)&&(u=f.id)}catch(f){if(f.code!=="ENOENT"&&!(f instanceof SyntaxError))throw f}e.set(l,{path:l,physical:a,root:o,kind:c.isDirectory()?"folder":"file",localId:u,size:c.isFile()?c.size:0,mtime:c.mtimeMs,inode:`${c.dev}:${c.ino}:${c.birthtimeMs}`})}if(c.isDirectory())for(let u of await mf(a,{withFileTypes:!0}))!Sf(u.name)||!u.isDirectory()&&!u.isFile()||await i(xt(a,u.name),l?`${l}/${u.name}`:u.name)}};await i(o,s.prefix)}return[...e.values()].sort((s,o)=>s.path.split("/").length-o.path.split("/").length||s.path.localeCompare(o.path))}async function Ms(t){if(t.kind!=="folder")throw Error("Folder identity required");if(t.localId)return t.localId;let e=await Qe(t.root,Os(t.root,xt(t.physical,Ja)).split(ur).join("/"),!0),n=Va();try{let r=await Ha(e,"wx",384);try{await r.writeFile(JSON.stringify({version:1,id:n})+`
|
|
264
|
+
`)}finally{await r.close()}return t.localId=n,n}catch(r){if(r.code!=="EEXIST")throw r;let s=JSON.parse(await $s(e,"utf8"));if(!/^[a-f0-9-]{36}$/i.test(s.id))throw Error("Invalid folder sync identity");return t.localId=s.id,s.id}}async function fr(t){let e=await Qe(t.root,Os(t.root,t.physical).split(ur).join("/")),n=await Ha(e,za.O_RDONLY|(za.O_NOFOLLOW||0));try{if((await n.stat()).size>50*1024*1024)throw Error("File exceeds 50 MB content limit");return await n.readFile()}finally{await n.close()}}function St(t,e){bt(e);let n=[...t].sort((r,s)=>s.prefix.length-r.prefix.length).find(r=>!r.prefix||e===r.prefix||e.startsWith(r.prefix+"/"));if(!n)throw Error("Content root unavailable");return{root:n.root,relative:n.prefix?e.slice(n.prefix.length).replace(/^\//,""):e}}async function Ga(t,e,n,r,s=async(o,i)=>i()){let o=St(t,e);await qa(o.root,{recursive:!0});let i=await Qe(o.root,o.relative),a=await $s(i).catch(c=>{if(c.code==="ENOENT")return null;throw c});if((a?Re(a):null)!==r)throw Error("Local file changed during download");let l=xt(o.root,`.forsion-sync-${Va()}.tmp`);try{await gf(l,n,{flag:"wx",mode:384}),await Qe(o.root,o.relative),await s(i,()=>{et(o.root,o.relative),cr(Wa(i),{recursive:!0}),et(o.root,o.relative);let c=null;try{c=uf(i)}catch(u){if(u.code!=="ENOENT")throw u}if((c?Re(c):null)!==r)throw Error("Local file changed during download");Ps(l,i)})}finally{await yf(l).catch(()=>{})}}async function Ka(t,e,n=async(r,s)=>s()){let r=St(t,e);await qa(r.root,{recursive:!0});let s=await Qe(r.root,r.relative);await n([s],()=>{et(r.root,r.relative),cr(s,{recursive:!0})})}async function Ns(t,e,n,r=async(s,o)=>o()){let s=St(t,e),o=St(t,n);if(s.root!==o.root)throw Error("Folder move crosses a managed source");let i=await Qe(s.root,s.relative),a=await Qe(o.root,o.relative);await r([i,a],()=>{if(et(s.root,s.relative),et(o.root,o.relative),vf(a))throw Error("Local rename destination exists");cr(Wa(a),{recursive:!0});let l=lr(i);if(l.isDirectory()){if(process.platform==="win32"){Ps(i,a);return}cr(a,{mode:448});try{Ps(i,a)}catch(c){try{hf(a)}catch{}throw c}}else{ff(i,a);let c=lr(i);if(c.ino!==l.ino||c.dev!==l.dev)throw Error("Source changed during rename");df(i)}})}function vf(t){try{return lr(t),!0}catch(e){if(e.code==="ENOENT")return!1;throw e}}var Df=()=>({config:structuredClone(Ma),owned:!1,paused:!1,folders:{},files:{},jobs:[]}),mn=50*1024*1024,el=1024*1024,Oe=(t,e)=>`${t}:${e}`,gn=t=>t.includes("/")?t.slice(0,t.lastIndexOf("/")):"",yn=t=>t.slice(t.lastIndexOf("/")+1),vt=t=>t.split("/").length,nt=t=>t instanceof Error?t.message:String(t),zs=t=>t.file.replace(/\.json$/,".bases");function nl(t){if(!t.contentSync)return;let e=new Hs(t);for(let[n,r]of Object.entries({[ct.get]:()=>e.snapshot(),[ct.preview]:s=>e.preview(s),[ct.apply]:s=>e.apply(typeof s=="string"?s:""),[ct.run]:()=>e.run(),[ct.pause]:s=>e.pause(s===!0),[ct.retry]:()=>e.run(),[ct.rename]:s=>e.rename(s),[ct.setup]:s=>e.setup(s)}))t.handle(n,async(s,...o)=>{if(!t.isTrustedSender(s))return{ok:!1,error:"untrusted"};try{return{ok:!0,value:await r(...o)}}catch(i){return{ok:!1,error:nt(i)}}});t.addQuitGuard?.(n=>e.running?{message:n==="zh"?"\u8FD8\u6709\u5185\u5BB9\u6B63\u5728\u540C\u6B65":"Content is still syncing"}:null),e.start()}var Hs=class{session=null;initializing=null;previewValue=null;watcher=null;sources=[];devices=[];others;deviceId="";customName="";serial=Promise.resolve();scheduled=null;tick=null;first=null;blocked=new Map;phase="idle";error;closed=!1;runFinished=Promise.resolve();running=!1;host;options;constructor(e,n={}){this.host=e,this.options=n}start(){(this.tick=setInterval(()=>{this.getSession().then(r=>{r.stored.config.enabled&&!r.stored.paused&&this.run()}).catch(r=>{this.error=nt(r)})},3e4)).unref?.(),(this.first=setTimeout(()=>{this.getSession().then(r=>{r.stored.config.enabled&&this.run()}).catch(r=>{this.error=nt(r)})},5e3)).unref?.()}async close(){this.closed=!0,this.tick&&clearInterval(this.tick),this.first&&clearTimeout(this.first),this.scheduled&&clearTimeout(this.scheduled),this.session?.abort.abort(),await this.watcher?.close(),await this.runFinished}guard(e,n=!0){if(this.closed)throw Error("content_sync_closed");if(this.host.accountId()!==e.account||this.session!==e)throw Error("account_changed");n&&e.abort.signal.throwIfAborted()}async persist(e){let n=e.writes.catch(()=>{}).then(async()=>{this.guard(e,!1),await js(wr(e.file),{recursive:!0,mode:448});let r=e.file+".tmp-"+tt();try{await hr(r,JSON.stringify(e.stored),{mode:384,flag:"wx"}),this.guard(e,!1),await Fs(r,e.file)}finally{await yr(r).catch(()=>{})}});return e.writes=n,n}async getSession(){let e=this.host.accountId();if(!e)throw this.session?.abort.abort(),this.session=null,Error("not_signed_in");return this.session?.account===e?this.session:this.initializing?this.initializing.then(n=>(this.guard(n),n)):(this.session?.abort.abort(new Error("account_changed")),await this.watcher?.close(),this.watcher=null,this.previewValue=null,this.sources=[],this.devices=[],this.initializing=(async()=>{let n=ze(this.host.homeDir(),"content-sync"),r=ze(n,Re(e)+".json"),s=Df();try{let c=JSON.parse(await pr(r,"utf8"));s={...s,...c,config:Ts(c.config,c.config.revision)},s.jobs=Array.isArray(c.jobs)?c.jobs.slice(-200):[]}catch(c){if(c.code!=="ENOENT")throw Error("Invalid content sync state; original data was retained")}let o,i=ze(this.host.homeDir(),"content-sync-device.json");try{if(o=JSON.parse(await pr(i,"utf8")),!/^[A-Za-z0-9_-]{1,64}$/.test(o.id))throw Error("Invalid device sync ID")}catch(c){if(c.code!=="ENOENT")throw c;o={id:tt()},await js(wr(i),{recursive:!0});try{await hr(i,JSON.stringify(o),{flag:"wx",mode:384})}catch(u){if(u.code!=="EEXIST")throw u;o=JSON.parse(await pr(i,"utf8"))}}if(this.host.accountId()!==e)throw Error("account_changed");this.deviceId=o.id,this.customName=typeof o.name=="string"?o.name:"";let a=await this.host.contentSync.roots();if(this.host.accountId()!==e)throw Error("account_changed");let l={account:e,file:r,stored:s,roots:a,abort:new AbortController,writes:Promise.resolve()};return this.session=l,await this.recoverTrash(l),s.owned&&await this.host.contentSync.claim(!0),this.setSources(await this.scan(l,a).catch(c=>(this.error=nt(c),[]))),await this.json(l,"devices",`/${encodeURIComponent(this.deviceId)}`,"PUT",{name:this.deviceName()}),this.devices=(await this.json(l,"devices")).devices,await this.watchRoots(l),l})().catch(n=>{throw this.session?.account===e&&(this.session.abort.abort(),this.session=null),n}).finally(()=>{this.initializing=null}),this.initializing)}async scan(e,n=e.roots){for(let r of e.stored.roots??[]){let s=n.find(i=>i.prefix===r.prefix);if(!s||s.root!==r.root)throw Error("content_roots_changed_preview_required");let o=await gr(r.root).catch(()=>{throw Error(`Sync root unavailable: ${r.prefix||"Forsion"}`)});if(!o.isDirectory()||r.dev!==void 0&&(o.dev!==r.dev||o.ino!==r.ino))throw Error("Sync root changed; preview before rebinding")}return dr(n)}async write(e,n,r,s){this.guard(e),await Ga(e.roots,n,r,s,(o,i)=>this.lock(e,o,i)),await this.recordRoots(e)}async recordRoots(e){this.guard(e);let n=!1;for(let r of e.roots){if(e.stored.roots?.some(o=>o.prefix===r.prefix&&o.root===r.root))continue;let s=await gr(r.root).catch(o=>{if(o.code==="ENOENT")return null;throw o});if(s){if(!s.isDirectory())throw Error("Sync root is not a directory");(e.stored.roots??=[]).push({...r,dev:s.dev,ino:s.ino}),n=!0}}n&&await this.persist(e)}lock(e,n,r,s=!1){let o=()=>{if(this.guard(e),e.stored.paused&&!s)throw Error("paused");r()};return this.host.contentSync.withWriteLock?.(n,o)??Promise.resolve().then(o)}async previewScan(e,n){for(let r of e.stored.roots??[])n.some(s=>s.prefix===r.prefix&&s.root===r.root)&&await mr(r.root).catch(()=>{throw Error(`Sync root unavailable: ${r.prefix||"Forsion"}`)});return dr(n)}async watchRoots(e){this.options.watch!==!1&&(this.guard(e),await this.watcher?.close(),this.watcher=$r(e.roots.map(n=>n.root),{ignoreInitial:!0,ignored:n=>{let r=n.split(/[\\/]/).at(-1)??"";return r.startsWith(".")&&r!==".memory-tombstones.json"||r==="node_modules"||r==="__pycache__"}}),this.watcher.on("all",()=>{this.scheduled&&clearTimeout(this.scheduled),this.scheduled=setTimeout(()=>{e.stored.config.enabled&&!e.stored.paused&&this.run()},1500),this.scheduled.unref?.()}))}async request(e,n,r="",s="GET",o,i){this.guard(e);let a=this.host.readCreds();if(!a.token)throw Error("not_signed_in");let l=a.cloudUrl.replace(/\/+$/,"")+`/api/remotesync/content/${encodeURIComponent(n)}${r}`,c={Authorization:`Bearer ${a.token}`},u;if(o instanceof Buffer){c["Content-Type"]="application/octet-stream",c["Content-Length"]=String(o.length);let h=async function*(){for(let g=0;g<o.length;g+=64*1024)e.abort.signal.throwIfAborted(),yield o.subarray(g,g+64*1024),i?.(Math.min(o.length,g+64*1024))};u=Qa.from(h())}else o!==void 0&&(c["Content-Type"]="application/json",u=JSON.stringify(o));let f={method:s,headers:c,body:u,signal:AbortSignal.any([e.abort.signal,AbortSignal.timeout(12e4)]),...o instanceof Buffer?{duplex:"half"}:{}},p=await fetch(l,f);if(this.guard(e),!p.ok){let h=await p.json().catch(()=>({}));throw Object.assign(new Error(typeof h.detail=="string"?h.detail:`content_http_${p.status}`),{status:p.status})}return p}async json(e,n,r="",s="GET",o){return await(await this.request(e,n,r,s,o)).json()}async manifests(e,n){let r=new Map;for(let s of new Set(n.rules.filter(o=>o.target!=="off").map(o=>o.target))){let o=await this.json(e,s);if(o.schemaVersion!==1||o.namespace!==s||!Array.isArray(o.nodes))throw Error("Incomplete cloud content manifest");let i=new Set;for(let a of o.nodes){if(bt(a.path),i.has(a.id))throw Error("Duplicate cloud content identity");i.add(a.id)}r.set(s,o)}return r}route(e,n){let r=ir(e,n.rules);return r&&r.target!=="off"?r.target:null}effective(e,n){let r=new Map(n.filter(s=>s.localId).map(s=>[s.localId,s.path]));return{...e,rules:e.rules.map(s=>s.sourceId&&r.has(s.sourceId)?{...s,source:r.get(s.sourceId)}:s)}}deviceName(){return this.customName||Na(Rf())}setSources(e){let n=new Map,r={files:0,size:0};for(let s of e)s.kind==="folder"&&n.set(s.path,{size:0,files:0});for(let s of e)if(s.kind==="file"){ja.some(o=>s.path.startsWith(o+"/"))||(r.files++,r.size+=s.size);for(let o=gn(s.path);o;o=gn(o)){let i=n.get(o);i&&(i.size+=s.size,i.files++)}}this.others=r,this.sources=[...n].sort(([s],[o])=>vt(s)-vt(o)||(s<o?-1:1)).slice(0,2e3).map(([s,o])=>({path:s,kind:"folder",size:o.size,files:o.files}))}async rename(e){let n=typeof e=="string"?e.trim():"";if(n.length>64||/[\u0000-\u001f\u007f]/.test(n))throw Error("Invalid device name");let r=await this.getSession(),s=ze(this.host.homeDir(),"content-sync-device.json"),o=s+".tmp-"+tt();try{await hr(o,JSON.stringify({id:this.deviceId,...n?{name:n}:{}}),{mode:384,flag:"wx"}),await Fs(o,s)}finally{await yr(o).catch(()=>{})}return this.customName=n,await this.json(r,"devices",`/${encodeURIComponent(this.deviceId)}`,"PUT",{name:this.deviceName()}),this.devices=(await this.json(r,"devices")).devices,this.deviceName()}async setup(e){let n=await this.getSession(),r=e&&typeof e=="object"?e:{};if(n.stored.config.enabled||n.stored.config.revision>0)return null;let s=Is(La(n.stored.config),"","off");for(let o of Lt)r[o.id]===!1&&(s=Is(s,o.path,"off"));return this.preview(s)}async snapshot(){let e=await this.getSession();return{available:!0,account:Re(e.account),deviceId:this.deviceId,deviceName:this.deviceName(),config:structuredClone(e.stored.config),running:this.running,paused:e.stored.paused,phase:this.phase,jobs:structuredClone(e.stored.jobs),devices:this.devices,sources:this.sources,...this.others?{others:this.others}:{},...this.error?{error:this.error}:{}}}async preview(e){let n=await this.getSession();if(e?.revision!==n.stored.config.revision)throw Error("config_changed");let s=Ts(e,n.stored.config.revision+1),o=await this.host.contentSync.roots();this.guard(n),n.roots=o;let i=await this.previewScan(n,o),a=this.effective(s,i),l=await this.manifests(n,a);this.guard(n),this.setSources(i);let c=0,u=0,f=0,p=0;for(let m of i.filter(w=>w.kind==="file")){let w=this.route(m.path,a);if(!w)continue;let k=l.get(w)?.nodes.find(O=>!O.deleted&&O.kind==="file"&&O.path===m.path);if(m.size>mn){c++,p+=m.size;continue}let P=Re(await fr(m));this.guard(n),P!==k?.hash&&(c++,p+=m.size,k?.version&&f++)}for(let[m,w]of l)for(let k of w.nodes)!k.deleted&&k.kind==="file"&&k.version&&this.route(k.path,a)===m&&!i.some(P=>P.path===k.path)&&u++;let h=this.signature(i,l,o),g={token:tt(),config:a,upload:s.enabled?c:0,download:s.enabled?u:0,conflicts:s.enabled?f:0,bytes:s.enabled?p:0,oldTargetsRetained:!0,expiresAt:Date.now()+5*6e4};return this.previewValue={value:g,account:n.account,signature:h},g}signature(e,n,r){return Re(JSON.stringify([r,e.map(s=>[s.path,s.size,s.mtime,s.inode]),[...n].map(([s,o])=>[s,o.nodes.map(i=>[i.id,i.revision,i.version,i.deleted])])]))}async apply(e){let n=this.serial,r;this.serial=new Promise(s=>{r=s}),await n;try{let s=await this.getSession(),o=this.previewValue;if(!o||o.value.token!==e||o.account!==s.account||o.value.expiresAt<Date.now()||o.value.config.revision!==s.stored.config.revision+1)throw Error("preview_expired");if(this.running)throw Error("sync_in_progress");let i=await this.host.contentSync.roots(),a=await this.previewScan(s,i),l=await this.manifests(s,o.value.config);if(this.signature(a,l,i)!==o.signature)throw Error("preview_changed");let c=[];for(let f of i){let p=await gr(f.root).catch(h=>{if(h.code==="ENOENT")return null;throw h});p&&c.push({...f,dev:p.dev,ino:p.ino})}this.guard(s);let u=structuredClone(s.stored);s.stored.config=o.value.config,s.stored.owned=!0,s.stored.paused=!1,delete s.stored.unconfirmed;for(let f of s.stored.config.rules){let p=a.find(h=>h.kind==="folder"&&h.path===f.source);p&&(f.sourceId=await Ms(p))}for(let[f,p]of Object.entries(s.stored.files))(u.config.enabled!==s.stored.config.enabled||JSON.stringify(u.roots??c)!==JSON.stringify(c)||this.route(p.path,u.config)!==this.route(p.path,s.stored.config))&&delete s.stored.files[f];for(let[f,p]of Object.entries(s.stored.folders))(u.config.enabled!==s.stored.config.enabled||JSON.stringify(u.roots??c)!==JSON.stringify(c)||this.route(p.path,u.config)!==this.route(p.path,s.stored.config))&&delete s.stored.folders[f];s.stored.roots=c,await this.persist(s);try{await this.host.contentSync.claim(!0),this.guard(s)}catch(f){throw s.stored=u,await this.persist(s),await this.host.contentSync.claim(u.owned).catch(()=>{}),f}this.previewValue=null,s.roots=i,await this.watchRoots(s)}finally{r()}this.run()}async pause(e){let n=await this.getSession();n.stored.paused=e,e?(n.abort.abort(new Error("paused")),this.phase="paused"):this.running||(n.abort=new AbortController),await this.persist(n),e||this.run()}job(e,n,r,s,o){let i=e.stored.jobs.findLast(l=>l.path===n&&l.target===r&&l.direction===s&&["failed","paused","queued"].includes(l.state));if(i)return Object.assign(i,{state:"active",done:0,size:o,at:Date.now(),error:void 0,finishedAt:void 0}),i;let a={id:tt(),path:n,target:r,direction:s,state:"active",done:0,size:o,at:Date.now()};return e.stored.jobs.push(a),e.stored.jobs=e.stored.jobs.slice(-200),a}done(e){e.state="done",e.done=e.size??e.done,e.finishedAt=Date.now()}async operation(e,n,r,s,o,i){if(this.guard(e),e.stored.paused)throw Error("paused");let a=this.job(e,n,r,s,o);try{let l=await i(a);if(this.guard(e),e.stored.paused)throw Error("paused");return this.done(a),l}catch(l){throw a.state=e.stored.paused?"paused":"failed",a.error=nt(l),a.finishedAt=Date.now(),l}}async run(){if(this.running||this.closed)return;this.running=!0;let e;this.runFinished=new Promise(r=>{e=r});let n;try{if(n=await this.getSession(),!n.stored.config.enabled||n.stored.paused)return;n.abort.signal.aborted&&(n.abort=new AbortController),this.blocked.clear(),this.phase="scanning",this.error=void 0;let r=await this.host.contentSync.roots();this.guard(n),n.roots=r;let s=await this.scan(n,r);await this.recordRoots(n);let o=this.effective(n.stored.config,s),i=await this.manifests(n,o);this.guard(n),await this.json(n,"devices",`/${encodeURIComponent(this.deviceId)}`,"PUT",{name:this.deviceName()}),this.devices=(await this.json(n,"devices")).devices,await this.folders(n,o,s,i),await this.recordRoots(n),await this.fileRenames(n,o,s,i),s=await this.scan(n,r),o=this.effective(o,s),n.stored.config=o,this.setSources(s),this.phase="syncing";for(let a of s.filter(l=>l.kind==="file")){if(this.guard(n),n.stored.paused)throw Error("paused");let l=this.route(a.path,o);if(!(!l||this.isBlocked(l,a.path)))try{await this.file(n,o,a,l,i.get(l))}catch(c){this.error=nt(c)}}for(let[a,l]of i)for(let c of l.nodes.filter(u=>u.kind==="file"&&!u.busy)){if(this.guard(n),n.stored.paused)throw Error("paused");if(!(this.isBlocked(a,c.path)||this.route(c.path,o)!==a||s.some(u=>u.path===c.path)))try{await this.missing(n,c,a)}catch(u){this.error=nt(u)}}await this.cleanupFolders(n,o,i),await this.host.contentSync.changed(),this.guard(n),await this.persist(n),await this.pruneBases(n)}catch(r){this.error=nt(r)}finally{this.running=!1,this.phase=n?.stored.paused?"paused":"idle",n&&this.host.accountId()===n.account&&(await this.persist(n).catch(()=>{}),!this.closed&&n.abort.signal.aborted&&!n.stored.paused&&n.stored.config.enabled&&(n.abort=new AbortController,queueMicrotask(()=>void this.run()))),e()}}isBlocked(e,n){return(this.blocked.get(e)??[]).some(r=>n===r||n.startsWith(r+"/"))}block(e,n,r){this.blocked.set(e,[...this.blocked.get(e)??[],n]),this.error=nt(r)}async folders(e,n,r,s){let o=r.filter(a=>a.kind==="folder"),i=new Map;for(let a of o)if(a.localId){if(i.has(a.localId))throw Error(`Duplicate folder sync identity: ${a.path}`);i.set(a.localId,a.path)}for(let[a,l]of s){for(let c of l.nodes.filter(u=>u.kind==="folder"&&!u.deleted&&!u.busy).sort((u,f)=>vt(u.path)-vt(f.path)))if(!this.isBlocked(a,c.path))try{let u=Object.entries(e.stored.folders).find(([p,h])=>p.startsWith(a+":")&&h.id===c.id)?.[1],f=(u?o.find(p=>p.localId===u.localId):null)??o.find(p=>p.path===c.path);if(u&&f&&c.path!==u.path&&f.path!==u.path&&c.path!==f.path)throw Error(`Concurrent folder rename: ${f.path}`);if(u&&f&&c.path!==u.path&&f.path===u.path){if(this.route(f.path,n)!==a)continue;if(this.route(c.path,n)!==a)throw Error("Remote rename crosses a sync rule; review the destination");await this.operation(e,f.path,a,"rename",null,()=>Ns(e.roots,f.path,c.path,(h,g)=>this.lock(e,h,g)));let p=f.path;for(let h of r)if(h.path===p||h.path.startsWith(p+"/")){let g=h.path;h.path=c.path+g.slice(p.length);let m=St(e.roots,h.path);h.physical=ze(m.root,m.relative)}for(let[h,g]of Object.entries(e.stored.files))h.startsWith(a+":")&&g.path.startsWith(u.path+"/")&&(g.path=c.path+g.path.slice(u.path.length));for(let h of n.rules)(h.source===u.path||h.source.startsWith(u.path+"/"))&&(h.source=c.path+h.source.slice(u.path.length))}if(!f&&this.route(c.path,n)===a&&!u){await Ka(e.roots,c.path,(h,g)=>this.lock(e,h,g));let p=(await this.scan(e)).find(h=>h.path===c.path);p&&(r.push(p),o.push(p))}}catch(u){this.block(a,c.path,u);let f=Object.entries(e.stored.folders).find(([p,h])=>p.startsWith(a+":")&&h.id===c.id)?.[1];f&&this.block(a,f.path,u)}for(let c of o.sort((u,f)=>vt(u.path)-vt(f.path)))if(!this.isBlocked(a,c.path))try{let u=this.route(c.path,n),f=n.rules.some(k=>k.target===a&&k.source.startsWith(c.path+"/"));if(u!==a&&!f)continue;let p=await Ms(c),h=e.stored.folders[Oe(a,p)],g=h?l.nodes.find(k=>k.id===h.id):l.nodes.find(k=>k.path===c.path&&!k.deleted);if(g?.deleted){if(h){let k=!1;for(let P of r.filter(O=>O.kind==="file"&&O.path.startsWith(c.path+"/")&&this.route(O.path,n)===a)){let O=Object.entries(e.stored.files).find(([A,$])=>A.startsWith(a+":")&&$.path===P.path)?.[1];if(!O||Re(await fr(P))!==O.hash){k=!0;break}}if(!k)continue}g=void 0}let m=gn(c.path),w=m?l.nodes.find(k=>k.path===m&&k.kind==="folder"&&!k.deleted)?.id:"";if(m&&!w)throw Error("Cloud parent is unavailable");if(!g)g=await this.json(e,a,"/nodes","POST",{id:h?tt():p,parentId:w,name:yn(c.path),kind:"folder"}),l.nodes.push(g);else if(h&&g.path!==c.path){if(g.revision!==h.revision)throw Error(`Concurrent folder rename: ${c.path}`);let k=g.path,P=await this.operation(e,c.path,a,"rename",null,()=>this.json(e,a,`/nodes/${g.id}`,"PATCH",{parentId:w,name:yn(c.path),revision:g.revision}));for(let O of l.nodes)O.path.startsWith(k+"/")&&(O.path=c.path+O.path.slice(k.length));Object.assign(g,P);for(let[O,A]of Object.entries(e.stored.files))O.startsWith(a+":")&&A.path.startsWith(k+"/")&&(A.path=c.path+A.path.slice(k.length))}e.stored.folders[Oe(a,p)]={id:g.id,localId:p,path:c.path,revision:g.revision,parentId:g.parentId,name:g.name}}catch(u){this.block(a,c.path,u);let f=this.job(e,c.path,a,"rename",null);f.state="conflict",f.error=nt(u),f.finishedAt=Date.now()}}}async cleanupFolders(e,n,r){let s=await this.scan(e);for(let[o,i]of r)for(let a of i.nodes.filter(l=>l.kind==="folder"&&!l.busy).sort((l,c)=>vt(c.path)-vt(l.path))){if(this.isBlocked(o,a.path)||this.route(a.path,n)!==o)continue;let l=Object.entries(e.stored.folders).find(([u,f])=>u.startsWith(o+":")&&f.id===a.id);if(!l)continue;let c=s.find(u=>u.path===a.path&&u.kind==="folder");if(a.deleted&&c){if(s.some(f=>f.path.startsWith(a.path+"/"))||(await Za(c.physical)).some(f=>f!==".forsion-sync-id.json"))continue;await this.operation(e,a.path,o,"delete",null,()=>this.lock(e,c.physical,()=>{et(c.root,Us(c.root,c.physical).split(Ls).join("/"));let f=_f(c.physical);if(f.some(g=>g!==".forsion-sync-id.json"))throw Error("Folder changed before deletion");let p=ze(c.physical,".forsion-sync-id.json"),h=f.length?hn(p):null;h&&Xa(p);try{Cf(c.physical)}catch(g){if(h)try{xf(p,h,{flag:"wx",mode:384})}catch{}throw g}})),delete e.stored.folders[l[0]]}else if(!a.deleted&&!c){if(i.nodes.some(u=>u.parentId===a.id&&!u.deleted))continue;await this.operation(e,a.path,o,"delete",null,()=>this.json(e,o,`/nodes/${a.id}`,"DELETE",{revision:a.revision,version:null})),a.deleted=!0,delete e.stored.folders[l[0]]}}}async download(e,n,r,s){if(n.size!==void 0&&n.size>mn)throw Error("File exceeds 50 MB content limit");let o=await this.request(e,r,`/nodes/${n.id}/content`),i=[],a=0;if(o.body){let c=o.body.getReader();for(;;){let u=await c.read();if(u.done)break;if(this.guard(e),a+=u.value.length,a>mn)throw await c.cancel(),Error("Content too large");i.push(u.value),s.done=a}}let l=Buffer.concat(i);if(n.hash&&Re(l)!==n.hash)throw Error("Cloud file changed during download");return l}async fileRenames(e,n,r,s){for(let[o,i]of s)for(let a of i.nodes.filter(l=>l.kind==="file"&&!l.deleted&&!l.busy)){let l=e.stored.files[Oe(o,a.id)];if(!l||l.path===a.path)continue;let c=r.find(u=>u.kind==="file"&&u.path===l.path);if(!(!c||this.route(c.path,n)!==o))try{if(this.route(a.path,n)!==o)throw Error("Remote rename crosses a sync rule; review the destination");await this.operation(e,c.path,o,"rename",null,()=>Ns(e.roots,c.path,a.path,(u,f)=>this.lock(e,u,f))),l.path=a.path}catch(u){this.block(o,c.path,u),this.block(o,a.path,u)}}}async upload(e,n,r,s,o){if(s.length>mn)throw Error("File exceeds 50 MB content limit");this.guard(e);let i=this.host.readCreds(),a=Qa.from((async function*(){for(let c=0;c<s.length;c+=64*1024)e.abort.signal.throwIfAborted(),yield s.subarray(c,c+64*1024),o.done=Math.min(s.length,c+64*1024)})()),l=await fetch(i.cloudUrl.replace(/\/+$/,"")+`/api/remotesync/content/${encodeURIComponent(r)}/nodes/${n.id}/content`,{method:"PUT",headers:{Authorization:`Bearer ${i.token}`,"Content-Type":"application/octet-stream","Content-Length":String(s.length),"X-Content-Version":n.version??"create"},body:a,duplex:"half",signal:AbortSignal.any([e.abort.signal,AbortSignal.timeout(12e4)])});if(this.guard(e),!l.ok){let c=await l.json().catch(()=>({}));throw Error(c.detail??`content_http_${l.status}`)}return await l.json()}async shadow(e,n,r,s,o){let i=Oe(n,r.id),a=Re(s),l=Pf(s);l&&s.length>=el&&await this.keepBase(e,a,s);for(let c of e.stored.jobs)c.path===r.path&&c.target===n&&["failed","paused","active"].includes(c.state)&&["upload","download","merge"].includes(c.direction)&&this.done(c);e.stored.pendingUploads&&delete e.stored.pendingUploads[i],delete e.stored.unconfirmed?.[i],e.stored.files[i]={id:r.id,path:r.path,version:r.version,hash:a,...l&&s.length<el?{base:s.toString("utf8")}:{},...o?{inode:o.inode}:{}}}async keepBase(e,n,r){let s=zs(e),o=ze(s,n);if(await mr(o).then(()=>!0,()=>!1))return;await js(s,{recursive:!0,mode:448});let i=o+".tmp-"+tt();try{await hr(i,r,{mode:384,flag:"wx"}),await Fs(i,o)}finally{await yr(i).catch(()=>{})}}async readBase(e,n){if(n.base!==void 0)return n.base;let r=await pr(ze(zs(e),n.hash)).catch(s=>{if(s.code==="ENOENT")return null;throw s});return r&&Re(r)===n.hash?r.toString("utf8"):null}async pruneBases(e){let n=new Set(Object.values(e.stored.files).map(s=>s.hash)),r=zs(e);for(let s of await Za(r).catch(()=>[]))n.has(s)||await yr(ze(r,s)).catch(()=>{})}async file(e,n,r,s,o){if(r.size>mn){await this.operation(e,r.path,s,"upload",r.size,async()=>{throw Error("File exceeds 50 MB content limit")});return}let i=await fr(r),a=Re(i);this.guard(e);let l=o.nodes.find(g=>g.kind==="file"&&!g.deleted&&g.path===r.path);if(!l){let g=Object.entries(e.stored.files).find(([m,w])=>m.startsWith(s+":")&&w.inode===r.inode&&w.path!==r.path)?.[1];if(g){let m=St(e.roots,g.path),w=await mr(ze(m.root,m.relative)).then(()=>!0,P=>P.code==="ENOENT"?!1:Promise.reject(P)),k=o.nodes.find(P=>P.id===g.id&&!P.deleted);if(!w&&k){if(k.path!==g.path)throw Error(`Concurrent file rename: ${r.path}`);let P=gn(r.path),O=P?o.nodes.find($=>$.path===P&&$.kind==="folder"&&!$.deleted)?.id:"";if(P&&!O)throw Error("Rename parent unavailable");let A=await this.operation(e,r.path,s,"rename",null,()=>this.json(e,s,`/nodes/${k.id}`,"PATCH",{name:yn(r.path),parentId:O,revision:k.revision}));Object.assign(k,A),g.path=r.path,l=k}}}let c=l?e.stored.files[Oe(s,l.id)]:Object.entries(e.stored.files).find(([g,m])=>g.startsWith(s+":")&&m.path===r.path)?.[1];if(!l){if((c?o.nodes.find(A=>A.id===c.id&&A.deleted):null)&&c?.hash===a){await this.operation(e,r.path,s,"delete",r.size,()=>this.trashFile(e,r,a)),delete e.stored.files[Oe(s,c.id)];return}let m=gn(r.path),w=m?o.nodes.find(A=>A.path===m&&!A.deleted&&A.kind==="folder")?.id:"";if(m&&!w)throw Error("Parent folder is unavailable");let k=Object.entries(e.stored.pendingUploads??{}).find(([A,$])=>A.startsWith(s+":")&&$.path===r.path&&!o.nodes.some(b=>b.id===$.id))?.[1];for(let[A,$]of Object.entries(e.stored.pendingUploads??{}))A.startsWith(s+":")&&$.path===r.path&&o.nodes.some(b=>b.id===$.id&&b.deleted)&&delete e.stored.pendingUploads[A];let P=k?.id??tt(),O=Oe(s,P);(e.stored.pendingUploads??={})[O]={id:P,path:r.path},await this.persist(e),l=await this.json(e,s,"/nodes","POST",{id:P,parentId:w,name:yn(r.path),kind:"file"}),l.id!==P&&delete e.stored.pendingUploads[O],o.nodes.push(l),c=void 0}if(l.busy)return;if(l.hash===a){await this.shadow(e,s,l,i,r);return}let u=Oe(s,l.id);if(l.hash&&e.stored.unconfirmed?.[u]===l.hash&&(await this.shadow(e,s,l,await this.operation(e,r.path,s,"download",l.size??null,g=>this.download(e,l,s,g)),r),c=e.stored.files[u]),!l.version||c&&l.version===c.version){(e.stored.unconfirmed??={})[u]=a,await this.persist(e);let g=await this.operation(e,r.path,s,"upload",i.length,m=>this.upload(e,l,s,i,m));Object.assign(l,g),await this.shadow(e,s,l,i,r);return}let f=await this.operation(e,r.path,s,"download",l.size??null,g=>this.download(e,l,s,g)),p=f,h=!1;if(!c||c.hash!==a){let g=i.toString("utf8"),m=f.toString("utf8"),w=c?await this.readBase(e,c):null,k=Buffer.from(g).equals(i)&&Buffer.from(m).equals(f)?this.host.contentSync.merge(r.path,g,w,m):null;if(k?(p=Buffer.from(k.content),h=k.conflict):h=!0,h){let P=r.path.lastIndexOf("."),O=` (conflict ${this.deviceId.slice(0,8)} ${Date.now()})`,A=P>r.path.lastIndexOf("/")?r.path.slice(0,P)+O+r.path.slice(P):r.path+O;await this.write(e,A,i,null);let $=this.job(e,r.path,s,"merge",i.length);$.state="conflict",$.error="Both versions preserved",$.finishedAt=Date.now()}if(!p.equals(f)){let P=await this.operation(e,r.path,s,"merge",p.length,O=>this.upload(e,l,s,p,O));Object.assign(l,P)}}await this.write(e,r.path,p,a),await this.shadow(e,s,l,p,r)}async missing(e,n,r){let s=e.stored.files[Oe(r,n.id)],o=e.stored.pendingUploads?.[Oe(r,n.id)];if(n.deleted){s&&delete e.stored.files[Oe(r,n.id)],o&&delete e.stored.pendingUploads[Oe(r,n.id)];return}if(n.busy)return;if(!n.version){o&&(await this.operation(e,n.path,r,"delete",null,()=>this.json(e,r,`/nodes/${n.id}`,"DELETE",{revision:n.revision,version:null})),delete e.stored.pendingUploads[Oe(r,n.id)],n.deleted=!0);return}if(s&&s.version===n.version){await this.operation(e,n.path,r,"delete",n.size??null,()=>this.json(e,r,`/nodes/${n.id}`,"DELETE",{revision:n.revision,version:n.version})),delete e.stored.files[Oe(r,n.id)],n.deleted=!0;return}let i=await this.operation(e,n.path,r,"download",n.size??null,a=>this.download(e,n,r,a));await this.write(e,n.path,i,null),await this.shadow(e,r,n,i)}async recoverTrash(e){for(let n of[...e.stored.trash??[]]){if(n.parentId){let l=(await dr(e.roots)).find(c=>c.kind==="folder"&&c.localId===n.parentId);l&&(n.path=l.path+"/"+yn(n.path))}let r=St(e.roots,n.path),s=await Qe(r.root,r.relative);if(!/^\.forsion-sync-trash-[a-f0-9-]+$/.test(n.stage))throw Error("Invalid sync recovery journal");let o=n.stageRoot??r.root,i=await gr(o);if(n.stageDev!==void 0&&(i.dev!==n.stageDev||i.ino!==n.stageIno))throw Error("Sync recovery root changed; journal retained");let a=ze(o,n.stage);await mr(a).then(()=>!0,l=>l.code==="ENOENT"?!1:Promise.reject(l))&&await this.lock(e,s,()=>{if(et(o,n.stage,!0),Re(hn(a))!==n.hash)throw Error("Sync recovery content changed");et(r.root,r.relative),Tf(wr(s),{recursive:!0});let l=$f(s)?s+` (sync recovery ${tt().slice(0,8)})`:s;try{Ef(a,l)}catch(c){if(c.code!=="EXDEV")throw c;if(Af(a,l,If.COPYFILE_EXCL),Re(hn(l))!==n.hash)throw Error("Sync recovery copy incomplete; original retained")}Xa(a)},!0),e.stored.trash=e.stored.trash.filter(l=>l!==n)}}async trashFile(e,n,r){this.guard(e);let s=await Qe(n.root,Us(n.root,n.physical).split(Ls).join("/")),o={path:n.path,stage:".forsion-sync-trash-"+tt(),hash:r},i=ze(n.root,o.stage),a=tl(n.root);o.stageRoot=n.root,o.stageDev=a.dev,o.stageIno=a.ino;try{let l=JSON.parse(hn(ze(wr(s),".forsion-sync-id.json"),"utf8")).id;/^[a-f0-9-]{36}$/i.test(l)&&(o.parentId=l)}catch{}(e.stored.trash??=[]).push(o),await this.persist(e);try{await this.lock(e,s,()=>{if(et(n.root,Us(n.root,s).split(Ls).join("/")),Re(hn(s))!==r)throw Error("Local file changed before deletion");kf(s,i)}),await this.host.contentSync.trash(i),e.stored.trash=e.stored.trash.filter(l=>l!==o)}catch(l){throw this.host.accountId()===e.account&&!e.abort.signal.aborted&&await this.recoverTrash(e),l}}};function $f(t){try{return tl(t),!0}catch(e){if(e.code==="ENOENT")return!1;throw e}}ro(No);function Rg(t){Mo(t.contentSync?.withWriteLock?.bind(t.contentSync)),fo(t),Jr(t),nl(t),t.log("[forsion-extend] cloud account handlers registered"),Fr(t)?Ur(t):t.log("[forsion-extend] host has no Connect seam (projectsRoot / transpileForServe / mimeOf / setPreviewHooks); Connect stays with the host"),zr(t)?Hr(t):t.log("[forsion-extend] host has no remote-sync seam (registerRemoteSyncBackend / readCreds); penzor stays with the host"),Kr(t)?Xr(t):t.log("[forsion-extend] host has no account seam (accountCommit / accountClear / \u2026); account core stays with the host"),us(t)?ds(t):t.log("[forsion-extend] host has no amadeus seam (setAmadeusSyncFactory); cloud sync stays with the host"),ps(t)?hs(t):t.log("[forsion-extend] host has no unit seam (setUnitHubFactory); the device channel stays with the host"),ks(t)?ma(t):t.log("[forsion-extend] host has no diagnostics seam (homeDir / readCreds / accountId / appVersion); diagnostics upload is off"),ks(t)&&Oa(t)}export{li as ACCOUNT_SEAM,Mi as AMADEUS_SEAM,Nr as CONNECT_MAX_FILES,Fo as CONNECT_MAX_FILE_BYTES,Uo as CONNECT_MAX_TOTAL_BYTES,Un as DIAGNOSTICS_VAULT,Wo as FORSION_CONNECT_LOCAL_SDK,uo as PAY_PERIODS,co as PAY_TABS,Yo as PENZOR_MAX_FILE,xe as SYNC_IPC,Fi as UNIT_SEAM,Yt as UPLOAD_MAX_FILE,sn as UnitCapsReporter,rn as UnitHost,De as cloudJson,Lo as collectProjectFiles,Wn as conflictCopyPath,nu as conflictCopyVariant,ai as createAccountCloud,Ni as createAmadeusCloud,Fn as createPenzorRemote,Ui as createUnitHub,jn as deviceHeader,Lr as expectedPartsOf,Fe as forsionAccountId,Bn as forsionRefreshToken,Jt as forsionWhoami,Kr as hasAccountHost,us as hasAmadeusHost,Fr as hasConnectHost,zr as hasRemoteSyncHost,ps as hasUnitHost,qo as makePreviewProxy,ri as multipartFrame,Ho as readConnectMeta,Xr as registerAccount,ds as registerAmadeus,Rg as registerCloud,Ur as registerConnect,Hr as registerPenzor,Jr as registerPenzorTransfers,hs as registerUnit,Ln as safeDownloadName,Hn as shouldRefreshToken,Br as speedOf,ji as streamWorthy,Ri as stripConflictSuffix,ru as textFingerprint,Gr as tokenAgeMs,si as tokenRemainingMs,qr as uploadError,Bo as writeConnectMeta};
|
|
254
265
|
/*! Bundled license information:
|
|
255
266
|
|
|
256
267
|
chokidar/index.js:
|