@zleap-ai/app-sdk 0.10.1 → 0.12.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/README.md CHANGED
@@ -37,4 +37,4 @@ const { data } = await db.collection('todos').orderBy('created_at', 'desc').limi
37
37
 
38
38
  ## 版本与许可
39
39
 
40
- 与 `@zleap-ai/app-cli` 同版本发布。专有许可,仅限在 zleapOS 应用中使用,见 [LICENSE](./LICENSE)。
40
+ 版本独立于 `@zleap-ai/app-cli`(SDK 只和 zleapOS 宿主握手,不依赖 CLI 版本)。专有许可,仅限在 zleapOS 应用中使用,见 [LICENSE](./LICENSE)。
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "package": "@zleap-ai/app-sdk",
3
- "version": "0.10.1",
4
- "source": "6d0ab79fb0aaa2df0163744d0e83efe3569235274040e464dc5b61ce7dee9e1e",
5
- "files": 21,
3
+ "version": "0.12.0",
4
+ "source": "593b98bd6d4f1600d48579da161460f6e38403fd35164621668a31dfeecab21f",
5
+ "files": 22,
6
6
  "outputs": {
7
7
  "index": {
8
8
  "bytes": 38237,
9
- "sha256": "d746f0ddba5c7949fa2b7980885624100314ca2f28b32de5ac3c062e98626d4c"
9
+ "sha256": "260761adced7464e2d9151f3eecb6768092b61a37f3f7a73c4f5e24b700c04bf"
10
10
  },
11
11
  "host": {
12
12
  "bytes": 11622,
13
- "sha256": "c11013f994aa866b2160bebcb020dceb9030c399d3785e44115751fdaf801c94"
13
+ "sha256": "0b5c724abbd798c90a7743e21823fb4a8ae0e1332af7c3bfffc2d7bf4e59b8b8"
14
14
  },
15
15
  "workspace": {
16
16
  "bytes": 2632,
17
- "sha256": "956e9aef2d41661f3f50c02b40d8d9aa3b0591c9d48afdaa614244a2c4ad4f88"
17
+ "sha256": "de9ca423763ce8007f2e4baf72b56f819c445b586cda92378e6ad8ac38cf785e"
18
18
  }
19
19
  }
20
20
  }
package/dist/host.js CHANGED
@@ -1,2 +1,2 @@
1
- /*! @zleap-ai/app-sdk v0.10.1 | (c) 2026 Zleap | 专有许可,仅限在 zleapOS 应用中使用,见 LICENSE */
1
+ /*! @zleap-ai/app-sdk v0.12.0 | (c) 2026 Zleap | 专有许可,仅限在 zleapOS 应用中使用,见 LICENSE */
2
2
  var U=Object.defineProperty;var F=(e,t,s)=>t in e?U(e,t,{enumerable:!0,configurable:!0,writable:!0,value:s}):e[t]=s;var V=(e,t,s)=>F(e,typeof t!="symbol"?t+"":t,s);var o=class extends Error{constructor(s,n){super(s);V(this,"code");this.code=n,this.name="SDKError"}},I=1024*1024,D=64*1024,z=16,$=2**31-1,K=/^[a-z0-9][a-z0-9._-]{0,127}$/,J=128,q=/[/\\:%?#<>|"*]/,Z=/\p{C}/u,L=new Set(["con","prn","aux","nul",".packageroot",".","..",...Array.from({length:9},(e,t)=>`com${t+1}`),...Array.from({length:9},(e,t)=>`lpt${t+1}`)]),P=new WeakMap,S=e=>!!(e&&typeof e=="object"&&!Array.isArray(e)),k=e=>new TextEncoder().encode(e).byteLength,A=e=>typeof e=="number"&&Number.isSafeInteger(e)&&e>=0;function O(e){if(typeof e!="string"||!K.test(e))throw new o(`KV 键不合法:须匹配 ${K.source}(首字符小写字母/数字,仅含小写字母/数字/._-,长度 1-128),收到 ${JSON.stringify(e)}`,42200)}function C(e){if(typeof e!="number"||!Number.isSafeInteger(e)||e<0||e>$)throw new o(`KV expectedVersion 不合法:须为 0..${$} 的整数(当前乐观锁版本,先 kv.get 取最新 version),收到 ${JSON.stringify(e)}`,42200)}function R(e){let t='文件名不合法:须为安全的根目录名称(非空、≤128 UTF-8 字节、无首尾空白、不以点结尾、不含 /\\:%?#<>|"* 与控制字符、非 con/com1-9 等系统保留名)',s=()=>{throw new o(t,42200)};if(typeof e!="string"||e.length===0)throw new o(t,42200);let n=e.normalize("NFC");Math.max(k(e),k(n))>J&&s(),(e!==e.trim()||e.endsWith("."))&&s(),(q.test(e)||Z.test(e))&&s();let a=n.toLowerCase(),f=a.split(".",1)[0]??a;(L.has(a)||L.has(f))&&s()}function X(e){let t=new Set,s=(n,a)=>{if(a>z)throw new o(`KV 值嵌套超过 ${z} 层上限`,42200);if(n===null)return"null";switch(typeof n){case"boolean":case"number":case"string":return JSON.stringify(n);case"bigint":throw new o("KV 值不支持 BigInt,请转换为 number 或 string",42200);case"undefined":case"function":case"symbol":return"";case"object":{if(t.has(n))throw new o("KV 值存在循环引用,无法序列化",42200);if(typeof n.toJSON=="function")throw new o("KV 值含带 toJSON 的对象(如 Date):请先显式转换(如 value.toISOString())后再写入",42200);t.add(n);try{return Array.isArray(n)?`[${n.map(f=>s(f,a+1)||"null").join(",")}]`:`{${Object.entries(n).filter(([,f])=>!["undefined","function","symbol"].includes(typeof f)).sort(([f],[d])=>f<d?-1:f>d?1:0).map(([f,d])=>`${JSON.stringify(f)}:${s(d,a+1)}`).join(",")}}`}finally{t.delete(n)}}default:throw new o(`KV 值含不支持的类型 ${typeof n}`,42200)}};return s(e,0)}function H(e){let t=X(e),s=new TextEncoder().encode(t).byteLength;if(s>D)throw new o(`KV 值过大:canonical JSON ${s} 字节,超过 64 KiB 上限`,42200)}function Q(e){switch(e){case 40400:return{code:e,retryable:!1,hint:"资源不存在:请确认 id / 路径正确后重试"};case 40900:return{code:e,retryable:!1,hint:"连接已关闭或请求 ID 冲突:请重新 connectHostedApp 后再试"};case 40901:return{code:e,retryable:!0,hint:"KV 版本冲突:请重新 kv.get 取最新 version 后以新的 expectedVersion 重试"};case 42200:return{code:e,retryable:!1,hint:"请求参数不合法:请检查键格式 / 值大小 / 文件上限后修正再提交"};case 42900:return{code:e,retryable:!0,hint:"并发请求过多:请降低并发(≤8)后重试"};case 40300:case 40301:case 40302:return{code:e,retryable:!1,hint:"宿主环境缺失或无权限:请确认从 Zleap OS 打开并已声明所需能力"};case 50200:return{code:e,retryable:!0,hint:"宿主响应异常:可重试;持续出现请向平台反馈"};case 50300:return{code:e,retryable:!0,hint:"连接不可用或超时:请检查宿主状态后重建连接重试"};default:return{code:e,retryable:!1,hint:"未识别的错误码:请结合 message 排查,必要时向平台反馈"}}}function j(e){if(!S(e)||typeof e.id!="string"||!/^[1-9]\d{0,19}$/.test(e.id)||typeof e.name!="string"||!e.name||e.name.length>512||e.mime_type!==null&&typeof e.mime_type!="string"||!A(e.size)||!A(e.version))throw new o("Invalid file response",50200);return{id:e.id,name:e.name,mime_type:e.mime_type,size:e.size,version:e.version}}function Y(e,t){if(!S(t))throw new o("Invalid runtime response",50200);if(e.startsWith("kv.")){if(typeof t.key!="string"||!A(t.version)||typeof t.exists!="boolean"||!Object.hasOwn(t,"value"))throw new o("Invalid KV response",50200);return{key:t.key,value:t.value,version:t.version,exists:t.exists}}if(e==="files.list"){if(!Array.isArray(t.list)||t.list.length>100||!A(t.total)||!A(t.page)||t.page<1||!A(t.page_size)||t.page_size<1||t.page_size>100)throw new o("Invalid file list response",50200);return{list:t.list.map(j),total:t.total,page:t.page,pageSize:t.page_size}}if(e==="files.read"){let s=j(t.file);if(typeof t.content_base64!="string"||t.content_base64.length>Math.ceil(I/3)*4||t.content_base64.length%4!==0||!/^[A-Za-z0-9+/]*={0,2}$/.test(t.content_base64))throw new o("Invalid file content",50200);let n=atob(t.content_base64);if(n.length>I||n.length!==s.size)throw new o("Invalid file content",50200);return{file:s,data:Uint8Array.from(n,a=>a.charCodeAt(0))}}return j(t)}function ee(e={}){let t=P.get(window);if(t)return t;let s=new URL(window.location.href),n=s.pathname.match(/^\/api\/v1\/app-packages\/runtime\/([A-Za-z0-9_-]{43})\/.+/)?.[1];if(!n||window.parent===window||!["http:","https:"].includes(s.protocol))return Promise.reject(new o("Open this app from AgentOS",40300));let a=e.timeoutMs??3e4;if(!Number.isFinite(a)||a<1||a>12e4)return Promise.reject(new o("Invalid connection timeout",42200));let f,d,y=new Promise((i,p)=>{f=i,d=p});P.set(window,y);let m;try{m=new MessageChannel}catch{return P.delete(window),Promise.reject(new o("MessageChannel unavailable",50300))}let l=m.port1,g=!1,r=!1,c=new Map,h=(i=new o("App connection closed; reopen the app",40900),p=!0)=>{if(!g){g=!0,clearTimeout(M),p&&l.postMessage({type:"__zleap_hosted_close"}),l.onmessage=null,l.onmessageerror=null,l.close(),m.port2.close(),window.removeEventListener("pagehide",x),P.get(window)===y&&P.delete(window),d(i);for(let u of c.values())clearTimeout(u.timer),u.reject(i);c.clear()}},x=()=>h(),M=setTimeout(()=>h(new o("App connection timed out",50300)),a);function _(i,p,u=[]){if(g||!r)return Promise.reject(new o("App connection closed; reopen the app",40900));if(c.size>=8)return Promise.reject(new o("Too many concurrent app requests",42900));let w=crypto.randomUUID();try{let b={requestId:w,method:i,args:i==="files.write"&&S(p)?{...p,data:null}:p},v=JSON.stringify(b),E=i==="files.write"?4096:I;if(v.length>E||new TextEncoder().encode(v).byteLength>E)return Promise.reject(new o("App request too large",42200))}catch{return Promise.reject(new o("Invalid app request",42200))}return new Promise((b,v)=>{let E=setTimeout(()=>{c.delete(w),v(new o("App request timed out",50300))},a);c.set(w,{method:i,resolve:b,reject:v,timer:E});try{l.postMessage({requestId:w,method:i,args:p},u)}catch{clearTimeout(E),c.delete(w),v(new o("Invalid app request",42200))}})}let T=i=>{try{return i(),null}catch(p){return Promise.reject(p)}},B={kv:{get:i=>T(()=>O(i?.key))??_("kv.get",i),set:i=>T(()=>{O(i?.key),H(i?.value),C(i?.expectedVersion)})??_("kv.set",i),delete:i=>T(()=>{O(i?.key),C(i?.expectedVersion)})??_("kv.delete",i)},files:{list:(i={})=>_("files.list",i),read:i=>_("files.read",i),write:i=>{let p=T(()=>R(i?.name));if(p)return p;if(!(i.data instanceof ArrayBuffer)&&!(i.data instanceof Uint8Array))return Promise.reject(new o("File content must be binary",42200));if(i.data.byteLength>I)return Promise.reject(new o("Files must be at most 1 MiB",42200));let u=i.data instanceof ArrayBuffer?i.data.slice(0):new Uint8Array(i.data).buffer;return _("files.write",{...i,data:u},[u])}},close:()=>h()};l.onmessage=i=>{if(g||!S(i.data))return;let p=i.data;if(p.type==="__zleap_hosted_ready"&&p.protocol===1&&!r){r=!0,clearTimeout(M),f(B);return}if(p.type==="__zleap_hosted_closed"){h(new o("App connection closed; reopen the app",40900),!1);return}if(typeof p.requestId!="string")return;let u=c.get(p.requestId);if(u){c.delete(p.requestId),clearTimeout(u.timer);try{let w=u.method==="files.read"?I*1.5:I,b=JSON.stringify(p.result??null);if(b.length>w||k(b)>w)throw new o("App response too large",50200);S(p.error)&&Number.isSafeInteger(p.error.code)&&typeof p.error.message=="string"?u.reject(new o(p.error.message.slice(0,512),Number(p.error.code))):u.resolve(Y(u.method,p.result))}catch(w){u.reject(w instanceof o?w:new o("Invalid runtime response",50200))}}},l.onmessageerror=()=>h(new o("Invalid runtime message",50200)),l.start(),window.addEventListener("pagehide",x);try{window.parent.postMessage({type:"__zleap_hosted_connect",protocol:1,nonce:n},s.origin,[m.port2])}catch{h(new o("App connection unavailable",50300))}return y}var N=null;function te(){if(N)return N;let e=window.__ZLEAP_OS__;if(!e||typeof e!="object")throw new o("Zleap OS host bridge missing; open this app from Zleap OS",40301);let{auth:t,api:s,storage:n,notify:a,eventBus:f,app:d,invite:y,social:m}=e;if(!t||!s)throw new o("Zleap OS host bridge missing; open this app from Zleap OS",40301);let l=r=>()=>Promise.reject(new o(`宿主未提供 ${r} 能力域(宿主版本过旧),请升级 Zleap OS 后重试`,40302)),g={auth:{getToken:()=>t.getToken(),getUser:()=>t.getUser(),hasPermission:r=>t.hasPermission(r)},storage:{getItem:r=>n?n.getItem(r):l("storage")(),setItem:(r,c)=>n?n.setItem(r,c):l("storage")(),removeItem:r=>n?n.removeItem(r):l("storage")()},notify:{show:(r,c)=>a?a.show(r,c):l("notify")(),confirm:(r,c)=>a?a.confirm(r,c):l("notify")()},eventBus:{emit:(r,c)=>f?f.emit(r,c):l("eventBus")(),on:(r,c)=>f?f.on(r,c):l("eventBus")(),off:r=>f?f.off(r):l("eventBus")()},api:{get:(r,c)=>s.get(r,c),post:(r,c)=>s.post(r,c),put:(r,c)=>s.put(r,c),del:r=>s.del(r)},app:{getManifest:()=>d?d.getManifest():l("app")(),getAppId:()=>d?d.getAppId():l("app")()},invite:{send:r=>y?y.send(r):l("invite")()},social:{follow:(r,c)=>m?m.follow(r,c):l("social")(),unfollow:(r,c)=>m?m.unfollow(r,c):l("social")(),isFollowing:(r,c)=>m?m.isFollowing(r,c):l("social")(),pickUsers:r=>m?m.pickUsers(r):l("social")(),pickConversations:r=>m?m.pickConversations(r):l("social")(),shareToConversation:r=>m?m.shareToConversation(r):l("social")(),shareToDynamic:r=>m?m.shareToDynamic(r):l("social")(),createGroup:r=>m?m.createGroup(r):l("social")()}};return N=g,g}function G(e,t){if(!t)return e;let s=new URLSearchParams;for(let[a,f]of Object.entries(t))f!==void 0&&s.set(a,String(f));let n=s.toString();return n?`${e}${e.includes("?")?"&":"?"}${n}`:e}function ne(e,t={}){let s={auth:{getToken:()=>Promise.resolve(e.auth.getToken()),getUser:()=>Promise.resolve(e.auth.getUser())},storage:{getItem:n=>Promise.resolve(e.storage.getItem(n)),setItem:(n,a)=>Promise.resolve(e.storage.setItem(n,a)),removeItem:n=>Promise.resolve(e.storage.removeItem(n))},notify:{show:(n,a="info")=>Promise.resolve(e.notify(a,n)),confirm:(n,a)=>e.confirm({title:n,content:a})},api:{get:(n,a)=>e.apiProxy(G(n,a),{method:"GET"}),post:(n,a)=>e.apiProxy(n,{method:"POST",body:a}),put:(n,a)=>e.apiProxy(n,{method:"PUT",body:a}),del:n=>e.apiProxy(n,{method:"DELETE"})},app:{getAppId:()=>t.appId?Promise.resolve(t.appId):Promise.reject(new o("appId is unavailable in this host form",40302))}};return e.invite&&(s.invite=e.invite),e.social&&(s.social=e.social),s}export{o as SDKError,ne as connectHostCapabilities,ee as connectHostedApp,te as connectZleapOs,Q as describeError};
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- /*! @zleap-ai/app-sdk v0.10.1 | (c) 2026 Zleap | 专有许可,仅限在 zleapOS 应用中使用,见 LICENSE */
1
+ /*! @zleap-ai/app-sdk v0.12.0 | (c) 2026 Zleap | 专有许可,仅限在 zleapOS 应用中使用,见 LICENSE */
2
2
  var Ue=Object.defineProperty;var Re=(t,e,n)=>e in t?Ue(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var O=(t,e,n)=>Re(t,typeof e!="symbol"?e+"":e,n);var re="__zleap_cloud_connect",oe="__zleap_cloud_ready",ie="__zleap_cloud_close",se="__zleap_cloud_closed",ae="__zleap_cloud_event",ce="__zleap_api_token",Pe=/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,L=/^op_\d{10}_[0-9a-f]{32}$/,De={BACKGROUND_CAPABILITY_UNAVAILABLE:"App Cloud: BACKGROUND_CAPABILITY_UNAVAILABLE(后台能力未开启:请在应用窗口顶部的「权限」里勾选并保存,应用会自动重新加载;如果应用没有声明后台能力,开发者要先在 Manifest 中声明)"},o=class extends Error{constructor(n,s,r,f){super(n);O(this,"errCode");O(this,"errMsg");O(this,"requestId");O(this,"operationId");O(this,"retryable");O(this,"jobId");O(this,"invocationId");this.name="CloudError",this.errCode=n,this.errMsg=De[n]??`App Cloud: ${n}`,this.requestId=s,this.operationId=r,this.jobId=f?.jobId,this.invocationId=f?.invocationId,this.retryable=["CALL_TIMEOUT","RUNTIME_UNAVAILABLE","COMMIT_UNKNOWN"].includes(n)}};function h(t){return!!(t&&typeof t=="object"&&(Object.getPrototypeOf(t)===Object.prototype||Object.getPrototypeOf(t)===null))}function E(t,e){return Object.keys(t).every(n=>e.includes(n))}function T(t,e=256*1024){let n=new Set,s=0;function r(f,u){if(++s>1e4||u>24)return!1;if(f===null||typeof f=="boolean")return!0;if(typeof f=="number")return Number.isFinite(f);if(typeof f=="string")return f.length<=e;if(typeof f!="object"||!h(f)&&!Array.isArray(f)||n.has(f))return!1;n.add(f);let d=Object.entries(f).every(([i,l])=>!["__proto__","prototype","constructor"].includes(i)&&r(l,u+1));return n.delete(f),d}if(!r(t,0))return!1;try{return new TextEncoder().encode(JSON.stringify(t)).length<=e}catch{return!1}}function de(t){if(!h(t)||!E(t,["requestId","method","args"])||typeof t.requestId!="string"||!Pe.test(t.requestId)||!h(t.args)||!(t.method==="files.chunk"?k(t.args)&&T({...t,args:{...t.args,data:null}}):T(t)))return null;let{args:e,method:n,requestId:s}=t;if(typeof n=="string"&&n.startsWith("files.")){let r=typeof e.operation_id=="string"&&L.test(e.operation_id),f=typeof e.file_id=="string"&&e.file_id.length>=32&&e.file_id.length<=1024,u=w=>typeof w=="string"&&w.length>0&&w.length<=128,d=w=>typeof w=="string"&&/^[a-f0-9]{64}$/.test(w),i=(w,I,_)=>typeof w=="number"&&Number.isInteger(w)&&w>=I&&w<=_;return["files.operation","files.commit","files.cancel"].includes(n)&&r&&E(e,["operation_id"])||n==="files.stat"&&f&&E(e,["file_id"])||n==="files.read"&&f&&u(e.etag)&&i(e.offset,0,4194304)&&i(e.length,1,262144)&&E(e,["file_id","etag","offset","length"])||n==="files.delete"&&f&&r&&u(e.expected_etag)&&E(e,["file_id","expected_etag","operation_id"])||n==="files.chunk"&&r&&i(e.index,0,15)&&d(e.sha256)&&k(e)&&E(e,["operation_id","index","sha256","data"])||n==="files.begin"&&r&&typeof e.cloud_path=="string"&&e.cloud_path.length>0&&e.cloud_path.length<=512&&i(e.size_bytes,0,4194304)&&d(e.sha256)&&typeof e.mime_type=="string"&&e.mime_type.length<=128&&typeof e.overwrite=="boolean"&&e.overwrite===!!e.expected_etag&&(e.expected_etag===void 0||u(e.expected_etag))&&E(e,["cloud_path","size_bytes","mime_type","sha256","overwrite","expected_etag","operation_id"])?{requestId:s,method:n,args:e}:null}if(n==="execution.get"||n==="execution.cancel")return E(e,["job_id"])&&typeof e.job_id=="string"&&/^[1-9][0-9]{0,18}$/.test(e.job_id)?{requestId:s,method:n,args:e}:null;if(n==="execution.invoke"){let r=e.capability_key??e.function_name;return E(e,["capability_key","function_name","data","operation_id","wait_seconds"])&&e.capability_key!==void 0!=(e.function_name!==void 0)&&typeof r=="string"&&/^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(r)&&h(e.data)&&T(e.data,65536)&&typeof e.operation_id=="string"&&L.test(e.operation_id)&&typeof e.wait_seconds=="number"&&Number.isInteger(e.wait_seconds)&&e.wait_seconds>=0&&e.wait_seconds<=25?{requestId:s,method:n,args:e}:null}return n==="operations.get"?E(e,["operation_id"])&&typeof e.operation_id=="string"&&L.test(e.operation_id)?{requestId:s,method:n,args:e}:null:typeof e.collection_key!="string"||!/^[a-z][a-z0-9_]{0,63}$/.test(e.collection_key)||/^(sys_|ac_|t_)/.test(e.collection_key)?null:n==="documents.query"&&E(e,["collection_key","operation","document_key","filter","order_by","projection","limit","skip"])&&["get","count"].includes(String(e.operation))?{requestId:s,method:n,args:e}:n==="documents.snapshot"&&E(e,["collection_key","query","cursor","max_docs"])&&h(e.query)&&E(e.query,["filter","order_by","projection","limit","skip"])&&(e.query.skip===void 0||e.query.skip===0)&&T(e.query,8192)&&typeof e.cursor=="number"&&Number.isSafeInteger(e.cursor)&&e.cursor>=0&&typeof e.max_docs=="number"&&Number.isSafeInteger(e.max_docs)&&e.max_docs>=1&&e.max_docs<=100?{requestId:s,method:n,args:e}:n==="documents.mutate"&&E(e,["collection_key","operation","document_key","data","value_types","field_operations","expected_version","operation_id"])&&["add","set","update","remove"].includes(String(e.operation))&&typeof e.operation_id=="string"&&L.test(e.operation_id)?{requestId:s,method:n,args:e}:null}function k(t){return h(t)&&t.data instanceof ArrayBuffer&&t.data.byteLength<=262144&&T({...t,data:null},16384)}function F(t){return["documents.mutate","execution.invoke","execution.cancel","files.begin","files.chunk","files.commit","files.cancel","files.delete"].includes(t)}var xe=60,ke=15e3;function qe(){if(typeof window>"u"||window.parent===window)return Promise.reject(new o("RUNTIME_UNAVAILABLE"));let t=window.location.pathname.match(/^\/api\/v1\/app-packages\/runtime\/([A-Za-z0-9_-]{43})\//)?.[1];return t?new Promise((e,n)=>{let s=new MessageChannel,r=u=>{clearTimeout(f),s.port1.onmessage=null,s.port1.close(),u()},f=setTimeout(()=>r(()=>n(new o("CALL_TIMEOUT"))),ke);s.port1.onmessage=u=>{let d=u.data,i=h(d)?d.result:void 0;if(h(i)&&typeof i.token=="string"&&typeof i.base_url=="string"&&typeof i.expires_at=="number"){let w={token:i.token,baseUrl:i.base_url,expiresAt:i.expires_at};r(()=>e(w));return}let l=h(d)&&h(d.error)&&typeof d.error.errCode=="string"?d.error.errCode:"RUNTIME_UNAVAILABLE";r(()=>n(new o(l)))},window.parent.postMessage({type:ce,nonce:t},"*",[s.port2])}):Promise.reject(new o("RUNTIME_UNAVAILABLE"))}function fe(t=qe){let e=null,n=null;function s(){return n??(n=t().then(i=>(e=i,i)).finally(()=>{n=null})),n}async function r(){return e&&e.expiresAt-Date.now()/1e3>xe?{...e}:{...await s()}}function f(i,l){if(typeof l!="string"||!l.startsWith("/")||l.startsWith("//"))throw new o("SCHEMA_INVALID");let w=new URL(i),I=new URL(i+l);if(I.origin!==w.origin||!I.pathname.startsWith(w.pathname+"/"))throw new o("SCHEMA_INVALID");return I}function u(i,l,w){let I=new Headers(w.headers);return I.set("Authorization","Bearer "+i.token),typeof w.body=="string"&&!I.has("Content-Type")&&I.set("Content-Type","application/json"),fetch(f(i.baseUrl,l),{...w,headers:I,credentials:"omit",redirect:"error"})}async function d(i,l={}){let w=await u(await r(),i,l),I=(l.method??"GET").toUpperCase();return w.status!==401||I!=="GET"&&I!=="HEAD"?w:(e=null,u(await r(),i,l))}return{token:r,fetch:d}}var He="__zleap_app_connect",Ve="__zleap_app_ready",je="__zleap_app_event";var M=class extends Error{constructor(n,s){super(s??n);O(this,"errCode");this.name="AppError",this.errCode=n}},j=t=>!!(t&&typeof t=="object"&&!Array.isArray(t)),V=null;function v(){return V||(V=new Promise((t,e)=>{if(typeof window>"u"||window.parent===window)return e(new M("OPEN_IN_ZLEAP_OS","请从 AgentOS 中打开应用"));let n=window.location.pathname.match(/^\/api\/v1\/app-packages\/runtime\/([A-Za-z0-9_-]{43})\//)?.[1];if(!n)return e(new M("OPEN_IN_ZLEAP_OS","请从 AgentOS 中打开应用"));let s=new MessageChannel,r=new Map,f=new Set,u=!1,d=setTimeout(()=>{u||(V=null,e(new M("HOST_UNAVAILABLE","宿主未响应,请升级 AgentOS 后重试")))},15e3);s.port1.onmessage=i=>{let l=i.data;if(!j(l))return;if(l.type===Ve&&l.protocol===1&&!u){u=!0,clearTimeout(d),t({call(I,_={},c=3e4){return new Promise((a,p)=>{if(r.size>=8)return p(new M("TOO_MANY_REQUESTS"));let y=crypto.randomUUID(),N=setTimeout(()=>{r.delete(y),p(new M("CALL_TIMEOUT"))},c);r.set(y,{resolve:a,reject:p,timer:N}),s.port1.postMessage({requestId:y,method:I,args:_})})},onEvent(I){return f.add(I),()=>f.delete(I)}});return}if(l.type===je&&typeof l.event=="string"){for(let I of f)try{I(l.event,l.data)}catch{}return}if(typeof l.requestId!="string")return;let w=r.get(l.requestId);w&&(r.delete(l.requestId),clearTimeout(w.timer),j(l.error)?w.reject(new M(typeof l.error.errCode=="string"?l.error.errCode:"RUNTIME_UNAVAILABLE",typeof l.error.message=="string"?l.error.message:void 0)):w.resolve(l.result))},s.port1.start(),window.parent.postMessage({type:He,protocol:1,nonce:n},"*",[s.port2])}),V.catch(()=>{}),V)}function Z(t){let e=j(t)?t:{};return{hasUpdate:e.hasUpdate===!0,currentVersion:typeof e.currentVersion=="string"?e.currentVersion:null,latestVersion:typeof e.latestVersion=="string"?e.latestVersion:null,notes:typeof e.notes=="string"?e.notes:null,deadline:typeof e.deadline=="number"?e.deadline:null}}var K=null;function ue(){if(K)return K;let t=new Set,e=new Set,n=new Set,s=null,r=!1,f=u=>{if(!(!u.hasUpdate||r)){r=!0;for(let d of e)d(u)}};return v().then(async u=>{u.onEvent((d,i)=>{d==="updateReady"&&(r=!1,f(Z(i)))}),s=Z(await u.call("app.checkUpdate"));for(let d of t)d(s);f(s)}).catch(u=>{let d=u instanceof M?u:new M("RUNTIME_UNAVAILABLE");for(let i of n)i(d)}),K={onCheckForUpdate(u){t.add(u),s&&u(s)},onUpdateReady(u){e.add(u),s?.hasUpdate&&r&&u(s)},onUpdateFailed(u){n.add(u)},async applyUpdate(){try{await(await v()).call("app.applyUpdate",{},6e4)}catch(u){let d=u instanceof M?u:new M("UPDATE_FAILED");for(let i of n)i(d);throw d}}},K}async function le(){return Z(await(await v()).call("app.checkUpdate"))}function pe(t){if(!j(t)||typeof t.openid!="string")throw new M("PROTOCOL_MISMATCH");let e={openid:t.openid,scopes:Array.isArray(t.scopes)?t.scopes.filter(n=>typeof n=="string"):[]};return j(t.profile)&&(e.profile={nickname:typeof t.profile.nickname=="string"?t.profile.nickname:"",avatarUrl:typeof t.profile.avatarUrl=="string"?t.profile.avatarUrl:null}),"phone"in t&&(e.phone=typeof t.phone=="string"?t.phone:null),"email"in t&&(e.email=typeof t.email=="string"?t.email:null),e}async function _e(t){if(!j(t)||!Array.isArray(t.scopes)||t.scopes.length===0||t.scopes.some(n=>!["profile","phone","email"].includes(n)))throw new M("SCHEMA_INVALID","scopes 只能是 profile、phone、email");if(t.reason!==void 0&&(typeof t.reason!="string"||t.reason.length>60))throw new M("SCHEMA_INVALID","reason 是不超过 60 字的用途说明");let e={scopes:t.scopes};return t.reason&&(e.reason=t.reason),pe(await(await v()).call("auth.authorize",e,3e5))}async function we(){return pe(await(await v()).call("auth.getIdentity"))}function he(t){if(typeof t.job_id!="string"||!/^\d+$/.test(t.job_id)||typeof t.invocation_id!="string"||!/^\d+$/.test(t.invocation_id)||typeof t.operation_id!="string"||!L.test(t.operation_id)||typeof t.status!="string"||!["accepted","queued","running","cancel_requested","cancelled","succeeded","failed","unknown"].includes(t.status)||!Array.isArray(t.committed_steps)||!t.committed_steps.every(e=>typeof e=="string"))throw new o("PROTOCOL_MISMATCH");return{jobId:t.job_id,invocationId:t.invocation_id,operationId:t.operation_id,status:t.status,result:t.result??null,errorCode:typeof t.error_code=="string"?t.error_code:null,committedSteps:t.committed_steps}}function ye(t){async function e(r,f,u,d=!1,i=0){if(typeof r!="string"||!/^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(r)||!h(f)||!T(f,65536))throw new o("SCHEMA_INVALID");if(u!==void 0&&(typeof u!="string"||!L.test(u)))throw new o("SCHEMA_INVALID");let l=u??t.createId(),{value:w}=await t.request("execution.invoke",{[d?"function_name":"capability_key"]:r,data:f,operation_id:l,wait_seconds:i});return he(w)}async function n(r){if(!h(r)||!E(r,["jobId"])||typeof r.jobId!="string"||!/^[1-9][0-9]{0,18}$/.test(r.jobId))throw new o("SCHEMA_INVALID");return he((await t.request("execution.get",{job_id:r.jobId})).value)}async function s(r){if(!h(r)||!E(r,["jobId","timeoutSeconds","pollMilliseconds"])||typeof r.jobId!="string"||!/^[1-9][0-9]{0,18}$/.test(r.jobId)||r.timeoutSeconds!==void 0&&(!Number.isInteger(r.timeoutSeconds)||r.timeoutSeconds<0||r.timeoutSeconds>300)||r.pollMilliseconds!==void 0&&(!Number.isInteger(r.pollMilliseconds)||r.pollMilliseconds<100||r.pollMilliseconds>5e3))throw new o("SCHEMA_INVALID");let f=(r.timeoutSeconds??25)*1e3,u=r.pollMilliseconds??500,d=Date.now()+f,i=await n({jobId:r.jobId});for(;["accepted","queued","running","cancel_requested"].includes(i.status)&&Date.now()<d;)await new Promise(l=>setTimeout(l,Math.min(u,Math.max(0,d-Date.now())))),i=await n({jobId:r.jobId});if(["accepted","queued","running","cancel_requested"].includes(i.status))throw new o("CALL_TIMEOUT",void 0,i.operationId,{jobId:i.jobId,invocationId:i.invocationId});return i}return{capabilities:{invoke:async r=>{if(!h(r)||!E(r,["id","input","operationId","waitSeconds"]))throw new o("UNSUPPORTED_OPERATION");return e(r.id,r.input,r.operationId,!1,r.waitSeconds)}},jobs:{submit:async r=>{if(!h(r)||!E(r,["kind","capability","input","operationId","waitSeconds"])||r.kind!=="capability")throw new o("UNSUPPORTED_OPERATION");return e(r.capability,r.input,r.operationId,!1,r.waitSeconds)},get:n,result:n,wait:s,cancel:async r=>{if(!h(r)||!E(r,["jobId"])||typeof r.jobId!="string"||!/^[1-9][0-9]{0,18}$/.test(r.jobId))throw new o("SCHEMA_INVALID");let{value:f}=await t.request("execution.cancel",{job_id:r.jobId});if(f.cancel_requested!==!0)throw new o("PROTOCOL_MISMATCH");return{cancelRequested:!0}}},callFunction:async r=>{if(!h(r)||!E(r,["name","data","agentos","success","fail","complete"])||r.agentos!==void 0&&(!h(r.agentos)||!E(r.agentos,["operationId"])))throw new o("UNSUPPORTED_OPERATION");let f=await e(r.name,r.data??{},r.agentos?.operationId,!0,25);if(["accepted","queued","running","cancel_requested","unknown"].includes(f.status))throw new o(f.status==="unknown"?"COMMIT_UNKNOWN":"CALL_TIMEOUT",void 0,f.operationId,{jobId:f.jobId,invocationId:f.invocationId});if(f.status==="failed"||f.status==="cancelled")throw new o(f.errorCode??"EXECUTION_FAILED",void 0,f.operationId,{jobId:f.jobId,invocationId:f.invocationId});return f}}}var Ae=4*1024*1024,z=256*1024,me=16,ze=2,Be=new Set(["VERSION_CONFLICT","UPLOAD_INTEGRITY_FAILED"]);function $(t,e){let n=e??t.createId();if(!L.test(n))throw new o("SCHEMA_INVALID",void 0,n);return n}function Y(t){let e=t instanceof Uint8Array?t:new Uint8Array(t);return crypto.subtle.digest("SHA-256",e).then(n=>[...new Uint8Array(n)].map(s=>s.toString(16).padStart(2,"0")).join(""))}function Ie(t){if(!h(t))throw new o("PROTOCOL_MISMATCH");let e=t.size_bytes;if(typeof t.file_id!="string"||t.file_id.length<32||typeof t.etag!="string"||t.etag.length===0||typeof t.sha256!="string"||!/^[a-f0-9]{64}$/.test(t.sha256)||typeof e!="number"||!Number.isSafeInteger(e)||e<0||e>Ae)throw new o("PROTOCOL_MISMATCH");return{fileID:t.file_id,etag:t.etag,sha256:t.sha256,size:e,errMsg:"ok"}}function W(t){if(!h(t)||typeof t.operation_id!="string"||!L.test(t.operation_id)||!["pending","succeeded","cancelled"].includes(String(t.state)))throw new o("PROTOCOL_MISMATCH");let e=t.received;if(e!==void 0&&(!Array.isArray(e)||!e.every(n=>Number.isInteger(n)&&n>=0&&n<me)))throw new o("PROTOCOL_MISMATCH");return{operation_id:t.operation_id,state:t.state,...typeof t.chunk_size=="number"?{chunk_size:t.chunk_size}:{},...e===void 0?{}:{received:e},...t.file===null||t.file===void 0?{file:null}:{file:t.file}}}function Oe(t){async function e(d){let i=$(t,d),l=await t.request("files.operation",{operation_id:i}),w=W(l.value);if(w.operation_id!==i)throw new o("PROTOCOL_MISMATCH",l.requestId,i);return w}async function n(d){if(!h(d)||typeof d.cloudPath!="string"||typeof Blob>"u"||!(d.filePath instanceof Blob)||d.filePath.size>Ae)throw new o("SCHEMA_INVALID");let i=$(t,d.agentos?.operationId),l=new Uint8Array(await d.filePath.arrayBuffer()),w=await Y(l),I=A=>{let g=Ie(A);if(g.size!==l.byteLength||g.sha256!==w)throw new o("PROTOCOL_MISMATCH");return g},_=Math.ceil(l.byteLength/z);if(_>me)throw new o("RESOURCE_EXHAUSTED",void 0,i);let c;try{let A=await t.request("files.begin",{cloud_path:d.cloudPath,size_bytes:l.byteLength,mime_type:d.filePath.type||"application/octet-stream",sha256:w,overwrite:d.agentos?.overwrite===!0,...d.agentos?.expectedETag?{expected_etag:d.agentos.expectedETag}:{},operation_id:i});c=W(A.value)}catch(A){if(!(A instanceof o)||A.errCode!=="COMMIT_UNKNOWN")throw A;c=await e(i)}if(c.operation_id!==i)throw new o("PROTOCOL_MISMATCH");if(c.state==="succeeded"){if(!c.file)throw new o("PROTOCOL_MISMATCH");return I(c.file)}if(c.state==="cancelled")throw new o("OPERATION_EXPIRED",void 0,i);if(c.chunk_size!==void 0&&c.chunk_size!==z)throw new o("PROTOCOL_MISMATCH",void 0,i);let a=new Set(c.received??[]),p=Array.from({length:_},(A,g)=>g).filter(A=>!a.has(A)),y,N=0;async function m(A){let g=l.slice(A*z,Math.min(l.length,(A+1)*z)),P=await Y(g);try{let b=await t.request("files.chunk",{operation_id:i,index:A,sha256:P,data:g.slice().buffer});if(b.value.operation_id!==i||b.value.index!==A||b.value.received!==!0)throw new o("PROTOCOL_MISMATCH",b.requestId,i);a.add(A)}catch(b){if(!(b instanceof o)||b.errCode!=="COMMIT_UNKNOWN")throw b;let x=await e(i);if(x.state==="succeeded"&&x.file){y=I(x.file);return}if(x.state==="cancelled")throw new o("OPERATION_EXPIRED",void 0,i);if(x.received?.forEach(C=>a.add(C)),a.has(A))return;let H=await t.request("files.chunk",{operation_id:i,index:A,sha256:P,data:g.slice().buffer});if(H.value.operation_id!==i||H.value.index!==A||H.value.received!==!0)throw new o("PROTOCOL_MISMATCH",H.requestId,i);a.add(A)}}async function S(){for(;N<p.length&&!y;){let A=p[N++];A!==void 0&&await m(A)}}if(await Promise.all(Array.from({length:Math.min(ze,p.length)},S)),y)return y;try{let A=await t.request("files.commit",{operation_id:i}),g=W(A.value);if(g.state!=="succeeded"||!g.file)throw new o("PROTOCOL_MISMATCH",A.requestId,i);return I(g.file)}catch(A){if(A instanceof o&&Be.has(A.errCode))throw await u(i).catch(()=>{}),A;if(!(A instanceof o)||A.errCode!=="COMMIT_UNKNOWN")throw A;let g=await e(i);if(g.state==="succeeded"&&g.file)return I(g.file);throw g.state==="cancelled"?new o("OPERATION_EXPIRED",void 0,i):A}}async function s(d){if(typeof d!="string"||d.length<32||d.length>1024)throw new o("SCHEMA_INVALID");let i=await t.request("files.stat",{file_id:d});return Ie(i.value)}async function r(d){let i=await s(d),l=[];for(let _=0;_<i.size;_+=z){let c=Math.min(z,i.size-_),a=await t.request("files.read",{file_id:d,etag:i.etag,offset:_,length:c});if(!(a.value.data instanceof ArrayBuffer)||a.value.etag!==i.etag||a.value.offset!==_||a.value.data.byteLength!==c)throw new o("PROTOCOL_MISMATCH",a.requestId);l.push(a.value.data)}let w=new Uint8Array(i.size),I=0;for(let _ of l)w.set(new Uint8Array(_),I),I+=_.byteLength;if(await Y(w)!==i.sha256)throw new o("PROTOCOL_MISMATCH");return{fileContent:new Blob([w],{type:"application/octet-stream"}),errMsg:"ok"}}async function f(d){if(!h(d)||!Array.isArray(d.fileList)||d.fileList.length===0||d.fileList.length>100||!h(d.agentos?.expectedETags))throw new o("SCHEMA_INVALID");let i=[],l=[],w=new Set;for(let I=0;I<d.fileList.length;I++){let _=d.fileList[I],c=d.agentos?.expectedETags?.[_];if(typeof c!="string"||c.length===0)throw new o("SCHEMA_INVALID");let a=$(t,I===0?d.agentos?.operationId:void 0);for(;w.has(a);)a=$(t);w.add(a);try{let p=await t.request("files.delete",{file_id:_,expected_etag:c,operation_id:a}),y=W(p.value);if(y.operation_id!==a||y.state!=="succeeded")throw new o("PROTOCOL_MISMATCH",p.requestId,a);i.push(_)}catch(p){if(p instanceof o&&p.errCode==="COMMIT_UNKNOWN")try{if((await e(a)).state==="succeeded"){i.push(_);continue}}catch{}l.push({fileID:_,error:p instanceof o?p:new o("RUNTIME_UNAVAILABLE",void 0,a)})}}return{deleted:i,failed:l,errMsg:l.length?"partial failure":"ok"}}async function u(d){let i=$(t,d),l=await t.request("files.cancel",{operation_id:i});return W(l.value)}return{upload:n,download:r,remove:f,stat:s,getOperation:e,cancel:u}}function Fe(t){if(!h(t)||typeof t.event!="string"||!/^[a-z][a-z0-9_.]{0,63}$/.test(t.event))return null;let e={event:t.event};for(let n of["app_id","collection_key","collection_id","document_key","change_seq","operation_id"])typeof t[n]=="string"&&(e[n]=t[n]);return e}function ge(t){if(typeof window>"u"||window.parent===window)throw new o("RUNTIME_UNAVAILABLE");let e=window.location.pathname.match(/^\/api\/v1\/app-packages\/runtime\/([A-Za-z0-9_-]{43})\//)?.[1];if(!e)throw new o("RUNTIME_UNAVAILABLE");let n=new MessageChannel,s=!1,r=!1,f,u,d=new Promise((c,a)=>{f=c,u=a});d.catch(()=>{});let i=new Map,l=new Set,w=(c="RUNTIME_UNAVAILABLE")=>{if(!s){s=!0,clearTimeout(_),u(new o(c));for(let[a,p]of i)clearTimeout(p.timer),p.reject(new o(c,a,p.operationId));i.clear(),n.port1.postMessage({type:ie}),n.port1.onmessage=null,n.port1.close(),window.removeEventListener("pagehide",I)}},I=()=>w(),_=setTimeout(()=>w("CALL_TIMEOUT"),15e3);return n.port1.onmessageerror=()=>w("PROTOCOL_MISMATCH"),n.port1.onmessage=c=>{let a=c.data;if(!h(a)||!(T(a,1024*1024)||typeof a.requestId=="string"&&i.get(a.requestId)?.method==="files.read"&&k(a.result)&&T({...a,result:null},16384))){w("PROTOCOL_MISMATCH");return}if(a.type===se){w(typeof a.errCode=="string"?a.errCode:"RUNTIME_UNAVAILABLE");return}if(a.type===ae){let y=Fe(a.event);if(y)for(let N of l)N(y);return}if(a.type===oe&&!r){let y=a.capabilities;if(a.protocol!==2||!h(y)||!h(y.protocol)||y.protocol.major!==2||!Array.isArray(y.profiles)||!y.profiles.some(N=>["document-core/1","app-execution/1","storage-object/1"].includes(String(N)))||!Array.isArray(y.operators)||!h(y.limits)||typeof y.serverTime!="number"){w("PROTOCOL_MISMATCH");return}r=!0,clearTimeout(_),f(y);return}if(typeof a.requestId!="string"){w("PROTOCOL_MISMATCH");return}let p=i.get(a.requestId);p&&(clearTimeout(p.timer),i.delete(a.requestId),h(a.error)?p.reject(new o(typeof a.error.errCode=="string"?a.error.errCode:"RUNTIME_UNAVAILABLE",a.requestId,p.operationId)):p.resolve(a.result))},n.port1.start(),window.addEventListener("pagehide",I),window.parent.postMessage({type:re,protocol:2,nonce:e,environmentKey:t},"*",[n.port2]),{ready:()=>d,onEvent(c){return l.add(c),()=>l.delete(c)},request:async(c,a,p)=>{if(await d,s)throw new o("RUNTIME_UNAVAILABLE",p);if(i.size>=8)throw new o("RESOURCE_EXHAUSTED",p);return new Promise((y,N)=>{let m=typeof a.operation_id=="string"?a.operation_id:void 0,S=setTimeout(()=>{i.delete(p),N(new o(F(c)?"COMMIT_UNKNOWN":"CALL_TIMEOUT",p,m))},3e4);i.set(p,{resolve:y,reject:N,timer:S,operationId:m,method:c}),n.port1.postMessage({requestId:p,method:c,args:a},c==="files.chunk"&&a.data instanceof ArrayBuffer?[a.data]:[])})},close:()=>w()}}var q=class t{constructor(e){O(this,"filters");this.filters=e}and(e){return new t([{op:"and",filters:[...this.filters,...e.filters]}])}or(e){return new t([{op:"or",filters:[...this.filters,...e.filters]}])}},D=class{constructor(e,n,s=0){O(this,"op");O(this,"value");O(this,"offset");this.op=e,this.value=n,this.offset=s}};function U(t,e){let n=e instanceof Date;if(n&&!Number.isFinite(e.getTime()))throw new o("SCHEMA_INVALID");if(["in","nin"].includes(t)){if(!Array.isArray(e)||e.length>100||e.length===0)throw new o("SCHEMA_INVALID");let s=e.every(r=>r instanceof Date);if(e.some(r=>r instanceof Date)&&!s)throw new o("SCHEMA_INVALID");return new q([{op:t,value:s?e.map(r=>r.getTime()):e,...s?{value_type:"date"}:{}}])}if(!T(n?e.getTime():e))throw new o("SCHEMA_INVALID");return new q([{op:t,value:n?e.getTime():e,...n?{value_type:"date"}:{}}])}function Ce(t,e){if(e.length<1)throw new o("SCHEMA_INVALID");return new q([{op:t,filters:e.map(n=>X(n))}])}var Ne=Object.freeze({eq:t=>U("eq",t),neq:t=>U("neq",t),gt:t=>U("gt",t),gte:t=>U("gte",t),lt:t=>U("lt",t),lte:t=>U("lte",t),in:t=>U("in",t),nin:t=>U("nin",t),exists:t=>U("exists",t),and:(...t)=>Ce("and",t),or:(...t)=>Ce("or",t),inc:t=>{if(!Number.isFinite(t))throw new o("SCHEMA_INVALID");return new D("inc",t)},set:t=>new D("set",t),remove:()=>new D("remove")});function B(t,e=!1){let n=t.split(".");if(!t||n.length>16||n.some(s=>!/^[A-Za-z][A-Za-z0-9_]*$/.test(s)&&!(e&&n.length===1&&["_id","_openid","_version"].includes(s))||["__proto__","prototype","constructor"].includes(s)))throw new o("SCHEMA_INVALID")}function X(t,e){if(t instanceof q){let s=function(r){return r.filters?{...r,filters:r.filters.map(s)}:{...r,...e?{field:e}:{}}};return t.filters.length===1?s(t.filters[0]):{op:"and",filters:t.filters.map(s)}}if(!h(t)||!Object.keys(t).length)throw new o("SCHEMA_INVALID");let n=Object.entries(t).map(([s,r])=>(B(s,!0),X(r instanceof q?r:U("eq",r),s)));return n.length===1?n[0]:{op:"and",filters:n}}function J(t,e){if(!h(t))throw new o("SCHEMA_INVALID");let n={},s=[],r=new Set,f=0,u=[],d=_=>{if(u.some(c=>c===_||c.startsWith(`${_}.`)||_.startsWith(`${c}.`)))throw new o("SCHEMA_INVALID");u.push(_)};function i(_,c,a,p){if(++f>1e4||c.length>16)throw new o("SCHEMA_INVALID");let y=c.join(".");if(_ instanceof D){if(!p||e!=="update"&&_.op!=="serverDate")throw new o("UNSUPPORTED_OPERATION");if(d(y),_.op==="set"){let m={};s.push({op:"set",path:y,value:i(_.value,[],m,!1),value_types:m})}else s.push({op:_.op,path:y,..._.op==="inc"?{value:_.value}:{},..._.op==="serverDate"?{offset:_.offset}:{}});return}if(_ instanceof Date){if(!Number.isFinite(_.getTime()))throw new o("SCHEMA_INVALID");return a[c.length?`/${c.join("/")}`:""]="date",_.getTime()}if(_===null||typeof _=="boolean"||typeof _=="string"||typeof _=="number"&&Number.isFinite(_))return _;if(typeof _!="object"||_===null||!h(_)&&!Array.isArray(_)||r.has(_))throw new o("SCHEMA_INVALID");r.add(_);let N;if(Array.isArray(_))N=_.map((m,S)=>i(m,[...c,String(S)],a,!1));else{let m={};for(let[S,A]of Object.entries(_)){if(B(S),S.includes(".")&&e!=="update")throw new o("SCHEMA_INVALID");let g=[...c,...S.split(".")],P=i(A,g,a,p);P!==void 0&&(m[S]=P)}N=m}return r.delete(_),N}function l(_,c){for(let[a,p]of Object.entries(_)){B(a);let y=[...c,...a.split(".")];if(y.length>16)throw new o("SCHEMA_INVALID");if(h(p)&&Object.keys(p).length){if(r.has(p))throw new o("SCHEMA_INVALID");r.add(p),l(p,y),r.delete(p)}else if(p instanceof D)i(p,y,n,!0);else{d(y.join("."));let N={};s.push({op:"set",path:y.join("."),value:i(p,[],N,!1),value_types:N})}}}let w={};e==="update"?l(t,[]):w=i(t,[],n,!0);let I={data:w,value_types:n,field_operations:s};if(!T(I)||s.length>256)throw new o("SCHEMA_INVALID");return I}function Te(t,e){if(!T(t))throw new o("PROTOCOL_MISMATCH");function n(s,r){let f=e[`/${r.join("/")}`];if(f!==void 0){if(f!=="date"||typeof s!="number"||!Number.isSafeInteger(s)||Math.abs(s)>864e13)throw new o("PROTOCOL_MISMATCH");return new Date(s)}return Array.isArray(s)?s.map((u,d)=>n(u,[...r,String(d)])):h(s)?Object.fromEntries(Object.entries(s).map(([u,d])=>[u,n(d,[...r,u])])):s}return n(t,[])}function R(t,e){let n=Promise.resolve().then(e);if(!t||![t.success,t.fail,t.complete].some(s=>typeof s=="function"))return n;n.then(s=>{try{t.success?.(s)}finally{t.complete?.(s)}},s=>{let r=s instanceof o?s:new o("RUNTIME_UNAVAILABLE");try{t.fail?.(r)}finally{t.complete?.(r)}}).catch(()=>{})}function Me(t){if(!t||new TextEncoder().encode(t).length>128||[...t].some(e=>{let n=e.codePointAt(0)??0;return n<32||n===127||e==="/"||e==="\\"}))throw new o("SCHEMA_INVALID");return t}var Le="DYNAMIC_CURRENT_ENV";function ve(t){if(h(t)){let e=Object.values(t);if(!e.length||!e.every(n=>n===e[0]))throw new o("ENV_MISMATCH");t=e[0]}if(t===Le)return t;if(t!=="dev"&&t!=="prod")throw new o("ENV_MISMATCH");return t}function G(t,e){if(!h(t)||!h(e))throw new o("PROTOCOL_MISMATCH");let n=Te(t,e);if(n._version!==void 0){if(typeof n._version!="number"&&typeof n._version!="string")throw new o("PROTOCOL_MISMATCH");n._version=String(n._version)}return n}function ne(t,e,n){if(typeof t.operation_id!="string"||!L.test(t.operation_id)||n!==void 0&&t.operation_id!==n||!h(t.stats))throw new o("PROTOCOL_MISMATCH",e);let s=t.stats,r=l=>typeof l=="number"&&Number.isSafeInteger(l)&&l>=0,f=s.created===void 0?0:s.created,u=s.updated===void 0?0:s.updated,d=s.removed===void 0?0:s.removed;if(!r(f)||!r(u)||!r(d))throw new o("PROTOCOL_MISMATCH",e,t.operation_id);let i=h(t.document)?t.document:null;return{...typeof i?._id=="string"?{_id:i._id}:{},stats:{created:f,updated:u,removed:d},errMsg:"database:ok",_meta:{requestId:e,operationId:t.operation_id,...typeof i?._version=="number"||typeof i?._version=="string"?{version:String(i._version)}:{}}}}var Q=class t{constructor(e,n,s={}){O(this,"session");O(this,"key");O(this,"query");this.session=e,this.key=n,this.query=s}with(e){return new t(this.session,this.key,{...this.query,...e})}where(e){let n=X(e);return this.with({filter:this.query.filter?{op:"and",filters:[this.query.filter,n]}:n})}orderBy(e,n){if(B(e,!0),n!=="asc"&&n!=="desc")throw new o("SCHEMA_INVALID");let s=this.query.order_by??[];if(s.length>=4)throw new o("RESOURCE_EXHAUSTED");return this.with({order_by:[...s,{field:e,direction:n}]})}limit(e){if(!Number.isSafeInteger(e)||e<1||e>100)throw new o("RESOURCE_EXHAUSTED");return this.with({limit:e})}skip(e){if(!Number.isSafeInteger(e)||e<0||e>1e3)throw new o("RESOURCE_EXHAUSTED");return this.with({skip:e})}field(e){if(!h(e))throw new o("SCHEMA_INVALID");let n=new Set;for(let[s,r]of Object.entries(e)){if(B(s,!0),typeof r!="boolean")throw new o("SCHEMA_INVALID");s!=="_id"&&n.add(r)}if(n.size>1)throw new o("SCHEMA_INVALID");return this.with({projection:{...e}})}get(e){return R(e,async()=>{let{value:n,requestId:s}=await this.session.request("documents.query",{collection_key:this.key,operation:"get",limit:20,skip:0,...this.query});if(!Array.isArray(n.list)||!Array.isArray(n.value_types)||n.list.length!==n.value_types.length)throw new o("PROTOCOL_MISMATCH",s);let r=n.value_types;return{data:n.list.map((f,u)=>G(f,r[u])),errMsg:"collection.get:ok",_meta:{requestId:s}}})}count(e){return R(e,async()=>{let{value:n,requestId:s}=await this.session.request("documents.query",{collection_key:this.key,operation:"count",...this.query});if(!Number.isSafeInteger(n.total)||Number(n.total)<0)throw new o("PROTOCOL_MISMATCH",s);return{total:n.total,errMsg:"collection.count:ok",_meta:{requestId:s}}})}watch(e){return Promise.resolve().then(async()=>{let n=e?.cursor,s=n===void 0?0:Number(n);if(n!==void 0&&(typeof n!="string"||!/^(0|[1-9]\d*)$/.test(n)))throw new o("SCHEMA_INVALID");let r=e?.maxDocs??100;if(!Number.isSafeInteger(s)||s<0||!Number.isSafeInteger(r)||r<1||r>100)throw new o("SCHEMA_INVALID");if(e?.query!==void 0&&!h(e.query))throw new o("SCHEMA_INVALID");let f=e?.query===void 0?this.query:{...this.query,...e.query};if(!h(f)||!E(f,["filter","order_by","projection","limit","skip"]))throw new o("SCHEMA_INVALID");let{value:u,requestId:d}=await this.session.request("documents.snapshot",{collection_key:this.key,query:f,cursor:s,max_docs:r}),i=u;if(!Array.isArray(i.list)||!Array.isArray(i.value_types)||i.list.length!==i.value_types.length||typeof i.cursor!="string"||!/^(0|[1-9]\d*)$/.test(i.cursor)||!Number.isSafeInteger(Number(i.cursor))||typeof i.has_more!="boolean")throw new o("PROTOCOL_MISMATCH",d);return{data:i.list.map((l,w)=>G(l,i.value_types[w])),cursor:i.cursor,changed:i.cursor!==String(s),hasMore:i.has_more,errMsg:"collection.watch:ok",_meta:{requestId:d}}})}after(){throw new o("UNSUPPORTED_OPERATION")}onChange(e){if(typeof e!="function")throw new o("SCHEMA_INVALID");return this.session.onEvent?this.session.onEvent(n=>{n.collection_key!==void 0&&n.collection_key!==this.key||e(n)}):()=>{}}update(){throw new o("UNSUPPORTED_OPERATION")}remove(){throw new o("UNSUPPORTED_OPERATION")}},ee=class{constructor(e,n,s,r){O(this,"session");O(this,"collection");O(this,"id");O(this,"throwOnNotFound");this.session=e,this.collection=n,this.id=s,this.throwOnNotFound=r}get(e){return R(e,async()=>{try{let{value:n,requestId:s}=await this.session.request("documents.query",{collection_key:this.collection,document_key:this.id,operation:"get"});if(!Array.isArray(n.list)||n.list.length!==1||!Array.isArray(n.value_types))throw new o("PROTOCOL_MISMATCH",s);return{data:G(n.list[0],n.value_types[0]),errMsg:"document.get:ok",_meta:{requestId:s}}}catch(n){if(!this.throwOnNotFound&&n instanceof o&&n.errCode==="DOCUMENT_NOT_FOUND")return{data:null,errMsg:"document.get:ok",_meta:{requestId:n.requestId??""}};throw n}})}mutate(e,n,s){return R(s,async()=>{if(!h(n))throw new o("SCHEMA_INVALID");let r=n,f=r.agentos?.operationId??this.session.createId(),u=r.agentos?.expectedVersion;if(u!==void 0&&(!/^[1-9]\d*$/.test(u)||!Number.isSafeInteger(Number(u))))throw new o("SCHEMA_INVALID",void 0,f);let d={collection_key:this.collection,document_key:this.id,operation:e,operation_id:f,..."data"in r?J(r.data,e):{},...u===void 0?{}:{expected_version:u}},{value:i,requestId:l}=await this.session.request("documents.mutate",d);return ne(i,l,f)})}set(e){return this.mutate("set",e,e)}update(e){return this.mutate("update",e,e)}remove(e={}){return this.mutate("remove",e,e)}},te=class extends Q{constructor(n,s,r){super(n,s);O(this,"throwOnNotFound");this.throwOnNotFound=r}doc(n){return new ee(this.session,this.key,Me(n),this.throwOnNotFound)}add(n){return R(n,async()=>{if(!h(n)||!h(n.data))throw new o("SCHEMA_INVALID");let s=n.agentos?.operationId??this.session.createId(),{_id:r,...f}=n.data;if(r!==void 0&&typeof r!="string")throw new o("SCHEMA_INVALID",void 0,s);let{value:u,requestId:d}=await this.session.request("documents.mutate",{collection_key:this.key,operation:"add",operation_id:s,...J(f,"add"),...typeof r=="string"?{document_key:Me(r)}:{}});return ne(u,d,s)})}};function $e(t=ge){let e=null,n=null,s=0,r=null,f=0;function u(c,a,p){let y=c.limits[a];return typeof y=="number"&&Number.isSafeInteger(y)&&y>0?Math.min(p,y):p}function d(c){try{return new TextEncoder().encode(JSON.stringify(c)).byteLength}catch{return null}}let i={ready:()=>r??Promise.reject(new o("INIT_REQUIRED")),createId:()=>`op_${Math.floor((Date.now()+s)/1e3)}_${crypto.randomUUID().replaceAll("-","")}`,onEvent(c){return n?n.onEvent(c):()=>{}},request:async(c,a)=>{let p=await i.ready(),y=crypto.randomUUID(),N=c==="documents.snapshot"?"watch-snapshot/1":c.startsWith("execution.")?"app-execution/1":c.startsWith("files.")?"storage-object/1":"document-core/1";if(!p.profiles.includes(N))throw new o(c.startsWith("execution.")?"BACKGROUND_CAPABILITY_UNAVAILABLE":"UNSUPPORTED_OPERATION",y);let m=typeof a.operation_id=="string"?a.operation_id:void 0,S=u(p,"max_concurrent_requests",8);if(f>=S)throw new o("RESOURCE_EXHAUSTED",y,m);let A=u(p,"max_request_bytes",256*1024),g=d({method:c,args:a});if(g===null||g>A)throw new o("REQUEST_TOO_LARGE",y,m);if(!de({requestId:y,method:c,args:a})||m!==void 0&&!L.test(m))throw new o("SCHEMA_INVALID",y,m);function P(C){if(!p.operators.includes(C.op))throw new o("UNSUPPORTED_OPERATION",y,m);C.filters?.forEach(P)}if(h(a.filter)&&P(a.filter),c==="documents.snapshot"&&h(a.query)&&h(a.query.filter)&&P(a.query.filter),Array.isArray(a.field_operations)){for(let C of a.field_operations)if(!h(C)||!p.operators.includes(String(C.op)))throw new o("UNSUPPORTED_OPERATION",y,m)}let b=u(p,"max_query_limit",100),x=u(p,"max_query_skip",1e3),H=u(p,"max_watch_docs",100);if(typeof a.limit=="number"&&a.limit>b||typeof a.skip=="number"&&a.skip>x||c==="documents.snapshot"&&typeof a.max_docs=="number"&&a.max_docs>H)throw new o("RESOURCE_EXHAUSTED",y,m);f+=1;try{let C=await n.request(c,a,y);if(!h(C)||!(c==="files.read"?k(C):T(C,1024*1024)))throw new o("PROTOCOL_MISMATCH",y,m);return{value:C,requestId:y}}catch(C){let Se=C instanceof o?C.errCode:F(c)?"COMMIT_UNKNOWN":"RUNTIME_UNAVAILABLE",be=C instanceof o&&C.jobId&&C.invocationId?{jobId:C.jobId,invocationId:C.invocationId}:void 0;throw new o(Se,y,C instanceof o?C.operationId??m:m,be)}finally{f-=1}}},l=ye(i),w=fe(),I=Oe(i),_=c=>R(c,async()=>{throw await i.ready(),new o("UNSUPPORTED_OPERATION")});return{app:{getUpdateManager:ue,checkUpdate:le},auth:{authorize:_e,getIdentity:we},cloud:{DYNAMIC_CURRENT_ENV:Le,init(c){if(!h(c)||Object.keys(c).some(p=>!["env","traceUser"].includes(p)))throw new o("SCHEMA_INVALID");let a={env:ve(c.env),traceUser:c.traceUser??!1};if(e){if(JSON.stringify(e)!==JSON.stringify(a))throw new o("INIT_CONFLICT");return}e=a;try{n=t(a.env),r=n.ready().then(p=>{if(p.protocol.major!==2||!p.profiles.some(y=>["document-core/1","app-execution/1","storage-object/1","watch-snapshot/1"].includes(y)))throw new o("PROTOCOL_MISMATCH");return s=p.serverTime*1e3-Date.now(),p})}catch(p){r=Promise.reject(p instanceof o?p:new o("RUNTIME_UNAVAILABLE"))}r.catch(()=>{})},database(c={}){if(Object.keys(c).some(a=>a!=="throwOnNotFound"))throw new o("SCOPE_FORBIDDEN");return{command:Ne,collection:a=>{if(!/^[a-z][a-z0-9_]{0,63}$/.test(a)||/^(sys_|ac_|t_)/.test(a))throw new o("SCHEMA_INVALID");return new te(i,a,c.throwOnNotFound!==!1)},serverDate:(a={})=>{let p=a.offset??0;if(!Number.isSafeInteger(p)||Math.abs(p)>864e5)throw new o("SCHEMA_INVALID");return new D("serverDate",void 0,p)},runTransaction:_}},callFunction(c){return R(c,()=>l.callFunction(c))},uploadFile(c){return R(c,()=>I.upload(c))},downloadFile(c){return R(c,()=>I.download(c.fileID))},deleteFile(c){return R(c,()=>I.remove(c))},getTempFileURL:_,os:{files:{getOperation:I.getOperation,cancel:I.cancel,stat:I.stat},capabilities:l.capabilities,jobs:l.jobs,api:w,ready:()=>i.ready(),getCapabilities:async()=>structuredClone(await i.ready()),close:()=>n?.close(),operations:{createId:()=>i.createId(),get:async c=>{if(!L.test(c))throw new o("SCHEMA_INVALID");let{value:a,requestId:p}=await i.request("operations.get",{operation_id:c});if(a.operation_id!==c||a.state!=="succeeded"||!h(a.result))throw new o("PROTOCOL_MISMATCH",p,c);return{operationId:c,state:"succeeded",result:ne(a.result,p)}}}}}}}var wt=$e();export{M as AppError,o as CloudError,Le as DYNAMIC_CURRENT_ENV,k as boundedBinary,$e as createCloudClient,F as writesCloud,wt as zl};
package/dist/workspace.js CHANGED
@@ -1,2 +1,2 @@
1
- /*! @zleap-ai/app-sdk v0.10.1 | (c) 2026 Zleap | 专有许可,仅限在 zleapOS 应用中使用,见 LICENSE */
1
+ /*! @zleap-ai/app-sdk v0.12.0 | (c) 2026 Zleap | 专有许可,仅限在 zleapOS 应用中使用,见 LICENSE */
2
2
  var I=Object.defineProperty;var E=(i,t,o)=>t in i?I(i,t,{enumerable:!0,configurable:!0,writable:!0,value:o}):i[t]=o;var _=(i,t,o)=>E(i,typeof t!="symbol"?t+"":t,o);var a=class extends Error{constructor(o,u){super(o);_(this,"code");_(this,"operationId");this.name="WorkspaceError",this.code=o,this.operationId=u}};function y(){if(window.parent===window)return Promise.reject(new a("OPEN_IN_ZLEAP_OS"));let i=window.location.pathname.match(/^\/api\/v1\/app-packages\/runtime\/([A-Za-z0-9_-]{43})\//)?.[1];if(!i)return Promise.reject(new a("OPEN_IN_ZLEAP_OS"));let t=new MessageChannel,o=!1,u=!1,l=new Map;function w(){if(!o){o=!0;for(let e of l.values())clearTimeout(e.timer),e.reject(new a(e.operationId?"COMMIT_UNKNOWN":"CONNECTION_CLOSED",e.operationId));l.clear(),t.port1.postMessage({type:"__zleap_workspace_close"}),t.port1.close()}}window.addEventListener("pagehide",w,{once:!0});let m=new Promise((e,s)=>{let r=setTimeout(()=>{u||(u=!0,w(),s(new a("WORKSPACE_UNAVAILABLE")))},15e3);t.port1.onmessage=c=>{let n=c.data;if(!u&&n?.type==="__zleap_workspace_ready"&&n.protocol===1){u=!0,clearTimeout(r),e();return}if(typeof n?.requestId!="string")return;let p=l.get(n.requestId);p&&(l.delete(n.requestId),clearTimeout(p.timer),typeof n.error=="string"?p.reject(new a(n.error,p.operationId)):p.resolve(n.result))},t.port1.onmessageerror=()=>w(),t.port1.start(),window.parent.postMessage({type:"__zleap_workspace_connect",protocol:1,nonce:i},"*",[t.port2])});async function d(e,s={},r){if(await m,o)throw new a("CONNECTION_CLOSED",r);if(l.size>=4)throw new a("TOO_MANY_REQUESTS");return new Promise((c,n)=>{let p=crypto.randomUUID(),O=setTimeout(()=>{l.delete(p),n(new a(r?"COMMIT_UNKNOWN":"CALL_TIMEOUT",r))},e==="select"?18e4:3e4);l.set(p,{resolve:N=>c(N),reject:n,timer:O,operationId:r}),t.port1.postMessage({requestId:p,method:e,args:s})})}async function f(e,s,r=crypto.randomUUID()){let c=await d(e,{...s,operationId:r},r);if(c.status!=="succeeded")throw new a(c.status==="failed"?c.code??"MOVE_FAILED":"COMMIT_UNKNOWN",r);return c}return m.then(()=>({selectFolder:()=>d("select"),restoreFolder:()=>d("restore"),list:e=>d("list",{handle:e}),readImage:(e,s,r)=>d("image",{handle:e,fileId:s,expectedVersion:r}),createFolder:async(e,s,r)=>(await f("mkdir",{handle:e,name:s},r)).result,move:async(e,s,r,c)=>(await f("move",{source:e,destination:s,fileIds:r},c)).result,operation:e=>d("operation",{operationId:e}),createOperationId:()=>crypto.randomUUID(),close:w}))}export{a as WorkspaceError,y as connectWorkspace};
package/dist/zleap.css ADDED
@@ -0,0 +1,582 @@
1
+ /*
2
+ * zleap.css — zleapOS 应用官方样式(随 @zleap-ai/app-sdk 分发,包内引用,符合沙箱 CSP)
3
+ *
4
+ * 用法:vanilla 页面 <link rel="stylesheet" href="./sdk/zleap.css" />;React 里 import '@zleap-ai/app-sdk/zleap.css'。
5
+ * 颜色、圆角、字号与 zleapOS 桌面同源(tokens 段由 zleap-app-kit scripts/sync-style-tokens.mjs 从平台设计 token 生成,勿手改)。
6
+ * 亮 / 暗主题跟随 zleapOS:宿主把当前主题设到应用窗口上,页面里 prefers-color-scheme 随之变化,不需要写代码。
7
+ * 组件类都以 zl- 开头,可与自己的样式混用;覆盖时改 --zl-* 变量,不要改本文件。
8
+ */
9
+
10
+ /* tokens:begin */
11
+ :root {
12
+ --zl-accent: #007AFF;
13
+ --zl-accent-text: #0066CC;
14
+ --zl-accent-subtle: rgb(0 122 255 / 12%);
15
+ --zl-danger: #EF4444;
16
+ --zl-success: #34C759;
17
+ --zl-warning: #8F6D00;
18
+ --zl-bg: #f9f9f9;
19
+ --zl-surface: #ffffff;
20
+ --zl-ink: #27272a;
21
+ --zl-ink-muted: #606066;
22
+ --zl-ink-faint: #73737a;
23
+ --zl-line: rgba(60, 60, 67, 0.22);
24
+ --zl-line-strong: rgba(60, 60, 67, 0.38);
25
+ --zl-shadow: 0 1px 2px rgb(0 0 0 / 0.05), 0 4px 14px rgb(0 0 0 / 0.08);
26
+ --zl-radius-sm: 6px;
27
+ --zl-radius-md: 8px;
28
+ --zl-radius-lg: 10px;
29
+ --zl-radius-xl: 14px;
30
+ --zl-font-xs: 12px;
31
+ --zl-font-sm: 13px;
32
+ --zl-font-base: 15px;
33
+ --zl-font-lg: 17px;
34
+ --zl-font-xl: 22px;
35
+ }
36
+ /* 暗色:跟随 zleapOS(宿主把主题设到应用窗口,prefers-color-scheme 随之变化);页面也可以自己设 data-theme。 */
37
+ @media (prefers-color-scheme: dark) {
38
+ :root:not([data-theme='light']) {
39
+ --zl-accent: #0A84FF;
40
+ --zl-accent-text: #409CFF;
41
+ --zl-accent-subtle: rgb(10 132 255 / 18%);
42
+ --zl-danger: #F87171;
43
+ --zl-success: #30D158;
44
+ --zl-warning: #E5B13B;
45
+ --zl-bg: #232323;
46
+ --zl-surface: #242424;
47
+ --zl-ink: #f1f1f2;
48
+ --zl-ink-muted: #b8b8bd;
49
+ --zl-ink-faint: #9b9ba1;
50
+ --zl-line: #3a3a3a;
51
+ --zl-line-strong: #686868;
52
+ --zl-shadow: 0 1px 2px rgb(0 0 0 / 0.24), 0 10px 28px rgb(0 0 0 / 0.28);
53
+ }
54
+ }
55
+ :root[data-theme='dark'] {
56
+ --zl-accent: #0A84FF;
57
+ --zl-accent-text: #409CFF;
58
+ --zl-accent-subtle: rgb(10 132 255 / 18%);
59
+ --zl-danger: #F87171;
60
+ --zl-success: #30D158;
61
+ --zl-warning: #E5B13B;
62
+ --zl-bg: #232323;
63
+ --zl-surface: #242424;
64
+ --zl-ink: #f1f1f2;
65
+ --zl-ink-muted: #b8b8bd;
66
+ --zl-ink-faint: #9b9ba1;
67
+ --zl-line: #3a3a3a;
68
+ --zl-line-strong: #686868;
69
+ --zl-shadow: 0 1px 2px rgb(0 0 0 / 0.24), 0 10px 28px rgb(0 0 0 / 0.28);
70
+ }
71
+ /* tokens:end */
72
+
73
+ :root {
74
+ --zl-font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Helvetica Neue', system-ui, 'Segoe UI',
75
+ 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
76
+ --zl-hover: color-mix(in srgb, var(--zl-ink) 6%, transparent);
77
+ --zl-pressed: color-mix(in srgb, var(--zl-ink) 10%, transparent);
78
+ --zl-success-subtle: color-mix(in srgb, var(--zl-success) 14%, transparent);
79
+ --zl-warning-subtle: color-mix(in srgb, var(--zl-warning) 14%, transparent);
80
+ --zl-danger-subtle: color-mix(in srgb, var(--zl-danger) 12%, transparent);
81
+ --zl-focus: 0 0 0 3px color-mix(in srgb, var(--zl-accent) 35%, transparent);
82
+ --zl-ease: cubic-bezier(0.2, 0, 0, 1);
83
+ color-scheme: light dark;
84
+ }
85
+
86
+ /* ---------- 基础 ---------- */
87
+ *,
88
+ *::before,
89
+ *::after {
90
+ box-sizing: border-box;
91
+ }
92
+ html {
93
+ font-family: var(--zl-font-family);
94
+ font-size: var(--zl-font-base);
95
+ line-height: 1.5;
96
+ -webkit-font-smoothing: antialiased;
97
+ text-rendering: optimizeLegibility;
98
+ }
99
+ body {
100
+ margin: 0;
101
+ min-height: 100vh;
102
+ background: var(--zl-bg);
103
+ color: var(--zl-ink);
104
+ }
105
+ ::selection {
106
+ background: var(--zl-accent-subtle);
107
+ }
108
+ :focus-visible {
109
+ outline: none;
110
+ box-shadow: var(--zl-focus);
111
+ }
112
+ h1, h2, h3, h4, p {
113
+ margin: 0;
114
+ }
115
+ code, kbd {
116
+ font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
117
+ font-size: 0.92em;
118
+ }
119
+ code {
120
+ padding: 1px 5px;
121
+ border-radius: var(--zl-radius-sm);
122
+ background: var(--zl-hover);
123
+ }
124
+ [hidden] {
125
+ display: none !important;
126
+ }
127
+
128
+ /* ---------- 布局 ---------- */
129
+ .zl-page {
130
+ max-width: 760px;
131
+ margin: 0 auto;
132
+ padding: 28px 24px 48px;
133
+ display: flex;
134
+ flex-direction: column;
135
+ gap: 20px;
136
+ }
137
+ .zl-page--wide { max-width: 1080px; }
138
+ .zl-page--full { max-width: none; }
139
+ /* 左列表右详情:<div class="zl-split"><aside>列表</aside><section>详情</section></div>,窄窗口上下排 */
140
+ .zl-split {
141
+ display: grid;
142
+ grid-template-columns: minmax(220px, 300px) minmax(0, 1fr);
143
+ gap: 20px;
144
+ align-items: start;
145
+ }
146
+ .zl-split > :first-child { position: sticky; top: 16px; max-height: calc(100vh - 32px); overflow: auto; }
147
+ .zl-header {
148
+ display: flex;
149
+ align-items: flex-start;
150
+ justify-content: space-between;
151
+ gap: 16px;
152
+ }
153
+ .zl-title {
154
+ font-size: var(--zl-font-xl);
155
+ line-height: 1.3;
156
+ font-weight: 650;
157
+ letter-spacing: -0.01em;
158
+ }
159
+ .zl-subtitle {
160
+ margin-top: 4px;
161
+ color: var(--zl-ink-muted);
162
+ font-size: var(--zl-font-sm);
163
+ }
164
+ .zl-section {
165
+ display: flex;
166
+ flex-direction: column;
167
+ gap: 12px;
168
+ }
169
+ .zl-section-title {
170
+ display: flex;
171
+ align-items: center;
172
+ justify-content: space-between;
173
+ gap: 12px;
174
+ font-size: var(--zl-font-sm);
175
+ font-weight: 600;
176
+ color: var(--zl-ink-muted);
177
+ }
178
+ .zl-stack { display: flex; flex-direction: column; gap: 12px; }
179
+ .zl-stack--sm { gap: 6px; }
180
+ .zl-stack--lg { gap: 20px; }
181
+ .zl-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
182
+ .zl-row--between { justify-content: space-between; }
183
+ .zl-row--end { justify-content: flex-end; }
184
+ .zl-spacer { flex: 1; }
185
+ .zl-grid {
186
+ display: grid;
187
+ grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
188
+ gap: 12px;
189
+ }
190
+ .zl-divider {
191
+ height: 1px;
192
+ border: 0;
193
+ margin: 0;
194
+ background: var(--zl-line);
195
+ }
196
+
197
+ /* ---------- 卡片 ---------- */
198
+ .zl-card {
199
+ background: var(--zl-surface);
200
+ border: 1px solid var(--zl-line);
201
+ border-radius: var(--zl-radius-xl);
202
+ box-shadow: var(--zl-shadow);
203
+ padding: 16px;
204
+ }
205
+ .zl-card--flat { box-shadow: none; }
206
+ .zl-card--interactive {
207
+ cursor: pointer;
208
+ transition: border-color 0.15s var(--zl-ease), transform 0.15s var(--zl-ease);
209
+ }
210
+ .zl-card--interactive:hover { border-color: var(--zl-line-strong); }
211
+ .zl-card--interactive:active { transform: scale(0.995); }
212
+ .zl-card-title {
213
+ font-size: var(--zl-font-base);
214
+ font-weight: 600;
215
+ }
216
+
217
+ /* ---------- 文字 ---------- */
218
+ .zl-muted { color: var(--zl-ink-muted); }
219
+ .zl-faint { color: var(--zl-ink-faint); }
220
+ .zl-text-sm { font-size: var(--zl-font-sm); }
221
+ .zl-text-xs { font-size: var(--zl-font-xs); }
222
+ .zl-strong { font-weight: 600; }
223
+ .zl-num { font-variant-numeric: tabular-nums; }
224
+ .zl-text-success { color: var(--zl-success); }
225
+ .zl-text-danger { color: var(--zl-danger); }
226
+ .zl-ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
227
+ .zl-prose {
228
+ line-height: 1.7;
229
+ overflow-wrap: anywhere;
230
+ white-space: pre-wrap;
231
+ }
232
+ .zl-prose ul, .zl-prose ol { margin: 4px 0; padding-left: 20px; }
233
+
234
+ /* ---------- 按钮 ---------- */
235
+ .zl-btn {
236
+ display: inline-flex;
237
+ align-items: center;
238
+ justify-content: center;
239
+ gap: 6px;
240
+ min-height: 34px;
241
+ padding: 0 14px;
242
+ border: 1px solid var(--zl-line-strong);
243
+ border-radius: var(--zl-radius-md);
244
+ background: var(--zl-surface);
245
+ color: var(--zl-ink);
246
+ font: inherit;
247
+ font-size: var(--zl-font-sm);
248
+ font-weight: 550;
249
+ line-height: 1;
250
+ white-space: nowrap;
251
+ cursor: pointer;
252
+ user-select: none;
253
+ transition: background 0.15s var(--zl-ease), border-color 0.15s var(--zl-ease), transform 0.1s var(--zl-ease);
254
+ }
255
+ .zl-btn:hover { background: var(--zl-hover); }
256
+ .zl-btn:active { transform: scale(0.97); }
257
+ .zl-btn:disabled,
258
+ .zl-btn[aria-disabled='true'] {
259
+ opacity: 0.5;
260
+ cursor: default;
261
+ transform: none;
262
+ }
263
+ .zl-btn--primary {
264
+ background: var(--zl-accent);
265
+ border-color: var(--zl-accent);
266
+ color: #fff;
267
+ }
268
+ .zl-btn--primary:hover { background: color-mix(in srgb, var(--zl-accent) 88%, #000); }
269
+ .zl-btn--danger {
270
+ color: var(--zl-danger);
271
+ border-color: color-mix(in srgb, var(--zl-danger) 40%, transparent);
272
+ }
273
+ .zl-btn--danger:hover { background: var(--zl-danger-subtle); }
274
+ .zl-btn--ghost {
275
+ border-color: transparent;
276
+ background: transparent;
277
+ color: var(--zl-ink-muted);
278
+ }
279
+ .zl-btn--ghost:hover { color: var(--zl-ink); background: var(--zl-hover); }
280
+ .zl-btn--sm { min-height: 28px; padding: 0 10px; font-size: var(--zl-font-xs); border-radius: var(--zl-radius-sm); }
281
+ .zl-btn--lg { min-height: 40px; padding: 0 18px; font-size: var(--zl-font-base); }
282
+ .zl-btn--block { width: 100%; }
283
+ /* 处理中:<button class="zl-btn" aria-busy="true">保存中…</button> */
284
+ .zl-btn[aria-busy='true']::before {
285
+ content: '';
286
+ width: 12px;
287
+ height: 12px;
288
+ border-radius: 50%;
289
+ border: 2px solid currentColor;
290
+ border-right-color: transparent;
291
+ animation: zl-spin 0.7s linear infinite;
292
+ }
293
+
294
+ /* ---------- 表单 ---------- */
295
+ .zl-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
296
+ .zl-label { font-size: var(--zl-font-sm); font-weight: 550; }
297
+ .zl-hint { font-size: var(--zl-font-xs); color: var(--zl-ink-faint); }
298
+ .zl-input,
299
+ .zl-textarea,
300
+ .zl-select {
301
+ width: 100%;
302
+ min-height: 36px;
303
+ padding: 7px 11px;
304
+ border: 1px solid var(--zl-line-strong);
305
+ border-radius: var(--zl-radius-md);
306
+ background: var(--zl-surface);
307
+ color: var(--zl-ink);
308
+ font: inherit;
309
+ font-size: var(--zl-font-base);
310
+ transition: border-color 0.15s var(--zl-ease), box-shadow 0.15s var(--zl-ease);
311
+ }
312
+ .zl-input::placeholder,
313
+ .zl-textarea::placeholder { color: var(--zl-ink-faint); }
314
+ .zl-input:focus,
315
+ .zl-textarea:focus,
316
+ .zl-select:focus {
317
+ outline: none;
318
+ border-color: var(--zl-accent);
319
+ box-shadow: var(--zl-focus);
320
+ }
321
+ .zl-input[aria-invalid='true'],
322
+ .zl-textarea[aria-invalid='true'] { border-color: var(--zl-danger); }
323
+ .zl-textarea { min-height: 96px; resize: vertical; line-height: 1.6; }
324
+ .zl-input:disabled, .zl-textarea:disabled, .zl-select:disabled { opacity: 0.6; }
325
+ .zl-check {
326
+ width: 18px;
327
+ height: 18px;
328
+ margin: 0;
329
+ flex: none;
330
+ accent-color: var(--zl-accent);
331
+ cursor: pointer;
332
+ }
333
+ /* 行内可编辑字段:平时像文字,悬停 / 聚焦时显出边框;原生日期框 type="date" 在沙箱里可用,也跟随亮 / 暗 */
334
+ .zl-input--inline {
335
+ width: auto;
336
+ min-height: 28px;
337
+ padding: 3px 6px;
338
+ border-color: transparent;
339
+ background: transparent;
340
+ font-size: var(--zl-font-sm);
341
+ }
342
+ .zl-input--inline:hover { border-color: var(--zl-line-strong); }
343
+ .zl-input--inline:focus { background: var(--zl-surface); }
344
+ /* 一行输入 + 按钮 */
345
+ .zl-composer { display: flex; gap: 8px; }
346
+ .zl-composer > .zl-input { flex: 1; min-width: 0; }
347
+
348
+ /* 分段切换:<div class="zl-segmented"><button aria-pressed="true">全部</button>…</div>(不用原生 select 时首选) */
349
+ .zl-segmented {
350
+ display: inline-flex;
351
+ padding: 2px;
352
+ gap: 2px;
353
+ border-radius: var(--zl-radius-md);
354
+ background: var(--zl-hover);
355
+ }
356
+ .zl-segmented > button {
357
+ min-height: 28px;
358
+ padding: 0 12px;
359
+ border: 0;
360
+ border-radius: var(--zl-radius-sm);
361
+ background: transparent;
362
+ color: var(--zl-ink-muted);
363
+ font: inherit;
364
+ font-size: var(--zl-font-sm);
365
+ white-space: nowrap;
366
+ cursor: pointer;
367
+ }
368
+ .zl-segmented > button[aria-pressed='true'] {
369
+ background: var(--zl-surface);
370
+ color: var(--zl-ink);
371
+ font-weight: 600;
372
+ box-shadow: 0 1px 2px rgb(0 0 0 / 0.08);
373
+ }
374
+
375
+ /* ---------- 列表 ---------- */
376
+ .zl-list {
377
+ list-style: none;
378
+ margin: 0;
379
+ padding: 0;
380
+ background: var(--zl-surface);
381
+ border: 1px solid var(--zl-line);
382
+ border-radius: var(--zl-radius-xl);
383
+ overflow: hidden;
384
+ }
385
+ .zl-list-item {
386
+ display: flex;
387
+ align-items: center;
388
+ gap: 12px;
389
+ min-height: 52px;
390
+ padding: 10px 16px;
391
+ }
392
+ .zl-list-item + .zl-list-item { border-top: 1px solid var(--zl-line); }
393
+ .zl-list-item:hover { background: color-mix(in srgb, var(--zl-ink) 3%, transparent); }
394
+ .zl-item-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
395
+ .zl-item-title { font-weight: 550; overflow-wrap: anywhere; }
396
+ .zl-item-meta { font-size: var(--zl-font-xs); color: var(--zl-ink-faint); }
397
+ .zl-item-actions { display: flex; gap: 4px; flex: none; }
398
+ .zl-list-item.is-done .zl-item-title { color: var(--zl-ink-faint); text-decoration: line-through; }
399
+ /* 可点选的列表行(左列表右详情):<button class="zl-list-item" aria-current="true">;选中项用 aria-current */
400
+ button.zl-list-item {
401
+ width: 100%;
402
+ border: 0;
403
+ background: transparent;
404
+ color: inherit;
405
+ font: inherit;
406
+ text-align: left;
407
+ cursor: pointer;
408
+ }
409
+ button.zl-list-item:focus-visible { outline: none; box-shadow: inset var(--zl-focus); }
410
+ .zl-list-item[aria-current='true'] { background: var(--zl-accent-subtle); }
411
+ .zl-list-item[aria-current='true'] .zl-item-title { color: var(--zl-accent-text); }
412
+ @media (hover: hover) {
413
+ .zl-item-actions--hover { opacity: 0; transition: opacity 0.15s var(--zl-ease); }
414
+ .zl-list-item:hover .zl-item-actions--hover,
415
+ .zl-list-item:focus-within .zl-item-actions--hover { opacity: 1; }
416
+ }
417
+
418
+ /* ---------- 标签与状态 ---------- */
419
+ .zl-tag {
420
+ display: inline-flex;
421
+ align-items: center;
422
+ gap: 4px;
423
+ height: 22px;
424
+ padding: 0 8px;
425
+ border-radius: 999px;
426
+ background: var(--zl-hover);
427
+ color: var(--zl-ink-muted);
428
+ font-size: var(--zl-font-xs);
429
+ font-weight: 550;
430
+ white-space: nowrap;
431
+ }
432
+ .zl-tag--accent { background: var(--zl-accent-subtle); color: var(--zl-accent-text); }
433
+ .zl-tag--success { background: var(--zl-success-subtle); color: var(--zl-success); }
434
+ .zl-tag--warning { background: var(--zl-warning-subtle); color: var(--zl-warning); }
435
+ .zl-tag--danger { background: var(--zl-danger-subtle); color: var(--zl-danger); }
436
+ /* 连接状态:<span class="zl-status" data-state="connecting|ready|error|preview">…</span> */
437
+ .zl-status {
438
+ display: inline-flex;
439
+ align-items: center;
440
+ gap: 6px;
441
+ font-size: var(--zl-font-xs);
442
+ color: var(--zl-ink-muted);
443
+ white-space: nowrap;
444
+ }
445
+ .zl-status::before {
446
+ content: '';
447
+ width: 7px;
448
+ height: 7px;
449
+ border-radius: 50%;
450
+ background: var(--zl-ink-faint);
451
+ }
452
+ .zl-status[data-state='connecting']::before { animation: zl-pulse 1.2s ease-in-out infinite; }
453
+ .zl-status[data-state='ready']::before { background: var(--zl-success); }
454
+ .zl-status[data-state='error'] { color: var(--zl-danger); }
455
+ .zl-status[data-state='preview']::before { background: var(--zl-accent); }
456
+ .zl-status[data-state='error']::before { background: var(--zl-danger); }
457
+
458
+ /* ---------- 提示 ---------- */
459
+ .zl-alert {
460
+ display: flex;
461
+ align-items: flex-start;
462
+ gap: 12px;
463
+ padding: 12px 14px;
464
+ border-radius: var(--zl-radius-lg);
465
+ border: 1px solid var(--zl-line);
466
+ background: var(--zl-surface);
467
+ font-size: var(--zl-font-sm);
468
+ }
469
+ .zl-alert > :first-child { flex: 1; min-width: 0; }
470
+ .zl-alert strong { display: block; margin-bottom: 2px; }
471
+ .zl-alert--info { background: var(--zl-accent-subtle); border-color: transparent; }
472
+ .zl-alert--success { background: var(--zl-success-subtle); border-color: transparent; }
473
+ .zl-alert--warning { background: var(--zl-warning-subtle); border-color: transparent; }
474
+ .zl-alert--danger { background: var(--zl-danger-subtle); border-color: transparent; color: var(--zl-ink); }
475
+ .zl-alert--danger strong { color: var(--zl-danger); }
476
+ /* 轻提示:<div class="zl-toast" role="status">已保存</div>,2–3 秒后移除 */
477
+ .zl-toast {
478
+ position: fixed;
479
+ left: 50%;
480
+ bottom: 24px;
481
+ transform: translateX(-50%);
482
+ z-index: 10;
483
+ padding: 8px 16px;
484
+ border-radius: 999px;
485
+ background: var(--zl-ink);
486
+ color: var(--zl-bg);
487
+ font-size: var(--zl-font-sm);
488
+ box-shadow: var(--zl-shadow);
489
+ animation: zl-rise 0.2s var(--zl-ease);
490
+ }
491
+
492
+ /* ---------- 空 / 加载 ---------- */
493
+ .zl-empty {
494
+ display: flex;
495
+ flex-direction: column;
496
+ align-items: center;
497
+ gap: 8px;
498
+ padding: 40px 16px;
499
+ text-align: center;
500
+ color: var(--zl-ink-muted);
501
+ }
502
+ .zl-empty-icon {
503
+ width: 44px;
504
+ height: 44px;
505
+ display: grid;
506
+ place-items: center;
507
+ border-radius: 12px;
508
+ background: var(--zl-accent-subtle);
509
+ color: var(--zl-accent);
510
+ font-size: 22px;
511
+ }
512
+ .zl-empty-title { font-weight: 600; color: var(--zl-ink); }
513
+ .zl-empty-text { font-size: var(--zl-font-sm); max-width: 360px; }
514
+ .zl-skeleton {
515
+ display: block;
516
+ height: 14px;
517
+ border-radius: var(--zl-radius-sm);
518
+ background: linear-gradient(90deg, var(--zl-hover) 0%, var(--zl-pressed) 50%, var(--zl-hover) 100%);
519
+ background-size: 200% 100%;
520
+ animation: zl-shimmer 1.2s ease-in-out infinite;
521
+ }
522
+ .zl-spinner {
523
+ display: inline-block;
524
+ width: 16px;
525
+ height: 16px;
526
+ border-radius: 50%;
527
+ border: 2px solid var(--zl-line-strong);
528
+ border-top-color: var(--zl-accent);
529
+ animation: zl-spin 0.7s linear infinite;
530
+ }
531
+
532
+ /* ---------- 数据展示 ---------- */
533
+ .zl-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; }
534
+ .zl-stat {
535
+ padding: 14px 16px;
536
+ border-radius: var(--zl-radius-xl);
537
+ background: var(--zl-surface);
538
+ border: 1px solid var(--zl-line);
539
+ }
540
+ .zl-stat-label { font-size: var(--zl-font-xs); color: var(--zl-ink-muted); }
541
+ .zl-stat-value {
542
+ margin-top: 4px;
543
+ font-size: var(--zl-font-xl);
544
+ font-weight: 650;
545
+ font-variant-numeric: tabular-nums;
546
+ line-height: 1.2;
547
+ }
548
+ .zl-progress {
549
+ height: 6px;
550
+ border-radius: 999px;
551
+ background: var(--zl-hover);
552
+ overflow: hidden;
553
+ }
554
+ .zl-progress > span {
555
+ display: block;
556
+ height: 100%;
557
+ border-radius: inherit;
558
+ background: var(--zl-accent);
559
+ transition: width 0.3s var(--zl-ease);
560
+ }
561
+
562
+ /* ---------- 动效 ---------- */
563
+ @keyframes zl-spin { to { transform: rotate(360deg); } }
564
+ @keyframes zl-pulse { 50% { opacity: 0.35; } }
565
+ @keyframes zl-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
566
+ @keyframes zl-rise { from { opacity: 0; transform: translate(-50%, 8px); } }
567
+ .zl-enter { animation: zl-fade 0.2s var(--zl-ease); }
568
+ @keyframes zl-fade { from { opacity: 0; transform: translateY(4px); } }
569
+ @media (prefers-reduced-motion: reduce) {
570
+ *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
571
+ }
572
+
573
+ /* ---------- 窄窗口 ---------- */
574
+ @media (max-width: 560px) {
575
+ .zl-page { padding: 20px 14px 36px; }
576
+ .zl-header { flex-direction: column; }
577
+ .zl-composer { flex-direction: column; }
578
+ }
579
+ @media (max-width: 720px) {
580
+ .zl-split { grid-template-columns: minmax(0, 1fr); }
581
+ .zl-split > :first-child { position: static; max-height: none; }
582
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zleap-ai/app-sdk",
3
- "version": "0.10.1",
3
+ "version": "0.12.0",
4
4
  "description": "zleapOS 云开发前端 SDK:Cloud 数据库 / 文件 / 云函数(zl.cloud)、宿主能力(connectHostedApp)与工作区连接",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "repository": {
@@ -28,6 +28,7 @@
28
28
  "import": "./dist/workspace.js",
29
29
  "default": "./dist/workspace.js"
30
30
  },
31
+ "./zleap.css": "./dist/zleap.css",
31
32
  "./package.json": "./package.json"
32
33
  },
33
34
  "files": [