@forsion/extend 0.3.0 → 0.4.0

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 CHANGED
@@ -1,5 +1,13 @@
1
1
  # 更新日志
2
2
 
3
+ ## 0.4.0 — 2026-09-28
4
+
5
+ - 笔记的云端同步与协作从 Forsion 本体搬入本包:云端笔记库镜像、按条目同步、与我共享、页面分享 / 发布 / 在线成员,行为与之前一致。没装本包的桌面端不再显示云端笔记库、云同步与分享入口。
6
+ - 需要较新的 Forsion 桌面端才会启用;旧桌面端上本包只提供 0.3 的功能,不影响使用。
7
+
8
+ Cloud sync and collaboration for notes now ship in this package, moved over from Forsion itself with their behavior unchanged: the cloud vault mirror, per-item sync, shared-with-me, page sharing / publishing / presence. Desktops without this package no longer show the cloud vault, cloud sync or sharing entry points.
9
+ This needs a newer Forsion Desktop build; on older desktops this package keeps providing the 0.3 features and nothing else changes.
10
+
3
11
  ## 0.3.0 — 2026-09-28
4
12
 
5
13
  - 账号登录态从 Forsion 本体搬入本包:登录、登出、切换账号、账号状态与登录态自动续期都由本包提供,行为与之前一致。没装本包的桌面端不再显示账号卡、Forsion 设置页与登录入口。
package/README.md CHANGED
@@ -1,14 +1,14 @@
1
1
  # Forsion Extend
2
2
 
3
- Forsion 桌面端里**跟云端账号打交道的那一半**:账号登录 / 登出 / 切换与登录态续期(0.3 起),个人中心 / 会员页入口、额度视图与重置卡、后台额度转换、反馈中心提交,插件以当前账号身份调 Forsion 云端 API 的通用接缝 `cloud:fetch`,Forsion Connect(0.2 起)—— Coding Space 项目发布、应用商店上架申请、预览态 AI 代理(预览页的 `window.forsion` SDK 与 `/__forsion/*` 云端代理),以及本地库远程同步的 Forsion 云端后端(0.3 起)。它是一个 Forsion 捆绑包(manifest.json + 渲染半身 + 主进程半身),编译产物以 npm 包 `@forsion/extend` 发布。
3
+ Forsion 桌面端里**跟云端账号打交道的那一半**:账号登录 / 登出 / 切换与登录态续期(0.3 起),个人中心 / 会员页入口、额度视图与重置卡、后台额度转换、反馈中心提交,插件以当前账号身份调 Forsion 云端 API 的通用接缝 `cloud:fetch`,Forsion Connect(0.2 起)—— Coding Space 项目发布、应用商店上架申请、预览态 AI 代理(预览页的 `window.forsion` SDK 与 `/__forsion/*` 云端代理),本地库远程同步的 Forsion 云端后端(0.3 起),以及笔记的云端同步与协作(0.4 起)—— 云端笔记库镜像、按条目同步、与我共享、页面分享 / 发布 / 在线成员。它是一个 Forsion 捆绑包(manifest.json + 渲染半身 + 主进程半身),编译产物以 npm 包 `@forsion/extend` 发布。
4
4
 
5
- The **cloud-account half of Forsion Desktop**: account sign-in, sign-out, switching and staying signed in (since 0.3), the account center and membership page shortcuts, the quota view and reset cards, background quota conversion, feedback submission, `cloud:fetch` (the shared seam plugins use to call the Forsion cloud API as the signed-in account), Forsion Connect (since 0.2): Coding Space project publishing, app store listing requests, and the preview-mode AI proxy (the `window.forsion` SDK served to preview pages plus the `/__forsion/*` cloud proxy), and the Forsion cloud backend for remote sync of the local vault (since 0.3). It is a Forsion bundle (manifest.json + a renderer half + a main-process half), published as the npm package `@forsion/extend`.
5
+ The **cloud-account half of Forsion Desktop**: account sign-in, sign-out, switching and staying signed in (since 0.3), the account center and membership page shortcuts, the quota view and reset cards, background quota conversion, feedback submission, `cloud:fetch` (the shared seam plugins use to call the Forsion cloud API as the signed-in account), Forsion Connect (since 0.2): Coding Space project publishing, app store listing requests, and the preview-mode AI proxy (the `window.forsion` SDK served to preview pages plus the `/__forsion/*` cloud proxy), the Forsion cloud backend for remote sync of the local vault (since 0.3), and cloud sync and collaboration for notes (since 0.4): the cloud vault mirror, per-item sync, shared-with-me, page sharing / publishing / presence. It is a Forsion bundle (manifest.json + a renderer half + a main-process half), published as the npm package `@forsion/extend`.
6
6
 
7
7
  ## Forsion 桌面端怎么装载它 / How Forsion Desktop loads it
8
8
 
9
- Forsion 桌面端把本包当**内置捆绑包**:随桌面安装包带一份,启动时播种进 `<home>/plugins/forsion-extend/`,之后由 npm 更新器在后台下载新版、下次启动换上。带主进程半身的包比普通捆绑包多一道闸:播种 / 换版前,桌面端用钉在自己代码里的 ed25519 公钥核对包内 `SIGNATURE`(每个打包文件的 sha256 + 签名),验不过的那份不换、不载;验过后 `import()` `dist/desktop.mjs`,调用 `registerCloud(host)` 注册 8 个云端账号 IPC 通道;桌面端够新(提供对应的宿主接缝)时再注册 7 个 `connect:*` 通道与预览挂钩(0.2)、5 个 `auth:*` 登录态通道与远程同步的 penzor 后端(0.3),旧桌面端上缺接缝的那块自动跳过、其余功能照常。桌面端的界面按这些通道是否存在显示或隐藏:没装本包就没有账号卡、Forsion 设置页、登录入口与「Forsion 云端」同步后端。
9
+ Forsion 桌面端把本包当**内置捆绑包**:随桌面安装包带一份,启动时播种进 `<home>/plugins/forsion-extend/`,之后由 npm 更新器在后台下载新版、下次启动换上。带主进程半身的包比普通捆绑包多一道闸:播种 / 换版前,桌面端用钉在自己代码里的 ed25519 公钥核对包内 `SIGNATURE`(每个打包文件的 sha256 + 签名),验不过的那份不换、不载;验过后 `import()` `dist/desktop.mjs`,调用 `registerCloud(host)` 注册 8 个云端账号 IPC 通道;桌面端够新(提供对应的宿主接缝)时再注册 7 个 `connect:*` 通道与预览挂钩(0.2)、5 个 `auth:*` 登录态通道与远程同步的 penzor 后端(0.3)、11 个 `amadeus:sync|entry-sync|collab:*` 通道与云同步引擎(0.4,宿主在笔记库建好后再调本包登记的工厂),旧桌面端上缺接缝的那块自动跳过、其余功能照常。桌面端的界面按这些通道是否存在显示或隐藏:没装本包就没有账号卡、Forsion 设置页、登录入口、「Forsion 云端」同步后端、云端笔记库与分享入口。
10
10
 
11
- Forsion Desktop treats this package as a **built-in bundle**: a copy ships inside the desktop installer, is seeded into `<home>/plugins/forsion-extend/` on startup, and the npm updater downloads newer versions in the background and switches to them on the next launch. A bundle with a main-process half has one extra gate: before seeding or switching, the desktop checks the in-package `SIGNATURE` (sha256 of every packed file plus an ed25519 signature) against the public key pinned in its own code; a copy that fails is neither installed nor loaded. Once verified, the desktop `import()`s `dist/desktop.mjs` and calls `registerCloud(host)`, which registers the 8 cloud-account IPC channels and, when the desktop is new enough to provide the matching host seam, the 7 `connect:*` channels plus the preview hooks (0.2) and the 5 `auth:*` sign-in channels plus the penzor remote-sync backend (0.3); on older desktops the parts without a seam are skipped and the rest works as before. The desktop shows or hides its UI by whether these channels exist: without this package there is no account card, Forsion settings page, sign-in entry point or "Forsion cloud" sync backend.
11
+ Forsion Desktop treats this package as a **built-in bundle**: a copy ships inside the desktop installer, is seeded into `<home>/plugins/forsion-extend/` on startup, and the npm updater downloads newer versions in the background and switches to them on the next launch. A bundle with a main-process half has one extra gate: before seeding or switching, the desktop checks the in-package `SIGNATURE` (sha256 of every packed file plus an ed25519 signature) against the public key pinned in its own code; a copy that fails is neither installed nor loaded. Once verified, the desktop `import()`s `dist/desktop.mjs` and calls `registerCloud(host)`, which registers the 8 cloud-account IPC channels and, when the desktop is new enough to provide the matching host seam, the 7 `connect:*` channels plus the preview hooks (0.2) the 5 `auth:*` sign-in channels plus the penzor remote-sync backend (0.3), and the 11 `amadeus:sync|entry-sync|collab:*` channels plus the cloud sync engine (0.4; the desktop calls the factory this package registers once the vault is ready); on older desktops the parts without a seam are skipped and the rest works as before. The desktop shows or hides its UI by whether these channels exist: without this package there is no account card, Forsion settings page, sign-in entry point, "Forsion cloud" sync backend, cloud vault or sharing entry point.
12
12
 
13
13
  | 包内文件 / file | 用途 / role |
14
14
  |---|---|
package/SIGNATURE CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "alg": "ed25519",
3
3
  "files": {
4
- "CHANGELOG.md": "00eab66ddc784373fa030c7f88885dac39e894fec99d1a9a192efba14e272eca",
4
+ "CHANGELOG.md": "a921a09c2e56c769b606b4aa874e45b55239240c36545040b0d20185f8a1c8b7",
5
5
  "LICENSE": "5594544ee08011ed5785ee26410f1f2ef005f66e9283833e8d435e34c10de1ed",
6
- "README.md": "2e47ea40144d4b49ad23bfb550b7acbb64f7eac2004bebdebfbc02184333314c",
7
- "dist/desktop.mjs": "652418d8a89ad3a9f7e306ed830b698df9b871147d58a9d5856b62e0f58b33fc",
6
+ "README.md": "6ab347b4b5a411ea75b75fec260b858ef8ccd9a1f81627de6cb75b639ae0fca7",
7
+ "dist/desktop.mjs": "3ec5bd8dd43eda39b84fc9b324e17100d39829dda19f560de89fabccccd49c21",
8
8
  "dist/main.js": "8669f048a0e9a5d47dc657306109ab437da6683ad925fbd6a451aef72542a787",
9
- "manifest.json": "619832ba87b6d239244d51062537601ff84181ee00e6baabba6e3867ebcd9de7",
10
- "package.json": "27cf696785b46a722f9efd4d7f114aeea02d7cf664ce343193f6ccc3efd9cfdf"
9
+ "manifest.json": "369c6e17ff9b71180432aa5a0d7ae9c4686072a2c8ddea1ba8f0e412f6f8bb41",
10
+ "package.json": "de8d907c29ff22fcab9f55443d56b47a48a4c328b18f3c94032b0e33db92d641"
11
11
  },
12
- "sig": "IrYOnk4++zOfgv9C/bm+Bcq27QnCRwe011X3Wste3V4aeib5Aa6HAsWK9Vh4EtdDlRnLxq5kA5hYajktDfnCCQ=="
12
+ "sig": "PHM6fcyaC/JUR3nhDcPQDJ/vh6ddh8+7tM/SCiOec2UtmkKyqJrkbphWp5dUPWsACEAoQrfM6wJnbkaAcPqgBA=="
13
13
  }
package/dist/desktop.mjs CHANGED
@@ -1,7 +1,7 @@
1
- function N(e,o){if(typeof o!="string"||!o.startsWith("/"))return null;let t=String(e||"").replace(/\/+$/,"").replace(/\/api$/,"");if(!t)return null;let r,n;try{r=new URL(t),n=new URL(t+"/api"+o)}catch{return null}return r.protocol!=="http:"&&r.protocol!=="https:"||n.origin!==r.origin||!n.pathname.startsWith("/api/")?null:n.toString()}async function w(e,o,t,r,n=6e4){let s=await fetch(e.base+t,{method:o,headers:{"Content-Type":"application/json","X-Project-Source":"connect",...e.token?{Authorization:`Bearer ${e.token}`}:{}},body:r===void 0?void 0:JSON.stringify(r),signal:AbortSignal.timeout(n)}),c=await s.json().catch(()=>({}));return{status:s.status,json:c}}import{readdirSync as ie,lstatSync as ce,readFileSync as E,writeFileSync as ue,realpathSync as L}from"node:fs";import{join as x,extname as le,sep as de}from"node:path";var A=300,H=5*1024*1024,z=20*1024*1024,fe=50*1024*1024,me=new Set(["node_modules"]),ge=new Set([".ts",".tsx",".jsx",".mts",".cts"]);function D(e,o){let t=[],r=0,n=(s,c)=>{for(let a of ie(s)){if(a.startsWith("."))continue;let i=x(s,a),l;try{l=ce(i)}catch{continue}if(l.isSymbolicLink())continue;let m=c?`${c}/${a}`:a;if(l.isDirectory()){me.has(a)||n(i,m);continue}if(!l.isFile()||a.endsWith(".d.ts"))continue;if(t.length>=A)throw new Error(`\u6587\u4EF6\u6570\u8D85\u8FC7 ${A}\uFF0C\u8BF7\u7CBE\u7B80\u9879\u76EE\uFF08node_modules \u4E0E\u9690\u85CF\u6587\u4EF6\u5DF2\u81EA\u52A8\u8DF3\u8FC7\uFF09`);let u=le(a).toLowerCase(),d,p=o.mimeOf(u)??"application/octet-stream";if(ge.has(u)){let f=o.transpile(E(i,"utf8"),u,m);d=Buffer.from(f??"","utf8"),p="text/javascript"}else d=E(i);if(d.length>H)throw new Error(`\u5355\u6587\u4EF6\u8D85\u8FC7 5MB\uFF1A${m}`);if(r+=d.length,r>z)throw new Error("\u9879\u76EE\u603B\u5927\u5C0F\u8D85\u8FC7 20MB\uFF0C\u65E0\u6CD5\u53D1\u5E03");t.push({path:m,content_b64:d.toString("base64"),content_type:p,size:d.length})}};if(n(e,""),!t.length)throw new Error("\u9879\u76EE\u4E3A\u7A7A\uFF0C\u6CA1\u6709\u53EF\u53D1\u5E03\u7684\u6587\u4EF6");return{files:t,totalBytes:r}}var B=".forsion-connect.json";function J(e){try{return JSON.parse(E(x(e,B),"utf8"))}catch{return{}}}function q(e,o){try{ue(x(e,B),JSON.stringify(o,null,2)+`
2
- `,"utf8")}catch{}}function W(e){let o={"/__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 t(r){if(o[r])return o[r];let n="/__forsion/agent-events/";if(r.startsWith(n)){let s=r.slice(n.length);if(/^[A-Za-z0-9-]{1,64}$/.test(s))return{method:"GET",path:`/api/agent/runs/${s}/events`,auth:!0,timeoutMs:9e5}}}return async(r,n)=>{let[s,c]=(r.url||"").split("?"),a=(f,g)=>{n.headersSent||(n.statusCode=f,n.setHeader("Content-Type","application/json")),n.end(JSON.stringify({detail:g}))},i=t(s);if(!i)return a(404,"unknown connect endpoint");if((r.method||"GET")!==i.method)return a(405,"method not allowed");let l="",m="";try{({base:l,token:m}=await e())}catch{}if(!l)return a(502,"\u672A\u914D\u7F6E Forsion \u4E91\u7AEF\u5730\u5740");if(i.auth&&!m)return a(401,"\u8BF7\u5148\u5728 Forsion Desktop \u4E2D\u767B\u5F55 Forsion \u8D26\u53F7");let u;if(i.method==="POST"){let f=[],g=0;try{for await(let h of r){if(g+=h.length,g>fe)return r.destroy(),a(413,"\u8BF7\u6C42\u4F53\u8FC7\u5927");f.push(h)}}catch(h){return a(400,`\u8BF7\u6C42\u4F53\u8BFB\u53D6\u5931\u8D25\uFF1A${h?.message||String(h)}`)}u=Buffer.concat(f)}if(i.agentRun){let f;try{f=JSON.parse((u||Buffer.alloc(0)).toString("utf8")||"{}")}catch{return a(400,"agent \u8BF7\u6C42\u4F53\u5FC5\u987B\u662F JSON")}u=Buffer.from(JSON.stringify({session_id:typeof f.session_id=="string"?f.session_id:"",message:typeof f.message=="string"?f.message:"",app_id:"connect",agent_config:{}}))}let d=new AbortController,p=setTimeout(()=>d.abort(new Error("proxy timeout")),i.timeoutMs??3e5);r.on("close",()=>d.abort());try{let f=await fetch(l+i.path+(c?`?${c}`:""),{method:i.method,headers:{"Content-Type":"application/json","X-Project-Source":"connect",...m?{Authorization:`Bearer ${m}`}:{}},body:u&&u.length?new Uint8Array(u):void 0,signal:d.signal});if(n.statusCode=f.status,n.setHeader("Content-Type",f.headers.get("content-type")||"application/json"),n.setHeader("Cache-Control","no-store"),f.body)for await(let g of f.body)n.write(g);n.end()}catch(f){let g=`\u4E91\u7AEF\u8BF7\u6C42\u4E2D\u65AD\uFF1A${f?.message||String(f)}`;if(n.headersSent){try{n.write(`data: ${JSON.stringify({error:g})}
1
+ function Tn(n,e){if(typeof e!="string"||!e.startsWith("/"))return null;let t=String(n||"").replace(/\/+$/,"").replace(/\/api$/,"");if(!t)return null;let s,r;try{s=new URL(t),r=new URL(t+"/api"+e)}catch{return null}return s.protocol!=="http:"&&s.protocol!=="https:"||r.origin!==s.origin||!r.pathname.startsWith("/api/")?null:r.toString()}async function me(n,e,t,s,r=6e4){let o=await fetch(n.base+t,{method:e,headers:{"Content-Type":"application/json","X-Project-Source":"connect",...n.token?{Authorization:`Bearer ${n.token}`}:{}},body:s===void 0?void 0:JSON.stringify(s),signal:AbortSignal.timeout(r)}),a=await o.json().catch(()=>({}));return{status:o.status,json:a}}import{readdirSync as Vr,lstatSync as Gr,readFileSync as Ft,writeFileSync as Yr,realpathSync as Rn}from"node:fs";import{join as Lt,extname as Jr,sep as Kr}from"node:path";var Ot=300,In=5*1024*1024,An=20*1024*1024,Xr=50*1024*1024,Qr=new Set(["node_modules"]),Zr=new Set([".ts",".tsx",".jsx",".mts",".cts"]);function Pn(n,e){let t=[],s=0,r=(o,a)=>{for(let c of Vr(o)){if(c.startsWith("."))continue;let l=Lt(o,c),h;try{h=Gr(l)}catch{continue}if(h.isSymbolicLink())continue;let f=a?`${a}/${c}`:c;if(h.isDirectory()){Qr.has(c)||r(l,f);continue}if(!h.isFile()||c.endsWith(".d.ts"))continue;if(t.length>=Ot)throw new Error(`\u6587\u4EF6\u6570\u8D85\u8FC7 ${Ot}\uFF0C\u8BF7\u7CBE\u7B80\u9879\u76EE\uFF08node_modules \u4E0E\u9690\u85CF\u6587\u4EF6\u5DF2\u81EA\u52A8\u8DF3\u8FC7\uFF09`);let m=Jr(c).toLowerCase(),u,w=e.mimeOf(m)??"application/octet-stream";if(Zr.has(m)){let v=e.transpile(Ft(l,"utf8"),m,f);u=Buffer.from(v??"","utf8"),w="text/javascript"}else u=Ft(l);if(u.length>In)throw new Error(`\u5355\u6587\u4EF6\u8D85\u8FC7 5MB\uFF1A${f}`);if(s+=u.length,s>An)throw new Error("\u9879\u76EE\u603B\u5927\u5C0F\u8D85\u8FC7 20MB\uFF0C\u65E0\u6CD5\u53D1\u5E03");t.push({path:f,content_b64:u.toString("base64"),content_type:w,size:u.length})}};if(r(n,""),!t.length)throw new Error("\u9879\u76EE\u4E3A\u7A7A\uFF0C\u6CA1\u6709\u53EF\u53D1\u5E03\u7684\u6587\u4EF6");return{files:t,totalBytes:s}}var Dn=".forsion-connect.json";function $n(n){try{return JSON.parse(Ft(Lt(n,Dn),"utf8"))}catch{return{}}}function Mn(n,e){try{Yr(Lt(n,Dn),JSON.stringify(e,null,2)+`
2
+ `,"utf8")}catch{}}function Nn(n){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 t(s){if(e[s])return e[s];let r="/__forsion/agent-events/";if(s.startsWith(r)){let o=s.slice(r.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(s,r)=>{let[o,a]=(s.url||"").split("?"),c=(v,R)=>{r.headersSent||(r.statusCode=v,r.setHeader("Content-Type","application/json")),r.end(JSON.stringify({detail:R}))},l=t(o);if(!l)return c(404,"unknown connect endpoint");if((s.method||"GET")!==l.method)return c(405,"method not allowed");let h="",f="";try{({base:h,token:f}=await n())}catch{}if(!h)return c(502,"\u672A\u914D\u7F6E Forsion \u4E91\u7AEF\u5730\u5740");if(l.auth&&!f)return c(401,"\u8BF7\u5148\u5728 Forsion Desktop \u4E2D\u767B\u5F55 Forsion \u8D26\u53F7");let m;if(l.method==="POST"){let v=[],R=0;try{for await(let _ of s){if(R+=_.length,R>Xr)return s.destroy(),c(413,"\u8BF7\u6C42\u4F53\u8FC7\u5927");v.push(_)}}catch(_){return c(400,`\u8BF7\u6C42\u4F53\u8BFB\u53D6\u5931\u8D25\uFF1A${_?.message||String(_)}`)}m=Buffer.concat(v)}if(l.agentRun){let v;try{v=JSON.parse((m||Buffer.alloc(0)).toString("utf8")||"{}")}catch{return c(400,"agent \u8BF7\u6C42\u4F53\u5FC5\u987B\u662F JSON")}m=Buffer.from(JSON.stringify({session_id:typeof v.session_id=="string"?v.session_id:"",message:typeof v.message=="string"?v.message:"",app_id:"connect",agent_config:{}}))}let u=new AbortController,w=setTimeout(()=>u.abort(new Error("proxy timeout")),l.timeoutMs??3e5);s.on("close",()=>u.abort());try{let v=await fetch(h+l.path+(a?`?${a}`:""),{method:l.method,headers:{"Content-Type":"application/json","X-Project-Source":"connect",...f?{Authorization:`Bearer ${f}`}:{}},body:m&&m.length?new Uint8Array(m):void 0,signal:u.signal});if(r.statusCode=v.status,r.setHeader("Content-Type",v.headers.get("content-type")||"application/json"),r.setHeader("Cache-Control","no-store"),v.body)for await(let R of v.body)r.write(R);r.end()}catch(v){let R=`\u4E91\u7AEF\u8BF7\u6C42\u4E2D\u65AD\uFF1A${v?.message||String(v)}`;if(r.headersSent){try{r.write(`data: ${JSON.stringify({error:R})}
3
3
 
4
- `)}catch{}n.end()}else a(502,g)}finally{clearTimeout(p)}}}var G=`
4
+ `)}catch{}r.end()}else c(502,R)}finally{clearTimeout(w)}}}var Fn=`
5
5
  (function () {
6
6
  'use strict';
7
7
  if (window.forsion) return;
@@ -190,4 +190,15 @@ function N(e,o){if(typeof o!="string"||!o.startsWith("/"))return null;let t=Stri
190
190
  ai: { chat: chat, agent: agentRun, generateImage: generateImage }
191
191
  };
192
192
  })();
193
- `,pe=e=>({transpile:(o,t,r)=>e.transpileForServe(o,t,r),mimeOf:o=>e.mimeOf(o)});function j(e){let o=e;return typeof o.projectsRoot=="function"&&typeof o.transpileForServe=="function"&&typeof o.mimeOf=="function"&&typeof o.setPreviewHooks=="function"}function P(e){e.setPreviewHooks({sdkJs:G,proxy:W(()=>e.getCloud())}),e.handle("connect:meta",(o,t)=>typeof t=="string"&&t?J(t):{}),e.handle("connect:list",async()=>{let o=await e.getCloud();if(!o.token)return{ok:!1,code:"not_logged_in",detail:"\u8BF7\u5148\u767B\u5F55 Forsion \u8D26\u53F7"};try{let{status:t,json:r}=await w(o,"GET","/api/connect/apps");return t===401||t===403?{ok:!1,code:"not_logged_in",detail:"\u767B\u5F55\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u767B\u5F55"}:t!==200?{ok:!1,code:"error",detail:r?.detail||`HTTP ${t}`}:{ok:!0,base:o.base,...r}}catch(t){return{ok:!1,code:"error",detail:t?.message||String(t)}}}),e.handle("connect:publish",async(o,t)=>{if(!t||typeof t.dir!="string"||!t.dir||!t.name||!t.slug||!t.entry)return{ok:!1,code:"error",detail:"\u53C2\u6570\u4E0D\u5B8C\u6574"};let r;try{let s=L(e.projectsRoot());if(r=L(t.dir),r!==s&&!r.startsWith(s+de))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 n=await e.getCloud();if(!n.token)return{ok:!1,code:"not_logged_in",detail:"\u8BF7\u5148\u767B\u5F55 Forsion \u8D26\u53F7"};try{let{files:s,totalBytes:c}=D(r,pe(e));if(!s.some(l=>l.path===t.entry))return{ok:!1,code:"error",detail:`\u5165\u53E3\u6587\u4EF6\u4E0D\u5B58\u5728:${t.entry}`};let{status:a,json:i}=await w(n,"POST","/api/connect/apps",{slug:t.slug,name:t.name,entry:t.entry,files:s},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:i?.code||"error",detail:i?.detail||`HTTP ${a}`,used:i?.used,limit:i?.limit}:(q(r,{slug:String(i.slug)}),{ok:!0,slug:i.slug,handle:i.handle,url:`${n.base}${i.url}`,totalBytes:c})}catch(s){return{ok:!1,code:"error",detail:s?.message||String(s)}}}),e.handle("connect:unpublish",async(o,t)=>{if(!t||typeof t!="string")return{ok:!1,code:"error",detail:"\u53C2\u6570\u4E0D\u5B8C\u6574"};let r=await e.getCloud();if(!r.token)return{ok:!1,code:"not_logged_in",detail:"\u8BF7\u5148\u767B\u5F55 Forsion \u8D26\u53F7"};try{let{status:n,json:s}=await w(r,"DELETE",`/api/connect/apps/${encodeURIComponent(t)}`);return n===401||n===403?{ok:!1,code:"not_logged_in",detail:"\u767B\u5F55\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u767B\u5F55"}:n!==200&&n!==404?{ok:!1,code:"error",detail:s?.detail||`HTTP ${n}`}:{ok:!0}}catch(n){return{ok:!1,code:"error",detail:n?.message||String(n)}}}),e.handle("connect:listingApply",async(o,t)=>{if(!t||typeof t.slug!="string"||!t.slug||typeof t.summary!="string"||!t.summary.trim())return{ok:!1,code:"error",detail:"\u53C2\u6570\u4E0D\u5B8C\u6574"};let r=await e.getCloud();if(!r.token)return{ok:!1,code:"not_logged_in",detail:"\u8BF7\u5148\u767B\u5F55 Forsion \u8D26\u53F7"};try{let{status:n,json:s}=await w(r,"PUT",`/api/connect/apps/${encodeURIComponent(t.slug)}/listing`,{summary:t.summary});return n===401?{ok:!1,code:"not_logged_in",detail:"\u767B\u5F55\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u767B\u5F55"}:n!==200?{ok:!1,code:s?.code||"error",detail:s?.detail||`HTTP ${n}`}:{ok:!0,status:s.status}}catch(n){return{ok:!1,code:"error",detail:n?.message||String(n)}}}),e.handle("connect:listingWithdraw",async(o,t)=>{if(!t||typeof t!="string")return{ok:!1,code:"error",detail:"\u53C2\u6570\u4E0D\u5B8C\u6574"};let r=await e.getCloud();if(!r.token)return{ok:!1,code:"not_logged_in",detail:"\u8BF7\u5148\u767B\u5F55 Forsion \u8D26\u53F7"};try{let{status:n,json:s}=await w(r,"DELETE",`/api/connect/apps/${encodeURIComponent(t)}/listing`);return n===401?{ok:!1,code:"not_logged_in",detail:"\u767B\u5F55\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u767B\u5F55"}:n!==200&&n!==404?{ok:!1,code:"error",detail:s?.detail||`HTTP ${n}`}:{ok:!0}}catch(n){return{ok:!1,code:"error",detail:n?.message||String(n)}}}),e.handle("connect:store",async()=>{let o=await e.getCloud();try{let{status:t,json:r}=await w(o,"GET","/api/connect/store");return t!==200?{ok:!1,detail:r?.detail||`HTTP ${t}`}:{ok:!0,base:o.base,items:Array.isArray(r.items)?r.items:[]}}catch(t){return{ok:!1,detail:t?.message||String(t)}}}),e.log("[forsion-extend] connect handlers registered")}import{createHash as he}from"node:crypto";async function v(e,o){if(!e||!o)return{status:"offline"};let t=e.replace(/\/+$/,"");try{let r=await fetch(`${t}/api/brain/users/me`,{headers:{Authorization:`Bearer ${o}`},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 n=await r.json();if(!n)return{status:"offline"};let s=n.avatar||n.avatarUrl||n.avatar_url||void 0;return s&&/^\/(?!\/)/.test(s)&&(s=t+s),{status:"ok",user:{username:n.username||n.nickname||void 0,nickname:n.nickname||void 0,avatar:s,membershipTier:n.membershipTier||n.membership_tier||void 0}}}catch{return{status:"offline"}}}var X=e=>`${e.seq}:${e.hash}`,ye=e=>he("sha256").update(e).digest("hex");function $(e){if(e===null)return{baseSeq:0,baseHash:null};if(typeof e!="string")return;let o=e.indexOf(":"),t=Number(o===-1?e:e.slice(0,o));if(!Number.isInteger(t)||t<=0)return;let r=o===-1?"":e.slice(o+1);return{baseSeq:t,baseHash:/^[0-9a-f]{64}$/.test(r)?r:null}}function V(e){let o=e.baseUrl.replace(/\/+$/,""),t=n=>`${o}/api/remotesync/vaults/${encodeURIComponent(e.vault)}${n}`,r=async(n,s)=>{let c=e.getToken();if(!c)throw new Error("penzor-not-logged-in");let a=await fetch(n,{...s,headers:{...s.headers,Authorization:`Bearer ${c}`}});if(a.status===409){let i=await a.json().catch(()=>({}));throw new Error(`cas-conflict ${String(i.code??"")}: seq=${String(i.seq??"?")}`)}if(!a.ok){let i=await a.text().catch(()=>"");throw new Error(`penzor ${s.method??"GET"} ${a.status}: ${i.slice(0,200)}`)}return a};return{kind:"penzor",async walk(n){let s=await r(t("/manifest"),{method:"GET",signal:n}),{files:c}=await s.json();return c.map(a=>({key:a.path,size:a.size,mtimeMs:a.mtimeMs,id:X(a)}))},async readFile(n,s){let a=await(await r(t(`/file?path=${encodeURIComponent(n)}`),{method:"GET",signal:s})).json(),i=await fetch(a.url,{signal:s});if(!i.ok)throw new Error(`penzor blob GET ${i.status}: ${n}`);let l=Buffer.from(await i.arrayBuffer());if(ye(l)!==a.hash)throw new Error(`penzor hash mismatch: ${n}`);return l},async writeFile(n,s,c,a,i){let l=$(i),m=new URLSearchParams({path:n,mtimeMs:String(Math.floor(c)||0)});l&&(m.set("baseSeq",String(l.baseSeq)),l.baseHash&&m.set("baseHash",l.baseHash));let d=await(await r(t(`/file?${m.toString()}`),{method:"PUT",body:new Uint8Array(s),headers:{"Content-Type":"application/octet-stream"},signal:a})).json();return{key:n,size:d.size,mtimeMs:d.mtimeMs,id:X(d)}},async rm(n,s,c){let a=$(c),i=new URLSearchParams({path:n});a&&a.baseSeq>0&&(i.set("baseSeq",String(a.baseSeq)),a.baseHash&&i.set("baseHash",a.baseHash)),await r(t(`/file?${i.toString()}`),{method:"DELETE",signal:s})},async check(){try{return await r(t("/manifest"),{method:"GET"}),{ok:!0}}catch(n){return{ok:!1,error:String(n?.message||n)}}}}}var Y=50*1024*1024,K=new Map;async function we(e,o){let t=K.get(o);if(t)return{id:t};let r=await v(e,o);if(r.status==="offline")return{error:"penzor-offline"};if(r.status!=="ok")return{error:"penzor-not-logged-in"};let n=r.user?.username?.trim();return n?(K.set(o,n),{id:n}):{error:"penzor-auth-unverified"}}var R=e=>typeof e.registerRemoteSyncBackend=="function"&&typeof e.readCreds=="function";function O(e){e.registerRemoteSyncBackend("penzor",async o=>{let t=e.readCreds();if(!t.token||!t.cloudUrl)return{error:"penzor-not-logged-in"};let r=o?.vault,n=(typeof r=="string"?r:"default").trim()||"default";if(!/^[A-Za-z0-9_-]{1,64}$/.test(n))return{error:"penzor-bad-vault"};let s=await we(t.cloudUrl,t.token);if("error"in s)return s;let c=t.token;return{remote:V({baseUrl:t.cloudUrl,vault:n,getToken:()=>c}),fingerprint:`penzor:${t.cloudUrl.replace(/\/+$/,"")}|u:${s.id}|${n}`,maxFileBytes:Y}}),e.log('[forsion-extend] remote-sync backend "penzor" registered')}import{readFileSync as ke,writeFileSync as be,mkdirSync as Ce,chmodSync as ve,renameSync as Se}from"node:fs";import{join as _e}from"node:path";function C(e,o){try{let t=new URL(e);if(t.protocol!=="https:"&&t.protocol!=="http:")return null;let r=o.split(".")[1];if(!r)return null;let n=r.replace(/-/g,"+").replace(/_/g,"/"),s=Uint8Array.from(atob(n),i=>i.charCodeAt(0)),c=JSON.parse(new TextDecoder().decode(s)),a=c.userId??c.sub;return typeof a!="string"&&typeof a!="number"||!String(a).trim()?null:`${t.origin}${t.pathname.replace(/\/+$/,"")}::${String(a)}`}catch{return null}}function U(e){try{let o=e.split(".")[1];if(!o)return null;let t=JSON.parse(Buffer.from(o,"base64url").toString("utf8"));return t&&typeof t=="object"?t:null}catch{return null}}function Q(e,o=Date.now()){let t=U(e)?.iat;return typeof t=="number"?o-t*1e3:1/0}function Te(e,o=Date.now()){let t=U(e)?.exp;return typeof t=="number"?t*1e3-o:1/0}var Ee=36e5;function ee(e,o=Date.now()){return!!e&&Q(e,o)>=Ee}async function te(e,o,t=8e3,r){if(!e||!o)return null;let n=e.replace(/\/+$/,"");try{let s=await fetch(`${n}/api/auth/refresh`,{method:"POST",headers:{Authorization:`Bearer ${o}`,...r?{"X-Forsion-Client":r}:{}},signal:AbortSignal.timeout(t)});if(!s.ok)return null;let c=await s.json().catch(()=>null),a=typeof c?.token=="string"?c.token:"";return a&&a!==o?a:null}catch{return null}}var T=(e,o)=>`${e.replace(/\/+$/,"")}\0${o}`,Ae=(e,o)=>new Promise((t,r)=>{let n=()=>{clearTimeout(s),r(new Error("Sign-in cancelled."))},s=setTimeout(()=>{o.removeEventListener("abort",n),t()},e);o.aborted?n():o.addEventListener("abort",n,{once:!0})});function ne(e){let o=()=>_e(e.homeDir(),"auth-accounts.json"),t=(u,d)=>{Ce(e.homeDir(),{recursive:!0});let p=`${u}.tmp`;be(p,JSON.stringify(d,null,2),{encoding:"utf8",mode:384}),ve(p,384),Se(p,u)},r=()=>{try{let u=JSON.parse(ke(o(),"utf8"));return Array.isArray(u.accounts)?u.accounts.filter(d=>d&&typeof d.token=="string"&&d.id===C(d.cloudUrl,d.token)):[]}catch{return[]}},n=(u,d)=>{let p=C(u.cloudUrl||"",u.token||"");if(!p||!u.token||!u.cloudUrl)return;let f=r(),g=f.find(k=>k.id===p),h=U(u.token),y={...g,id:p,cloudUrl:u.cloudUrl.replace(/\/+$/,""),token:u.token,username:d?.username||g?.username||h?.username,nickname:d?.nickname||g?.nickname};JSON.stringify(g)!==JSON.stringify(y)&&t(o(),{version:1,accounts:[...f.filter(k=>k.id!==p),y]})},s=()=>{let u=e.readCreds();n(u);let d=C(u.cloudUrl,u.token);return r().map(({token:p,...f})=>({...f,active:f.id===d}))},c=u=>{let d=r().find(p=>p.id===u);if(!d)throw new Error("Account is no longer signed in. Sign in again.");return{cloudUrl:d.cloudUrl,token:d.token}},a=u=>{let d=C(u.cloudUrl||"",u.token||"");d&&t(o(),{version:1,accounts:r().filter(p=>p.id!==d)})},i=null;return{rememberForsionAccount:n,forsionAccounts:s,savedForsionAccount:c,forgetForsionAccount:a,cancelForsionLogin:()=>{i?.abort(),i=null},forsionDeviceLogin:async(u,d,p)=>{if(i)throw new Error("A sign-in is already in progress.");if(!u)throw new Error("\u8BF7\u5148\u586B\u5199 Forsion \u4E91\u7AEF\u5730\u5740(\u6216\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF TANGU_CLOUD_URL)");let f=new AbortController;i=f;let g=()=>{if(f.signal.aborted||i!==f)throw new Error("Sign-in cancelled.")};try{let h=u.replace(/\/+$/,""),y;try{y=await fetch(`${h}/api/auth/cli/start`,{method:"POST",headers:{"Content-Type":"application/json"},body:"{}",signal:AbortSignal.any([f.signal,AbortSignal.timeout(15e3)])}).then(b=>b.json())}catch(b){throw new Error(`\u65E0\u6CD5\u8FDE\u63A5 ${h}:${b?.message||b}`)}if(g(),!y?.device_code)throw new Error("\u4E91\u7AEF\u4E0D\u652F\u6301 CLI \u767B\u5F55(/api/auth/cli/start \u8FD4\u56DE\u5F02\u5E38)");let k=y.verification_uri_complete||`${y.verification_uri}?code=${y.user_code}`,S=new URL(`${h}/auth`);S.searchParams.set("logout","1"),S.searchParams.set("app","forsion-desktop"),S.searchParams.set("redirect",k);let M=S.toString();d?.({url:M,userCode:String(y.user_code||"")}),e.openExternal(M);let oe=Date.now()+(y.expires_in||600)*1e3,se=(y.interval||2)*1e3;for(;Date.now()<oe;){await Ae(se,f.signal),g();let b=null;try{b=await fetch(`${h}/api/auth/cli/poll`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({device_code:y.device_code}),signal:AbortSignal.any([f.signal,AbortSignal.timeout(15e3)])})}catch{g();continue}if(g(),b.status===410)throw new Error("\u767B\u5F55\u7801\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u53D1\u8D77\u767B\u5F55");let _=await b.json().catch(()=>({status:"pending"}));if(g(),_.status==="approved"&&_.token){let ae={cloudUrl:h,token:_.token};return await p(ae,g),g(),{token:_.token,cloudUrl:h}}}throw new Error("\u767B\u5F55\u8D85\u65F6,\u8BF7\u91CD\u8BD5")}finally{i===f&&(i=null)}},readAccounts:r}}var re=["homeDir","appVersion","broadcast","accountBackendState","accountTransition","accountCommit","accountClear","writeCreds","onExternalCredsChange","setTokenRefresher","readCreds"],I=e=>re.every(o=>typeof e[o]=="function");function F(e){let o=ne(e),t=0,r=()=>{let s=e.readCreds();return T(s.cloudUrl,s.token)},n=null;e.handle("auth:status",async()=>{let s=t,c=r(),{base:a}=await e.getCloud(),i=e.readCreds().token,l=i?await v(a,i):null,m=await e.accountBackendState(),{base:u}=await e.getCloud(),d=e.readCreds(),p=T(u,d.token)!==T(a,i),f=T(a,i);!p&&l?.status==="ok"&&l.user&&(n={key:f,user:l.user},o.rememberForsionAccount({...d,cloudUrl:a},l.user));let g=p?void 0:l?.status==="ok"?l.user:l?.status==="offline"&&n?.key===f?n.user:void 0;if(p)return{loggedIn:!!d.token,tokenValid:null,cloudUrl:u,accountId:C(u,d.token),username:null,nickname:null,avatar:null,membershipTier:null,tokenSource:d.token?"tangu-login":null,backendState:m};if(l?.status==="expired"){await e.accountTransition(async()=>{if(s!==t||r()!==c)return;let y=()=>{if(s!==t||r()!==c)throw Z};try{await e.accountClear(y,()=>{e.log("[auth] token \u5DF2\u5931\u6548(\u670D\u52A1\u7AEF 401/403),\u81EA\u52A8\u767B\u51FA"),++t,o.cancelForsionLogin(),o.forgetForsionAccount(e.readCreds()),n=null})}catch(k){if(k!==Z)throw k}});let h=e.readCreds();return{loggedIn:!!h.token,tokenValid:null,cloudUrl:h.cloudUrl||a,accountId:C(h.cloudUrl||a,h.token),username:null,nickname:null,avatar:null,membershipTier:null,tokenSource:h.token?"tangu-login":null,backendState:m}}return{loggedIn:!!i,tokenValid:l&&l.status==="ok"?!0:null,cloudUrl:a,accountId:C(a,i),username:g?.username||null,nickname:g?.nickname||null,avatar:g?.avatar||null,membershipTier:g?.membershipTier||null,tokenSource:i?"tangu-login":null,backendState:m}}),e.handle("auth:accounts",()=>o.forsionAccounts()),e.handle("auth:switchAccount",async(s,c)=>{if(typeof c!="string")throw new Error("Invalid account.");let a=++t;return o.cancelForsionLogin(),e.accountTransition(async()=>{let i=o.savedForsionAccount(c);return await e.accountCommit(i,()=>{if(a!==t)throw new Error("Account switch cancelled.")},()=>{o.rememberForsionAccount(i),n=null}),{ok:!0,cloudUrl:i.cloudUrl||""}})}),e.handle("auth:forsionLogin",async(s,c)=>{let a=++t;o.cancelForsionLogin();let{base:i}=await e.getCloud();if(a!==t)throw new Error("Sign-in cancelled.");let l=(c||i||"").trim();return{ok:!0,cloudUrl:(await o.forsionDeviceLogin(l,u=>e.broadcast("auth:device",u),(u,d)=>e.accountTransition(()=>e.accountCommit(u,()=>{if(d(),a!==t)throw new Error("Sign-in cancelled.")},()=>{o.rememberForsionAccount(u),n=null})))).cloudUrl}}),e.handle("auth:logout",async()=>(++t,o.cancelForsionLogin(),e.accountTransition(async()=>{let{base:s}=await e.getCloud(),c=e.readCreds();return await e.accountClear(void 0,()=>{o.forgetForsionAccount(c),n=null,s&&c.token&&fetch(`${s}/api/auth/logout`,{method:"POST",headers:{Authorization:`Bearer ${c.token}`},signal:AbortSignal.timeout(5e3)}).catch(()=>{})}),{ok:!0}}))),e.onExternalCredsChange(({previous:s,current:c})=>{++t,o.cancelForsionLogin(),s.token&&!c.token&&o.forgetForsionAccount(s),n=null,o.rememberForsionAccount(c)}),e.setTokenRefresher(async s=>{let c=t,a=r(),i=e.readCreds().token;if(!ee(i))return;let{base:l}=await e.getCloud(),m=await te(l,i,s,`desktop/${e.appVersion()}`);if(!m){e.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}c!==t||r()!==a||(o.rememberForsionAccount({cloudUrl:l,token:m}),e.writeCreds({cloudUrl:l,token:m}),e.log("[auth] \u767B\u5F55\u6001\u5DF2\u6ED1\u52A8\u7EED\u671F(\u6709\u6548\u671F\u91CD\u65B0\u8BA1\u6EE1 2 \u5468)"))}),e.log("[forsion-extend] account core registered")}var Z=Symbol("stale-auth-intent");function Ge(e){e.handle("auth:openAccountCenter",async(t,r)=>{let{base:n,token:s}=await e.getCloud();if(!n)return{ok:!1};let c=r&&/^[a-z0-9-]+$/i.test(r)?`#${r}`:"",a=`${n}/account${s?`?token=${encodeURIComponent(s)}`:""}${c}`;return await e.openExternal(a),{ok:!0}}),e.handle("auth:openPayCenter",async()=>{let{base:t,token:r}=await e.getCloud();if(!t)return{ok:!1};let n=`${t}/pay?tab=membership${r?`&token=${encodeURIComponent(r)}`:""}&redirect=${encodeURIComponent(`${t}/account`)}`;return await e.openExternal(n),{ok:!0}});let o=()=>e.getCloud();e.handle("account:quota",async()=>{let t=await o();if(!t.token)return{status:401,json:null};try{return await w(t,"GET","/api/token-quota/my",void 0,15e3)}catch(r){return{status:0,json:{detail:String(r?.message||r)}}}}),e.handle("account:useResetCard",async(t,r)=>{let n=await o();if(!n.token)return{status:401,json:null};if(r!==void 0&&r!=="both"&&r!=="weekly")return{status:400,json:{error:"invalid_type",detail:`invalid reset card type: ${r}`}};let s=r??"both";try{return await w(n,"POST","/api/token-quota/reset-card/use",{type:s},15e3)}catch(c){return{status:0,json:{detail:String(c?.message||c)}}}}),e.handle("account:bgConvert",async(t,r)=>{let n=await o();if(!n.token)return{status:401,json:null};if(!Number.isInteger(r)||r<1||r>100)return{status:400,json:{error:"invalid_percent"}};try{return await w(n,"POST","/api/token-quota/background/convert",{percent:r},15e3)}catch(s){return{status:0,json:{detail:String(s?.message||s)}}}}),e.handle("account:bgAutoMain",async(t,r)=>{let n=await o();if(!n.token)return{status:401,json:null};if(typeof r!="boolean")return{status:400,json:{error:"invalid_request"}};try{return await w(n,"POST","/api/token-quota/background/auto-main",{enabled:r},15e3)}catch(s){return{status:0,json:{detail:String(s?.message||s)}}}}),e.handle("feedback:submit",async(t,r)=>{let{base:n,token:s}=await e.getCloud();if(!n||!s)return{ok:!1,error:"not-logged-in"};let c=(r?.description||"").trim();if(!c)return{ok:!1,error:"empty"};if(c.length>1e4)return{ok:!1,error:"description-too-long"};let a=[],i=!1;if(r?.sessionLogJson){let l=Buffer.from(r.sessionLogJson,"utf8");if(l.length>5*1024*1024)return{ok:!1,error:"attachment-too-large"};a.push({filename:r.sessionLogName||"tangu-session.json",mime_type:"application/json",size:l.length,data_base64:l.toString("base64")})}try{let l=await fetch(`${n}/api/feedback`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify({description:c,attachments:a}),signal:AbortSignal.timeout(2e4)});if(!l.ok){let u=`HTTP ${l.status}`;try{u=(await l.json())?.detail||u}catch{}return{ok:!1,error:u}}return{ok:!0,id:(await l.json().catch(()=>({})))?.id??null,attachmentSkipped:i}}catch(l){return{ok:!1,error:l?.message||String(l)}}}),e.handle("cloud:fetch",async(t,r)=>{if(!e.isTrustedSender(t))return{status:0,error:"untrusted"};let n=r??{},s=typeof n.path=="string"?n.path:"",c=Math.min(12e4,Math.max(1e3,Number(n.timeoutMs)||15e3)),a=typeof n.method=="string"?n.method.toUpperCase():"GET";if(!/^(GET|POST|PUT|PATCH|DELETE)$/.test(a))return{status:0,error:"bad_method"};if(!s.startsWith("/"))return{status:0,error:"bad_path"};let{base:i,token:l}=await e.getCloud();if(!String(i||""))return{status:0,error:"no_cloud_url"};let m=N(i,s);if(!m)return{status:0,error:"bad_path"};if(!l)return{status:401,error:"not_signed_in"};let u=n.body!==void 0&&a!=="GET"&&a!=="DELETE",d=new AbortController,p=setTimeout(()=>d.abort(),c);try{let f=await fetch(m,{method:a,headers:{Authorization:`Bearer ${l}`,...u?{"Content-Type":"application/json"}:{}},body:u?JSON.stringify(n.body):void 0,signal:d.signal});return{status:f.status,json:await f.json().catch(()=>null)}}catch(f){return{status:0,error:String(f?.message||f)}}finally{clearTimeout(p)}}),e.log("[forsion-extend] cloud account handlers registered"),j(e)?P(e):e.log("[forsion-extend] host has no Connect seam (projectsRoot / transpileForServe / mimeOf / setPreviewHooks); Connect stays with the host"),R(e)?O(e):e.log("[forsion-extend] host has no remote-sync seam (registerRemoteSyncBackend / readCreds); penzor stays with the host"),I(e)?F(e):e.log("[forsion-extend] host has no account seam (accountCommit / accountClear / \u2026); account core stays with the host")}export{re as ACCOUNT_SEAM,A as CONNECT_MAX_FILES,H as CONNECT_MAX_FILE_BYTES,z as CONNECT_MAX_TOTAL_BYTES,G as FORSION_CONNECT_LOCAL_SDK,Y as PENZOR_MAX_FILE,w as cloudJson,D as collectProjectFiles,ne as createAccountCloud,V as createPenzorRemote,$ as expectedPartsOf,C as forsionAccountId,te as forsionRefreshToken,v as forsionWhoami,I as hasAccountHost,j as hasConnectHost,R as hasRemoteSyncHost,W as makePreviewProxy,J as readConnectMeta,F as registerAccount,Ge as registerCloud,P as registerConnect,O as registerPenzor,ee as shouldRefreshToken,Q as tokenAgeMs,Te as tokenRemainingMs,q as writeConnectMeta};
193
+ `,es=n=>({transpile:(e,t,s)=>n.transpileForServe(e,t,s),mimeOf:e=>n.mimeOf(e)});function jt(n){let e=n;return typeof e.projectsRoot=="function"&&typeof e.transpileForServe=="function"&&typeof e.mimeOf=="function"&&typeof e.setPreviewHooks=="function"}function Ut(n){n.setPreviewHooks({sdkJs:Fn,proxy:Nn(()=>n.getCloud())}),n.handle("connect:meta",(e,t)=>typeof t=="string"&&t?$n(t):{}),n.handle("connect:list",async()=>{let e=await n.getCloud();if(!e.token)return{ok:!1,code:"not_logged_in",detail:"\u8BF7\u5148\u767B\u5F55 Forsion \u8D26\u53F7"};try{let{status:t,json:s}=await me(e,"GET","/api/connect/apps");return t===401||t===403?{ok:!1,code:"not_logged_in",detail:"\u767B\u5F55\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u767B\u5F55"}:t!==200?{ok:!1,code:"error",detail:s?.detail||`HTTP ${t}`}:{ok:!0,base:e.base,...s}}catch(t){return{ok:!1,code:"error",detail:t?.message||String(t)}}}),n.handle("connect:publish",async(e,t)=>{if(!t||typeof t.dir!="string"||!t.dir||!t.name||!t.slug||!t.entry)return{ok:!1,code:"error",detail:"\u53C2\u6570\u4E0D\u5B8C\u6574"};let s;try{let o=Rn(n.projectsRoot());if(s=Rn(t.dir),s!==o&&!s.startsWith(o+Kr))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 r=await n.getCloud();if(!r.token)return{ok:!1,code:"not_logged_in",detail:"\u8BF7\u5148\u767B\u5F55 Forsion \u8D26\u53F7"};try{let{files:o,totalBytes:a}=Pn(s,es(n));if(!o.some(h=>h.path===t.entry))return{ok:!1,code:"error",detail:`\u5165\u53E3\u6587\u4EF6\u4E0D\u5B58\u5728:${t.entry}`};let{status:c,json:l}=await me(r,"POST","/api/connect/apps",{slug:t.slug,name:t.name,entry:t.entry,files:o},3e5);return c===401?{ok:!1,code:"not_logged_in",detail:"\u767B\u5F55\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u767B\u5F55"}:c!==200?{ok:!1,code:l?.code||"error",detail:l?.detail||`HTTP ${c}`,used:l?.used,limit:l?.limit}:(Mn(s,{slug:String(l.slug)}),{ok:!0,slug:l.slug,handle:l.handle,url:`${r.base}${l.url}`,totalBytes:a})}catch(o){return{ok:!1,code:"error",detail:o?.message||String(o)}}}),n.handle("connect:unpublish",async(e,t)=>{if(!t||typeof t!="string")return{ok:!1,code:"error",detail:"\u53C2\u6570\u4E0D\u5B8C\u6574"};let s=await n.getCloud();if(!s.token)return{ok:!1,code:"not_logged_in",detail:"\u8BF7\u5148\u767B\u5F55 Forsion \u8D26\u53F7"};try{let{status:r,json:o}=await me(s,"DELETE",`/api/connect/apps/${encodeURIComponent(t)}`);return r===401||r===403?{ok:!1,code:"not_logged_in",detail:"\u767B\u5F55\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u767B\u5F55"}:r!==200&&r!==404?{ok:!1,code:"error",detail:o?.detail||`HTTP ${r}`}:{ok:!0}}catch(r){return{ok:!1,code:"error",detail:r?.message||String(r)}}}),n.handle("connect:listingApply",async(e,t)=>{if(!t||typeof t.slug!="string"||!t.slug||typeof t.summary!="string"||!t.summary.trim())return{ok:!1,code:"error",detail:"\u53C2\u6570\u4E0D\u5B8C\u6574"};let s=await n.getCloud();if(!s.token)return{ok:!1,code:"not_logged_in",detail:"\u8BF7\u5148\u767B\u5F55 Forsion \u8D26\u53F7"};try{let{status:r,json:o}=await me(s,"PUT",`/api/connect/apps/${encodeURIComponent(t.slug)}/listing`,{summary:t.summary});return r===401?{ok:!1,code:"not_logged_in",detail:"\u767B\u5F55\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u767B\u5F55"}:r!==200?{ok:!1,code:o?.code||"error",detail:o?.detail||`HTTP ${r}`}:{ok:!0,status:o.status}}catch(r){return{ok:!1,code:"error",detail:r?.message||String(r)}}}),n.handle("connect:listingWithdraw",async(e,t)=>{if(!t||typeof t!="string")return{ok:!1,code:"error",detail:"\u53C2\u6570\u4E0D\u5B8C\u6574"};let s=await n.getCloud();if(!s.token)return{ok:!1,code:"not_logged_in",detail:"\u8BF7\u5148\u767B\u5F55 Forsion \u8D26\u53F7"};try{let{status:r,json:o}=await me(s,"DELETE",`/api/connect/apps/${encodeURIComponent(t)}/listing`);return r===401?{ok:!1,code:"not_logged_in",detail:"\u767B\u5F55\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u767B\u5F55"}:r!==200&&r!==404?{ok:!1,code:"error",detail:o?.detail||`HTTP ${r}`}:{ok:!0}}catch(r){return{ok:!1,code:"error",detail:r?.message||String(r)}}}),n.handle("connect:store",async()=>{let e=await n.getCloud();try{let{status:t,json:s}=await me(e,"GET","/api/connect/store");return t!==200?{ok:!1,detail:s?.detail||`HTTP ${t}`}:{ok:!0,base:e.base,items:Array.isArray(s.items)?s.items:[]}}catch(t){return{ok:!1,detail:t?.message||String(t)}}}),n.log("[forsion-extend] connect handlers registered")}import{createHash as ts}from"node:crypto";async function nt(n,e){if(!n||!e)return{status:"offline"};let t=n.replace(/\/+$/,"");try{let s=await fetch(`${t}/api/brain/users/me`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(5e3)});if(s.status===401||s.status===403)return{status:(s.headers.get("content-type")||"").includes("application/json")?"expired":"offline"};if(!s.ok)return{status:"offline"};let r=await s.json();if(!r)return{status:"offline"};let o=r.avatar||r.avatarUrl||r.avatar_url||void 0;return o&&/^\/(?!\/)/.test(o)&&(o=t+o),{status:"ok",user:{username:r.username||r.nickname||void 0,nickname:r.nickname||void 0,avatar:o,membershipTier:r.membershipTier||r.membership_tier||void 0}}}catch{return{status:"offline"}}}var On=n=>`${n.seq}:${n.hash}`,ns=n=>ts("sha256").update(n).digest("hex");function Ht(n){if(n===null)return{baseSeq:0,baseHash:null};if(typeof n!="string")return;let e=n.indexOf(":"),t=Number(e===-1?n:n.slice(0,e));if(!Number.isInteger(t)||t<=0)return;let s=e===-1?"":n.slice(e+1);return{baseSeq:t,baseHash:/^[0-9a-f]{64}$/.test(s)?s:null}}function jn(n){let e=n.baseUrl.replace(/\/+$/,""),t=r=>`${e}/api/remotesync/vaults/${encodeURIComponent(n.vault)}${r}`,s=async(r,o)=>{let a=n.getToken();if(!a)throw new Error("penzor-not-logged-in");let c=await fetch(r,{...o,headers:{...o.headers,Authorization:`Bearer ${a}`}});if(c.status===409){let l=await c.json().catch(()=>({}));throw new Error(`cas-conflict ${String(l.code??"")}: seq=${String(l.seq??"?")}`)}if(!c.ok){let l=await c.text().catch(()=>"");throw new Error(`penzor ${o.method??"GET"} ${c.status}: ${l.slice(0,200)}`)}return c};return{kind:"penzor",async walk(r){let o=await s(t("/manifest"),{method:"GET",signal:r}),{files:a}=await o.json();return a.map(c=>({key:c.path,size:c.size,mtimeMs:c.mtimeMs,id:On(c)}))},async readFile(r,o){let c=await(await s(t(`/file?path=${encodeURIComponent(r)}`),{method:"GET",signal:o})).json(),l=await fetch(c.url,{signal:o});if(!l.ok)throw new Error(`penzor blob GET ${l.status}: ${r}`);let h=Buffer.from(await l.arrayBuffer());if(ns(h)!==c.hash)throw new Error(`penzor hash mismatch: ${r}`);return h},async writeFile(r,o,a,c,l){let h=Ht(l),f=new URLSearchParams({path:r,mtimeMs:String(Math.floor(a)||0)});h&&(f.set("baseSeq",String(h.baseSeq)),h.baseHash&&f.set("baseHash",h.baseHash));let u=await(await s(t(`/file?${f.toString()}`),{method:"PUT",body:new Uint8Array(o),headers:{"Content-Type":"application/octet-stream"},signal:c})).json();return{key:r,size:u.size,mtimeMs:u.mtimeMs,id:On(u)}},async rm(r,o,a){let c=Ht(a),l=new URLSearchParams({path:r});c&&c.baseSeq>0&&(l.set("baseSeq",String(c.baseSeq)),c.baseHash&&l.set("baseHash",c.baseHash)),await s(t(`/file?${l.toString()}`),{method:"DELETE",signal:o})},async check(){try{return await s(t("/manifest"),{method:"GET"}),{ok:!0}}catch(r){return{ok:!1,error:String(r?.message||r)}}}}}var Un=50*1024*1024,Ln=new Map;async function rs(n,e){let t=Ln.get(e);if(t)return{id:t};let s=await nt(n,e);if(s.status==="offline")return{error:"penzor-offline"};if(s.status!=="ok")return{error:"penzor-not-logged-in"};let r=s.user?.username?.trim();return r?(Ln.set(e,r),{id:r}):{error:"penzor-auth-unverified"}}var zt=n=>typeof n.registerRemoteSyncBackend=="function"&&typeof n.readCreds=="function";function qt(n){n.registerRemoteSyncBackend("penzor",async e=>{let t=n.readCreds();if(!t.token||!t.cloudUrl)return{error:"penzor-not-logged-in"};let s=e?.vault,r=(typeof s=="string"?s:"default").trim()||"default";if(!/^[A-Za-z0-9_-]{1,64}$/.test(r))return{error:"penzor-bad-vault"};let o=await rs(t.cloudUrl,t.token);if("error"in o)return o;let a=t.token;return{remote:jn({baseUrl:t.cloudUrl,vault:r,getToken:()=>a}),fingerprint:`penzor:${t.cloudUrl.replace(/\/+$/,"")}|u:${o.id}|${r}`,maxFileBytes:Un}}),n.log('[forsion-extend] remote-sync backend "penzor" registered')}import{readFileSync as ss,writeFileSync as os,mkdirSync as is,chmodSync as as,renameSync as ls}from"node:fs";import{join as cs}from"node:path";function Se(n,e){try{let t=new URL(n);if(t.protocol!=="https:"&&t.protocol!=="http:")return null;let s=e.split(".")[1];if(!s)return null;let r=s.replace(/-/g,"+").replace(/_/g,"/"),o=Uint8Array.from(atob(r),l=>l.charCodeAt(0)),a=JSON.parse(new TextDecoder().decode(o)),c=a.userId??a.sub;return typeof c!="string"&&typeof c!="number"||!String(c).trim()?null:`${t.origin}${t.pathname.replace(/\/+$/,"")}::${String(c)}`}catch{return null}}function Wt(n){try{let e=n.split(".")[1];if(!e)return null;let t=JSON.parse(Buffer.from(e,"base64url").toString("utf8"));return t&&typeof t=="object"?t:null}catch{return null}}function zn(n,e=Date.now()){let t=Wt(n)?.iat;return typeof t=="number"?e-t*1e3:1/0}function us(n,e=Date.now()){let t=Wt(n)?.exp;return typeof t=="number"?t*1e3-e:1/0}var ds=36e5;function qn(n,e=Date.now()){return!!n&&zn(n,e)>=ds}async function Wn(n,e,t=8e3,s){if(!n||!e)return null;let r=n.replace(/\/+$/,"");try{let o=await fetch(`${r}/api/auth/refresh`,{method:"POST",headers:{Authorization:`Bearer ${e}`,...s?{"X-Forsion-Client":s}:{}},signal:AbortSignal.timeout(t)});if(!o.ok)return null;let a=await o.json().catch(()=>null),c=typeof a?.token=="string"?a.token:"";return c&&c!==e?c:null}catch{return null}}var bt=(n,e)=>`${n.replace(/\/+$/,"")}\0${e}`,fs=(n,e)=>new Promise((t,s)=>{let r=()=>{clearTimeout(o),s(new Error("Sign-in cancelled."))},o=setTimeout(()=>{e.removeEventListener("abort",r),t()},n);e.aborted?r():e.addEventListener("abort",r,{once:!0})});function Bn(n){let e=()=>cs(n.homeDir(),"auth-accounts.json"),t=(m,u)=>{is(n.homeDir(),{recursive:!0});let w=`${m}.tmp`;os(w,JSON.stringify(u,null,2),{encoding:"utf8",mode:384}),as(w,384),ls(w,m)},s=()=>{try{let m=JSON.parse(ss(e(),"utf8"));return Array.isArray(m.accounts)?m.accounts.filter(u=>u&&typeof u.token=="string"&&u.id===Se(u.cloudUrl,u.token)):[]}catch{return[]}},r=(m,u)=>{let w=Se(m.cloudUrl||"",m.token||"");if(!w||!m.token||!m.cloudUrl)return;let v=s(),R=v.find(j=>j.id===w),_=Wt(m.token),L={...R,id:w,cloudUrl:m.cloudUrl.replace(/\/+$/,""),token:m.token,username:u?.username||R?.username||_?.username,nickname:u?.nickname||R?.nickname};JSON.stringify(R)!==JSON.stringify(L)&&t(e(),{version:1,accounts:[...v.filter(j=>j.id!==w),L]})},o=()=>{let m=n.readCreds();r(m);let u=Se(m.cloudUrl,m.token);return s().map(({token:w,...v})=>({...v,active:v.id===u}))},a=m=>{let u=s().find(w=>w.id===m);if(!u)throw new Error("Account is no longer signed in. Sign in again.");return{cloudUrl:u.cloudUrl,token:u.token}},c=m=>{let u=Se(m.cloudUrl||"",m.token||"");u&&t(e(),{version:1,accounts:s().filter(w=>w.id!==u)})},l=null;return{rememberForsionAccount:r,forsionAccounts:o,savedForsionAccount:a,forgetForsionAccount:c,cancelForsionLogin:()=>{l?.abort(),l=null},forsionDeviceLogin:async(m,u,w)=>{if(l)throw new Error("A sign-in is already in progress.");if(!m)throw new Error("\u8BF7\u5148\u586B\u5199 Forsion \u4E91\u7AEF\u5730\u5740(\u6216\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF TANGU_CLOUD_URL)");let v=new AbortController;l=v;let R=()=>{if(v.signal.aborted||l!==v)throw new Error("Sign-in cancelled.")};try{let _=m.replace(/\/+$/,""),L;try{L=await fetch(`${_}/api/auth/cli/start`,{method:"POST",headers:{"Content-Type":"application/json"},body:"{}",signal:AbortSignal.any([v.signal,AbortSignal.timeout(15e3)])}).then(Y=>Y.json())}catch(Y){throw new Error(`\u65E0\u6CD5\u8FDE\u63A5 ${_}:${Y?.message||Y}`)}if(R(),!L?.device_code)throw new Error("\u4E91\u7AEF\u4E0D\u652F\u6301 CLI \u767B\u5F55(/api/auth/cli/start \u8FD4\u56DE\u5F02\u5E38)");let j=L.verification_uri_complete||`${L.verification_uri}?code=${L.user_code}`,te=new URL(`${_}/auth`);te.searchParams.set("logout","1"),te.searchParams.set("app","forsion-desktop"),te.searchParams.set("redirect",j);let G=te.toString();u?.({url:G,userCode:String(L.user_code||"")}),n.openExternal(G);let B=Date.now()+(L.expires_in||600)*1e3,X=(L.interval||2)*1e3;for(;Date.now()<B;){await fs(X,v.signal),R();let Y=null;try{Y=await fetch(`${_}/api/auth/cli/poll`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({device_code:L.device_code}),signal:AbortSignal.any([v.signal,AbortSignal.timeout(15e3)])})}catch{R();continue}if(R(),Y.status===410)throw new Error("\u767B\u5F55\u7801\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u53D1\u8D77\u767B\u5F55");let ne=await Y.json().catch(()=>({status:"pending"}));if(R(),ne.status==="approved"&&ne.token){let ue={cloudUrl:_,token:ne.token};return await w(ue,R),R(),{token:ne.token,cloudUrl:_}}}throw new Error("\u767B\u5F55\u8D85\u65F6,\u8BF7\u91CD\u8BD5")}finally{l===v&&(l=null)}},readAccounts:s}}var Vn=["homeDir","appVersion","broadcast","accountBackendState","accountTransition","accountCommit","accountClear","writeCreds","onExternalCredsChange","setTokenRefresher","readCreds"],Bt=n=>Vn.every(e=>typeof n[e]=="function");function Vt(n){let e=Bn(n),t=0,s=()=>{let o=n.readCreds();return bt(o.cloudUrl,o.token)},r=null;n.handle("auth:status",async()=>{let o=t,a=s(),{base:c}=await n.getCloud(),l=n.readCreds().token,h=l?await nt(c,l):null,f=await n.accountBackendState(),{base:m}=await n.getCloud(),u=n.readCreds(),w=bt(m,u.token)!==bt(c,l),v=bt(c,l);!w&&h?.status==="ok"&&h.user&&(r={key:v,user:h.user},e.rememberForsionAccount({...u,cloudUrl:c},h.user));let R=w?void 0:h?.status==="ok"?h.user:h?.status==="offline"&&r?.key===v?r.user:void 0;if(w)return{loggedIn:!!u.token,tokenValid:null,cloudUrl:m,accountId:Se(m,u.token),username:null,nickname:null,avatar:null,membershipTier:null,tokenSource:u.token?"tangu-login":null,backendState:f};if(h?.status==="expired"){await n.accountTransition(async()=>{if(o!==t||s()!==a)return;let L=()=>{if(o!==t||s()!==a)throw Hn};try{await n.accountClear(L,()=>{n.log("[auth] token \u5DF2\u5931\u6548(\u670D\u52A1\u7AEF 401/403),\u81EA\u52A8\u767B\u51FA"),++t,e.cancelForsionLogin(),e.forgetForsionAccount(n.readCreds()),r=null})}catch(j){if(j!==Hn)throw j}});let _=n.readCreds();return{loggedIn:!!_.token,tokenValid:null,cloudUrl:_.cloudUrl||c,accountId:Se(_.cloudUrl||c,_.token),username:null,nickname:null,avatar:null,membershipTier:null,tokenSource:_.token?"tangu-login":null,backendState:f}}return{loggedIn:!!l,tokenValid:h&&h.status==="ok"?!0:null,cloudUrl:c,accountId:Se(c,l),username:R?.username||null,nickname:R?.nickname||null,avatar:R?.avatar||null,membershipTier:R?.membershipTier||null,tokenSource:l?"tangu-login":null,backendState:f}}),n.handle("auth:accounts",()=>e.forsionAccounts()),n.handle("auth:switchAccount",async(o,a)=>{if(typeof a!="string")throw new Error("Invalid account.");let c=++t;return e.cancelForsionLogin(),n.accountTransition(async()=>{let l=e.savedForsionAccount(a);return await n.accountCommit(l,()=>{if(c!==t)throw new Error("Account switch cancelled.")},()=>{e.rememberForsionAccount(l),r=null}),{ok:!0,cloudUrl:l.cloudUrl||""}})}),n.handle("auth:forsionLogin",async(o,a)=>{let c=++t;e.cancelForsionLogin();let{base:l}=await n.getCloud();if(c!==t)throw new Error("Sign-in cancelled.");let h=(a||l||"").trim();return{ok:!0,cloudUrl:(await e.forsionDeviceLogin(h,m=>n.broadcast("auth:device",m),(m,u)=>n.accountTransition(()=>n.accountCommit(m,()=>{if(u(),c!==t)throw new Error("Sign-in cancelled.")},()=>{e.rememberForsionAccount(m),r=null})))).cloudUrl}}),n.handle("auth:logout",async()=>(++t,e.cancelForsionLogin(),n.accountTransition(async()=>{let{base:o}=await n.getCloud(),a=n.readCreds();return await n.accountClear(void 0,()=>{e.forgetForsionAccount(a),r=null,o&&a.token&&fetch(`${o}/api/auth/logout`,{method:"POST",headers:{Authorization:`Bearer ${a.token}`},signal:AbortSignal.timeout(5e3)}).catch(()=>{})}),{ok:!0}}))),n.onExternalCredsChange(({previous:o,current:a})=>{++t,e.cancelForsionLogin(),o.token&&!a.token&&e.forgetForsionAccount(o),r=null,e.rememberForsionAccount(a)}),n.setTokenRefresher(async o=>{let a=t,c=s(),l=n.readCreds().token;if(!qn(l))return;let{base:h}=await n.getCloud(),f=await Wn(h,l,o,`desktop/${n.appVersion()}`);if(!f){n.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}a!==t||s()!==c||(e.rememberForsionAccount({cloudUrl:h,token:f}),n.writeCreds({cloudUrl:h,token:f}),n.log("[auth] \u767B\u5F55\u6001\u5DF2\u6ED1\u52A8\u7EED\u671F(\u6709\u6548\u671F\u91CD\u65B0\u8BA1\u6EE1 2 \u5468)"))}),n.log("[forsion-extend] account core registered")}var Hn=Symbol("stale-auth-intent");import{promises as Xe}from"node:fs";import je from"node:path";import{createHash as hs}from"node:crypto";var Gt=null;function Gn(n){Gt=n}function de(){if(!Gt)throw new Error("amadeus sync env not set (registerAmadeus factory has not run)");return Gt}var fe=()=>de().accountId();function rt(n=fe()){return n?hs("sha256").update(n).digest("hex"):"signed-out"}var Ee=(n=fe())=>de().readConfig(n),Ae=(n,e=fe())=>de().writeConfig(n,e),qe=(n,e=fe())=>de().updateConfig(n,e),De=(n=fe())=>de().cloudVaultDir(n),St=n=>de().isManagedCloudVault(n);import{createHash as wo}from"node:crypto";import{promises as ee,existsSync as Cr}from"node:fs";import se from"node:path";import{EventEmitter as zs}from"node:events";import{stat as qs}from"node:fs";import{readdir as Ws,stat as Bs}from"node:fs/promises";import*as z from"node:path";import{lstat as Yn,readdir as ms,realpath as ps,stat as gs}from"node:fs/promises";import{join as ys,resolve as ws,sep as Jn}from"node:path";import{Readable as bs}from"node:stream";var pe={FILE_TYPE:"files",DIR_TYPE:"directories",FILE_DIR_TYPE:"files_directories",EVERYTHING_TYPE:"all"},We={root:".",fileFilter:n=>!0,directoryFilter:n=>!0,type:pe.FILE_TYPE,lstat:!1,depth:2147483648,alwaysStat:!1,highWaterMark:256};Object.freeze(We);var Zn="READDIRP_RECURSIVE_ERROR",Ss=new Set(["ENOENT","EPERM","EACCES","ELOOP",Zn]),Kn=[pe.DIR_TYPE,pe.EVERYTHING_TYPE,pe.FILE_DIR_TYPE,pe.FILE_TYPE],Es=new Set([pe.DIR_TYPE,pe.EVERYTHING_TYPE,pe.FILE_DIR_TYPE]),vs=new Set([pe.EVERYTHING_TYPE,pe.FILE_DIR_TYPE,pe.FILE_TYPE]),_s=n=>Ss.has(n.code),ks=process.platform==="win32",Xn=n=>!0,Qn=n=>{if(n===void 0)return Xn;if(typeof n=="function")return n;if(typeof n=="string"){let e=n.trim();return t=>t.basename===e}if(Array.isArray(n)){let e=n.map(t=>t.trim());return t=>e.some(s=>t.basename===s)}return Xn},Yt=class extends bs{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??We.highWaterMark});let t={...We,...e},s=t.root??We.root,r=t.type??We.type;this._fileFilter=Qn(t.fileFilter),this._directoryFilter=Qn(t.directoryFilter);let o=t.lstat?Yn:gs;ks?this._stat=c=>o(c,{bigint:!0}):this._stat=o,this._maxDepth=t.depth!=null&&Number.isSafeInteger(t.depth)?t.depth:We.depth,this._wantsDir=Es.has(r),this._wantsFile=vs.has(r),this._wantsEverything=r===pe.EVERYTHING_TYPE,this._root=ws(s),this._relStart=this._root.endsWith(Jn)?this._root.length:this._root.length+1,this._isDirent=!t.alwaysStat,this._statsProp=this._isDirent?"dirent":"stats",this._rdOptions={encoding:"utf8",withFileTypes:this._isDirent};let a={path:this._root,depth:1};a.pending=this._exploreDir(this._root,1),this.parents=[a],this.reading=!1,this.parent=void 0}async _read(e){if(!this.reading){this.reading=!0;try{for(;!this.destroyed&&e>0;){let t=this.parent,s=t&&t.files;if(s&&s.length>0){let{path:r,depth:o}=t,a=s.splice(0,e).map(l=>this._formatEntry(l,r)),c=this._isDirent?a:await Promise.all(a);for(let l of c){if(!l)continue;if(this.destroyed)return;let h=this._getEntryType(l);typeof h!="string"&&(h=await h),h==="directory"&&this._directoryFilter(l)?(o<=this._maxDepth&&this.parents.push({path:l.fullPath,depth:o+1}),this._wantsDir&&(this.push(l),e--)):(h==="file"||this._includeAsFile(l))&&this._fileFilter(l)&&this._wantsFile&&(this.push(l),e--)}}else{let r=this.parents.pop();if(!r){this.push(null);break}let o=r.pending??this._exploreDir(r.path,r.depth),a=this.parents[this.parents.length-1];if(a&&!a.pending&&(a.pending=this._exploreDir(a.path,a.depth)),this.parent=await o,this.destroyed)return}}}catch(t){this.destroy(t)}finally{this.reading=!1}}}async _exploreDir(e,t){let s;try{s=await ms(e,this._rdOptions)}catch(r){this._onError(r)}return{files:s,depth:t,path:e}}_formatEntry(e,t){let s=this._isDirent?e.name:e,r=ys(t,s),o={path:r.slice(this._relStart),fullPath:r,basename:s};return this._isDirent?(o.dirent=e,o):this._stat(r).then(a=>(o.stats=a,o),a=>{this._onError(a)})}_onError(e){_s(e)&&!this.destroyed?this.emit("warn",e):this.destroy(e)}_getEntryType(e){if(!e||!(this._statsProp in e))return"";let t=e[this._statsProp];return t.isFile()?"file":t.isDirectory()?"directory":t.isSymbolicLink()?this._getSymlinkEntryType(e):""}async _getSymlinkEntryType(e){let t=e.fullPath;try{let s=await ps(t),r=await Yn(s);if(r.isFile())return"file";if(r.isDirectory()){let o=s.length;if(t.startsWith(s)&&t[o]===Jn){let a=new Error(`Circular symlink detected: "${t}" points to "${s}"`);return a.code=Zn,this._onError(a),""}return"directory"}}catch(s){this._onError(s)}return""}_includeAsFile(e){let t=e&&e[this._statsProp];return t&&this._wantsEverything&&!t.isDirectory()}};function er(n,e={}){let t=e.entryType||e.type;if(t==="both"&&(t=pe.FILE_DIR_TYPE),n){if(typeof n!="string")throw new TypeError("readdirp: root argument must be a string. Usage: readdirp(root, options)");if(t&&!Kn.includes(t))throw new Error(`readdirp: Invalid type passed. Use one of ${Kn.join(", ")}`)}else throw new Error("readdirp: root argument is required. Usage: readdirp(root, options)");let s={...e,root:n};return t&&(s.type=t),new Yt(s)}import{watch as Cs,unwatchFile as tr,watchFile as xs}from"node:fs";import{realpath as Jt,lstat as Ts,open as Rs,stat as rr}from"node:fs/promises";import{type as Is}from"node:os";import*as K from"node:path";var As="data",Qt="end",sr="close",Ct=()=>{};var xt=process.platform,Zt=xt==="win32",Ps=xt==="darwin",Ds=xt==="linux",$s=xt==="freebsd",or=Is()==="OS400",Z={ALL:"all",READY:"ready",ADD:"add",CHANGE:"change",ADD_DIR:"addDir",UNLINK:"unlink",UNLINK_DIR:"unlinkDir",RAW:"raw",ERROR:"error"},ve=Z,Ms="watch",Ns={lstat:Ts,stat:rr},Le="listeners",Et="errHandlers",Be="rawEmitters",Fs=[Le,Et,Be],Os=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"]),Ls=n=>Os.has(K.extname(n).slice(1).toLowerCase()),Xt=(n,e)=>{n instanceof Set?n.forEach(e):e(n)},st=(n,e,t)=>{let s=n[e];s instanceof Set||(n[e]=s=new Set([s])),s.add(t)},js=n=>e=>{let t=n[e];t instanceof Set?t.clear():delete n[e]},ot=(n,e,t)=>{let s=n[e];s instanceof Set?s.delete(t):s===t&&delete n[e]},ir=n=>n instanceof Set?n.size===0:!n,vt=new Map;function nr(n,e,t,s,r){let o=(a,c)=>{t(n),r(a,c,{watchedPath:n}),c&&n!==c&&_t(K.resolve(n,c),Le,K.join(n,c))};try{return Cs(n,{persistent:e.persistent},o)}catch(a){s(a);return}}var _t=(n,e,t,s,r)=>{let o=vt.get(n);o&&Xt(o[e],a=>{a(t,s,r)})},Us=(n,e,t,s)=>{let{listener:r,errHandler:o,rawEmitter:a}=s,c=vt.get(e),l;if(!t.persistent)return l=nr(n,t,r,o,a),l?l.close.bind(l):void 0;if(c)st(c,Le,r),st(c,Et,o),st(c,Be,a);else{if(l=nr(n,t,_t.bind(null,e,Le),o,_t.bind(null,e,Be)),!l)return;l.on(ve.ERROR,async h=>{let f=_t.bind(null,e,Et);if(c&&(c.watcherUnusable=!0),Zt&&h.code==="EPERM")try{await(await Rs(n,"r")).close(),f(h)}catch{}else f(h)}),c={listeners:r,errHandlers:o,rawEmitters:a,watcher:l},vt.set(e,c)}return()=>{ot(c,Le,r),ot(c,Et,o),ot(c,Be,a),ir(c.listeners)&&(c.watcher.close(),vt.delete(e),Fs.forEach(js(c)),c.watcher=void 0,Object.freeze(c))}},Kt=new Map,Hs=(n,e,t,s)=>{let{listener:r,rawEmitter:o}=s,a=Kt.get(e),c=a&&a.options;return c&&(c.persistent<t.persistent||c.interval>t.interval)&&(tr(e),a=void 0),a?(st(a,Le,r),st(a,Be,o)):(a={listeners:r,rawEmitters:o,options:t,watcher:xs(e,t,(l,h)=>{Xt(a.rawEmitters,m=>{m(ve.CHANGE,e,{curr:l,prev:h})});let f=l.mtimeMs;(l.size!==h.size||f>h.mtimeMs||f===0)&&Xt(a.listeners,m=>m(n,l))})},Kt.set(e,a)),()=>{ot(a,Le,r),ot(a,Be,o),ir(a.listeners)&&(Kt.delete(e),tr(e),a.options=a.watcher=void 0,Object.freeze(a))}},kt=class{fsw;_boundHandleError;constructor(e){this.fsw=e,this._boundHandleError=t=>e._handleError(t)}_watchWithNodeFs(e,t){let s=this.fsw.options,r=K.dirname(e),o=K.basename(e);this.fsw._getWatchedDir(r).add(o);let c=K.resolve(e),l={persistent:s.persistent};t||(t=Ct);let h;if(s.usePolling){let f=s.interval!==s.binaryInterval;l.interval=f&&Ls(o)?s.binaryInterval:s.interval,h=Hs(e,c,l,{listener:t,rawEmitter:this.fsw._emitRaw})}else h=Us(e,c,l,{listener:t,errHandler:this._boundHandleError,rawEmitter:this.fsw._emitRaw});return h}_handleFile(e,t,s){if(this.fsw.closed)return;let r=K.dirname(e),o=K.basename(e),a=this.fsw._getWatchedDir(r),c=t;if(a.has(o))return;let l=async(f,m)=>{if(this.fsw._throttle(Ms,e,5)){if(!m||m.mtimeMs===0)try{let u=await rr(e);if(this.fsw.closed)return;let w=u.atimeMs,v=u.mtimeMs;if((!w||w<=v||v!==c.mtimeMs)&&this.fsw._emit(ve.CHANGE,e,u),(Ps||Ds||$s)&&c.ino!==u.ino){this.fsw._closeFile(f),c=u;let R=this._watchWithNodeFs(e,l);R&&this.fsw._addPathCloser(f,R)}else c=u}catch{this.fsw._remove(r,o)}else if(a.has(o)){let u=m.atimeMs,w=m.mtimeMs;(!u||u<=w||w!==c.mtimeMs)&&this.fsw._emit(ve.CHANGE,e,m),c=m}}},h=this._watchWithNodeFs(e,l);if(!(s&&this.fsw.options.ignoreInitial)&&this.fsw._isntIgnored(e)){if(!this.fsw._throttle(ve.ADD,e,0))return;this.fsw._emit(ve.ADD,e,t)}return h}async _handleSymlink(e,t,s,r){if(this.fsw.closed)return;let o=e.fullPath,a=this.fsw._getWatchedDir(t);if(!this.fsw.options.followSymlinks){this.fsw._incrReadyCount();let c;try{c=await Jt(s)}catch{return this.fsw._emitReady(),!0}return this.fsw.closed?void 0:(a.has(r)?this.fsw._symlinkPaths.get(o)!==c&&(this.fsw._symlinkPaths.set(o,c),this.fsw._emit(ve.CHANGE,s,e.stats)):(a.add(r),this.fsw._symlinkPaths.set(o,c),this.fsw._emit(ve.ADD,s,e.stats)),this.fsw._emitReady(),!0)}if(this.fsw._symlinkPaths.has(o))return!0;this.fsw._symlinkPaths.set(o,!0)}_handleRead(e,t,s,r,o,a,c){e=K.join(e,"");let l=r?`${e}:${r}`:e;if(c=this.fsw._throttle("readdir",l,1e3),!c)return;let h=this.fsw._getWatchedDir(s.path),f=new Set,m=this.fsw._readdirp(e,{fileFilter:u=>s.filterPath(u),directoryFilter:u=>s.filterDir(u)});if(m)return m.on(As,async u=>{if(this.fsw.closed){m=void 0;return}let w=u.path,v=K.join(e,w);if(f.add(w),!(u.stats.isSymbolicLink()&&await this._handleSymlink(u,e,v,w))){if(this.fsw.closed){m=void 0;return}(w===r||!r&&!h.has(w))&&(this.fsw._incrReadyCount(),v=K.join(o,K.relative(o,v)),this._addToNodeFs(v,t,s,a+1))}}).on(ve.ERROR,this._boundHandleError),new Promise((u,w)=>{if(!m)return w();m.once(Qt,()=>{if(this.fsw.closed){m=void 0;return}let v=c?c.clear():!1;u(void 0),h.getChildren().filter(R=>R!==e&&!f.has(R)).forEach(R=>{this.fsw._remove(e,R)}),m=void 0,v&&this._handleRead(e,!1,s,r,o,a,c)})})}async _handleDir(e,t,s,r,o,a,c){let l=this.fsw._getWatchedDir(K.dirname(e)),h=l.has(K.basename(e));!(s&&this.fsw.options.ignoreInitial)&&!o&&!h&&this.fsw._emit(ve.ADD_DIR,e,t),l.add(K.basename(e)),this.fsw._getWatchedDir(e);let f,m,u=this.fsw.options.depth;if((u==null||r<=u)&&!this.fsw._symlinkPaths.has(c)){if(!o&&(await this._handleRead(e,s,a,o,e,r,f),this.fsw.closed))return;m=this._watchWithNodeFs(e,(w,v)=>{v&&v.mtimeMs===0||this._handleRead(w,!1,a,o,e,r,f)})}return m}async _addToNodeFs(e,t,s,r,o){let a=this.fsw._emitReady;if(this.fsw._isIgnored(e)||this.fsw.closed)return a(),!1;let c=this.fsw._getWatchHelpers(e);s&&(c.filterPath=l=>s.filterPath(l),c.filterDir=l=>s.filterDir(l));try{let l=await Ns[c.statMethod](c.watchPath);if(this.fsw.closed)return;if(this.fsw._isIgnored(c.watchPath,l))return a(),!1;let h=this.fsw.options.followSymlinks,f;if(l.isDirectory()){let m=K.resolve(e),u=h?await Jt(e):e;if(this.fsw.closed||(f=await this._handleDir(c.watchPath,l,t,r,o,c,u),this.fsw.closed))return;m!==u&&u!==void 0&&this.fsw._symlinkPaths.set(m,u)}else if(l.isSymbolicLink()){let m=h?await Jt(e):e;if(this.fsw.closed)return;let u=K.dirname(c.watchPath);if(this.fsw._getWatchedDir(u).add(c.watchPath),this.fsw._emit(ve.ADD,c.watchPath,l),f=await this._handleDir(u,l,t,r,e,c,m),this.fsw.closed)return;m!==void 0&&this.fsw._symlinkPaths.set(K.resolve(e),m)}else f=this._handleFile(c.watchPath,l,t);return a(),f&&this.fsw._addPathCloser(e,f),!1}catch(l){if(this.fsw._handleError(l))return a(),e}}};var en="/",Vs="//",dr=".",Gs="..",Ys="string",Js=/\\/g,fr=/\/\//g,Ks=/\..*\.(sw[px])$|~$|\.subl.*\.tmp/,Xs=/^\.[/\\]/;function Tt(n){return Array.isArray(n)?n:[n]}var tn=n=>typeof n=="object"&&n!==null&&!(n instanceof RegExp);function Qs(n){return typeof n=="function"?n:typeof n=="string"?e=>n===e:n instanceof RegExp?e=>n.test(e):typeof n=="object"&&n!==null?e=>{if(n.path===e)return!0;if(n.recursive){let t=z.relative(n.path,e);return t?!t.startsWith("..")&&!z.isAbsolute(t):!1}return!1}:()=>!1}function Zs(n){if(typeof n!="string")throw new Error("string expected");n=z.normalize(n),n=n.replace(/\\/g,"/");let e=!1;return n.startsWith("//")&&(e=!0),n=n.replace(fr,"/"),e&&(n="/"+n),n}function ar(n,e,t){let s=Zs(e);for(let r=0;r<n.length;r++){let o=n[r];if(o(s,t))return!0}return!1}function eo(n,e){if(n==null)throw new TypeError("anymatch: specify first argument");let s=Tt(n).map(r=>Qs(r));return e==null?(r,o)=>ar(s,r,o):ar(s,e)}var lr=n=>{let e=Tt(n).flat();if(!e.every(t=>typeof t===Ys))throw new TypeError(`Non-string provided as watch path: ${e}`);return e.map(hr)},cr=n=>{let e=n.replace(Js,en),t=!1;return e.startsWith(Vs)&&(t=!0),e=e.replace(fr,en),t&&(e=en+e),e},hr=n=>cr(z.normalize(cr(n))),ur=(n="")=>e=>typeof e=="string"?hr(z.isAbsolute(e)?e:z.join(n,e)):e,to=(n,e)=>z.isAbsolute(n)?n:z.join(e,n),no=Object.freeze(new Set),nn=class{path;_removeWatcher;items;constructor(e,t){this.path=e,this._removeWatcher=t,this.items=new Set}add(e){let{items:t}=this;t&&e!==dr&&e!==Gs&&t.add(e)}async remove(e){let{items:t}=this;if(!t||(t.delete(e),t.size>0))return;let s=this.path;try{await Ws(s)}catch{this._removeWatcher&&this._removeWatcher(z.dirname(s),z.basename(s))}}has(e){let{items:t}=this;if(t)return t.has(e)}getChildren(){let{items:e}=this;return e?[...e.values()]:[]}dispose(){this.items.clear(),this.path="",this._removeWatcher=Ct,this.items=no,Object.freeze(this)}},ro="stat",so="lstat",rn=class{fsw;path;watchPath;fullWatchPath;dirParts;followSymlinks;statMethod;constructor(e,t,s){this.fsw=s;let r=e;this.path=e=e.replace(Xs,""),this.watchPath=r,this.fullWatchPath=z.resolve(r),this.dirParts=[],this.dirParts.forEach(o=>{o.length>1&&o.pop()}),this.followSymlinks=t,this.statMethod=t?ro:so}entryPath(e){return z.join(this.watchPath,z.relative(this.watchPath,e.fullPath))}filterPath(e){let{stats:t}=e;if(t&&t.isSymbolicLink())return this.filterDir(e);let s=this.entryPath(e);return this.fsw._isntIgnored(s,t)&&this.fsw._hasReadPermissions(t)}filterDir(e){return this.fsw._isntIgnored(this.entryPath(e),e.stats)}},Rt=class extends zs{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 t=e.awaitWriteFinish,s={stabilityThreshold:2e3,pollInterval:100},r={persistent:!0,ignoreInitial:!1,ignorePermissionErrors:!1,interval:100,binaryInterval:300,followSymlinks:!0,usePolling:!1,atomic:!0,...e,ignored:e.ignored?Tt(e.ignored):Tt([]),awaitWriteFinish:t===!0?s:typeof t=="object"?{...s,...t}:!1};or&&(r.usePolling=!0),r.atomic===void 0&&(r.atomic=!r.usePolling);let o=process.env.CHOKIDAR_USEPOLLING;if(o!==void 0){let l=o.toLowerCase();l==="false"||l==="0"?r.usePolling=!1:l==="true"||l==="1"?r.usePolling=!0:r.usePolling=!!l}let a=process.env.CHOKIDAR_INTERVAL;a&&(r.interval=Number.parseInt(a,10));let c=0;this._emitReady=()=>{c++,c>=this._readyCount&&(this._emitReady=Ct,this._readyEmitted=!0,process.nextTick(()=>this.emit(Z.READY)))},this._emitRaw=(...l)=>this.emit(Z.RAW,...l),this._boundRemove=this._remove.bind(this),this.options=r,this._nodeFsHandler=new kt(this),Object.freeze(r)}_addIgnoredPath(e){if(tn(e)){for(let t of this._ignoredPaths)if(tn(t)&&t.path===e.path&&t.recursive===e.recursive)return}this._ignoredPaths.add(e)}_removeIgnoredPath(e){if(this._ignoredPaths.delete(e),typeof e=="string")for(let t of this._ignoredPaths)tn(t)&&t.path===e&&this._ignoredPaths.delete(t)}add(e,t,s){let{cwd:r}=this.options;this.closed=!1,this._closePromise=void 0;let o=lr(e);return r&&(o=o.map(a=>to(a,r))),o.forEach(a=>{this._removeIgnoredPath(a)}),this._userIgnored=void 0,this._readyCount||(this._readyCount=0),this._readyCount+=o.length,Promise.all(o.map(async a=>{let c=await this._nodeFsHandler._addToNodeFs(a,!s,void 0,0,t);return c&&this._emitReady(),c})).then(a=>{this.closed||a.forEach(c=>{c&&this.add(z.dirname(c),z.basename(t||c))})}),this}unwatch(e){if(this.closed)return this;let t=lr(e),{cwd:s}=this.options;return t.forEach(r=>{!z.isAbsolute(r)&&!this._closers.has(r)&&(s&&(r=z.join(s,r)),r=z.resolve(r)),this._closePath(r),this._addIgnoredPath(r),this._watched.has(r)&&this._addIgnoredPath({path:r,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(t=>t.forEach(s=>{let r=s();r instanceof Promise&&e.push(r)})),this._streams.forEach(t=>t.destroy()),this._userIgnored=void 0,this._readyCount=0,this._readyEmitted=!1,this._watched.forEach(t=>t.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((t,s)=>{let o=(this.options.cwd?z.relative(this.options.cwd,s):s)||dr;e[o]=t.getChildren().sort()}),e}emitWithAll(e,t){this.emit(e,...t),e!==Z.ERROR&&this.emit(Z.ALL,e,...t)}async _emit(e,t,s){if(this.closed)return;let r=this.options;Zt&&(t=z.normalize(t)),r.cwd&&(t=z.relative(r.cwd,t));let o=[t];s!=null&&o.push(s);let a=r.awaitWriteFinish,c;if(a&&(c=this._pendingWrites.get(t)))return c.lastChange=new Date,this;if(r.atomic){if(e===Z.UNLINK)return this._pendingUnlinks.set(t,[e,...o]),setTimeout(()=>{this._pendingUnlinks.forEach((l,h)=>{this.emit(...l),this.emit(Z.ALL,...l),this._pendingUnlinks.delete(h)})},typeof r.atomic=="number"?r.atomic:100),this;e===Z.ADD&&this._pendingUnlinks.has(t)&&(e=Z.CHANGE,this._pendingUnlinks.delete(t))}if(a&&(e===Z.ADD||e===Z.CHANGE)&&this._readyEmitted){let l=(h,f)=>{h?(e=Z.ERROR,o[0]=h,this.emitWithAll(e,o)):f&&(o.length>1?o[1]=f:o.push(f),this.emitWithAll(e,o))};return this._awaitWriteFinish(t,a.stabilityThreshold,e,l),this}if(e===Z.CHANGE&&!this._throttle(Z.CHANGE,t,50))return this;if(r.alwaysStat&&s===void 0&&(e===Z.ADD||e===Z.ADD_DIR||e===Z.CHANGE)){let l=r.cwd?z.join(r.cwd,t):t,h;try{h=await Bs(l)}catch{}if(!h||this.closed)return;o.push(h)}return this.emitWithAll(e,o),this}_handleError(e){let t=e&&e.code;return e&&t!=="ENOENT"&&t!=="ENOTDIR"&&(!this.options.ignorePermissionErrors||t!=="EPERM"&&t!=="EACCES")&&this.emit(Z.ERROR,e),e||this.closed}_throttle(e,t,s){this._throttled.has(e)||this._throttled.set(e,new Map);let r=this._throttled.get(e);if(!r)throw new Error("invalid throttle");let o=r.get(t);if(o)return o.count++,!1;let a,c=()=>{let h=r.get(t),f=h?h.count:0;return r.delete(t),clearTimeout(a),h&&clearTimeout(h.timeoutObject),f};a=setTimeout(c,s);let l={timeoutObject:a,clear:c,count:0};return r.set(t,l),l}_incrReadyCount(){return this._readyCount++}_awaitWriteFinish(e,t,s,r){let o=this.options.awaitWriteFinish;if(typeof o!="object")return;let a=o.pollInterval,c,l=e;this.options.cwd&&!z.isAbsolute(e)&&(l=z.join(this.options.cwd,e));let h=new Date,f=this._pendingWrites;function m(u){qs(l,(w,v)=>{if(w||!f.has(e)){w&&w.code!=="ENOENT"&&r(w);return}let R=Number(new Date);u&&v.size!==u.size&&(f.get(e).lastChange=R);let _=f.get(e);R-_.lastChange>=t?(f.delete(e),r(void 0,v)):c=setTimeout(m,a,v)})}f.has(e)||(f.set(e,{lastChange:h,cancelWait:()=>(f.delete(e),clearTimeout(c),s)}),c=setTimeout(m,a))}_isIgnored(e,t){if(this.options.atomic&&Ks.test(e))return!0;if(!this._userIgnored){let{cwd:s}=this.options,o=(this.options.ignored||[]).map(ur(s)),c=[...[...this._ignoredPaths].map(ur(s)),...o];this._userIgnored=eo(c,void 0)}return this._userIgnored(e,t)}_isntIgnored(e,t){return!this._isIgnored(e,t)}_getWatchHelpers(e){return new rn(e,this.options.followSymlinks,this)}_getWatchedDir(e){let t=z.resolve(e);return this._watched.has(t)||this._watched.set(t,new nn(t,this._boundRemove)),this._watched.get(t)}_hasReadPermissions(e){return this.options.ignorePermissionErrors?!0:!!(Number(e.mode)&256)}_remove(e,t,s){let r=z.join(e,t),o=z.resolve(r);if(s=s??(this._watched.has(r)||this._watched.has(o)),!this._throttle("remove",r,100))return;!s&&this._watched.size===1&&this.add(e,t,!0),this._getWatchedDir(r).getChildren().forEach(u=>this._remove(r,u));let l=this._getWatchedDir(e),h=l.has(t);l.remove(t),this._symlinkPaths.has(o)&&this._symlinkPaths.delete(o);let f=r;if(this.options.cwd&&(f=z.relative(this.options.cwd,r)),this.options.awaitWriteFinish&&this._pendingWrites.has(f)&&this._pendingWrites.get(f).cancelWait()===Z.ADD)return;this._watched.delete(r),this._watched.delete(o);let m=s?Z.UNLINK_DIR:Z.UNLINK;h&&!this._isIgnored(r)&&this._emit(m,r),this._closePath(r)}_closePath(e){this._closeFile(e);let t=z.dirname(e);this._getWatchedDir(t).remove(z.basename(e))}_closeFile(e){let t=this._closers.get(e);t&&(t.forEach(s=>s()),this._closers.delete(e))}_addPathCloser(e,t){if(!t)return;let s=this._closers.get(e);s||(s=[],this._closers.set(e,s)),s.push(t)}_readdirp(e,t){if(this.closed)return;let s={type:Z.ALL,alwaysStat:!0,lstat:!0,...t,depth:0},r=er(e,s);return this._streams.add(r),r.once(sr,()=>{r=void 0}),r.once(Qt,()=>{r&&(this._streams.delete(r),r=void 0)}),r}};function oo(n,e={}){let t=new Rt(e);return t.add(n),t}var mr={watch:oo,FSWatcher:Rt};function io(n,e){let t=Object.create(null);for(let o=0;o<e.length;o++){let a=e[o];t[a]?t[a].push(o):t[a]=[o]}let r=[{buffer1index:-1,buffer2index:-1,chain:null}];for(let o=0;o<n.length;o++){let a=n[o],c=t[a]||[],l=0,h=r[0];for(let f of c){let m;for(m=l;m<r.length&&!(r[m].buffer2index<f&&(m===r.length-1||r[m+1].buffer2index>f));m++);if(m<r.length){let u={buffer1index:o,buffer2index:f,chain:r[m]};if(l===r.length?r.push(h):r[l]=h,l=m+1,h=u,l===r.length)break}}r[l]=h}return r[r.length-1]}function pr(n,e){let t=io(n,e),s=[],r=n.length,o=e.length;for(let a=t;a!==null;a=a.chain){let c=r-a.buffer1index-1,l=o-a.buffer2index-1;r=a.buffer1index,o=a.buffer2index,(c||l)&&s.push({buffer1:[r+1,c],buffer1Content:n.slice(r+1,r+1+c),buffer2:[o+1,l],buffer2Content:e.slice(o+1,o+1+l)})}return s.reverse(),s}function ao(n,e,t){let s=[];function r(l,h){s.push({ab:h,oStart:l.buffer1[0],oLength:l.buffer1[1],abStart:l.buffer2[0],abLength:l.buffer2[1]})}pr(e,n).forEach(l=>r(l,"a")),pr(e,t).forEach(l=>r(l,"b")),s.sort((l,h)=>l.oStart-h.oStart);let o=[],a=0;function c(l){l>a&&(o.push({stable:!0,buffer:"o",bufferStart:a,bufferLength:l-a,bufferContent:e.slice(a,l)}),a=l)}for(;s.length;){let l=s.shift(),h=l.oStart,f=l.oStart+l.oLength,m=[l];for(c(h);s.length;){let u=s[0],w=u.oStart;if(w>f)break;f=Math.max(f,w+u.oLength),m.push(s.shift())}if(m.length===1){if(l.abLength>0){let u=l.ab==="a"?n:t;o.push({stable:!0,buffer:l.ab,bufferStart:l.abStart,bufferLength:l.abLength,bufferContent:u.slice(l.abStart,l.abStart+l.abLength)})}}else{let u={a:[n.length,-1,e.length,-1],b:[t.length,-1,e.length,-1]};for(;m.length;){l=m.shift();let j=l.oStart,te=j+l.oLength,G=l.abStart,B=G+l.abLength,X=u[l.ab];X[0]=Math.min(G,X[0]),X[1]=Math.max(B,X[1]),X[2]=Math.min(j,X[2]),X[3]=Math.max(te,X[3])}let w=u.a[0]+(h-u.a[2]),v=u.a[1]+(f-u.a[3]),R=u.b[0]+(h-u.b[2]),_=u.b[1]+(f-u.b[3]),L={stable:!1,aStart:w,aLength:v-w,aContent:n.slice(w,v),oStart:h,oLength:f-h,oContent:e.slice(h,f),bStart:R,bLength:_-R,bContent:t.slice(R,_)};o.push(L)}a=f}return c(e.length),o}function gr(n,e,t,s){s=Object.assign({excludeFalseConflicts:!0,stringSeparator:/\s+/},s),typeof n=="string"&&(n=n.split(s.stringSeparator)),typeof e=="string"&&(e=e.split(s.stringSeparator)),typeof t=="string"&&(t=t.split(s.stringSeparator));let o=[],a=ao(n,e,t),c=[];function l(){c.length&&o.push({ok:c}),c=[]}function h(f,m){if(f.length!==m.length)return!1;for(let u=0;u<f.length;u++)if(f[u]!==m[u])return!1;return!0}return a.forEach(f=>{f.stable?c.push(...f.bufferContent):s.excludeFalseConflicts&&h(f.aContent,f.bContent)?c.push(...f.aContent):(l(),o.push({conflict:{a:f.aContent,aIndex:f.aStart,o:f.oContent,oIndex:f.oStart,b:f.bContent,bIndex:f.bStart}}))}),l(),o}function It(n,e){let t=n.lastIndexOf("/"),s=t<0?"":n.slice(0,t+1),r=t<0?n:n.slice(t+1),o=r.lastIndexOf("."),a=o>0?r.slice(0,o):r,c=o>0?r.slice(o):"",l=f=>String(f).padStart(2,"0"),h=`${e.getFullYear()}-${l(e.getMonth()+1)}-${l(e.getDate())} ${l(e.getHours())}${l(e.getMinutes())}`;return`${s}${a} (conflict ${h})${c}`}function lo(n,e){if(e<2)return n;let t=n.lastIndexOf("."),s=t>n.lastIndexOf("/")&&t>n.lastIndexOf(")"),r=s?n.slice(0,t):n,o=s?n.slice(t):"";return`${r}-${e}${o}`}function co(n){let e=3735928559,t=1103547991;for(let r=0;r<n.length;r++){let o=n.charCodeAt(r);e=Math.imul(e^o,2654435761),t=Math.imul(t^o,1597334677)}e=Math.imul(e^e>>>16,2246822507)^Math.imul(t^t>>>13,3266489909),t=Math.imul(t^t>>>16,2246822507)^Math.imul(e^e>>>13,3266489909);let s=4294967296*(2097151&t)+(e>>>0);return`${n.length.toString(36)}-${s.toString(36)}`}function At(n,e,t){if(n===null&&e===null&&t===null)return{kind:"none"};if(t===null)return n===null?e?{kind:"dropShadow"}:{kind:"none"}:e?n===e.hash?{kind:"deleteLocal"}:{kind:"pushCreate"}:{kind:"pushCreate"};if(n===null)return e?t.seq===e.seq?{kind:"pushDelete"}:{kind:"pull"}:{kind:"pull"};if(!e)return n===t.hash?{kind:"adopt"}:{kind:"conflict"};let s=n!==e.hash,r=t.seq!==e.seq;return!s&&!r?{kind:"none"}:s?r?n===t.hash?{kind:"adopt"}:t.hash===e.hash?{kind:"push",baseSeq:t.seq}:{kind:"conflict"}:{kind:"push",baseSeq:e.seq}:{kind:"pull"}}function yr(n,e,t){let s=gr(n.split(`
194
+ `),e.split(`
195
+ `),t.split(`
196
+ `),{excludeFalseConflicts:!0}),r=[];for(let o of s){if(o.conflict)return null;o.ok&&r.push(...o.ok)}return r.join(`
197
+ `)}function sn(n,e,t=200){return n>=t||e>=5&&n>=Math.max(5,Math.ceil(e/2))}var uo=/[\u0000-\u001f\u007f]/;function Ve(n){let e=n.replace(/\\/g,"/").normalize("NFC").trim();if(e=e.replace(/\/+$/,""),!e||e.length>512||e.startsWith("/")||uo.test(e))return null;let t=e.split("/");for(let s of t)if(!s||s==="."||s==="..")return null;return t.join("/")}function on(n,e){let t=n.replace(/\\/g,"/").normalize("NFC");return e===""?Ve(t):t.startsWith(`${e}/`)?Ve(t.slice(e.length+1)):null}function wr(n,e){return e===""?n:`${e}/${n}`}function it(n){return!!(n===".DS_Store"||n==="Icon\r"||n===".sync-trash"||/\.tmp-\d+-\d+-\d+$/.test(n)||/^\..+\.lock$/.test(n))}function Ce(n){return/\.md$/i.test(n)?"page":/\.db$/i.test(n)?"db":"binary"}var $e=n=>n==="page"||n==="db";import{gzip as fo}from"node:zlib";import{promisify as ho}from"node:util";var mo=ho(fo),po=1024,le=class extends Error{status;body;constructor(e,t,s){super(`cloud http ${e} on ${s}`),this.status=e,this.body=t}},br=n=>12e4+Math.ceil(n/256);function Sr(n){let e=`${n.baseUrl.replace(/\/+$/,"")}/api/amadeus`,t=async(r,o,a)=>{let c={Authorization:`Bearer ${n.token}`,...a?.headers};r!=="GET"&&(c["X-Amadeus-Client"]=n.clientId);let l;a?.json!==void 0?(c["Content-Type"]="application/json",l=JSON.stringify(a.json),l.length>=po&&(c["Content-Encoding"]="gzip",l=await mo(l))):a?.form&&(l=a.form);let h=await fetch(o,{method:r,headers:c,body:l,signal:AbortSignal.timeout(a?.timeoutMs??3e4)});if(!h.ok){let f=null;try{f=await h.json()}catch{}throw new le(h.status,f,o)}return h.json()},s=r=>new URLSearchParams(r).toString();return{clientId:n.clientId,async listVaults(){return((await t("GET",`${e}/vaults`)).vaults??[]).map(o=>({id:String(o.id),name:String(o.name),lastChangeSeq:Number(o.lastChangeSeq??0)}))},async tree(r){let o=await t("GET",`${e}/vaults/${r}/tree`);if(!Array.isArray(o.entries))throw new Error("server too old: tree has no entries[] (deploy the amadeus microserver update)");return{folders:o.folders??[],seq:Number(o.seq??0),maxFileBytes:Number.isInteger(o.maxFileBytes)&&o.maxFileBytes>0?o.maxFileBytes:void 0,entries:o.entries.map(a=>({path:String(a.path),kind:a.kind,seq:Number(a.seq??0),hash:a.hash??null,size:Number(a.size??0)}))}},async getFile(r,o){let a=await t("GET",`${e}/vaults/${r}/file?${s({path:o})}`);return{content:String(a.content??""),seq:Number(a.seq??0),hash:a.hash??null}},putFile(r,o,a,c,l=!1){return t("PUT",`${e}/vaults/${r}/file`,{json:{path:o,content:a,baseSeq:c,...l?{force:!0}:{}}})},async deleteFile(r,o,a,c){let l={path:o};a!==void 0&&(l.baseSeq=String(a)),await t("DELETE",`${e}/vaults/${r}/file?${s(l)}`,c?.confirmed?{headers:{"X-Amadeus-Delete-Confirmed":"1"}}:void 0)},move(r,o,a){return t("POST",`${e}/vaults/${r}/move`,{json:{from:o,to:a}})},renameFolder(r,o,a){return t("POST",`${e}/vaults/${r}/folders/rename`,{json:{path:o,newName:a}})},moveFolder(r,o,a){return t("POST",`${e}/vaults/${r}/folders/move`,{json:{path:o,dest:a}})},async deleteFolder(r,o){await t("DELETE",`${e}/vaults/${r}/folders?${s({path:o})}`)},putBinary(r,o,a,c){let l=new FormData;return l.set("path",o),c?.ifAbsent&&l.set("ifAbsent","true"),c?.baseSeq!==void 0&&l.set("baseSeq",String(c.baseSeq)),l.set("file",new Blob([new Uint8Array(a)]),o.split("/").pop()||"file"),t("POST",`${e}/vaults/${r}/binary`,{form:l,timeoutMs:br(a.length)})},async listVersions(r,o){return((await t("GET",`${e}/vaults/${r}/file/versions?${s({path:o})}`)).versions??[]).map(c=>({id:String(c.id),seq:Number(c.seq??0)}))},async getVersion(r,o){let a=await t("GET",`${e}/vaults/${r}/file/versions/${o}`);return String(a.content??"")},async getAsset(r,o){let a=new AbortController,c=setTimeout(()=>a.abort(),12e4);try{let l=await fetch(`${e}/vaults/${r}/asset?${s({ref:o})}`,{headers:{Authorization:`Bearer ${n.token}`},signal:a.signal});if(!l.ok)throw new le(l.status,null,"asset:"+o);return clearTimeout(c),c=setTimeout(()=>a.abort(),br(Number(l.headers.get("content-length"))||0)),Buffer.from(await l.arrayBuffer())}finally{clearTimeout(c)}},async changes(r,o){let a=await t("GET",`${e}/vaults/${r}/changes?${s({since:String(o)})}`);return{changes:a.changes??[],seq:Number(a.seq??0)}}}}function Er(n,e){let t=!1,s=0,r=null,o=null,a=()=>`${n.baseUrl.replace(/\/+$/,"")}/api/amadeus/vaults/${n.vaultId}/events?since=${e.getSince()}`,c=h=>{if(t)return;e.onDown(h);let f=Math.min(3e4,1e3*2**s)*(.7+Math.random()*.6);s++,o=setTimeout(()=>void l(),f)},l=async()=>{if(t)return;r=new AbortController;let h;try{h=await fetch(a(),{headers:{Authorization:`Bearer ${n.token}`,Accept:"text/event-stream"},signal:r.signal})}catch(_){c(_);return}if(!h.ok||!h.body){c(new Error(`sse http ${h.status}`));return}s=0,e.onOpen();let f=h.body.getReader(),m=new TextDecoder,u="",w="",v=[],R=()=>{if(!v.length&&!w)return;let _=v.join(`
198
+ `),L=w||"message";w="",v=[];let j=null;try{j=_?JSON.parse(_):null}catch{return}L==="hello"?e.onHello(Number(j?.seq??0)):L==="change"?e.onChange(j):L==="reset"?e.onReset():L==="presence"?e.onPresence?.(j):L==="presence-roster"&&e.onPresenceRoster?.(j)};try{for(;;){let{done:_,value:L}=await f.read();if(_)break;for(u+=m.decode(L,{stream:!0});;){let j=u.indexOf(`
199
+ `);if(j<0)break;let te=u.slice(0,j).replace(/\r$/,"");if(u=u.slice(j+1),te==="")R();else{if(te.startsWith(":"))continue;te.startsWith("event:")?w=te.slice(6).trim():te.startsWith("data:")&&v.push(te.slice(5).replace(/^ /,""))}}}}catch(_){t||c(_);return}c(new Error("sse stream ended"))};return l(),{stop:()=>{t=!0,o&&clearTimeout(o),r?.abort()}}}import{constants as go,promises as Ye}from"node:fs";import yo from"node:path";var Ge=n=>yo.join(de().userDataDir(),de().isDevMode()?`${n}.dev.json`:`${n}.json`);async function an(n){try{let e=JSON.parse(await Ye.readFile(Ge(n),"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 vr(n){let e=null,t=null,s=Promise.resolve(),r=null,o=()=>{if(!e)return s;let a=e,c=JSON.stringify(e);return e=null,s=s.then(async()=>{try{let l=Ge(n),h=`${l}.tmp-${process.pid}-${Date.now()}-0`;await Ye.writeFile(h,c,"utf8"),await Ye.rename(h,l),r=null}catch(l){e??=a,r=l}}),s};return{save(a){e=a,!t&&(t=setTimeout(()=>{t=null,o()},500))},async flush(a=!1){if(t&&(clearTimeout(t),t=null),await o(),a&&r)throw r}}}async function _r(n){try{await Ye.unlink(Ge(n))}catch{}}async function kr(n,e){try{await Ye.copyFile(Ge(n),Ge(e),go.COPYFILE_EXCL)}catch(t){let s=t?.code;if(s==="EEXIST"||s==="ENOENT")return!1;throw t}return await Ye.unlink(Ge(n)).catch(()=>{}),!0}var bo=5*1024*1024,So=5*1024*1024,Eo=3e4,vo=2500,_o=3e3,ko=5,Co=256*1024,xo=5,xr=1024*1024,Tr=200,To=6e4,Ro=50,Io=".sync-trash",Je=n=>wo("sha256").update(n).digest("hex");function at(n,e={localRoot:De(),shadowName:`amadeus-sync-${rt()}`,vaultId:"first",serverDir:"",excludePrefixes:["\u4E0E\u6211\u5171\u4EAB/"]}){let t=i=>{let d=on(i,"");if(!d)return null;for(let p of e.excludePrefixes??[])if(d===p.replace(/\/$/,"")||d.startsWith(p))return null;if(e.ignoreNames?.length&&d.split("/").some(p=>e.ignoreNames.includes(p)))return null;let g=e.serverDir?`${e.serverDir}/${d}`:d;return e.inScope&&!e.inScope(g,Ce(g))?null:g},s=i=>{let d;if(e.serverDir){if(!i.startsWith(`${e.serverDir}/`))return null;d=i.slice(e.serverDir.length+1)}else{for(let g of e.excludePrefixes??[])if(i.startsWith(g))return null;d=i}return d.split("/").some(g=>it(g)||!!e.ignoreNames?.includes(g))?null:d},r=(i,d)=>!e.inScope||e.inScope(i,d),o=e.accountId??fe(),a=!1,c=0,l=Promise.resolve(),h=new Set,f="disabled",m=null,u=null,w=null,v=null,R=null,_=null,L=0,j=new Map,te=null,G=vr(e.shadowName),B=new Map,X=!1,Y=!1,ne=[],ue=()=>{u&&(u.pending=B.size?Object.fromEntries(B):void 0,G.save(u))},ut=()=>{Y=!1,ne.length=0},Qe=()=>{if(Y)return!0;let i=Date.now();for(;ne.length&&i-ne[0]>To;)ne.shift();return ne.length>=Ro?(Y=!0,!0):!1},xe=[],Ne=new Set,Ze=!1,E=null,C=null,y=null,b=()=>{!a||y||(y=setTimeout(()=>{y=null,n.onStatus(Oe())},200))},A=(i,d)=>{f=i,d!==void 0&&(m=d),b()},S=(i,d=!1)=>{if(a){if(i.key){if(Ne.has(i.key))return;Ne.add(i.key)}d?xe.unshift(i):xe.push(i),V()}},x=new Map,D=i=>{if(!a)return;let d=(u?.files[i]?.size??0)>Co,g=(e.pushQuietMs??_o)*(d?xo:1),p=Date.now(),k=x.get(i);k&&clearTimeout(k.timer);let I=k?.since??p,$=Math.max(0,Math.min(g,I+g*ko-p)),T=setTimeout(()=>{x.delete(i),S({key:i,run:()=>ae(i,!0)})},$);x.set(i,{timer:T,since:I}),b()},U=()=>{for(let{timer:i}of x.values())clearTimeout(i);x.clear()},N=i=>!(i instanceof le)||i.status>=500||i.status===0,F=i=>i instanceof le&&(i.status===401||i.status===403),V=async()=>{if(!Ze){Ze=!0;try{for(;xe.length;){(f==="idle"||f==="starting")&&A("syncing");let i=xe.shift();i.key&&Ne.delete(i.key);try{await i.run()}catch(d){if(!a)return;if(F(d)){xe.length=0,Ne.clear(),gt(),A("auth-required","login-expired");return}if(N(d)){S(i,!0),gt(),A("offline",d?.message||"network error"),W();return}let g=i.key??"(op)";j.set(g,d?.body?.code||`http ${d?.status}`),b()}}a&&f==="syncing"&&(u&&(u.lastSyncAt=Date.now(),G.save(u)),A("idle",null))}finally{Ze=!1;for(let i of h)i();h.clear()}}},W=()=>{!a||E||(E=setTimeout(()=>{E=null,tt()},Eo))},q=i=>{if(!_||!u)throw new Error("engine not bound");let d=s(i);if(d===null)throw new Error("path outside binding: "+i);let g=se.resolve(_,wr(d,u.folder)),p=se.relative(_,g);if(p.startsWith("..")||se.isAbsolute(p))throw new Error("path escapes vault: "+i);return g},Q=i=>({size:i,mtimeMs:-1}),J=async i=>{try{let d=await ee.stat(i);return d.isFile()?{size:d.size,mtimeMs:Math.floor(d.mtimeMs)}:null}catch{return null}},we=0,Fe=async(i,d,g=()=>!0)=>{await ee.mkdir(se.dirname(i),{recursive:!0});let p=`${i}.tmp-${process.pid}-${Date.now()}-${we++}`;await ee.writeFile(p,d);let k=await J(p)??Q(Buffer.byteLength(d));return g()?(await ee.rename(p,i),k):(await ee.rm(p,{force:!0}),null)},Ue=async i=>{let d;try{d=await ee.readdir(i,{withFileTypes:!0})}catch{return}for(let g of d)g.isDirectory()&&await Ue(se.join(i,g.name));try{await ee.rmdir(i)}catch{}},oe=async i=>{let d=q(i),g=await J(d),p;try{p=await ee.readFile(d)}catch{return null}return{hash:$e(Ce(i))?Je(p.toString("utf8")):Je(p),size:g?.size??p.length,mtimeMs:g?.mtimeMs??-1,buf:p}},_e=async(i,d,g,p)=>{u&&(u.files[i]={seq:d,hash:g,size:p.size,mtimeMs:p.mtimeMs},G.save(u))},ye=i=>{u&&i in u.files&&(delete u.files[i],G.save(u))},Te=async(i,d)=>{if(!w||!u||be(i))return;let g=re,p=Ce(i),k,I,$;if($e(p)){let O;try{O=await w.getFile(u.vaultId,i)}catch(H){if(H instanceof le&&H.status===404){await $t(i);return}throw H}k=O.content,I=O.seq,$=O.hash??Je(O.content)}else{let O;try{O=await w.getAsset(u.vaultId,i)}catch(H){if(H instanceof le&&H.status===404){j.set(i,"ASSET_404"),b();return}throw H}k=O,I=d??0,$=Je(O)}let T=await oe(i);if(g!==re||be(i))return;if(T&&T.hash===$){await _e(i,I,$,T);return}let M=u.files[i];if(T&&M&&$===M.hash&&T.hash!==M.hash){await _e(i,I,$,Q(M.size)),S({key:i,run:()=>ae(i)});return}if(T&&(!M||T.hash!==M.hash)){if(M&&p==="page"&&typeof k=="string"&&await Or(i,M,T,k,I,$,()=>g===re&&!be(i))||g!==re||be(i))return;await Lr(i)}let P=await Fe(q(i),k,()=>g===re&&!be(i));P&&await _e(i,I,$,P)},Or=async(i,d,g,p,k,I,$)=>{try{if(!w||!u||g.buf.length>xr||p.length>xr)return!1;let M=(await w.listVersions(u.vaultId,i)).find(H=>H.seq===d.seq);if(!M)return!1;let P=await w.getVersion(u.vaultId,M.id);if(Je(P)!==d.hash)return!1;let O=yr(g.buf.toString("utf8"),P,p);return O===null?!1:(await Fe(q(i),O,$)&&(await _e(i,k,I,Q(Buffer.byteLength(O))),S({key:i,run:()=>ae(i)})),!0)}catch{return!1}},Lr=async i=>{let d=Ve(It(i,new Date));if(!d)return;let g=d.lastIndexOf("."),p=g>d.lastIndexOf("/"),k=p?d.slice(0,g):d,I=p?d.slice(g):"",$=d;for(let T=2;Cr(q($));T++)$=`${k}-${T}${I}`;try{await ee.rename(q(i),q($))}catch(T){if(T?.code==="ENOENT")return;throw T}L++,S({key:$,run:()=>ae($)}),b()},yn=async i=>{if(!_)return;let d=q(i),g=s(i)??i,p=se.join(_,Io,new Date().toISOString().slice(0,10),...g.split("/")),k=Cr(p)?`${p}.${Date.now()}`:p;try{await ee.mkdir(se.dirname(k),{recursive:!0}),await ee.rename(d,k)}catch(I){if(I?.code==="ENOENT")return;throw new Error(`\u8F6F\u5220\u5931\u8D25,\u4FDD\u7559\u672C\u5730\u6587\u4EF6 ${d}: ${I?.message??String(I)}`)}},$t=async i=>{if(!u)return;let d=await oe(i);if(be(i))return;let g=u.files[i]??null,p=At(d?.hash??null,g,null);if(p.kind==="deleteLocal"){if(!X&&Qe()){B.set(i,"local"),ue(),b();return}ne.push(Date.now()),await yn(i),ye(i)}else p.kind==="pushCreate"?(ye(i),S({key:i,run:()=>ae(i)})):ye(i)},wn=(i,d)=>{if(u){for(let g of Object.keys(u.files))if(g===i||g.startsWith(`${i}/`)){let p=d+g.slice(i.length);u.files[p]=u.files[g],delete u.files[g]}G.save(u)}},bn=async i=>{if(!w||!u||i.seq<=u.cursor||!await ht())return;if(i.origin.client&&w.clientId===i.origin.client){u.cursor=i.seq,G.save(u);return}let d=i.type==="structure"?"folder":i.type,g=k=>s(k)!==null&&r(k,d);if(!g(i.path)&&!(i.newPath&&g(i.newPath))){u.cursor=i.seq,G.save(u);return}let p=i.path;switch(i.op){case"write":await Te(p,i.fileSeq);break;case"delete":await $t(p);break;case"move":{let k=i.newPath;if(!k)break;let I=u.files[p];if(await oe(p)&&I)try{await ee.mkdir(se.dirname(q(k)),{recursive:!0}),await ee.rename(q(p),q(k)),u.files[k]={...I,seq:i.fileSeq??I.seq},delete u.files[p],G.save(u)}catch{await Te(k,i.fileSeq)}else ye(p),await Te(k,i.fileSeq);break}case"mkdir":await ee.mkdir(q(p),{recursive:!0});break;case"rename-folder":case"move-folder":{let k=i.newPath;if(!k)break;try{await ee.mkdir(se.dirname(q(k)),{recursive:!0}),await ee.rename(q(p),q(k))}catch{}wn(p,k);break}case"delete-folder":{let k=`${p}/`;for(let I of Object.keys(u.files))(I===p||I.startsWith(k))&&await $t(I);await Ue(q(p));break}}if(u.cursor=i.seq,G.save(u),i.op==="move"||i.op==="rename-folder"||i.op==="move-folder"||i.op==="delete"||i.op==="delete-folder")try{await n.onRemoteApplied?.(i)}catch{}},jr=async(i,d,g)=>{let p=Number(d?.seq??0),k=d?.content??null;if(k!==null&&Je(k)===g.hash){await _e(i,p,g.hash,g);return}if(k===null&&p===0){if(!u?.files[i]){j.set(i,d?.code||"EXISTS"),b();return}ye(i),S({key:i,run:()=>ae(i)});return}await Te(i,p)},dt=async(i,d)=>{if(!w||!u)return;let g=await oe(i);if(!g){S({key:i,run:()=>ae(i)});return}if(g.size>bo){j.set(i,"TOO_LARGE"),b();return}let p=g.buf.toString("utf8");try{let k=await w.putFile(u.vaultId,i,p,d);j.delete(i),await _e(i,k.seq,k.hash??g.hash,g)}catch(k){if(k instanceof le&&k.status===409){await jr(i,k.body,g);return}throw k}},ft=async(i,d)=>{if(!w||!u)return;let g=await oe(i);if(!g){S({key:i,run:()=>ae(i)});return}if(g.size>(te??So)){j.set(i,"TOO_LARGE"),b();return}try{let p=await w.putBinary(u.vaultId,i,g.buf,{baseSeq:d});j.delete(i),await _e(i,p.seq,g.hash,g)}catch(p){if(p instanceof le&&p.status===409){let k=Number(p.body?.seq??0),I=p.body?.hash??null;if(I!==null&&I===g.hash){await _e(i,k,g.hash,g);return}if(k===0){if(!u.files[i]){j.set(i,p.body?.code||"EXISTS"),b();return}ye(i),S({key:i,run:()=>ae(i)});return}await Te(i,k);return}throw p}},Sn=async i=>{if(!w||!u||be(i))return;let d=re,g=u.files[i];if(g){if($e(Ce(i)))try{let p=await w.getFile(u.vaultId,i);if(p.seq!==g.seq){await Te(i,p.seq);return}}catch(p){if(p instanceof le&&p.status===404){ye(i);return}throw p}if(!(d!==re||be(i))){try{await w.deleteFile(u.vaultId,i,g.seq,{confirmed:X})}catch(p){if(p instanceof le&&p.status===409){await Te(i,Number(p.body?.seq??0)||null);return}if(p instanceof le&&p.status===429&&p.body?.code==="MASS_DELETE_BLOCKED"){B.set(i,"remote"),Y=!0,ue(),b();return}throw p}ye(i)}}},ht=async()=>_?await ee.stat(_).then(d=>d.isDirectory()).catch(()=>!1)||!e.requireRootExists&&!Object.keys(u?.files??{}).length?!0:(A("error",`vault-missing: ${_}`),W(),!1):!1,re=0,mt=new Set,pt=new Map,he=i=>JSON.stringify([i.from,i.to]),Pe=(i,d)=>i===d||i.startsWith(`${d}/`),be=i=>[...u?.moves??[],...mt].some(d=>Pe(i,d.from)||Pe(i,d.to)),Re=()=>!!(u?.moves?.length||mt.size),Mt=async i=>{if(!w||!u)return;let{from:d,to:g,kind:p}=i;if(s(d)===null||s(g)===null)throw new Error("Invalid queued cloud move");i.hashes??=Object.fromEntries(Object.entries(u.files).filter(([T])=>Pe(T,d)).map(([T,M])=>[T.slice(d.length),M.hash])),G.save(u),await G.flush(!0);let k,I=!1;try{if(p==="folder"){let T=se.posix.dirname(d)==="."?"":se.posix.dirname(d),M=se.posix.dirname(g)==="."?"":se.posix.dirname(g);T===M?await w.renameFolder(u.vaultId,d,se.posix.basename(g)):await w.moveFolder(u.vaultId,d,M)}else{let T=await w.move(u.vaultId,d,g);k=Number(T.seq)}}catch(T){if(!(T instanceof le)||T.status!==404)throw T;let M=await w.tree(u.vaultId);if(M.entries.some(H=>Pe(H.path,d))||M.folders.some(H=>Pe(H,d)))throw T;let O=M.entries.find(H=>H.path===g);if(k=O?.seq,I=!O&&!M.entries.some(H=>Pe(H.path,g))&&!M.folders.some(H=>Pe(H,g)),!I){let H=Object.entries(i.hashes);if(!(H.length>0&&H.every(([ke,He])=>M.entries.some(ze=>ze.path===g+ke&&ze.hash===He))))throw new le(409,{code:"MOVE_DESTINATION_CHANGED"},"local-move")}}if(I)for(let T of Object.keys(u.files))Pe(T,d)&&delete u.files[T];else wn(d,g),k!==void 0&&u.files[g]&&(u.files[g].seq=k);u.moves=(u.moves??[]).filter(T=>he(T)!==he(i)),G.save(u);try{await G.flush(!0)}catch(T){throw u.moves.unshift(i),G.save(u),T}let $=pt.get(he(i));pt.delete(he(i)),$?.(),be(g)||(p==="folder"?await Nt():await ae(g))},ae=async(i,d=!1)=>{if(!u||be(i))return;if(!r(i,Ce(i))){ye(i);return}if(!await ht())return;let g=await oe(i);if(be(i))return;let p=u.files[i]??null,k=At(g?.hash??null,p,p?{seq:p.seq,hash:p.hash}:null);switch(k.kind){case"push":$e(Ce(i))?await dt(i,k.baseSeq):await ft(i,k.baseSeq);break;case"pushCreate":$e(Ce(i))?await dt(i,0):await ft(i,0);break;case"pushDelete":if(d){wt();break}if(!X&&(B.has(i)||Qe())){B.set(i,"remote"),ue(),b();break}ne.push(Date.now()),await Sn(i);break;case"dropShadow":ye(i);break;default:g&&p&&g.hash===p.hash&&g.mtimeMs>=0&&(p.size!==g.size||p.mtimeMs!==g.mtimeMs)&&await _e(i,p.seq,p.hash,g);break}},En=async()=>{let i=new Map;if(!_||!u)return i;let d=_,g=null,p=async k=>{if(g)return;let I;try{I=await ee.readdir(k,{withFileTypes:!0})}catch($){g=`${k}: ${$?.message??String($)}`;return}for(let $ of I){if(it($.name)||$.isDirectory()&&e.ignoreNames?.includes($.name))continue;let T=se.join(k,$.name);if($.isDirectory())await p(T);else if($.isFile()){let M=se.relative(d,T).split(se.sep).join("/"),P=t(M);if(!P)continue;try{let O=await ee.stat(T);if(!O.isFile())continue;i.set(P,{size:O.size,mtimeMs:Math.floor(O.mtimeMs)})}catch(O){if(O?.code==="ENOENT")continue;g=`${T}: ${O?.message??String(O)}`;return}}}};return await p(d),g?(A("error",`scan-failed: ${g}`),W(),null):i},Nt=async()=>{let i=re;if(Re()||i!==re||!u||!await ht())return;let d=await En();if(!d||Re()||i!==re)return;let g=!1;for(let[I,$]of[...B])($==="remote"&&d.has(I)||$==="local"&&!d.has(I))&&(B.delete(I),g=!0);B.size||ut();for(let[I,$]of d){let T=u.files[I];T&&T.size===$.size&&T.mtimeMs===$.mtimeMs||S({key:I,run:()=>ae(I)})}let p=Object.keys(u.files),k=p.filter(I=>!d.has(I));if(k.length&&!X&&(Y||sn(k.length,p.length,Tr))){Y=!0;for(let I of k)B.set(I,"remote");ue(),b();return}g&&(ue(),b());for(let I of k)B.has(I)||S({key:I,run:()=>ae(I)})},et=async()=>{let i=re;if(Re()||i!==re||!w||!u||!_||!await ht())return;let d=await w.tree(u.vaultId);if(d.maxFileBytes!==void 0&&d.maxFileBytes!==te&&(te=d.maxFileBytes,b()),Re()||i!==re)return;let g=new Map;for(let P of d.entries)s(P.path)===null||!r(P.path,P.kind)||g.set(P.path,P);let p=await En();if(!p||Re()||i!==re)return;let k=new Set([...g.keys(),...p.keys(),...Object.keys(u.files)]),I=Object.keys(u.files).length,$=[];for(let P of k){if(Re()||i!==re)return;let O=u.files[P]??null,H=g.get(P)??null,ce=p.get(P)??null,ke=null,He=Q(ce?.size??0);if(ce)if(O&&O.size===ce.size&&O.mtimeMs===ce.mtimeMs)ke=O.hash,He=ce;else{let ze=await oe(P);ze&&(ke=ze.hash,He=ze)}$.push({sp:P,d:At(ke,O,H?{seq:H.seq,hash:H.hash}:null),rSeq:H?.seq??null,localHash:ke,localStat:He})}if(Re()||i!==re)return;let T=$.filter(P=>P.d.kind==="deleteLocal"||P.d.kind==="pushDelete").length,M=!X&&(Y||sn(T,I,Tr));M&&T&&(Y=!0),B.clear();for(let{sp:P,d:O,rSeq:H,localHash:ce,localStat:ke}of $){if(Re()||i!==re)return;if(M&&(O.kind==="deleteLocal"||O.kind==="pushDelete")){B.set(P,O.kind==="deleteLocal"?"local":"remote");continue}if((O.kind==="deleteLocal"||O.kind==="pushDelete")&&((await oe(P))?.hash??null)!==ce){S({key:P,run:()=>ae(P)});continue}if(Re()||i!==re)return;switch(O.kind){case"adopt":await _e(P,H,ce,ke);break;case"pull":await Te(P,H);break;case"push":$e(Ce(P))?await dt(P,O.baseSeq):await ft(P,O.baseSeq);break;case"pushCreate":$e(Ce(P))?await dt(P,0):await ft(P,0);break;case"pushDelete":await Sn(P);break;case"deleteLocal":await yn(P),ye(P);break;case"conflict":await Te(P,H);break;case"dropShadow":ye(P);break;case"none":break}}X&&(X=!1,ne.length=0),B.size||ut(),ue(),M&&b();for(let P of d.folders)if(!(s(P)===null||!r(P,"folder")))try{await ee.mkdir(q(P),{recursive:!0})}catch{}u.cursor=d.seq,u.lastSyncAt=Date.now(),G.save(u)},Ur=async()=>{if(!w||!u)return;let i=u.cursor,d=await w.changes(u.vaultId,i);if(d.changes.length===0&&d.seq>i||d.changes.length>0&&d.changes[0].seq!==i+1){await et();return}for(let p of d.changes)await bn(p)},Ie=null,vn=[],_n=()=>{Ie&&vn.push(Ie.close()),Ie=null},Hr=()=>{if(!a||Ie||!_)return;Ie=mr.watch(_,{ignoreInitial:!0,depth:12,ignored:d=>{let g=se.basename(d);return it(g)||!!e.ignoreNames?.includes(g)}});let i=d=>{if(!_)return;let g=se.relative(_,d);if(!g||g.startsWith(".."))return;let p=t(g);p&&D(p)};Ie.on("change",i),Ie.on("add",i),Ie.on("unlink",()=>wt()),Ie.on("unlinkDir",()=>wt())},gt=()=>{v?.stop(),v=null},zr=()=>{if(!a||!w||!u||v)return;let i=R;i&&(v=Er({baseUrl:i.cloudUrl,vaultId:u.vaultId,token:i.token},{getSince:()=>u?.cursor??0,onHello:d=>{u&&d>u.cursor&&S({run:Ur})},onChange:d=>{S({run:()=>bn(d)})},onReset:()=>{S({run:et})},onOpen:()=>{(f==="offline"||f==="starting")&&A("idle",null),S({run:Nt})},onDown:()=>{(f==="idle"||f==="syncing")&&A("offline")},onPresence:d=>n.onPresence?.(u?.vaultId??"",d),onPresenceRoster:d=>n.onPresenceRoster?.(u?.vaultId??"",d)}))},qr=async()=>{let i=await Ee(o);if(i.cloudSync?.deviceId)return i.cloudSync.deviceId;let d=`desk-${Math.random().toString(36).slice(2,10)}${Date.now().toString(36)}`;return await Ae({cloudSync:{...i.cloudSync??{},deviceId:d}},o),d},Wr=async i=>{gt(),_n(),xe.length=0,Ne.clear(),B.clear(),X=!1,Y=!1,ne.length=0;let d=await Ee(o);if(i!==c)return;let g=d.cloudSync;if(g?.enabled===!1){_=null,w=null,A("disabled",null);return}if(!o||o!==fe()){A("auth-required","not-logged-in");return}if(_=e.localRoot,e.requireRootExists){let $=await ee.stat(_).then(T=>T.isDirectory()).catch(()=>!1);if(i!==c)return;if(!$){A("error",`vault-missing: ${_}`),W();return}}if(i!==c)return;let p=n.loadCreds();if(!p.cloudUrl||!p.token){w=null,A("auth-required","not-logged-in");return}A("starting",null);let k=g?.deviceId??await qr();if(i!==c)return;let I=e.clientIdSuffix?`${k}#${e.clientIdSuffix}`:k;R={cloudUrl:p.cloudUrl,token:p.token},w=Sr({baseUrl:p.cloudUrl,token:p.token,clientId:I});try{let $=e.vaultId==="first"?g?.vaultId:e.vaultId;if(!$){let M=await w.listVaults();if(i!==c)return;if(!M.length)throw new Error("\u4E91\u7AEF\u65E0\u53EF\u7528 vault");$=M[0].id,await Ae({cloudSync:{...g??{},vaultId:$}},o)}if(i!==c)return;let T=await an(e.shadowName);if(i!==c||(u=T&&T.vaultRoot===_&&T.vaultId===$&&T.folder===""?T:{vaultRoot:_,folder:"",vaultId:$,cursor:0,lastSyncAt:null,files:{}},i!==c))return;for(let[M,P]of Object.entries(u.pending??{}))B.set(M,P);if(B.size&&(Y=!0),!e.requireRootExists){let M=await ee.stat(_).then(P=>P.isDirectory()).catch(()=>!1);if(i!==c)return;if(!M){if(Object.keys(u.files).length){A("error",`mirror-missing: ${_}`),W();return}if(await ee.mkdir(_,{recursive:!0}),i!==c)return}}Hr();for(let M of u.moves??[])S({key:`move:${he(M)}`,run:()=>Mt(M)});S({run:et}),S({run:async()=>{zr()}})}catch($){if(i!==c)return;F($)?A("auth-required","login-expired"):(A("offline",$?.message||String($)),W())}},kn=()=>{a=!1,gt(),_n(),xe.length=0,Ne.clear(),U();for(let i of[E,C,y])i&&clearTimeout(i);E=C=y=null},Cn=async()=>{Ze&&await new Promise(i=>h.add(i)),await Promise.all(vn.splice(0)),await G.flush(),u=null,w=null,R=null,_=null,L=0,j.clear(),te=null,B.clear(),X=!1,Y=!1,ne.length=0,f="disabled",m=null},Br=()=>{xn()},yt=null,tt=()=>{yt?.(),yt=de().onBeforeQuit(Br);let i=++c;kn();let d=l.catch(()=>{}).then(async()=>{await Cn(),i===c&&(a=!0,await Wr(i))});return l=d,d},xn=()=>{yt?.(),yt=null,++c,kn();let i=l.catch(()=>{}).then(Cn);return l=i,i},Oe=()=>({enabled:f!=="disabled",state:f==="idle"&&x.size?"syncing":f,lastSyncAt:u?.lastSyncAt??null,pending:xe.length+x.size,conflicts:L,skipped:[...j].map(([i,d])=>({path:i,reason:d})),error:m,pendingDeletions:B.size,maxFileBytes:te});return{getStatus:Oe,start(){tt()},notifyLocal(i,d,g){if(!u||f==="disabled"||f==="auth-required")return;let p=t(i),k=g?t(g):null;if(d==="write"&&p){it(p.split("/").pop()||"")||D(p);return}if(d==="remove"){if(!p)return;let I=`${p}/`,$=!1;for(let T of Object.keys(u.files))(T===p||T.startsWith(I))&&($=!0,S({key:T,run:()=>ae(T)}));!$&&p&&S({key:p,run:()=>ae(p)})}},holdLocalMove(i,d){let g=k=>e.serverDir?`${e.serverDir}/${k.replace(/\\/g,"/").normalize("NFC")}`:k.replace(/\\/g,"/").normalize("NFC"),p={from:g(i),to:g(d)};return++re,mt.add(p),()=>{mt.delete(p)}},async notifyLocalMove(i,d,g,p){let k=t(i),I=t(d),$=u??await an(e.shadowName),T=on(i,""),M=T&&(e.serverDir?`${e.serverDir}/${T}`:T);if(!k&&I&&M&&$&&Object.keys($.files).some(P=>P===M||P.startsWith(`${M}/`))&&(k=M),!k&&!I){g?.();return}if(k&&I){let P=u??$;if(!P){g?.();return}let O=p??(Object.keys(P.files).some(ce=>ce.startsWith(`${k}/`))?"folder":"file"),H={from:k,to:I,kind:O};P.moves??=[],P.moves.some(ce=>he(ce)===he(H))||(P.moves.push(H),++re),g&&pt.set(he(H),g),G.save(P);try{await G.flush(!0)}catch(ce){throw P.moves=P.moves.filter(ke=>he(ke)!==he(H)),pt.delete(he(H)),G.save(P),ce}u===P&&a&&f!=="disabled"&&f!=="auth-required"&&S({key:`move:${he(H)}`,run:()=>Mt(H)});return}k&&this.notifyLocal(i,"remove"),I&&(S({key:I,run:()=>ae(I)}),wt()),g?.()},async setEnabled(i){let d=await Ee(o);return await Ae({cloudSync:{...d.cloudSync??{},enabled:i}},o),await tt(),Oe()},async restart(){return await tt(),Oe()},async syncNow(){if(j.clear(),f==="disabled"||f==="auth-required"||!w)await tt();else{for(let i of u?.moves??[])S({key:`move:${he(i)}`,run:()=>Mt(i)});S({run:et})}return Oe()},confirmMassDeletions(){return B.size&&(X=!0,Y=!1,B.clear(),ne.length=0,ue(),S({run:et})),Oe()},stop:xn};function wt(){a&&(C&&clearTimeout(C),C=setTimeout(()=>{C=null,S({run:Nt})},vo))}}import{createHash as Ao}from"node:crypto";function Rr(n){let e=n.replace(/\.md$/i,""),t=n.lastIndexOf("/"),s=t<0?"":n.slice(0,t);return{root:n,fdPrefix:`${e}.fd/`,assetPrefix:s?`${s}/.amadeus/`:".amadeus/"}}function Ir(n,e,t){return!!(e===n.root||e.startsWith(n.fdPrefix)||`${e}/`===n.fdPrefix||t==="binary"&&e.startsWith(n.assetPrefix)||t==="folder"&&(`${e}/`===n.assetPrefix||e.startsWith(n.assetPrefix)))}var Po=n=>Ao("sha256").update(n).digest("hex").slice(0,8),Do=n=>n.replace(/[\\/:*?"<>|]/g," ").trim().slice(0,40)||"shared",Pt="\u4E0E\u6211\u5171\u4EAB";function ln(n){let e=Po(`${n.vaultId}:${n.path}`),t=Rr(n.path),s=n.path.includes("/")?n.path.slice(0,n.path.lastIndexOf("/")):"";return{key:e,vaultId:n.vaultId,rootPath:n.path,title:n.title,localRelDir:`${Pt}/${Do(n.title)}-${e}`,serverDir:s,inScope:(r,o)=>Ir(t,r,o)}}function cn(){let n=de().readCreds(),e=Se(n.cloudUrl??"",n.token??""),t=new AbortController,s=()=>{let m=de().readCreds();if(t.signal.aborted||!e||Se(m.cloudUrl??"",m.token??"")!==e)throw Object.assign(new Error("Cloud account changed; retry from the current account"),{status:401});return m},r=()=>{let m=s();if(!m.cloudUrl||!m.token)throw Object.assign(new Error("\u672A\u767B\u5F55 Forsion \u8D26\u53F7"),{status:401});return m.cloudUrl.replace(/\/+$/,"")},o=async(m,u,w)=>{let v=s();if(!v.cloudUrl||!v.token)throw Object.assign(new Error("\u672A\u767B\u5F55 Forsion \u8D26\u53F7"),{status:401});let R=await fetch(`${v.cloudUrl.replace(/\/+$/,"")}/api/amadeus${u}`,{method:m,headers:{Authorization:`Bearer ${v.token}`,...w!==void 0?{"Content-Type":"application/json"}:{}},body:w!==void 0?JSON.stringify(w):void 0,signal:AbortSignal.any([t.signal,AbortSignal.timeout(2e4)])});if(!R.ok){let L=null;try{L=await R.json()}catch{}throw Object.assign(new Error(L?.detail||`http ${R.status}`),{status:R.status,code:L?.code})}let _=await R.json();return s(),_},a=null,c=async()=>(s(),a||(a=(await o("GET","/vaults")).vaults[0]?.id??"default",a)),l=()=>{try{let m=(s().token??"").split(".")[1],u=JSON.parse(Buffer.from(m.replace(/-/g,"+").replace(/_/g,"/"),"base64").toString());return typeof u.userId=="string"?u.userId:null}catch{return null}},h=async()=>(await o("GET","/shared-with-me")).items.map(u=>{let w=ln(u),v=u.path.split("/").pop()??u.path;return{...u,localPath:`${w.localRelDir}/${v}`}}),f=null;return{stop:()=>t.abort(),call:o,ensureOwnVault:c,myUserId:l,sharedWithMe:h,linkBase:async()=>{if(s(),f)return f;try{f=((await o("GET","/collab/link-base")).webOrigin??"").trim().replace(/\/+$/,"")||r()}catch{f=r()}return f},async heartbeat(m,u){let w=(m??"").replace(/\\/g,"/"),v,R=null,_=u.find(L=>w.startsWith(`${L.localRelDir}/`));_?(v=_.vaultId,R=_.serverDir?`${_.serverDir}/${w.slice(_.localRelDir.length+1)}`:w.slice(_.localRelDir.length+1)):(v=await c(),R=w||null),await o("POST",`/vaults/${encodeURIComponent(v)}/presence`,{page:R})}}}import{promises as Ar}from"node:fs";import $o from"node:path";var un=".forsion-vault.md",dn=n=>`${n}/${un}`;var ge=n=>n.replace(/\\/g,"/").normalize("NFC");function fn(n){let e=ge(n.path);return e?n.kind==="folder"?`${e}/`:n.kind==="page"?`${e.replace(/\.md$/i,"")}.fd/`:null:null}function Ke(n,e,t){let s=ge(t);if(!s)return!1;if(n.some(r=>ge(r.path)===s))return!0;for(let r of e??[]){let o=ge(r);if(!o)continue;let a=`${o.replace(/\.md$/i,"")}.fd`;if(s===o||s.startsWith(`${o}/`)||s===a||s.startsWith(`${a}/`))return!1}return n.some(r=>{let o=fn(r);return!!o&&s.startsWith(o)})}function hn(n,e,t){let s=ge(n),r=ge(e);return s===r?ge(t):s.startsWith(`${r}/`)?ge(t)+s.slice(r.length):null}function lt(n,e,t){let s=!1,r=n.map(o=>{let a=hn(o,e,t);return a===null?o:(s=!0,a)});return{changed:s,next:r}}async function Pr(n){let e=await Ar.readdir(n,{withFileTypes:!0}).catch(()=>[]),t=[];for(let s of e)!s.isDirectory()||s.name.startsWith(".")||await Ar.access($o.join(n,s.name,un)).then(()=>!0,()=>!1)&&t.push(s.name);return t.sort()}var ie={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",entryClosure:"amadeus:entry-sync:closure",entryChange:"amadeus:entry-sync:change",otherSideDbs:"amadeus:entry-sync:other-side-dbs"};import{createHash as Mo}from"node:crypto";var Dt=n=>Mo("sha256").update(n).digest("hex").slice(0,8);function Dr(n){return n.replace(/ \(conflict \d{4}-\d{2}-\d{2} \d{4}\)(?=(?:\.[^./]+)?$)/,"")}function Me(n,e=[]){let t=[],s=[];for(let r of n){let o=ge(r.path);if(!o)continue;s.push(o);let a=fn(r);a&&t.push(a)}return{entries:n,exclude:e,prefixes:t,paths:s}}function $r(n,e){let t=Dr(ge(e));if(!t)return!1;if(Ke(n.entries,n.exclude,t))return!0;let s=`${t}/`;for(let r of n.paths)if(r.startsWith(s))return!0;for(let r of n.prefixes)if(r.startsWith(s))return!0;return!1}function ct(n,e,t){let s=!1,r=n.map(o=>{let a=hn(o.path,e,t);return a===null?o:(s=!0,{...o,path:a})});return{changed:s,next:r}}function Mr(n,e,t,s){if(e==="delete"||e==="delete-folder"){let r=ge(t),o=n.filter(a=>{let c=ge(a.path);return!(c===r||e==="delete-folder"&&c.startsWith(`${r}/`))});return{changed:o.length!==n.length,next:o}}return s?ct(n,t,s):{changed:!1,next:n}}function mn(n,e){let t=Ve(n);return!t||t!==n.normalize("NFC").trim()?"\u540D\u79F0\u4E0D\u5408\u6CD5":t.includes("/")?"\u540D\u79F0\u4E0D\u80FD\u5305\u542B /":t===Pt?`\u300C${Pt}\u300D\u662F\u4FDD\u7559\u540D\u79F0`:e.includes(t)?"\u8BE5\u540D\u79F0\u5DF2\u88AB\u5176\u4ED6\u667A\u5E93\u7684\u4E91\u540C\u6B65\u5360\u7528":null}var Nr=["setAmadeusSyncFactory","readCreds","accountId","homeDir"],pn=n=>Nr.every(e=>typeof n[e]=="function"),No=()=>({enabled:!1,state:"disabled",lastSyncAt:null,pending:0,conflicts:0,skipped:[],error:null,pendingDeletions:0,maxFileBytes:null,side:"local"});function gn(n){let e=null,t=()=>{if(!e)throw new Error("Cloud sync is not ready");return e};n.handle(ie.get,()=>e?e.get():No()),n.handle(ie.setEnabled,(s,r)=>t().setEnabled(r)),n.handle(ie.syncNow,()=>t().syncNow()),n.handle(ie.confirmDeletions,()=>t().confirmDeletions()),n.handle(ie.entryGet,()=>t().entryGet()),n.handle(ie.otherSideDbs,()=>t().otherSideDbs()),n.handle(ie.entryEnable,(s,r)=>t().entryEnable(r)),n.handle(ie.entryDisable,(s,r)=>t().entryDisable(r)),n.handle(ie.entryClosure,(s,r,o)=>t().entryClosure(r,o)),n.handle(ie.collabCall,(s,r,o)=>t().collabCall(r,o)),n.handle(ie.switchSide,(s,r)=>t().switchSide(s.sender.id,r)),n.setAmadeusSyncFactory(s=>{Gn(s);let r=Fr(s);return e=r.handlers,r.instance}),n.log("[forsion-extend] amadeus cloud sync registered")}function Fr(n){let e=n.notifyAll,t=()=>n.vaultRoot(),s=0,r=!1,o=cn(),a=new Map,c=()=>{let E=Date.now();for(let[C,y]of a)E-y.at>7e4&&a.delete(C);e(ie.presence,[...a.values()])},l={loadCreds:()=>n.readCreds(),onStatus:E=>e(ie.status,{...E,pendingDeletions:ne(),side:v()?"cloud":"local"}),onPresence:(E,C)=>{let y=C;y?.userId&&(a.set(y.userId,{userId:y.userId,username:String(y.username??"user"),page:y.page??null,at:Number(y.at)||Date.now()}),c())},onPresenceRoster:(E,C)=>{if(Array.isArray(C)){for(let y of C){let b=y;b?.userId&&a.set(b.userId,{userId:b.userId,username:String(b.username??"user"),page:b.page??null,at:Number(b.at)||Date.now()})}c()}}},h=()=>{let E=s;return{...l,onStatus:C=>{E===s&&l.onStatus(C)},onPresence:(C,y)=>{E===s&&l.onPresence(C,y)},onPresenceRoster:(C,y)=>{E===s&&l.onPresenceRoster(C,y)}}},f=at(h()),m=new Map,u=[],w=async()=>{if(!r||!fe())return;let E=s,C=o,y;try{y=await C.sharedWithMe()}catch{return}if(E!==s||!r)return;let b=y.map(S=>ln(S));u=b;let A=new Set(b.map(S=>S.key));for(let[S,x]of m)if(!A.has(S)){if(await x.engine.stop(),E!==s)return;m.delete(S)}for(let S of b){if(m.has(S.key))continue;let x=at(h(),{localRoot:je.join(De(),...S.localRelDir.split("/")),shadowName:`amadeus-sync-${rt()}-share-${S.key}`,vaultId:S.vaultId,serverDir:S.serverDir,inScope:S.inScope});m.set(S.key,{engine:x,plan:S}),x.start()}},v=()=>t()===De(),R=(E,C=E.base)=>{E.base=C;let y=[C,...E.pendingMoves];E.scope.current=Me(y.flatMap(b=>b.entries),y.flatMap(b=>b.exclude))},_=new Map,L=new Set,j=()=>{e(ie.entryChange)},te=async(E,C)=>{let y=_.get(E);if(!y)return;let b=x=>x&&x.startsWith(`${y.cloudName}/`)?x.slice(y.cloudName.length+1):null,A=b(C.path);if(!A)return;let S=!1;await qe(x=>{if(_.get(E)!==y)return!1;let D=(x.entrySync??[]).find(W=>W.vaultRoot===E);if(!D)return!1;let U=C.op,N=b(C.newPath),F=Mr(D.entries,U,A,N),V=N?lt(D.exclude??[],A,N):{changed:!1,next:D.exclude??[]};if(!F.changed&&!V.changed)return!1;S=!0,D.entries=F.next,V.changed&&(D.exclude=V.next),R(y,Me(D.entries,D.exclude??[]))}),S&&_.get(E)===y&&j()},G=E=>{let C=s;return{...h(),onStatus:y=>{C===s&&e(ie.status,{...y,pendingDeletions:ne(),side:"local",binding:E})},onRemoteApplied:async y=>{C===s&&await te(E,y)}}},B=async()=>{let E=fe();if(!r||!E)return;let C=s,y=o,b=rt(E);await n.adoptLegacyCloudState(E,kr);let A=await Ee(E),S=A.entrySync??[];if(C!==s||!r||E!==fe())return;let x=new Map(S.map(D=>[D.vaultRoot,D]));for(let[D,U]of _){let N=x.get(D);if(!(N&&N.cloudName===U.cloudName)&&(await U.engine.stop(),C!==s||(_.delete(D),N&&await _r(`amadeus-sync-${b}-entry-${Dt(D)}`),C!==s)))return}for(let D of S){let U=_.get(D.vaultRoot);if(U){R(U,Me(D.entries,D.exclude??[]));continue}let N={current:Me(D.entries,D.exclude??[])},F=D.cloudName,V=at(G(D.vaultRoot),{accountId:E,localRoot:D.vaultRoot,shadowName:`amadeus-sync-${b}-entry-${Dt(D.vaultRoot)}`,vaultId:"first",serverDir:F,clientIdSuffix:`entry-${Dt(D.vaultRoot)}`,requireRootExists:!0,ignoreNames:[".git","node_modules",".trash"],inScope:W=>W===F?!0:W.startsWith(`${F}/`)?$r(N.current,W.slice(F.length+1)):!1});_.set(D.vaultRoot,{engine:V,scope:N,cloudName:F,base:N.current,pendingMoves:new Set}),V.start()}if(A.cloudSync?.enabled!==!1)for(let D of S)L.has(D.cloudName)||(async()=>{try{let U=await y.ensureOwnVault();await y.call("PUT",`/vaults/${encodeURIComponent(U)}/file`,{path:dn(D.cloudName),content:"",baseSeq:0}),C===s&&L.add(D.cloudName)}catch(U){U?.status===409&&C===s&&L.add(D.cloudName)}})()},X=async(E,C,y,b,A)=>{let S=C.replace(/\\/g,"/").normalize("NFC"),x=y.replace(/\\/g,"/").normalize("NFC"),D=!1,U,N,F,V=A??"file";try{await qe(async W=>{if(_.get(E)!==b)return!1;let q=(W.entrySync??[]).find(oe=>oe.vaultRoot===E);if(!q)return!1;let Q=ct(q.entries,S,x),J=lt(q.exclude??[],S,x),we=Ke(q.entries,q.exclude,S);!A&&await Xe.stat(je.join(E,...x.split("/"))).then(oe=>oe.isDirectory(),()=>!1)&&(V="folder");let Fe=V==="folder"?"folder":/\.md$/i.test(x)?"page":"asset";we&&!Ke(Q.next,J.next,x)&&(Q.next.push({path:x,kind:Fe}),Q.changed=!0),D=Q.changed||J.changed;let Ue=q.entries.filter(oe=>ct([oe],S,x).changed);return we&&!Ue.some(oe=>oe.path===S)&&Ue.push({path:S,kind:Fe}),U=Me(Ue,(q.exclude??[]).filter(oe=>lt([oe],S,x).changed)),N=b.base,b.pendingMoves.add(U),q.entries=Q.next,q.exclude=J.next,F=Me(q.entries,q.exclude),R(b,F),D})}catch(W){throw U&&b.pendingMoves.delete(U),R(b,b.base===F&&N?N:b.base),W}try{U&&await b.engine.notifyLocalMove(S,x,()=>{b.pendingMoves.delete(U),R(b)},V)}catch(W){throw U&&b.pendingMoves.delete(U),await qe(q=>{let Q=q.entrySync?.find(J=>J.vaultRoot===E);if(!Q)return!1;Q.entries=ct(Q.entries,x,S).next,Q.exclude=lt(Q.exclude??[],x,S).next,R(b,Me(Q.entries,Q.exclude))}),W}D&&_.get(E)===b&&j()},Y=E=>{let C=E.replace(/\\/g,"/");for(let{engine:y,plan:b}of m.values())if(C.startsWith(`${b.localRelDir}/`))return{engine:y,rel:C.slice(b.localRelDir.length+1)};return{engine:f,rel:C}};n.setMutationHooks((E,C)=>{if(v()){let y=Y(E);y.engine.notifyLocal(y.rel,C);return}_.get(t()??"")?.engine.notifyLocal(E,C)},(E,C,y)=>{if(v()){let S=Y(E),x=Y(C);if(S.engine===x.engine)return S.engine.notifyLocalMove(S.rel,x.rel,void 0,y);S.engine.notifyLocal(S.rel,"remove"),x.engine.notifyLocal(x.rel,"write");return}let b=t()??"",A=_.get(b);if(A)return X(b,E,C,A,y)},(E,C)=>{if(v()){let y=Y(E),b=Y(C),A=[y.engine.holdLocalMove(y.rel,b.rel)];return y.engine!==b.engine&&A.push(b.engine.holdLocalMove(y.rel,b.rel)),()=>{for(let S of A)S()}}return _.get(t()??"")?.engine.holdLocalMove(E,C)});let ne=()=>{let E=f.getStatus().pendingDeletions;for(let{engine:C}of m.values())E+=C.getStatus().pendingDeletions;for(let{engine:C}of _.values())E+=C.getStatus().pendingDeletions;return E},ue=E=>({...E,pendingDeletions:ne(),side:v()?"cloud":"local"}),ut=()=>{if(!r)return Promise.resolve(f.getStatus());w();for(let{engine:E}of m.values())E.syncNow();for(let{engine:E}of _.values())E.syncNow();return f.syncNow()},Qe=async()=>{++s,r=!1,o.stop();let E=[f.stop(),...[...m.values()].map(({engine:y})=>y.stop()),...[..._.values()].map(({engine:y})=>y.stop())];m.clear(),_.clear(),u=[],L.clear(),a.clear(),c(),await Promise.all(E),await n.awaitPendingVaultWrites();let C=t();if(C&&St(C)){let y=await Ee(),b=y.localVault&&!St(y.localVault)?y.localVault:je.join(n.workspaceDir(),"Amadeus");await Xe.mkdir(b,{recursive:!0}),await Ae({lastVault:b,localVault:b,lastPage:void 0}),await n.activateRoot(b,!1)}j()};return{handlers:{get:()=>ue(f.getStatus()),setEnabled:async E=>{if(!r)throw new Error("Cloud account is changing");let C=s;return await f.setEnabled(E),C!==s?f.getStatus():(await Promise.all([...m.values(),..._.values()].map(({engine:y})=>y.restart())),ue(f.getStatus()))},syncNow:()=>ut(),confirmDeletions:()=>{for(let{engine:E}of m.values())E.confirmMassDeletions();for(let{engine:E}of _.values())E.confirmMassDeletions();return ue(f.confirmMassDeletions())},entryGet:async()=>{let E=await Ee(),C=De();return{vaults:E.entrySync??[],activeRoot:t(),cloudRoot:C,mirrorVaults:await Pr(C)}},otherSideDbs:async()=>{let E=t();if(!E)return null;let C=De(),y=await Ee(),b=E===C?y.localVault&&y.localVault!==C?y.localVault:null:C;if(!b)return null;let A=[],S=500,x=async(D,U)=>{if(A.length>=S)return;let N;try{N=await Xe.readdir(D,{withFileTypes:!0})}catch{return}for(let F of N){if(A.length>=S)break;if(F.name.startsWith(".")||F.isSymbolicLink())continue;let V=U?`${U}/${F.name}`:F.name;if(F.isDirectory())await x(je.join(D,F.name),V);else if(F.isFile()&&/\.db$/i.test(F.name))try{A.push({rel:V,source:await Xe.readFile(je.join(D,F.name),"utf8")})}catch{}}};return await x(b,""),{root:b,vaultName:b===C?"\u4E91\u7AEF":je.basename(b),dbs:A}},entryEnable:async E=>{let C=s,y=o;if(!r||!fe())return{error:"Sign in to enable cloud sync"};let b=t();if(!b||v())return{error:"\u4EC5\u672C\u5730 vault \u53EF\u5F00\u542F\u4E91\u540C\u6B65"};let A=await Ee(),S=A.entrySync??[],x=S.find(D=>D.vaultRoot===b);if(!x){let D=(E.cloudName??je.basename(b)).normalize("NFC").trim(),U=mn(D,S.map(N=>N.cloudName));if(U)return{error:U};if(!E.merge)try{let N=await y.ensureOwnVault(),F=await y.call("GET",`/vaults/${encodeURIComponent(N)}/tree`);if((F.folders??[]).some(W=>W===D||W.startsWith(`${D}/`))||(F.entries??[]).some(W=>W.path===D||W.path.startsWith(`${D}/`)))return{conflict:D}}catch(N){return{error:N?.message||"\u65E0\u6CD5\u8FDE\u63A5\u4E91\u7AEF(\u9996\u6B21\u5F00\u542F\u9700\u8981\u5728\u7EBF)"}}x={vaultRoot:b,cloudName:D,entries:[]},S.push(x),(async()=>{try{let N=await y.ensureOwnVault();await y.call("PUT",`/vaults/${encodeURIComponent(N)}/file`,{path:dn(x.cloudName),content:"",baseSeq:0})}catch{}})()}return C!==s||!r?{error:"Cloud account changed; retry from the current account"}:(await qe(D=>{if(C!==s||!r)return!1;let U=D.entrySync??[],N=U.find(J=>J.vaultRoot===b);if(!N){let J=mn(x.cloudName,U.map(we=>we.cloudName));if(J)throw new Error(J);N={vaultRoot:b,cloudName:x.cloudName,entries:[]},U.push(N)}let F=J=>String(J??"").replace(/\\/g,"/").normalize("NFC"),V=new Set;for(let J of E.entries??[]){let we=F(J.path);we&&(V.add(we),!N.entries.some(Fe=>Fe.path===we)&&N.entries.push({path:we,kind:J.kind==="folder"||J.kind==="asset"?J.kind:"page"}))}let W=(E.exclude??[]).map(F).filter(Boolean),q=new Set([...V,...(E.include??[]).map(F).filter(Boolean)]);N.exclude=[...new Set([...(N.exclude??[]).filter(J=>!q.has(J)),...W])];let Q=new Set(W);N.entries=N.entries.filter(J=>!Q.has(J.path)),D.entrySync=U,x=N},A.cloudAccountId),C!==s?{error:"Cloud account changed; retry from the current account"}:(await B(),_.get(b)?.engine.syncNow(),j(),{ok:!0,cloudName:x.cloudName}))},entryDisable:async E=>{let C=t(),y=!1,b=s;return await qe(A=>{if(b!==s||!r)return!1;let S=(A.entrySync??[]).find(U=>U.vaultRoot===C);if(!C||!S)return!1;let x=String(E??"").replace(/\\/g,"/").normalize("NFC"),D=S.entries.length;if(S.entries=S.entries.filter(U=>U.path!==x),Ke(S.entries,S.exclude,x))S.exclude=[...new Set([...S.exclude??[],x])];else if(S.entries.length===D)return!1;y=!0}),!y||b!==s?{ok:!1}:(await B(),j(),{ok:!0})},entryClosure:(E,C)=>n.relatedClosure(String(E??""),C==="folder"?"folder":"page"),collabCall:async(E,C)=>{let y=o,b=async()=>y.ensureOwnVault(),A=x=>String((C??[])[x]??""),S=x=>(C??[])[x]??{};switch(E){case"listVaults":return(await y.call("GET","/vaults")).vaults;case"activeVaultId":return b();case"pageShare":return y.call("GET",`/vaults/${encodeURIComponent(await b())}/page-shares?path=${encodeURIComponent(A(0))}`);case"createPageShare":return y.call("POST",`/vaults/${encodeURIComponent(await b())}/page-shares`,{path:A(0),...S(1)});case"updatePageShare":return y.call("PATCH",`/vaults/${encodeURIComponent(await b())}/page-shares/${encodeURIComponent(A(0))}`,S(1));case"revokePageShare":return y.call("DELETE",`/vaults/${encodeURIComponent(await b())}/page-shares/${encodeURIComponent(A(0))}`);case"setParticipantRole":return y.call("PATCH",`/vaults/${encodeURIComponent(await b())}/page-shares/${encodeURIComponent(A(0))}/members/${encodeURIComponent(A(1))}`,{role:A(2)});case"removeParticipant":return y.call("DELETE",`/vaults/${encodeURIComponent(await b())}/page-shares/${encodeURIComponent(A(0))}/members/${encodeURIComponent(A(1))}`);case"sharedWithMe":{let x=await y.sharedWithMe();return w(),x}case"leaveShare":{let x=y.myUserId();if(!x)throw new Error("\u672A\u767B\u5F55");return y.call("DELETE",`/vaults/${encodeURIComponent(await b())}/page-shares/${encodeURIComponent(A(0))}/members/${encodeURIComponent(x)}`)}case"publishes":return y.call("GET",`/vaults/${encodeURIComponent(await b())}/shares`);case"listAllShares":{let x=(await y.call("GET","/vaults")).vaults||[],D=y.myUserId(),U=[],N=[];for(let F of x){try{let V=await y.call("GET",`/vaults/${encodeURIComponent(F.id)}/shares`);for(let W of V.shares||[])U.push({...W,vaultId:F.id,vaultName:F.name||""})}catch(V){n.log(`[connect] listAllShares publishes vault ${F.id} failed: ${V?.message}`)}try{let V=await y.call("GET",`/vaults/${encodeURIComponent(F.id)}/page-shares`),W=V?.shares||V?.pageShares||(Array.isArray(V)?V:[]);for(let q of W){let Q=q.created_by??q.createdBy;(!D||!Q||Q===D)&&N.push({...q,vaultId:F.id,vaultName:F.name||""})}}catch(V){n.log(`[connect] listAllShares pageShares vault ${F.id} failed: ${V?.message}`)}}return{publishes:U,pageShares:N,linkBase:await y.linkBase()}}case"createPublish":{let x=await y.call("POST",`/vaults/${encodeURIComponent(await b())}/shares`,{mode:A(0),path:A(1)});return{...x,url:`${await y.linkBase()}/share/${x.token}`}}case"revokePublish":return y.call("DELETE",`/vaults/${encodeURIComponent(await b())}/shares/${encodeURIComponent(A(0))}`);case"revokePublishIn":return y.call("DELETE",`/vaults/${encodeURIComponent(A(0))}/shares/${encodeURIComponent(A(1))}`);case"revokePageShareIn":return y.call("DELETE",`/vaults/${encodeURIComponent(A(0))}/page-shares/${encodeURIComponent(A(1))}`);case"myUserId":return y.myUserId();case"linkBase":return y.linkBase();case"heartbeat":return y.heartbeat((C??[])[0]??null,u);default:throw new Error(`unknown collab fn: ${E}`)}},switchSide:async(E,C)=>{let y=await Ee();if(C==="cloud"){if(!r||!fe())throw new Error("Sign in to open cloud notes");let S=De();await Xe.mkdir(S,{recursive:!0}),y.lastVault&&!St(y.lastVault)&&await Ae({localVault:y.lastVault}),await Ae({lastVault:S});let x=await n.activateRoot(S,!1);return n.bindRenderer(E,S),{...x,side:"cloud"}}let b=y.localVault&&await Xe.stat(y.localVault).then(S=>S.isDirectory()).catch(()=>!1)?y.localVault:null;if(!b){let S=await n.ensureDefaultVault();return n.bindRenderer(E,S.root),{...S,side:"local"}}await Ae({lastVault:b});let A=await n.activateRoot(b,!1);return n.bindRenderer(E,b),{...A,side:"local"}}},instance:{start:()=>{r=!0,f.start(),w(),B()},stopAllSync:Qe,restartAllSync:async()=>{await Qe(),o=cn(),f=at(h()),r=!0,await Promise.all([f.restart(),w(),B()]),j(),e(ie.status,ue(f.getStatus()))}}}}function Ea(n){n.handle("auth:openAccountCenter",async(t,s)=>{let{base:r,token:o}=await n.getCloud();if(!r)return{ok:!1};let a=s&&/^[a-z0-9-]+$/i.test(s)?`#${s}`:"",c=`${r}/account${o?`?token=${encodeURIComponent(o)}`:""}${a}`;return await n.openExternal(c),{ok:!0}}),n.handle("auth:openPayCenter",async()=>{let{base:t,token:s}=await n.getCloud();if(!t)return{ok:!1};let r=`${t}/pay?tab=membership${s?`&token=${encodeURIComponent(s)}`:""}&redirect=${encodeURIComponent(`${t}/account`)}`;return await n.openExternal(r),{ok:!0}});let e=()=>n.getCloud();n.handle("account:quota",async()=>{let t=await e();if(!t.token)return{status:401,json:null};try{return await me(t,"GET","/api/token-quota/my",void 0,15e3)}catch(s){return{status:0,json:{detail:String(s?.message||s)}}}}),n.handle("account:useResetCard",async(t,s)=>{let r=await e();if(!r.token)return{status:401,json:null};if(s!==void 0&&s!=="both"&&s!=="weekly")return{status:400,json:{error:"invalid_type",detail:`invalid reset card type: ${s}`}};let o=s??"both";try{return await me(r,"POST","/api/token-quota/reset-card/use",{type:o},15e3)}catch(a){return{status:0,json:{detail:String(a?.message||a)}}}}),n.handle("account:bgConvert",async(t,s)=>{let r=await e();if(!r.token)return{status:401,json:null};if(!Number.isInteger(s)||s<1||s>100)return{status:400,json:{error:"invalid_percent"}};try{return await me(r,"POST","/api/token-quota/background/convert",{percent:s},15e3)}catch(o){return{status:0,json:{detail:String(o?.message||o)}}}}),n.handle("account:bgAutoMain",async(t,s)=>{let r=await e();if(!r.token)return{status:401,json:null};if(typeof s!="boolean")return{status:400,json:{error:"invalid_request"}};try{return await me(r,"POST","/api/token-quota/background/auto-main",{enabled:s},15e3)}catch(o){return{status:0,json:{detail:String(o?.message||o)}}}}),n.handle("feedback:submit",async(t,s)=>{let{base:r,token:o}=await n.getCloud();if(!r||!o)return{ok:!1,error:"not-logged-in"};let a=(s?.description||"").trim();if(!a)return{ok:!1,error:"empty"};if(a.length>1e4)return{ok:!1,error:"description-too-long"};let c=[],l=!1;if(s?.sessionLogJson){let h=Buffer.from(s.sessionLogJson,"utf8");if(h.length>5*1024*1024)return{ok:!1,error:"attachment-too-large"};c.push({filename:s.sessionLogName||"tangu-session.json",mime_type:"application/json",size:h.length,data_base64:h.toString("base64")})}try{let h=await fetch(`${r}/api/feedback`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify({description:a,attachments:c}),signal:AbortSignal.timeout(2e4)});if(!h.ok){let m=`HTTP ${h.status}`;try{m=(await h.json())?.detail||m}catch{}return{ok:!1,error:m}}return{ok:!0,id:(await h.json().catch(()=>({})))?.id??null,attachmentSkipped:l}}catch(h){return{ok:!1,error:h?.message||String(h)}}}),n.handle("cloud:fetch",async(t,s)=>{if(!n.isTrustedSender(t))return{status:0,error:"untrusted"};let r=s??{},o=typeof r.path=="string"?r.path:"",a=Math.min(12e4,Math.max(1e3,Number(r.timeoutMs)||15e3)),c=typeof r.method=="string"?r.method.toUpperCase():"GET";if(!/^(GET|POST|PUT|PATCH|DELETE)$/.test(c))return{status:0,error:"bad_method"};if(!o.startsWith("/"))return{status:0,error:"bad_path"};let{base:l,token:h}=await n.getCloud();if(!String(l||""))return{status:0,error:"no_cloud_url"};let f=Tn(l,o);if(!f)return{status:0,error:"bad_path"};if(!h)return{status:401,error:"not_signed_in"};let m=r.body!==void 0&&c!=="GET"&&c!=="DELETE",u=new AbortController,w=setTimeout(()=>u.abort(),a);try{let v=await fetch(f,{method:c,headers:{Authorization:`Bearer ${h}`,...m?{"Content-Type":"application/json"}:{}},body:m?JSON.stringify(r.body):void 0,signal:u.signal});return{status:v.status,json:await v.json().catch(()=>null)}}catch(v){return{status:0,error:String(v?.message||v)}}finally{clearTimeout(w)}}),n.log("[forsion-extend] cloud account handlers registered"),jt(n)?Ut(n):n.log("[forsion-extend] host has no Connect seam (projectsRoot / transpileForServe / mimeOf / setPreviewHooks); Connect stays with the host"),zt(n)?qt(n):n.log("[forsion-extend] host has no remote-sync seam (registerRemoteSyncBackend / readCreds); penzor stays with the host"),Bt(n)?Vt(n):n.log("[forsion-extend] host has no account seam (accountCommit / accountClear / \u2026); account core stays with the host"),pn(n)?gn(n):n.log("[forsion-extend] host has no amadeus seam (setAmadeusSyncFactory); cloud sync stays with the host")}export{Vn as ACCOUNT_SEAM,Nr as AMADEUS_SEAM,Ot as CONNECT_MAX_FILES,In as CONNECT_MAX_FILE_BYTES,An as CONNECT_MAX_TOTAL_BYTES,Fn as FORSION_CONNECT_LOCAL_SDK,Un as PENZOR_MAX_FILE,ie as SYNC_IPC,me as cloudJson,Pn as collectProjectFiles,It as conflictCopyPath,lo as conflictCopyVariant,Bn as createAccountCloud,Fr as createAmadeusCloud,jn as createPenzorRemote,Ht as expectedPartsOf,Se as forsionAccountId,Wn as forsionRefreshToken,nt as forsionWhoami,Bt as hasAccountHost,pn as hasAmadeusHost,jt as hasConnectHost,zt as hasRemoteSyncHost,Nn as makePreviewProxy,$n as readConnectMeta,Vt as registerAccount,gn as registerAmadeus,Ea as registerCloud,Ut as registerConnect,qt as registerPenzor,qn as shouldRefreshToken,Dr as stripConflictSuffix,co as textFingerprint,zn as tokenAgeMs,us as tokenRemainingMs,Mn as writeConnectMeta};
200
+ /*! Bundled license information:
201
+
202
+ chokidar/index.js:
203
+ (*! chokidar - MIT License (c) 2012 Paul Miller (paulmillr.com) *)
204
+ */
package/manifest.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "id": "forsion-extend",
3
3
  "name": "Forsion 扩展",
4
4
  "nameEn": "Forsion Extend",
5
- "version": "0.3.0",
5
+ "version": "0.4.0",
6
6
  "apiVersion": 1,
7
7
  "minAppVersion": "2.11.4",
8
8
  "main": "dist/main.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forsion/extend",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Forsion Extend: the cloud-account half of Forsion Desktop plus Forsion Connect (Coding Space publishing and the preview-mode AI proxy), shipped as a built-in bundle (signed, updated through npm).",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -27,12 +27,18 @@
27
27
  "build": "node scripts/build.mjs",
28
28
  "sign": "node scripts/sign.mjs",
29
29
  "verify": "node scripts/verify-package.mjs",
30
- "test": "node --test 'test/*.test.ts'",
31
- "typecheck": "tsc --noEmit"
30
+ "test": "node --test 'test/*.test.ts' && vitest run",
31
+ "typecheck": "tsc --noEmit",
32
+ "test:vitest": "vitest run"
32
33
  },
33
34
  "devDependencies": {
34
35
  "@types/node": "^22.10.0",
35
36
  "esbuild": "^0.25.0",
36
- "typescript": "^5.6.0"
37
+ "typescript": "^5.6.0",
38
+ "vitest": "^3.2.7"
39
+ },
40
+ "dependencies": {
41
+ "chokidar": "^5.0.0",
42
+ "node-diff3": "^3.2.1"
37
43
  }
38
44
  }