@storvia/sdk 0.5.3 → 0.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs.js CHANGED
@@ -1,5 +1,5 @@
1
- "use strict";var B=Object.defineProperty;var ie=Object.getOwnPropertyDescriptor;var se=Object.getOwnPropertyNames;var re=Object.prototype.hasOwnProperty;var oe=(o,e)=>{for(var t in e)B(o,t,{get:e[t],enumerable:!0})},ae=(o,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of se(e))!re.call(o,i)&&i!==t&&B(o,i,{get:()=>e[i],enumerable:!(n=ie(e,i))||n.enumerable});return o};var de=o=>ae(B({},"__esModule",{value:!0}),o);var Re={};oe(Re,{StorviaError:()=>g,StorviaSDK:()=>D,createStorviaSDK:()=>te,extractFieldValue:()=>ne,isRichFieldValue:()=>j,setToastEnabled:()=>K,showToast:()=>H});module.exports=de(Re);var g=class extends Error{constructor(e,t){super(t),this.name="StorviaError",this.code=e}};var V="storvia-sdk-toast-style",$="storvia-sdk-toast-stack",le=`
2
- #${$} {
1
+ "use strict";var j=Object.defineProperty;var ae=Object.getOwnPropertyDescriptor;var de=Object.getOwnPropertyNames;var le=Object.prototype.hasOwnProperty;var ce=(r,e)=>{for(var t in e)j(r,t,{get:e[t],enumerable:!0})},pe=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of de(e))!le.call(r,i)&&i!==t&&j(r,i,{get:()=>e[i],enumerable:!(n=ae(e,i))||n.enumerable});return r};var he=r=>pe(j({},"__esModule",{value:!0}),r);var Oe={};ce(Oe,{PROTOCOL_VERSION:()=>N,StorviaBus:()=>I,StorviaError:()=>g,StorviaSDK:()=>B,createStorviaSDK:()=>oe,envelope:()=>x,extractFieldValue:()=>re,isProtocolEnvelope:()=>U,isRichFieldValue:()=>Y,setToastEnabled:()=>Z,showToast:()=>z});module.exports=he(Oe);var g=class extends Error{constructor(e,t){super(t),this.name="StorviaError",this.code=e}};var X="storvia-sdk-toast-style",H="storvia-sdk-toast-stack",ge=`
2
+ #${H} {
3
3
  position: fixed;
4
4
  top: max(20px, env(safe-area-inset-top, 0px) + 20px);
5
5
  right: max(20px, env(safe-area-inset-right, 0px) + 20px);
@@ -12,7 +12,7 @@
12
12
  }
13
13
 
14
14
  @media (max-width: 768px) {
15
- #${$} {
15
+ #${H} {
16
16
  top: max(10px, env(safe-area-inset-top, 0px) + 10px);
17
17
  left: 10px;
18
18
  right: 10px;
@@ -76,11 +76,11 @@
76
76
  @media (max-width: 768px) {
77
77
  .storvia-toast { max-width: none; }
78
78
  }
79
- `,ce={success:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>',error:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>',warning:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>',info:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>'},pe={UNAUTHORIZED:"\u767B\u5F55\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55",INSUFFICIENT_CREDITS:"\u82B1\u56ED\u5E01\u4E0D\u8DB3\uFF0C\u8BF7\u5145\u503C\u540E\u518D\u7EE7\u7EED\u6E38\u620F",VIOLATION_WORD_DETECTED:"\u5185\u5BB9\u542B\u6709\u8FDD\u7981\u8BCD\uFF0C\u8BF7\u4FEE\u6539\u540E\u91CD\u8BD5",MESSAGE_TOO_LONG:"\u6D88\u606F\u8FC7\u957F\uFF0C\u8BF7\u7CBE\u7B80\u540E\u518D\u53D1\u9001",CONTENT_FILTERED:"\u5185\u5BB9\u88AB\u5B89\u5168\u7B56\u7565\u62E6\u622A\uFF0C\u8BF7\u8C03\u6574\u540E\u91CD\u8BD5",MODEL_REFUSAL:"\u6A21\u578B\u62D2\u7EDD\u54CD\u5E94\uFF0C\u6362\u4E2A\u8BF4\u6CD5\u8BD5\u8BD5",STREAM_INTERRUPTED:"\u56DE\u590D\u5DF2\u4E2D\u65AD\uFF0C\u8BF7\u91CD\u8BD5",RATE_LIMITED:"\u64CD\u4F5C\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",MODEL_NOT_FOUND:"\u6240\u9009\u6A21\u578B\u4E0D\u53EF\u7528\uFF0C\u8BF7\u5207\u6362\u5176\u4ED6\u6A21\u578B",GAME_NOT_FOUND:"\u672A\u627E\u5230\u5BF9\u5E94\u6E38\u620F",INVALID_REQUEST:"\u8BF7\u6C42\u65E0\u6548\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",INTERNAL_ERROR:"\u670D\u52A1\u51FA\u4E86\u70B9\u5C0F\u95EE\u9898\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",NOT_INITIALIZED:"SDK \u5C1A\u672A\u521D\u59CB\u5316",NETWORK_ERROR:"\u7F51\u7EDC\u5F02\u5E38\uFF0C\u8BF7\u68C0\u67E5\u8FDE\u63A5"},W=!0;function K(o){W=o}function he(){if(typeof document>"u")return null;let o=document.getElementById($);if(!o){if(!document.getElementById(V)){let e=document.createElement("style");e.id=V,e.textContent=le,document.head.appendChild(e)}o=document.createElement("div"),o.id=$,document.body.appendChild(o)}return o}function H(o,e="info",t=3500){if(!W)return;let n=he();if(!n)return;let i=document.createElement("div");i.className=`storvia-toast ${e}`,i.innerHTML=`
80
- <span class="storvia-toast-icon">${ce[e]}</span>
79
+ `,ue={success:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>',error:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>',warning:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>',info:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>'},me={UNAUTHORIZED:"\u767B\u5F55\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55",INSUFFICIENT_CREDITS:"\u82B1\u56ED\u5E01\u4E0D\u8DB3\uFF0C\u8BF7\u5145\u503C\u540E\u518D\u7EE7\u7EED\u6E38\u620F",VIOLATION_WORD_DETECTED:"\u5185\u5BB9\u542B\u6709\u8FDD\u7981\u8BCD\uFF0C\u8BF7\u4FEE\u6539\u540E\u91CD\u8BD5",MESSAGE_TOO_LONG:"\u6D88\u606F\u8FC7\u957F\uFF0C\u8BF7\u7CBE\u7B80\u540E\u518D\u53D1\u9001",CONTENT_FILTERED:"\u5185\u5BB9\u88AB\u5B89\u5168\u7B56\u7565\u62E6\u622A\uFF0C\u8BF7\u8C03\u6574\u540E\u91CD\u8BD5",MODEL_REFUSAL:"\u6A21\u578B\u62D2\u7EDD\u54CD\u5E94\uFF0C\u6362\u4E2A\u8BF4\u6CD5\u8BD5\u8BD5",STREAM_INTERRUPTED:"\u56DE\u590D\u5DF2\u4E2D\u65AD\uFF0C\u8BF7\u91CD\u8BD5",RATE_LIMITED:"\u64CD\u4F5C\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",MODEL_NOT_FOUND:"\u6240\u9009\u6A21\u578B\u4E0D\u53EF\u7528\uFF0C\u8BF7\u5207\u6362\u5176\u4ED6\u6A21\u578B",GAME_NOT_FOUND:"\u672A\u627E\u5230\u5BF9\u5E94\u6E38\u620F",INVALID_REQUEST:"\u8BF7\u6C42\u65E0\u6548\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",INTERNAL_ERROR:"\u670D\u52A1\u51FA\u4E86\u70B9\u5C0F\u95EE\u9898\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",NOT_INITIALIZED:"SDK \u5C1A\u672A\u521D\u59CB\u5316",NETWORK_ERROR:"\u7F51\u7EDC\u5F02\u5E38\uFF0C\u8BF7\u68C0\u67E5\u8FDE\u63A5"},q=!0;function Z(r){q=r}function ve(){if(typeof document>"u")return null;let r=document.getElementById(H);if(!r){if(!document.getElementById(X)){let e=document.createElement("style");e.id=X,e.textContent=ge,document.head.appendChild(e)}r=document.createElement("div"),r.id=H,document.body.appendChild(r)}return r}function z(r,e="info",t=3500){if(!q)return;let n=ve();if(!n)return;let i=document.createElement("div");i.className=`storvia-toast ${e}`,i.innerHTML=`
80
+ <span class="storvia-toast-icon">${ue[e]}</span>
81
81
  <span class="storvia-toast-msg"></span>
82
- `;let r=i.querySelector(".storvia-toast-msg");r&&(r.textContent=o),n.appendChild(i),requestAnimationFrame(()=>i.classList.add("show")),setTimeout(()=>{i.isConnected&&(i.classList.add("leaving"),i.classList.remove("show"),setTimeout(()=>i.remove(),320))},t)}function A(o,e){let t=pe[o]||e||"\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5";H(t,o==="INSUFFICIENT_CREDITS"||o==="RATE_LIMITED"?"warning":"error")}var L=class{constructor(e,t,n=!1,i=""){this.baseUrl=e,this.token=t,this.debug=n,this.devApiKey=i}setToken(e){this.token=e}setDebug(e){this.debug=e}maybeShowNetworkToast(e){e instanceof g||A("NETWORK_ERROR")}buildHeaders(){let e={"Content-Type":"application/json"};return this.token&&(e.Authorization=`Bearer ${this.token}`),this.devApiKey&&(e["x-api-key"]=this.devApiKey),e}log(e){if(!this.debug)return;let{method:t,path:n,body:i,status:r,rawResponse:s,parsedData:a,error:d,durationMs:l,modelName:h}=e,m="%c[Storvia SDK]",p="color: #6366f1; font-weight: bold",c=l!==void 0?` (${l}ms)`:"",u=r!==void 0?` [${r}]`:"",v=h?` [model: ${h}]`:"";d?(console.groupCollapsed(`${m} %c${t} ${n}${u}${v}${c} %c\u2717`,p,"color: #e0e0e0","color: #ef4444"),i!==void 0&&console.log("Request:",i),s!==void 0&&console.log("Response (raw):",s),console.error("Error:",d),console.groupEnd()):(console.groupCollapsed(`${m} %c${t} ${n}${u}${v}${c} %c\u2713`,p,"color: #e0e0e0","color: #22c55e"),i!==void 0&&console.log("Request:",i),s!==void 0&&console.log("Response (raw):",s),a!==void 0&&a!==s&&console.log("Response (data):",a),console.groupEnd())}async get(e,t){let n=new URL(`${this.baseUrl}${e}`);t&&Object.entries(t).forEach(([a,d])=>n.searchParams.set(a,d));let i=Date.now(),r,s;try{let a=await fetch(n.toString(),{method:"GET",headers:this.buildHeaders()});r=a.status;let{raw:d,data:l}=await this.handleResponseWithRaw(a);return s=d,this.log({method:"GET",path:e,body:t,status:r,rawResponse:s,parsedData:l,durationMs:Date.now()-i}),l}catch(a){throw this.log({method:"GET",path:e,body:t,status:r,rawResponse:s,error:a,durationMs:Date.now()-i}),this.maybeShowNetworkToast(a),a}}async post(e,t,n){let i=Date.now(),r,s;try{let a=await fetch(`${this.baseUrl}${e}`,{method:"POST",headers:this.buildHeaders(),body:t?JSON.stringify(t):void 0});r=a.status;let{raw:d,data:l}=await this.handleResponseWithRaw(a);return s=d,this.log({method:"POST",path:e,body:t,status:r,rawResponse:s,parsedData:l,durationMs:Date.now()-i,modelName:n?.modelName}),l}catch(a){throw this.log({method:"POST",path:e,body:t,status:r,rawResponse:s,error:a,durationMs:Date.now()-i,modelName:n?.modelName}),this.maybeShowNetworkToast(a),a}}async patch(e,t){let n=Date.now(),i,r;try{let s=await fetch(`${this.baseUrl}${e}`,{method:"PATCH",headers:this.buildHeaders(),body:t?JSON.stringify(t):void 0});i=s.status;let{raw:a,data:d}=await this.handleResponseWithRaw(s);return r=a,this.log({method:"PATCH",path:e,body:t,status:i,rawResponse:r,parsedData:d,durationMs:Date.now()-n}),d}catch(s){throw this.log({method:"PATCH",path:e,body:t,status:i,rawResponse:r,error:s,durationMs:Date.now()-n}),this.maybeShowNetworkToast(s),s}}async put(e,t){let n=Date.now(),i,r;try{let s=await fetch(`${this.baseUrl}${e}`,{method:"PUT",headers:this.buildHeaders(),body:t?JSON.stringify(t):void 0});i=s.status;let{raw:a,data:d}=await this.handleResponseWithRaw(s);return r=a,this.log({method:"PUT",path:e,body:t,status:i,rawResponse:r,parsedData:d,durationMs:Date.now()-n}),d}catch(s){throw this.log({method:"PUT",path:e,body:t,status:i,rawResponse:r,error:s,durationMs:Date.now()-n}),this.maybeShowNetworkToast(s),s}}async delete(e){let t=Date.now(),n,i;try{let r=await fetch(`${this.baseUrl}${e}`,{method:"DELETE",headers:this.buildHeaders()});n=r.status;let{raw:s,data:a}=await this.handleResponseWithRaw(r);return i=s,this.log({method:"DELETE",path:e,status:n,rawResponse:i,parsedData:a,durationMs:Date.now()-t}),a}catch(r){throw this.log({method:"DELETE",path:e,status:n,rawResponse:i,error:r,durationMs:Date.now()-t}),this.maybeShowNetworkToast(r),r}}async stream(e,t,n,i,r){let s=Date.now(),a=r?.modelName?` [model: ${r.modelName}]`:"",d=[],l=v=>{this.debug&&d.push({t:Date.now()-s,event:v})},h=await fetch(`${this.baseUrl}${e}`,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(t)});if(!h.ok){let v=await h.text().catch(()=>""),f={};try{f=JSON.parse(v)}catch{}let N=f.code||"INTERNAL_ERROR",x=new g(N,f.message||`HTTP ${h.status}`);throw A(N,f.message),this.log({method:"STREAM",path:e,body:t,status:h.status,rawResponse:v,error:x,durationMs:Date.now()-s,modelName:r?.modelName}),x}let m=h.body?.getReader();if(!m)throw new g("INTERNAL_ERROR","No response body for stream");let p=new TextDecoder,c="",u="";try{for(;;){let{done:v,value:f}=await m.read();if(v)break;let x=p.decode(f,{stream:!0}).split(`
83
- `);for(let y of x){if(!y.startsWith("data: "))continue;let U=y.slice(6);if(U==="[DONE]"){l("[DONE]"),this.debug&&(console.groupCollapsed(`%c[Storvia SDK] %cSTREAM ${e} [${h.status}]${a} (${Date.now()-s}ms) %c\u2713`,"color: #6366f1; font-weight: bold","color: #e0e0e0","color: #22c55e"),console.log("Request:",t),console.log(`Accumulated content (${u.length} chars):`,u),console.log("Message ID:",c),console.log(`SSE events (${d.length}):`,d),console.groupEnd()),i(c);return}try{let C=JSON.parse(U);l(C),C.type==="done"&&C.id?c=C.id:C.content&&(u+=C.content,n(C.content))}catch{l({raw:U})}}}}catch(v){throw this.debug&&(console.groupCollapsed(`%c[Storvia SDK] %cSTREAM ${e} [${h.status}]${a} (${Date.now()-s}ms) %c\u2717`,"color: #6366f1; font-weight: bold","color: #e0e0e0","color: #ef4444"),console.log("Request:",t),console.log(`Accumulated content (${u.length} chars):`,u),console.log(`SSE events (${d.length}):`,d),console.error("Stream error:",v),console.groupEnd()),v}c&&i(c)}async handleResponseWithRaw(e){let t=await e.text(),n;try{n=t?JSON.parse(t):null}catch{n=t}if(!e.ok){let i=n&&typeof n=="object"?n:{},r={401:"UNAUTHORIZED",402:"INSUFFICIENT_CREDITS",404:"GAME_NOT_FOUND",429:"RATE_LIMITED"},s=i.code||r[e.status]||"INTERNAL_ERROR",a=new g(s,i.message||`HTTP ${e.status}`);throw A(s,i.message),a}return n&&typeof n=="object"&&"data"in n?{raw:n,data:n.data}:{raw:n,data:n}}};var _=[{value:"zh-CN",label:"\u7B80\u4F53\u4E2D\u6587"},{value:"zh-TW",label:"\u7E41\u9AD4\u4E2D\u6587"},{value:"en",label:"English"},{value:"ja",label:"\u65E5\u672C\u8A9E"},{value:"ko",label:"\uD55C\uAD6D\uC5B4"}],Y=[{value:"low",label:"\u7B80\u77ED"},{value:"medium",label:"\u9002\u4E2D"},{value:"high",label:"\u8BE6\u7EC6"}],ge="https://cdn.storvia.ai/default/logo.png",me="https://api.storvia.ai/storage/v1/object/public/storvia/default/credits.png",ue=`
82
+ `;let s=i.querySelector(".storvia-toast-msg");s&&(s.textContent=r),n.appendChild(i),requestAnimationFrame(()=>i.classList.add("show")),setTimeout(()=>{i.isConnected&&(i.classList.add("leaving"),i.classList.remove("show"),setTimeout(()=>i.remove(),320))},t)}function F(r,e){let t=me[r]||e||"\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5";z(t,r==="INSUFFICIENT_CREDITS"||r==="RATE_LIMITED"?"warning":"error")}var $=class{constructor(e,t,n=!1,i=""){this.baseUrl=e,this.token=t,this.debug=n,this.devApiKey=i}setToken(e){this.token=e}setDebug(e){this.debug=e}maybeShowNetworkToast(e){e instanceof g||F("NETWORK_ERROR")}buildHeaders(){let e={"Content-Type":"application/json"};return this.token&&(e.Authorization=`Bearer ${this.token}`),this.devApiKey&&(e["x-api-key"]=this.devApiKey),e}log(e){if(!this.debug)return;let{method:t,path:n,body:i,status:s,rawResponse:o,parsedData:a,error:d,durationMs:l,modelName:h}=e,u="%c[Storvia SDK]",c="color: #6366f1; font-weight: bold",p=l!==void 0?` (${l}ms)`:"",m=s!==void 0?` [${s}]`:"",f=h?` [model: ${h}]`:"";d?(console.groupCollapsed(`${u} %c${t} ${n}${m}${f}${p} %c\u2717`,c,"color: #e0e0e0","color: #ef4444"),i!==void 0&&console.log("Request:",i),o!==void 0&&console.log("Response (raw):",o),console.error("Error:",d),console.groupEnd()):(console.groupCollapsed(`${u} %c${t} ${n}${m}${f}${p} %c\u2713`,c,"color: #e0e0e0","color: #22c55e"),i!==void 0&&console.log("Request:",i),o!==void 0&&console.log("Response (raw):",o),a!==void 0&&a!==o&&console.log("Response (data):",a),console.groupEnd())}async get(e,t){let n=new URL(`${this.baseUrl}${e}`);t&&Object.entries(t).forEach(([a,d])=>n.searchParams.set(a,d));let i=Date.now(),s,o;try{let a=await fetch(n.toString(),{method:"GET",headers:this.buildHeaders()});s=a.status;let{raw:d,data:l}=await this.handleResponseWithRaw(a);return o=d,this.log({method:"GET",path:e,body:t,status:s,rawResponse:o,parsedData:l,durationMs:Date.now()-i}),l}catch(a){throw this.log({method:"GET",path:e,body:t,status:s,rawResponse:o,error:a,durationMs:Date.now()-i}),this.maybeShowNetworkToast(a),a}}async post(e,t,n){let i=Date.now(),s,o;try{let a=await fetch(`${this.baseUrl}${e}`,{method:"POST",headers:this.buildHeaders(),body:t?JSON.stringify(t):void 0});s=a.status;let{raw:d,data:l}=await this.handleResponseWithRaw(a);return o=d,this.log({method:"POST",path:e,body:t,status:s,rawResponse:o,parsedData:l,durationMs:Date.now()-i,modelName:n?.modelName}),l}catch(a){throw this.log({method:"POST",path:e,body:t,status:s,rawResponse:o,error:a,durationMs:Date.now()-i,modelName:n?.modelName}),this.maybeShowNetworkToast(a),a}}async patch(e,t){let n=Date.now(),i,s;try{let o=await fetch(`${this.baseUrl}${e}`,{method:"PATCH",headers:this.buildHeaders(),body:t?JSON.stringify(t):void 0});i=o.status;let{raw:a,data:d}=await this.handleResponseWithRaw(o);return s=a,this.log({method:"PATCH",path:e,body:t,status:i,rawResponse:s,parsedData:d,durationMs:Date.now()-n}),d}catch(o){throw this.log({method:"PATCH",path:e,body:t,status:i,rawResponse:s,error:o,durationMs:Date.now()-n}),this.maybeShowNetworkToast(o),o}}async put(e,t){let n=Date.now(),i,s;try{let o=await fetch(`${this.baseUrl}${e}`,{method:"PUT",headers:this.buildHeaders(),body:t?JSON.stringify(t):void 0});i=o.status;let{raw:a,data:d}=await this.handleResponseWithRaw(o);return s=a,this.log({method:"PUT",path:e,body:t,status:i,rawResponse:s,parsedData:d,durationMs:Date.now()-n}),d}catch(o){throw this.log({method:"PUT",path:e,body:t,status:i,rawResponse:s,error:o,durationMs:Date.now()-n}),this.maybeShowNetworkToast(o),o}}async delete(e){let t=Date.now(),n,i;try{let s=await fetch(`${this.baseUrl}${e}`,{method:"DELETE",headers:this.buildHeaders()});n=s.status;let{raw:o,data:a}=await this.handleResponseWithRaw(s);return i=o,this.log({method:"DELETE",path:e,status:n,rawResponse:i,parsedData:a,durationMs:Date.now()-t}),a}catch(s){throw this.log({method:"DELETE",path:e,status:n,rawResponse:i,error:s,durationMs:Date.now()-t}),this.maybeShowNetworkToast(s),s}}async stream(e,t,n,i,s){let o=Date.now(),a=s?.modelName?` [model: ${s.modelName}]`:"",d=[],l=f=>{this.debug&&d.push({t:Date.now()-o,event:f})},h=await fetch(`${this.baseUrl}${e}`,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(t)});if(!h.ok){let f=await h.text().catch(()=>""),v={};try{v=JSON.parse(f)}catch{}let L=v.code||"INTERNAL_ERROR",E=new g(L,v.message||`HTTP ${h.status}`);throw F(L,v.message),this.log({method:"STREAM",path:e,body:t,status:h.status,rawResponse:f,error:E,durationMs:Date.now()-o,modelName:s?.modelName}),E}let u=h.body?.getReader();if(!u)throw new g("INTERNAL_ERROR","No response body for stream");let c=new TextDecoder,p="",m="";try{for(;;){let{done:f,value:v}=await u.read();if(f)break;let E=c.decode(v,{stream:!0}).split(`
83
+ `);for(let w of E){if(!w.startsWith("data: "))continue;let G=w.slice(6);if(G==="[DONE]"){l("[DONE]"),this.debug&&(console.groupCollapsed(`%c[Storvia SDK] %cSTREAM ${e} [${h.status}]${a} (${Date.now()-o}ms) %c\u2713`,"color: #6366f1; font-weight: bold","color: #e0e0e0","color: #22c55e"),console.log("Request:",t),console.log(`Accumulated content (${m.length} chars):`,m),console.log("Message ID:",p),console.log(`SSE events (${d.length}):`,d),console.groupEnd()),i(p);return}try{let C=JSON.parse(G);l(C),C.type==="done"&&C.id?p=C.id:C.content&&(m+=C.content,n(C.content))}catch{l({raw:G})}}}}catch(f){throw this.debug&&(console.groupCollapsed(`%c[Storvia SDK] %cSTREAM ${e} [${h.status}]${a} (${Date.now()-o}ms) %c\u2717`,"color: #6366f1; font-weight: bold","color: #e0e0e0","color: #ef4444"),console.log("Request:",t),console.log(`Accumulated content (${m.length} chars):`,m),console.log(`SSE events (${d.length}):`,d),console.error("Stream error:",f),console.groupEnd()),f}p&&i(p)}async handleResponseWithRaw(e){let t=await e.text(),n;try{n=t?JSON.parse(t):null}catch{n=t}if(!e.ok){let i=n&&typeof n=="object"?n:{},s={401:"UNAUTHORIZED",402:"INSUFFICIENT_CREDITS",404:"GAME_NOT_FOUND",429:"RATE_LIMITED"},o=i.code||s[e.status]||"INTERNAL_ERROR",a=new g(o,i.message||`HTTP ${e.status}`);throw F(o,i.message),a}return n&&typeof n=="object"&&"data"in n?{raw:n,data:n.data}:{raw:n,data:n}}};var A=[{value:"zh-CN",label:"\u7B80\u4F53\u4E2D\u6587"},{value:"zh-TW",label:"\u7E41\u9AD4\u4E2D\u6587"},{value:"en",label:"English"},{value:"ja",label:"\u65E5\u672C\u8A9E"},{value:"ko",label:"\uD55C\uAD6D\uC5B4"}],J=[{value:"low",label:"\u7B80\u77ED"},{value:"medium",label:"\u9002\u4E2D"},{value:"high",label:"\u8BE6\u7EC6"}],fe="https://cdn.storvia.ai/default/logo.png",ye="https://api.storvia.ai/storage/v1/object/public/storvia/default/credits.png",be=`
84
84
  :host {
85
85
  position: fixed;
86
86
  z-index: 2147483647;
@@ -754,7 +754,7 @@
754
754
  padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px));
755
755
  }
756
756
  }
757
- `,fe='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6L6 18M6 6l12 12"/></svg>',ve='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 2v6h-6M3 12a9 9 0 0 1 15-6.7L21 8M3 22v-6h6M21 12a9 9 0 0 1-15 6.7L3 16"/></svg>',be='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="spin"><path d="M21 12a9 9 0 1 1-6.219-8.56"/></svg>',we='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>',ye='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>',X='<svg class="check" viewBox="0 0 24 24" fill="none" stroke="#8246FF" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>',b=48,w=16,Ce=5,I=class{constructor(e){this.selectedModelId="";this.pendingModelId="";this.fabWrap=null;this.models=[];this.settings={temperature:1,replyLength:"medium",replyLanguage:"zh-CN",playerNote:""};this.activeTab="model";this.selectedCategory=null;this.hasWorldUpdate=!1;this.fabDot=null;this.syncHint=null;this.fabX=0;this.fabY=0;this.fab=null;this.panel=null;this.modelTabBtn=null;this.settingsTabBtn=null;this.modelBody=null;this.settingsBody=null;this.footer=null;this.modelGrid=null;this.modelDetail=null;this.tempValueEl=null;this.segmentBtns=[];this.langDropdown=null;this.langOptions=[];this.langArrow=null;this.langDropdownOpen=!1;this.noteCounter=null;this.saveBtn=null;this.syncBtn=null;this.syncState="idle";this.dragStartX=0;this.dragStartY=0;this.dragOffsetX=0;this.dragOffsetY=0;this.dragMoved=!1;this.dragging=!1;this.handlePointerDown=e=>{this.fab&&(e.preventDefault(),this.dragStartX=e.clientX,this.dragStartY=e.clientY,this.dragOffsetX=e.clientX-this.fabX,this.dragOffsetY=e.clientY-this.fabY,this.dragMoved=!1,this.dragging=!0,this.fab.setPointerCapture(e.pointerId),this.fab.addEventListener("pointermove",this.handlePointerMove),this.fab.addEventListener("pointerup",this.handlePointerUp),this.fab.addEventListener("pointercancel",this.handlePointerUp))};this.handlePointerMove=e=>{if(!this.dragging)return;let t=e.clientX-this.dragStartX,n=e.clientY-this.dragStartY;!this.dragMoved&&Math.hypot(t,n)>Ce&&(this.dragMoved=!0,this.fab?.classList.add("dragging"),this.closePanel()),this.dragMoved&&(this.fabX=e.clientX-this.dragOffsetX,this.fabY=e.clientY-this.dragOffsetY,this.applyHostPosition())};this.handlePointerUp=e=>{if(!this.fab)return;this.fab.removeEventListener("pointermove",this.handlePointerMove),this.fab.removeEventListener("pointerup",this.handlePointerUp),this.fab.removeEventListener("pointercancel",this.handlePointerUp);try{this.fab.releasePointerCapture(e.pointerId)}catch{}if(this.dragging=!1,!this.dragMoved){this.togglePanel();return}this.fab.classList.remove("dragging");let n=this.fabX+b/2<window.innerWidth/2;this.fabX=n?w:window.innerWidth-b-w,this.fabY=Math.max(w,Math.min(window.innerHeight-b-w,this.fabY)),this.fab&&(this.fab.style.transition="left 0.25s cubic-bezier(0.32, 0.72, 0, 1), top 0.25s cubic-bezier(0.32, 0.72, 0, 1), transform 0.2s, box-shadow 0.2s"),this.applyHostPosition(),setTimeout(()=>{this.fab&&(this.fab.style.transition="")},260)};this.handleResize=()=>{this.fabX=Math.max(w,Math.min(window.innerWidth-b-w,this.fabX)),this.fabY=Math.max(w,Math.min(window.innerHeight-b-w,this.fabY)),this.applyHostPosition()};this.handleDocClick=e=>{this.host.contains(e.target)||(this.closePanel(),this.closeLangDropdown())};this.savedBodyOverflow=null;this.callbacks=e,this.host=document.createElement("div"),this.host.id="storvia-settings",this.shadowRoot=this.host.attachShadow({mode:"closed"})}mount(e,t,n,i=!1){this.models=e,this.selectedModelId=t,this.pendingModelId=t,this.settings={...n},this.hasWorldUpdate=i,this.fabX=window.innerWidth-b-w,this.fabY=window.innerHeight-b-w,document.body.appendChild(this.host),this.render(),this.applyHostPosition(),window.addEventListener("resize",this.handleResize),document.addEventListener("click",this.handleDocClick)}unmount(){window.removeEventListener("resize",this.handleResize),document.removeEventListener("click",this.handleDocClick),this.host.remove()}getSelectedModelId(){return this.selectedModelId}getSettings(){return{...this.settings}}render(){let e=document.createElement("style");e.textContent=ue;let t=document.createElement("div");t.className="fab-wrap",this.fabWrap=t;let n=document.createElement("div");n.className="fab",n.title="\u6E38\u620F\u8BBE\u7F6E";let i=document.createElement("img");i.src=ge,i.alt="Storvia",n.appendChild(i),this.fab=n;let r=document.createElement("div");r.className=`fab-dot${this.hasWorldUpdate?" visible":""}`,this.fabDot=r,t.appendChild(n),t.appendChild(r);let s=document.createElement("div");s.className="panel",this.panel=s;let a=document.createElement("div");a.className="panel-header";let d=document.createElement("h2");d.className="panel-title",d.textContent="\u6E38\u620F\u8BBE\u7F6E";let l=document.createElement("button");l.className="close-btn",l.innerHTML=fe,l.addEventListener("click",()=>this.closePanel()),a.appendChild(d),a.appendChild(l),s.appendChild(a);let h=document.createElement("div");h.className="tabs",this.modelTabBtn=this.createTabBtn("model","\u6A21\u578B\u9009\u62E9"),this.settingsTabBtn=this.createTabBtn("settings","\u6E38\u620F\u8BBE\u7F6E"),this.models.length===0&&(this.activeTab="settings",this.modelTabBtn.style.display="none"),h.appendChild(this.modelTabBtn),h.appendChild(this.settingsTabBtn),s.appendChild(h);let m=document.createElement("div");m.className="panel-body",this.modelBody=this.buildModelTab(),this.settingsBody=this.buildSettingsTab(),m.appendChild(this.modelBody),m.appendChild(this.settingsBody),s.appendChild(m);let p=document.createElement("div");p.className="panel-footer";let c=document.createElement("button");c.className="btn btn-save",c.textContent="\u4FDD\u5B58",this.saveBtn=c,c.addEventListener("click",()=>this.handleSave()),p.appendChild(c),this.footer=p,s.appendChild(p),n.addEventListener("pointerdown",this.handlePointerDown);let u=document.createElement("div");u.appendChild(s),u.appendChild(t),this.shadowRoot.appendChild(e),this.shadowRoot.appendChild(u),this.applyTab()}createTabBtn(e,t){let n=document.createElement("button");return n.className=`tab-btn${this.activeTab===e?" active":""}`,n.textContent=t,n.addEventListener("click",()=>{this.activeTab=e,this.applyTab()}),n}applyTab(){this.modelTabBtn&&this.modelTabBtn.classList.toggle("active",this.activeTab==="model"),this.settingsTabBtn&&this.settingsTabBtn.classList.toggle("active",this.activeTab==="settings"),this.modelBody&&(this.modelBody.style.display=this.activeTab==="model"?"block":"none"),this.settingsBody&&(this.settingsBody.style.display=this.activeTab==="settings"?"block":"none"),this.footer&&(this.footer.style.display="flex")}buildModelTab(){let e=document.createElement("div"),t=this.getCategories();if(t.length>0){let r=document.createElement("div");r.className="category-tabs";let s=(a,d)=>{let l=document.createElement("button");return l.className=`category-tab${this.selectedCategory===d?" active":""}`,l.textContent=a,l.addEventListener("click",()=>{this.selectedCategory=d,r.querySelectorAll(".category-tab").forEach(h=>h.classList.remove("active")),l.classList.add("active"),this.renderModelGrid()}),l};r.appendChild(s("\u5168\u90E8",null)),t.forEach(a=>r.appendChild(s(a,a))),e.appendChild(r)}let n=document.createElement("div");n.className="models-grid",this.modelGrid=n,e.appendChild(n);let i=document.createElement("div");return i.className="model-detail",i.style.display="none",this.modelDetail=i,e.appendChild(i),this.renderModelGrid(),this.renderModelDetail(),e}getCategories(){let e=new Set;return this.models.forEach(t=>{t.category&&e.add(t.category)}),Array.from(e)}getFilteredModels(){return this.selectedCategory?this.models.filter(e=>e.category===this.selectedCategory):this.models}renderModelGrid(){this.modelGrid&&(this.modelGrid.innerHTML="",this.getFilteredModels().forEach(e=>{let t=document.createElement("button"),n=e.is_active!==!1;t.className=`model-card${e.id===this.pendingModelId?" selected":""}${n?"":" disabled"}`;let i=this.getStatusDotColor(e);t.innerHTML=`<span class="status-dot" style="background:${i}"></span><span class="model-name">${this.escapeHtml(e.name)}</span>`,t.addEventListener("click",()=>this.handleSelectModel(e)),this.modelGrid.appendChild(t)}))}handleSelectModel(e){this.pendingModelId=e.id;let t=this.getFilteredModels();this.modelGrid&&this.modelGrid.querySelectorAll(".model-card").forEach((n,i)=>{n.classList.toggle("selected",t[i].id===this.pendingModelId)}),this.renderModelDetail()}renderModelDetail(){if(!this.modelDetail)return;let e=this.models.find(s=>s.id===this.pendingModelId);if(!e){this.modelDetail.style.display="none";return}this.modelDetail.style.display="block";let t=this.getStatusClass(e),n=this.getStatusText(e),i=this.getCreditsRange(e),r=e.description||"";this.modelDetail.innerHTML=`
757
+ `,we='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6L6 18M6 6l12 12"/></svg>',xe='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 2v6h-6M3 12a9 9 0 0 1 15-6.7L21 8M3 22v-6h6M21 12a9 9 0 0 1-15 6.7L3 16"/></svg>',Ce='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="spin"><path d="M21 12a9 9 0 1 1-6.219-8.56"/></svg>',Ie='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>',Ee='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>',Q='<svg class="check" viewBox="0 0 24 24" fill="none" stroke="#8246FF" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>',y=48,b=16,Se=5,S=class{constructor(e){this.selectedModelId="";this.pendingModelId="";this.fabWrap=null;this.models=[];this.settings={temperature:1,replyLength:"medium",replyLanguage:"zh-CN",playerNote:""};this.activeTab="model";this.selectedCategory=null;this.hasWorldUpdate=!1;this.fabDot=null;this.syncHint=null;this.fabX=0;this.fabY=0;this.fab=null;this.panel=null;this.modelTabBtn=null;this.settingsTabBtn=null;this.modelBody=null;this.settingsBody=null;this.footer=null;this.modelGrid=null;this.modelDetail=null;this.tempValueEl=null;this.segmentBtns=[];this.langDropdown=null;this.langOptions=[];this.langArrow=null;this.langDropdownOpen=!1;this.noteCounter=null;this.saveBtn=null;this.syncBtn=null;this.syncState="idle";this.dragStartX=0;this.dragStartY=0;this.dragOffsetX=0;this.dragOffsetY=0;this.dragMoved=!1;this.dragging=!1;this.handlePointerDown=e=>{this.fab&&(e.preventDefault(),this.dragStartX=e.clientX,this.dragStartY=e.clientY,this.dragOffsetX=e.clientX-this.fabX,this.dragOffsetY=e.clientY-this.fabY,this.dragMoved=!1,this.dragging=!0,this.fab.setPointerCapture(e.pointerId),this.fab.addEventListener("pointermove",this.handlePointerMove),this.fab.addEventListener("pointerup",this.handlePointerUp),this.fab.addEventListener("pointercancel",this.handlePointerUp))};this.handlePointerMove=e=>{if(!this.dragging)return;let t=e.clientX-this.dragStartX,n=e.clientY-this.dragStartY;!this.dragMoved&&Math.hypot(t,n)>Se&&(this.dragMoved=!0,this.fab?.classList.add("dragging"),this.closePanel()),this.dragMoved&&(this.fabX=e.clientX-this.dragOffsetX,this.fabY=e.clientY-this.dragOffsetY,this.applyHostPosition())};this.handlePointerUp=e=>{if(!this.fab)return;this.fab.removeEventListener("pointermove",this.handlePointerMove),this.fab.removeEventListener("pointerup",this.handlePointerUp),this.fab.removeEventListener("pointercancel",this.handlePointerUp);try{this.fab.releasePointerCapture(e.pointerId)}catch{}if(this.dragging=!1,!this.dragMoved){this.togglePanel();return}this.fab.classList.remove("dragging");let n=this.fabX+y/2<window.innerWidth/2;this.fabX=n?b:window.innerWidth-y-b,this.fabY=Math.max(b,Math.min(window.innerHeight-y-b,this.fabY)),this.fab&&(this.fab.style.transition="left 0.25s cubic-bezier(0.32, 0.72, 0, 1), top 0.25s cubic-bezier(0.32, 0.72, 0, 1), transform 0.2s, box-shadow 0.2s"),this.applyHostPosition(),setTimeout(()=>{this.fab&&(this.fab.style.transition="")},260)};this.handleResize=()=>{this.fabX=Math.max(b,Math.min(window.innerWidth-y-b,this.fabX)),this.fabY=Math.max(b,Math.min(window.innerHeight-y-b,this.fabY)),this.applyHostPosition()};this.handleDocClick=e=>{this.host.contains(e.target)||(this.closePanel(),this.closeLangDropdown())};this.savedBodyOverflow=null;this.callbacks=e,this.host=document.createElement("div"),this.host.id="storvia-settings",this.shadowRoot=this.host.attachShadow({mode:"closed"})}mount(e,t,n,i=!1){this.models=e,this.selectedModelId=t,this.pendingModelId=t,this.settings={...n},this.hasWorldUpdate=i,this.fabX=window.innerWidth-y-b,this.fabY=window.innerHeight-y-b,document.body.appendChild(this.host),this.render(),this.applyHostPosition(),window.addEventListener("resize",this.handleResize),document.addEventListener("click",this.handleDocClick)}unmount(){window.removeEventListener("resize",this.handleResize),document.removeEventListener("click",this.handleDocClick),this.host.remove()}getSelectedModelId(){return this.selectedModelId}getSettings(){return{...this.settings}}render(){let e=document.createElement("style");e.textContent=be;let t=document.createElement("div");t.className="fab-wrap",this.fabWrap=t;let n=document.createElement("div");n.className="fab",n.title="\u6E38\u620F\u8BBE\u7F6E";let i=document.createElement("img");i.src=fe,i.alt="Storvia",n.appendChild(i),this.fab=n;let s=document.createElement("div");s.className=`fab-dot${this.hasWorldUpdate?" visible":""}`,this.fabDot=s,t.appendChild(n),t.appendChild(s);let o=document.createElement("div");o.className="panel",this.panel=o;let a=document.createElement("div");a.className="panel-header";let d=document.createElement("h2");d.className="panel-title",d.textContent="\u6E38\u620F\u8BBE\u7F6E";let l=document.createElement("button");l.className="close-btn",l.innerHTML=we,l.addEventListener("click",()=>this.closePanel()),a.appendChild(d),a.appendChild(l),o.appendChild(a);let h=document.createElement("div");h.className="tabs",this.modelTabBtn=this.createTabBtn("model","\u6A21\u578B\u9009\u62E9"),this.settingsTabBtn=this.createTabBtn("settings","\u6E38\u620F\u8BBE\u7F6E"),this.models.length===0&&(this.activeTab="settings",this.modelTabBtn.style.display="none"),h.appendChild(this.modelTabBtn),h.appendChild(this.settingsTabBtn),o.appendChild(h);let u=document.createElement("div");u.className="panel-body",this.modelBody=this.buildModelTab(),this.settingsBody=this.buildSettingsTab(),u.appendChild(this.modelBody),u.appendChild(this.settingsBody),o.appendChild(u);let c=document.createElement("div");c.className="panel-footer";let p=document.createElement("button");p.className="btn btn-save",p.textContent="\u4FDD\u5B58",this.saveBtn=p,p.addEventListener("click",()=>this.handleSave()),c.appendChild(p),this.footer=c,o.appendChild(c),n.addEventListener("pointerdown",this.handlePointerDown);let m=document.createElement("div");m.appendChild(o),m.appendChild(t),this.shadowRoot.appendChild(e),this.shadowRoot.appendChild(m),this.applyTab()}createTabBtn(e,t){let n=document.createElement("button");return n.className=`tab-btn${this.activeTab===e?" active":""}`,n.textContent=t,n.addEventListener("click",()=>{this.activeTab=e,this.applyTab()}),n}applyTab(){this.modelTabBtn&&this.modelTabBtn.classList.toggle("active",this.activeTab==="model"),this.settingsTabBtn&&this.settingsTabBtn.classList.toggle("active",this.activeTab==="settings"),this.modelBody&&(this.modelBody.style.display=this.activeTab==="model"?"block":"none"),this.settingsBody&&(this.settingsBody.style.display=this.activeTab==="settings"?"block":"none"),this.footer&&(this.footer.style.display="flex")}buildModelTab(){let e=document.createElement("div"),t=this.getCategories();if(t.length>0){let s=document.createElement("div");s.className="category-tabs";let o=(a,d)=>{let l=document.createElement("button");return l.className=`category-tab${this.selectedCategory===d?" active":""}`,l.textContent=a,l.addEventListener("click",()=>{this.selectedCategory=d,s.querySelectorAll(".category-tab").forEach(h=>h.classList.remove("active")),l.classList.add("active"),this.renderModelGrid()}),l};s.appendChild(o("\u5168\u90E8",null)),t.forEach(a=>s.appendChild(o(a,a))),e.appendChild(s)}let n=document.createElement("div");n.className="models-grid",this.modelGrid=n,e.appendChild(n);let i=document.createElement("div");return i.className="model-detail",i.style.display="none",this.modelDetail=i,e.appendChild(i),this.renderModelGrid(),this.renderModelDetail(),e}getCategories(){let e=new Set;return this.models.forEach(t=>{t.category&&e.add(t.category)}),Array.from(e)}getFilteredModels(){return this.selectedCategory?this.models.filter(e=>e.category===this.selectedCategory):this.models}renderModelGrid(){this.modelGrid&&(this.modelGrid.innerHTML="",this.getFilteredModels().forEach(e=>{let t=document.createElement("button"),n=e.is_active!==!1;t.className=`model-card${e.id===this.pendingModelId?" selected":""}${n?"":" disabled"}`;let i=this.getStatusDotColor(e);t.innerHTML=`<span class="status-dot" style="background:${i}"></span><span class="model-name">${this.escapeHtml(e.name)}</span>`,t.addEventListener("click",()=>this.handleSelectModel(e)),this.modelGrid.appendChild(t)}))}handleSelectModel(e){this.pendingModelId=e.id;let t=this.getFilteredModels();this.modelGrid&&this.modelGrid.querySelectorAll(".model-card").forEach((n,i)=>{n.classList.toggle("selected",t[i].id===this.pendingModelId)}),this.renderModelDetail()}renderModelDetail(){if(!this.modelDetail)return;let e=this.models.find(o=>o.id===this.pendingModelId);if(!e){this.modelDetail.style.display="none";return}this.modelDetail.style.display="block";let t=this.getStatusClass(e),n=this.getStatusText(e),i=this.getCreditsRange(e),s=e.description||"";this.modelDetail.innerHTML=`
758
758
  <div class="detail-header">
759
759
  <span class="detail-title">${this.escapeHtml(e.name)}</span>
760
760
  <span class="detail-status ${t}">${n}</span>
@@ -762,8 +762,8 @@
762
762
  ${i?`<div class="detail-credits">
763
763
  <span class="credits-label">\u6D88\u8017</span>
764
764
  <span class="credits-value">${i}</span>
765
- <img class="credits-icon" src="${me}" alt="credits" />
765
+ <img class="credits-icon" src="${ye}" alt="credits" />
766
766
  <span class="credits-unit">/\u6B21</span>
767
767
  </div>`:""}
768
- ${r?`<div class="detail-description">${this.escapeHtml(r)}</div>`:""}
769
- `}getStatusDotColor(e){if(e.is_active===!1)return"#6b7280";let t=e.success_rate??100;return t>=95?"#10b981":t>=80?"#3b82f6":t>=60?"#eab308":"#f97316"}getStatusClass(e){if(e.is_active===!1)return"inactive";let t=e.success_rate??100;return t>=95?"excellent":t>=80?"good":t>=60?"normal":"crowded"}getStatusText(e){if(e.is_active===!1)return"\u505C\u7528";let t=e.success_rate??100;return t>=95?"\u6D41\u7545":t>=80?"\u826F\u597D":t>=60?"\u4E00\u822C":"\u62E5\u6324"}getCreditsRange(e){let t=e.credits_config?.min??0,n=e.credits_config?.max??0;return t===0&&n===0?"":t===n?`${t}`:`${t}\uFF5E${n}`}buildSettingsTab(){let e=document.createElement("div"),t=document.createElement("div");return t.className="form-stack",t.appendChild(this.buildTemperatureSection()),t.appendChild(this.buildReplyLengthSection()),t.appendChild(this.buildReplyLanguageSection()),t.appendChild(this.buildNoteSection()),t.appendChild(this.buildSyncSection()),e.appendChild(t),e}buildTemperatureSection(){let e=document.createElement("div");e.className="form-group";let t=document.createElement("label");t.className="form-label";let n=document.createElement("span");n.textContent="\u6E29\u5EA6";let i=document.createElement("span");i.className="temperature-value",i.textContent=this.settings.temperature.toFixed(1),this.tempValueEl=i,t.appendChild(n),t.appendChild(i),e.appendChild(t);let r=document.createElement("p");r.className="form-hint",r.textContent="\u66F4\u4F4E\u8BA9 AI \u56DE\u590D\u66F4\u7A33\u5B9A\u7406\u667A\uFF0C\u66F4\u9AD8\u8BA9\u56DE\u590D\u66F4\u5177\u591A\u6837\u6027",e.appendChild(r);let s=document.createElement("input");s.type="range",s.className="slider",s.min="0",s.max="1",s.step="0.1",s.value=String(this.settings.temperature),s.addEventListener("input",()=>{let d=parseFloat(s.value);this.settings.temperature=d,this.tempValueEl&&(this.tempValueEl.textContent=d.toFixed(1))}),e.appendChild(s);let a=document.createElement("div");return a.className="slider-labels",a.innerHTML="<span>\u7CBE\u786E</span><span>\u521B\u610F</span>",e.appendChild(a),e}buildReplyLengthSection(){let e=document.createElement("div");e.className="form-group";let t=document.createElement("label");t.className="form-label",t.textContent="\u56DE\u590D\u957F\u5EA6",e.appendChild(t);let n=document.createElement("div");return n.className="segment-control",this.segmentBtns=[],Y.forEach(i=>{let r=document.createElement("button");r.className=`segment-button${i.value===this.settings.replyLength?" active":""}`,r.textContent=i.label,r.addEventListener("click",()=>{this.settings.replyLength=i.value,this.segmentBtns.forEach((s,a)=>{s.classList.toggle("active",Y[a].value===i.value)})}),this.segmentBtns.push(r),n.appendChild(r)}),e.appendChild(n),e}buildReplyLanguageSection(){let e=document.createElement("div");e.className="form-group";let t=document.createElement("label");t.className="form-label",t.textContent="\u56DE\u590D\u8BED\u8A00",e.appendChild(t);let n=document.createElement("div");n.className="custom-select";let i=document.createElement("button");i.className="select-trigger";let r=document.createElement("span");r.textContent=_.find(d=>d.value===this.settings.replyLanguage)?.label||"";let s=document.createElement("span");s.className="select-arrow",s.textContent="\u25BE",this.langArrow=s,i.appendChild(r),i.appendChild(s),i.addEventListener("click",d=>{d.stopPropagation(),this.toggleLangDropdown()}),n.appendChild(i);let a=document.createElement("div");return a.className="select-dropdown",this.langDropdown=a,this.langOptions=[],_.forEach(d=>{let l=document.createElement("button");l.className=`select-option${d.value===this.settings.replyLanguage?" active":""}`,l.innerHTML=`<span>${d.label}</span>${d.value===this.settings.replyLanguage?X:""}`,l.addEventListener("click",()=>{this.settings.replyLanguage=d.value,r.textContent=d.label,this.langOptions.forEach((h,m)=>{h.classList.toggle("active",_[m].value===d.value),h.innerHTML=`<span>${_[m].label}</span>${_[m].value===d.value?X:""}`}),this.closeLangDropdown()}),this.langOptions.push(l),a.appendChild(l)}),n.appendChild(a),e.appendChild(n),e}toggleLangDropdown(){this.langDropdownOpen?this.closeLangDropdown():this.openLangDropdown()}openLangDropdown(){this.langDropdownOpen=!0,this.langDropdown?.classList.add("open"),this.langArrow&&(this.langArrow.textContent="\u25B4")}closeLangDropdown(){this.langDropdownOpen=!1,this.langDropdown?.classList.remove("open"),this.langArrow&&(this.langArrow.textContent="\u25BE")}buildNoteSection(){let e=document.createElement("div");e.className="form-group";let t=document.createElement("label");t.className="form-label";let n=document.createElement("span");n.textContent="\u5907\u6CE8";let i=document.createElement("span");i.className="char-count",i.textContent=`${this.settings.playerNote.length}/50`,this.noteCounter=i,t.appendChild(n),t.appendChild(i),e.appendChild(t);let r=document.createElement("p");r.className="form-hint",r.textContent="\u5199\u4E0B\u4F60\u5BF9\u8FD9\u4E2A\u6E38\u620F\u7684\u5907\u6CE8\uFF0C\u4F1A\u663E\u793A\u5728\u5B58\u6863\u5217\u8868",e.appendChild(r);let s=document.createElement("textarea");return s.className="player-note-input",s.placeholder="\u5907\u6CE8",s.maxLength=50,s.rows=2,s.value=this.settings.playerNote,s.addEventListener("input",()=>{this.settings.playerNote=s.value,this.noteCounter&&(this.noteCounter.textContent=`${s.value.length}/50`)}),e.appendChild(s),e}buildSyncSection(){let e=document.createElement("div");e.className="form-group";let t=document.createElement("label");t.className="form-label",t.textContent="\u540C\u6B65\u6E38\u620F\u8BBE\u5B9A",e.appendChild(t);let n=document.createElement("p");n.className=`sync-hint${this.hasWorldUpdate?" visible":""}`,n.textContent="\u26A0 \u4F5C\u8005\u5DF2\u66F4\u65B0\u6E38\u620F\u5185\u5BB9\uFF0C\u5EFA\u8BAE\u70B9\u51FB\u540C\u6B65",this.syncHint=n,e.appendChild(n);let i=document.createElement("p");i.className="form-hint",i.textContent="\u5C06\u6700\u65B0\u6E38\u620F\u8BBE\u5B9A\u548C\u5F00\u5E55\u5C0F\u5267\u573A\u540C\u6B65\u5230\u5F53\u524D\u5BF9\u8BDD",e.appendChild(i);let r=document.createElement("button");return r.className="btn btn-sync",this.syncBtn=r,this.renderSyncBtn(),r.addEventListener("click",async()=>{if(this.syncState!=="loading"){this.setSyncState("loading");try{await this.callbacks.onSync(),this.setSyncState("success"),this.hasWorldUpdate=!1,this.fabDot&&this.fabDot.classList.remove("visible"),this.syncHint&&this.syncHint.classList.remove("visible"),setTimeout(()=>this.setSyncState("idle"),3e3)}catch{this.setSyncState("error"),setTimeout(()=>this.setSyncState("idle"),4e3)}}}),e.appendChild(r),e}setSyncState(e){this.syncState=e,this.renderSyncBtn()}renderSyncBtn(){if(!this.syncBtn)return;let e=this.syncState,t={idle:ve,loading:be,success:we,error:ye},n={idle:"\u540C\u6B65\u6700\u65B0\u8BBE\u5B9A",loading:"\u540C\u6B65\u4E2D...",success:"\u5DF2\u540C\u6B65",error:"\u540C\u6B65\u5931\u8D25"};this.syncBtn.className=`btn btn-sync${e==="success"||e==="error"?` ${e}`:""}`,this.syncBtn.disabled=e==="loading",this.syncBtn.innerHTML=`${t[e]}<span>${n[e]}</span>`}async handleSave(){if(!(!this.saveBtn||this.saveBtn.disabled)){this.saveBtn.disabled=!0,this.saveBtn.innerHTML='<span class="spinner"></span>\u4FDD\u5B58\u4E2D...';try{if(this.pendingModelId&&this.pendingModelId!==this.selectedModelId){let e=this.models.find(t=>t.id===this.pendingModelId);if(e&&e.is_active!==!1){this.selectedModelId=this.pendingModelId,this.callbacks.onModelChange(this.pendingModelId);try{localStorage.setItem("storvia_model_id",this.pendingModelId)}catch{}}else this.pendingModelId=this.selectedModelId}await this.callbacks.onSettingsChange({temperature:this.settings.temperature,replyLength:this.settings.replyLength,replyLanguage:this.settings.replyLanguage,playerNote:this.settings.playerNote}),this.saveBtn&&(this.saveBtn.textContent="\u4FDD\u5B58",this.saveBtn.disabled=!1),this.closePanel()}catch{this.saveBtn&&(this.saveBtn.textContent="\u4FDD\u5B58\u5931\u8D25",setTimeout(()=>{this.saveBtn&&(this.saveBtn.textContent="\u4FDD\u5B58",this.saveBtn.disabled=!1)},2e3))}}}escapeHtml(e){return e.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t])}applyHostPosition(){this.host.style.left=`${this.fabX}px`,this.host.style.top=`${this.fabY}px`,this.host.style.right="auto",this.host.style.bottom="auto",this.applyPanelPosition()}isMobile(){return window.innerWidth<=768}applyPanelPosition(){if(!this.panel)return;if(this.isMobile()){this.panel.style.left="",this.panel.style.right="",this.panel.style.top="",this.panel.style.bottom="";return}let e=this.fabX+b/2<window.innerWidth/2,t=380;e?(this.panel.style.left="0",this.panel.style.right="auto"):(this.panel.style.left=`${b-t}px`,this.panel.style.right="auto"),this.fabY>500?(this.panel.style.bottom=`${b+8}px`,this.panel.style.top="auto"):(this.panel.style.top=`${b+8}px`,this.panel.style.bottom="auto")}togglePanel(){this.panel&&(this.panel.classList.contains("open")?this.closePanel():(this.applyPanelPosition(),this.panel.classList.add("open"),requestAnimationFrame(()=>{this.panel?.classList.contains("open")&&(this.fab&&(this.fab.style.visibility="hidden"),this.fabDot&&(this.fabDot.style.visibility="hidden"),this.fabWrap&&(this.fabWrap.style.pointerEvents="none"))}),this.isMobile()&&this.lockBodyScroll()))}closePanel(){if(this.panel&&this.panel.classList.remove("open"),this.fab&&(this.fab.style.visibility="visible"),this.fabDot&&(this.fabDot.style.visibility="visible"),this.fabWrap&&(this.fabWrap.style.pointerEvents=""),this.unlockBodyScroll(),this.pendingModelId!==this.selectedModelId){if(this.pendingModelId=this.selectedModelId,this.modelGrid){let e=this.getFilteredModels();this.modelGrid.querySelectorAll(".model-card").forEach((t,n)=>{t.classList.toggle("selected",e[n].id===this.pendingModelId)})}this.renderModelDetail()}}lockBodyScroll(){this.savedBodyOverflow===null&&(this.savedBodyOverflow=document.body.style.overflow||"",document.body.style.overflow="hidden")}unlockBodyScroll(){this.savedBodyOverflow!==null&&(document.body.style.overflow=this.savedBodyOverflow,this.savedBodyOverflow=null)}};var S=class{constructor(e,t,n,i,r=!1,s,a,d){this.http=e;this.getGameId=t;this.getConversationId=n;this.getModelId=i;this.isPreview=r;this.previewConfig=s,this.getSettings=a,this.getModelName=d}reqMeta(){let e=this.getModelName?.();return e?{modelName:e}:void 0}updatePreviewConfig(e){this.previewConfig=e}async send(e){if(this.isPreview)return this.sendPreview(e);let t={game_id:this.getGameId(),conversation_id:this.getConversationId(),model_id:this.getModelId(),message:e.message,topic:e.topic,scene_key:e.sceneKey,stream:e.stream??!1};if(e.stream){await this.http.stream("/chat",t,e.onChunk??(()=>{}),e.onDone??(()=>{}),this.reqMeta());return}return this.http.post("/chat",t,this.reqMeta())}async save(e){return this.isPreview?{id:`preview-${Date.now()}`}:this.http.post("/messages/save",{conversation_id:this.getConversationId(),role:e.role,content:e.content,topic:e.topic})}async generate(e){if(this.isPreview)return this.sendPreview({message:"",topic:e.topic,sceneKey:e.sceneKey,stream:e.stream,onChunk:e.onChunk,onDone:e.onDone});let t={conversation_id:this.getConversationId(),model_id:this.getModelId(),topic:e.topic,scene_key:e.sceneKey,stream:e.stream??!1};if(e.stream){await this.http.stream("/generate",t,e.onChunk??(()=>{}),e.onDone??(()=>{}),this.reqMeta());return}return this.http.post("/generate",t,this.reqMeta())}async retry(e={}){if(this.isPreview)throw new Error("Retry is not supported in preview mode");let t={conversation_id:this.getConversationId(),model_id:this.getModelId(),topic:e.topic,scene_key:e.sceneKey,stream:e.stream??!1};if(e.stream){await this.http.stream("/retry",t,e.onChunk??(()=>{}),e.onDone??(()=>{}),this.reqMeta());return}return this.http.post("/retry",t,this.reqMeta())}async messages(e){if(this.isPreview)return{data:[],hasMore:!1,nextCursor:null};let t={conversation_id:this.getConversationId(),order:e.order,limit:String(e.limit??20)};e.topic&&(t.topic=e.topic),e.cursor&&(t.cursor_uuid=e.cursor.uuid,t.cursor_created_at=e.cursor.createdAt);let n=await this.http.get("/messages",t);return{data:n.messages.map(i=>({uuid:i.uuid,role:i.role,content:i.content,topic:i.topic,status:i.status,model:i.model,createdAt:i.created_at})),hasMore:n.has_more,nextCursor:n.next_cursor?{uuid:n.next_cursor.cursor_uuid,createdAt:n.next_cursor.cursor_created_at}:null}}async sendPreview(e){let t={model_id:this.getModelId(),message:e.message,topic:e.topic,scene_key:e.sceneKey,history_messages:[]};this.previewConfig?t.prompt_config=this.previewConfig:t.game_id=this.getGameId();let n=this.getSettings?.();if(n&&(typeof n.temperature=="number"&&(t.temperature=n.temperature),n.replyLength&&(t.reply_length=n.replyLength),n.replyLanguage&&(t.reply_language=n.replyLanguage)),e.stream){await this.http.stream("/preview",t,e.onChunk??(()=>{}),e.onDone??(()=>{}),this.reqMeta());return}let i="";return await this.http.stream("/preview",t,r=>{i+=r},()=>{},this.reqMeta()),{id:"",content:i}}};var F=class{constructor(e,t,n=!1,i){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={};i&&(this.mem={...i})}setInitial(e){this.mem=e?{...e}:{}}async get(e,t){if(this.isPreview){let i=this.mem[e]||{};return t?{...i[t]||{}}:{...i}}let n=t?{group:t}:void 0;return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/state`,n)}async update(e,t,n){if(this.isPreview){let i=this.mem[e]||(this.mem[e]={});i[t]={...i[t]||{},...n};return}await this.http.patch(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/state`,{group:t,values:n})}},E=class{constructor(e,t,n=!1,i,r){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[];i&&(this.mem=i.map(q)),this.state=new F(e,t,n,r)}setInitial(e,t){this.mem=e?e.map(q):[],this.state.setInitial(t)}async list(){return this.isPreview?this.mem.map(Z):this.http.get(`/conversations/${this.getConversationId()}/characters`)}async get(e){if(this.isPreview){let t=this.mem.find(n=>n.name===e);return t?Z(t):{name:e}}return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}`)}async add(e){if(this.isPreview){this.mem.push({...e,isPreset:!1});return}await this.http.post(`/conversations/${this.getConversationId()}/characters`,e)}async update(e,t){if(this.isPreview){let n=this.mem.find(i=>i.name===e);n&&Object.assign(n,t);return}await this.http.patch(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}`,t)}async remove(e){if(this.isPreview){this.mem=this.mem.filter(t=>t.name!==e);return}await this.http.delete(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}`)}async detail(e){if(this.isPreview){let t=this.mem.find(n=>n.name===e);return{name:e,avatar:t?.avatar,description:t?.description,userDescription:t?.userDescription,...t?.gender?{gender:t.gender}:{},...t?.isPreset!==void 0?{isPreset:t.isPreset}:{},state:await this.state.get(e)}}return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/detail`)}async setPriority(e,t){let n=Math.max(0,Math.min(100,Math.round(t)));this.isPreview||await this.http.patch(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/state`,{priority:n})}};function q(o){return{name:o.name,description:o.description,avatar:o.avatar,...o.gender?{gender:o.gender}:{},...o.userDescription!==void 0?{userDescription:o.userDescription}:{},...o.isPreset!==void 0?{isPreset:o.isPreset}:{}}}function Z(o){return{name:o.name,avatar:o.avatar,description:o.description,...o.userDescription!==void 0?{userDescription:o.userDescription}:{},...o.gender?{gender:o.gender}:{},...o.isPreset!==void 0?{isPreset:o.isPreset}:{}}}var R=class{constructor(e,t,n=!1,i){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[];i&&(this.mem=i.map(r=>({...r})))}setInitial(e){this.mem=e?e.map(t=>({...t})):[]}async list(){return this.isPreview?[...this.mem]:this.http.get(`/conversations/${this.getConversationId()}/relationships`)}async get(e,t){if(this.isPreview){let n=this.mem.find(i=>i.from===e&&i.to===t);if(n)return{...n};throw new Error("Relationship not found")}return this.http.get(`/conversations/${this.getConversationId()}/relationships/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)}async add(e){if(this.isPreview){this.mem.push({...e});return}await this.http.post(`/conversations/${this.getConversationId()}/relationships`,e)}async update(e,t,n){if(this.isPreview){let i=this.mem.find(r=>r.from===e&&r.to===t);i?Object.assign(i,n):this.mem.push({from:e,to:t,...n});return}await this.http.patch(`/conversations/${this.getConversationId()}/relationships/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,n)}async remove(e,t){if(this.isPreview){this.mem=this.mem.filter(n=>!(n.from===e&&n.to===t));return}await this.http.delete(`/conversations/${this.getConversationId()}/relationships/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)}};function J(o){let e={count:o.count};return o.desc!==void 0&&(e.desc=o.desc),o.icon_url!==void 0&&(e.iconUrl=o.icon_url),e}function G(o){let e={};if(!o)return e;for(let[t,n]of Object.entries(o)){let i={};for(let[r,s]of Object.entries(n))i[r]=J(s);e[t]=i}return e}function xe(o){let e={};if(!o)return e;for(let[t,n]of Object.entries(o))e[t]=J(n);return e}var T=class{constructor(e,t,n=!1,i){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={};i&&(this.mem=G(i))}setInitial(e){this.mem=e?G(e):{}}async list(e){if(this.isPreview){if(e!==void 0)return{...this.mem[e]||{}};let n={};for(let[i,r]of Object.entries(this.mem))n[i]={...r};return n}if(e!==void 0){let n=await this.http.get(`/conversations/${this.getConversationId()}/inventory/${encodeURIComponent(e)}`);return xe(n)}let t=await this.http.get(`/conversations/${this.getConversationId()}/inventory`);return G(t)}async add(e){let{group:t,name:n,count:i=1,desc:r,iconUrl:s}=e;if(this.isPreview){if(!this.mem[t])throw new Error(`Group "${t}" does not exist`);if(n in this.mem[t])throw new Error(`Item "${n}" already exists in group "${t}"`);let d={count:i};r!==void 0&&(d.desc=r),s!==void 0&&(d.iconUrl=s),this.mem[t][n]=d;return}let a={group:t,name:n,count:i};r!==void 0&&(a.desc=r),s!==void 0&&(a.icon_url=s),await this.http.post(`/conversations/${this.getConversationId()}/inventory`,a)}async update(e){let{group:t,name:n,count:i,desc:r,iconUrl:s}=e;if(this.isPreview){let d=this.mem[t];if(!d||!(n in d))throw new Error(`Item "${t}/${n}" not found`);let l=d[n];i!==void 0&&(l.count=i),r!==void 0&&(l.desc=r),s!==void 0&&(l.iconUrl=s);return}let a={};i!==void 0&&(a.count=i),r!==void 0&&(a.desc=r),s!==void 0&&(a.icon_url=s),await this.http.patch(`/conversations/${this.getConversationId()}/inventory/${encodeURIComponent(t)}/${encodeURIComponent(n)}`,a)}async remove(e){let{group:t,name:n}=e;if(this.isPreview){this.mem[t]&&delete this.mem[t][n];return}await this.http.delete(`/conversations/${this.getConversationId()}/inventory/${encodeURIComponent(t)}/${encodeURIComponent(n)}`)}async move(e){let{fromGroup:t,toGroup:n,name:i,newName:r}=e;if(this.isPreview){let s=this.mem[t];if(!s||!(i in s))throw new Error(`Source item "${t}/${i}" not found`);if(!this.mem[n])throw new Error(`Target group "${n}" does not exist`);let a=r||i;if(t===n&&a===i)return;if(a in this.mem[n])throw new Error(`Item "${a}" already exists in target group`);this.mem[n][a]=s[i],delete s[i];return}await this.http.post(`/conversations/${this.getConversationId()}/inventory/move`,{fromGroup:t,toGroup:n,name:i,newName:r})}async ensureGroup(e){if(this.isPreview){this.mem[e]||(this.mem[e]={});return}await this.http.post(`/conversations/${this.getConversationId()}/inventory/groups/${encodeURIComponent(e)}`,{})}async removeGroup(e,t){let n=t?.cascade??!1;if(this.isPreview){let r=this.mem[e];if(r&&Object.keys(r).length>0&&!n)throw new Error(`Group "${e}" is not empty, pass cascade: true to force delete`);delete this.mem[e];return}let i=n?"?cascade=true":"";await this.http.delete(`/conversations/${this.getConversationId()}/inventory/groups/${encodeURIComponent(e)}${i}`)}};var k=class{constructor(e,t,n=!1,i){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={};i&&(this.mem={...i})}setInitial(e){this.mem=e?{...e}:{}}async get(){return this.isPreview?{...this.mem}:this.http.get(`/conversations/${this.getConversationId()}/world`)}async update(e){if(this.isPreview){Object.assign(this.mem,e);return}await this.http.patch(`/conversations/${this.getConversationId()}/world`,e)}};var z=class{constructor(e,t,n=!1,i){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={};i&&(this.mem={...i})}setInitial(e){this.mem=e?{...e}:{}}async get(e){if(this.isPreview)return e?{...this.mem[e]||{}}:{...this.mem};let t=e?{group:e}:void 0;return this.http.get(`/conversations/${this.getConversationId()}/player/state`,t)}async update(e,t){if(this.isPreview){this.mem[e]={...this.mem[e]||{},...t};return}await this.http.patch(`/conversations/${this.getConversationId()}/player/state`,{group:e,values:t})}},P=class{constructor(e,t,n=!1,i,r){this.http=e;this.getConversationId=t;this.isPreview=n;this.memPersona={name:""};i&&(this.memPersona={...i}),this.state=new z(e,t,n,r)}setInitial(e,t){this.memPersona=e?{...e}:{name:""},this.state.setInitial(t)}async get(){return this.isPreview?{...this.memPersona}:this.http.get(`/conversations/${this.getConversationId()}/player`)}async update(e){if(this.isPreview){Object.assign(this.memPersona,e);return}await this.http.patch(`/conversations/${this.getConversationId()}/player`,e)}};var M=class{constructor(e,t,n=!1,i){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={};i&&(this.mem=Q(i))}setInitial(e){this.mem=e?Q(e):{}}async get(e){if(this.isPreview)return e!==void 0?this.mem[e]:{...this.mem};let t=await this.http.get(`/conversations/${this.getConversationId()}/custom`);return e!==void 0?t[e]:t}async set(e){if(this.isPreview){for(let[t,n]of Object.entries(e))typeof n=="object"&&n!==null&&typeof this.mem[t]=="object"&&this.mem[t]!==null?this.mem[t]={...this.mem[t],...n}:this.mem[t]=n;return}await this.http.patch(`/conversations/${this.getConversationId()}/custom`,e)}async delete(e){if(this.isPreview){delete this.mem[e];return}await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}`)}async setGroupField(e,t,n){if(this.isPreview){(!this.mem[e]||typeof this.mem[e]!="object")&&(this.mem[e]={}),this.mem[e][t]=n;return}await this.http.patch(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{value:n})}async deleteGroupField(e,t){if(this.isPreview){if(typeof this.mem[e]=="object"&&this.mem[e]!==null){let n=this.mem[e];delete n[t]}return}await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)}};function Q(o){let e={};for(let[t,n]of Object.entries(o))typeof n=="object"&&n!==null&&!Array.isArray(n)?e[t]={...n}:e[t]=n;return e}var O=class{constructor(e,t,n=!1,i){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={};i&&(this.mem={...i})}setInitial(e){this.mem=e?{...e}:{}}async get(){return this.isPreview?{...this.mem}:await this.http.get(`/conversations/${this.getConversationId()}/save`)}async set(e){if(this.isPreview){this.mem={...e};return}await this.http.put(`/conversations/${this.getConversationId()}/save`,e)}};var ee="/functions/v1/world-engine/v1",Ie="https://api.storvia.ai";function Se(){return window.__STORVIA__||{}}function Ee(o=5e3){let e=Se();return e.apiBase?Promise.resolve(e):new Promise((t,n)=>{let i=setTimeout(()=>{window.removeEventListener("message",r),n(new g("NOT_INITIALIZED","Timed out waiting for __STORVIA__ config from parent frame."))},o);function r(s){let a=null;if(s.data?.type==="storvia-init"&&s.data.apiBase?a={apiBase:s.data.apiBase,gameId:s.data.gameId,accessToken:s.data.accessToken}:s.data?.type==="storvia-preview-init"&&s.data.config&&(a=s.data.config),a&&a.apiBase){clearTimeout(i),window.removeEventListener("message",r);let d=window;d.__STORVIA__=a,t(a)}}window.addEventListener("message",r)})}var D=class{constructor(){this.baseUrl="";this.gameId="";this.conversationId="";this.modelId="";this.models=[];this.accessToken="";this.initialized=!1;this.isPreview=!1;this.previewConfig=void 0}async init(){if(this.initialized)return;let e=await Ee(),t=e.apiBase;if(!t)throw new g("NOT_INITIALIZED","window.__STORVIA__.apiBase is not set. The platform must inject it before SDK init.");if(this.baseUrl=`${t}${ee}`,this.isPreview=!!e.preview,this.previewConfig=e.previewConfig,!e.gameId)throw new g("GAME_NOT_FOUND","window.__STORVIA__.gameId is not set. The platform must inject it before SDK init.");if(this.gameId=e.gameId,!e.accessToken)throw new g("UNAUTHORIZED","window.__STORVIA__.accessToken is not set. The platform must inject the user token before SDK init.");if(this.accessToken=e.accessToken,this.http=new L(this.baseUrl,this.accessToken,!!e.debug),this.isPreview){this.conversationId="00000000-0000-0000-0000-000000000000";let[p,c]=await Promise.all([this.fetchModels(),this.fetchPreviewSnapshot()]);this.models=p;let u=this.getSavedModelId();this.modelId=e.selectedModelId||(u&&p.some(y=>y.id===u)?u:"")||p[0]?.id||"",this.settingsSheet=new I({onModelChange:y=>{this.modelId=y},onSettingsChange:()=>Promise.resolve(),onSync:()=>Promise.resolve()}),p.length>0&&this.settingsSheet.mount(p,this.modelId,{temperature:1,replyLength:"medium",replyLanguage:"zh-CN",playerNote:""},!1);let v=()=>this.gameId,f=()=>this.conversationId,N=()=>this.modelId,x=()=>this.models.find(y=>y.id===this.modelId)?.name;this.chat=new S(this.http,v,f,N,!0,this.previewConfig,()=>this.settingsSheet?.getSettings()??null,x),this.characters=new E(this.http,f,!0,c?.characters,c?.characterStates),this.relationships=new R(this.http,f,!0,c?.relationships),this.inventory=new T(this.http,f,!0,c?.inventory),this.world=new k(this.http,f,!0,c?.world),this.player=new P(this.http,f,!0,c?.player,c?.playerState),this.custom=new M(this.http,f,!0,c?.custom),this.save=new O(this.http,f,!0,c?.save_data),this.initialized=!0,this.listenForPreviewMessages(),this.listenForTokenUpdate();return}let[n,i]=await Promise.all([this.authenticate(),this.fetchModels()]);this.conversationId=n.conversationId,this.models=i;let r=this.getSavedModelId();this.modelId=r&&i.some(p=>p.id===r)?r:i[0]?.id||"";let s=n.settings,a=s?{temperature:s.temperature??1,replyLength:s.reply_length??"medium",replyLanguage:s.reply_language??"zh-CN",playerNote:s.player_note??""}:{temperature:1,replyLength:"medium",replyLanguage:"zh-CN",playerNote:""};this.settingsSheet=new I({onModelChange:p=>{this.modelId=p},onSettingsChange:p=>this.saveSettings(p),onSync:()=>this.syncSettings()}),this.settingsSheet.mount(i,this.modelId,a,n.hasWorldUpdate??!1);let d=()=>this.gameId,l=()=>this.conversationId,h=()=>this.modelId,m=()=>this.models.find(p=>p.id===this.modelId)?.name;this.chat=new S(this.http,d,l,h,!1,void 0,void 0,m),this.characters=new E(this.http,l),this.relationships=new R(this.http,l),this.inventory=new T(this.http,l),this.world=new k(this.http,l),this.player=new P(this.http,l),this.custom=new M(this.http,l),this.save=new O(this.http,l),this.listenForTokenUpdate(),this.initialized=!0}listenForTokenUpdate(){window.addEventListener("message",e=>{if(e.data?.type!=="storvia-token-update")return;let t=e.data.accessToken;typeof t!="string"||!t||(this.accessToken=t,this.http?.setToken(t))})}listenForPreviewMessages(){window.addEventListener("message",e=>{!e.data||e.data.type!=="storvia-preview"||(e.data.action==="set-model"&&(this.modelId=e.data.modelId||""),e.data.action==="update-config"&&(this.previewConfig=e.data.previewConfig,this.chat&&this.chat.updatePreviewConfig(this.previewConfig),this.refreshPreviewSnapshot().catch(t=>{console.warn("[Storvia SDK] refreshPreviewSnapshot failed:",t)})))})}async fetchPreviewSnapshot(){try{let e={game_id:this.gameId};return this.previewConfig&&("game_config"in this.previewConfig&&(e.game_config=this.previewConfig.game_config),"game_state"in this.previewConfig&&(e.game_state_override=this.previewConfig.game_state)),await this.http.post("/preview/initial-snapshot",e)}catch(e){return console.warn("[Storvia SDK] fetchPreviewSnapshot failed:",e),null}}async refreshPreviewSnapshot(){let e=await this.fetchPreviewSnapshot();e&&(this.characters?.setInitial(e.characters,e.characterStates),this.player?.setInitial(e.player,e.playerState),this.inventory?.setInitial(e.inventory),this.relationships?.setInitial(e.relationships),this.world?.setInitial(e.world),this.custom?.setInitial(e.custom),this.save?.setInitial(e.save_data))}async saveSettings(e){let t={conversation_id:this.conversationId};e.temperature!==void 0&&(t.temperature=e.temperature),e.replyLength!==void 0&&(t.reply_length=e.replyLength),e.replyLanguage!==void 0&&(t.reply_language=e.replyLanguage),e.playerNote!==void 0&&(t.player_note=e.playerNote),await this.http.patch("/settings",t)}async syncSettings(){await this.http.post("/sync",{conversation_id:this.conversationId})}async fetchModels(){try{return await this.http.get("/models")}catch{}return[]}async authenticate(){let e=await fetch(`${this.baseUrl}/auth`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.accessToken}`},body:JSON.stringify({game_id:this.gameId})});if(!e.ok)throw e.status===401?new g("UNAUTHORIZED","User not authenticated"):e.status===404?new g("GAME_NOT_FOUND","Game not found or not published"):new g("INTERNAL_ERROR",`Auth failed: HTTP ${e.status}`);let t=await e.json();return t.data??t}getSavedModelId(){try{return localStorage.getItem("storvia_model_id")||""}catch{return""}}async initDev(e){if(this.initialized)return;this.baseUrl=`${Ie}${ee}`,this.gameId=e.gameId,this.isPreview=!0,this.http=new L(this.baseUrl,"",!1,e.apiKey);let[t,n]=await Promise.all([this.fetchModels(),this.fetchPreviewSnapshot()]);this.models=t;let i=this.getSavedModelId();this.modelId=(i&&t.some(l=>l.id===i)?i:"")||t[0]?.id||"",this.conversationId="00000000-0000-0000-0000-000000000000",this.settingsSheet=new I({onModelChange:l=>{this.modelId=l},onSettingsChange:()=>Promise.resolve(),onSync:()=>Promise.resolve()}),t.length>0&&this.settingsSheet.mount(t,this.modelId,{temperature:1,replyLength:"medium",replyLanguage:"zh-CN",playerNote:""},!1);let r=()=>this.gameId,s=()=>this.conversationId,a=()=>this.modelId,d=()=>this.models.find(l=>l.id===this.modelId)?.name;this.chat=new S(this.http,r,s,a,!0,void 0,()=>this.settingsSheet?.getSettings()??null,d),this.characters=new E(this.http,s,!0,n?.characters,n?.characterStates),this.relationships=new R(this.http,s,!0,n?.relationships),this.inventory=new T(this.http,s,!0,n?.inventory),this.world=new k(this.http,s,!0,n?.world),this.player=new P(this.http,s,!0,n?.player,n?.playerState),this.custom=new M(this.http,s,!0,n?.custom),this.save=new O(this.http,s,!0,n?.save_data),this.initialized=!0}};async function te(o){let e=new D;return o?.dev?await e.initDev(o.dev):await e.init(),e}function j(o){return typeof o=="object"&&o!==null&&"value"in o&&"type"in o&&(o.type==="number"||o.type==="text")}function ne(o){return j(o)?o.value:o}0&&(module.exports={StorviaError,StorviaSDK,createStorviaSDK,extractFieldValue,isRichFieldValue,setToastEnabled,showToast});
768
+ ${s?`<div class="detail-description">${this.escapeHtml(s)}</div>`:""}
769
+ `}getStatusDotColor(e){if(e.is_active===!1)return"#6b7280";let t=e.success_rate??100;return t>=90?"#10b981":t>=80?"#3b82f6":t>=60?"#eab308":"#f97316"}getStatusClass(e){if(e.is_active===!1)return"inactive";let t=e.success_rate??100;return t>=90?"excellent":t>=80?"good":t>=60?"normal":"crowded"}getStatusText(e){if(e.is_active===!1)return"\u505C\u7528";let t=e.success_rate??100;return t>=90?"\u6D41\u7545":t>=80?"\u826F\u597D":t>=60?"\u4E00\u822C":"\u62E5\u6324"}getCreditsRange(e){let t=e.credits_config?.min??0,n=e.credits_config?.max??0;return t===0&&n===0?"":t===n?`${t}`:`${t}\uFF5E${n}`}buildSettingsTab(){let e=document.createElement("div"),t=document.createElement("div");return t.className="form-stack",t.appendChild(this.buildTemperatureSection()),t.appendChild(this.buildReplyLengthSection()),t.appendChild(this.buildReplyLanguageSection()),t.appendChild(this.buildNoteSection()),t.appendChild(this.buildSyncSection()),e.appendChild(t),e}buildTemperatureSection(){let e=document.createElement("div");e.className="form-group";let t=document.createElement("label");t.className="form-label";let n=document.createElement("span");n.textContent="\u6E29\u5EA6";let i=document.createElement("span");i.className="temperature-value",i.textContent=this.settings.temperature.toFixed(1),this.tempValueEl=i,t.appendChild(n),t.appendChild(i),e.appendChild(t);let s=document.createElement("p");s.className="form-hint",s.textContent="\u66F4\u4F4E\u8BA9 AI \u56DE\u590D\u66F4\u7A33\u5B9A\u7406\u667A\uFF0C\u66F4\u9AD8\u8BA9\u56DE\u590D\u66F4\u5177\u591A\u6837\u6027",e.appendChild(s);let o=document.createElement("input");o.type="range",o.className="slider",o.min="0",o.max="1",o.step="0.1",o.value=String(this.settings.temperature),o.addEventListener("input",()=>{let d=parseFloat(o.value);this.settings.temperature=d,this.tempValueEl&&(this.tempValueEl.textContent=d.toFixed(1))}),e.appendChild(o);let a=document.createElement("div");return a.className="slider-labels",a.innerHTML="<span>\u7CBE\u786E</span><span>\u521B\u610F</span>",e.appendChild(a),e}buildReplyLengthSection(){let e=document.createElement("div");e.className="form-group";let t=document.createElement("label");t.className="form-label",t.textContent="\u56DE\u590D\u957F\u5EA6",e.appendChild(t);let n=document.createElement("div");return n.className="segment-control",this.segmentBtns=[],J.forEach(i=>{let s=document.createElement("button");s.className=`segment-button${i.value===this.settings.replyLength?" active":""}`,s.textContent=i.label,s.addEventListener("click",()=>{this.settings.replyLength=i.value,this.segmentBtns.forEach((o,a)=>{o.classList.toggle("active",J[a].value===i.value)})}),this.segmentBtns.push(s),n.appendChild(s)}),e.appendChild(n),e}buildReplyLanguageSection(){let e=document.createElement("div");e.className="form-group";let t=document.createElement("label");t.className="form-label",t.textContent="\u56DE\u590D\u8BED\u8A00",e.appendChild(t);let n=document.createElement("div");n.className="custom-select";let i=document.createElement("button");i.className="select-trigger";let s=document.createElement("span");s.textContent=A.find(d=>d.value===this.settings.replyLanguage)?.label||"";let o=document.createElement("span");o.className="select-arrow",o.textContent="\u25BE",this.langArrow=o,i.appendChild(s),i.appendChild(o),i.addEventListener("click",d=>{d.stopPropagation(),this.toggleLangDropdown()}),n.appendChild(i);let a=document.createElement("div");return a.className="select-dropdown",this.langDropdown=a,this.langOptions=[],A.forEach(d=>{let l=document.createElement("button");l.className=`select-option${d.value===this.settings.replyLanguage?" active":""}`,l.innerHTML=`<span>${d.label}</span>${d.value===this.settings.replyLanguage?Q:""}`,l.addEventListener("click",()=>{this.settings.replyLanguage=d.value,s.textContent=d.label,this.langOptions.forEach((h,u)=>{h.classList.toggle("active",A[u].value===d.value),h.innerHTML=`<span>${A[u].label}</span>${A[u].value===d.value?Q:""}`}),this.closeLangDropdown()}),this.langOptions.push(l),a.appendChild(l)}),n.appendChild(a),e.appendChild(n),e}toggleLangDropdown(){this.langDropdownOpen?this.closeLangDropdown():this.openLangDropdown()}openLangDropdown(){this.langDropdownOpen=!0,this.langDropdown?.classList.add("open"),this.langArrow&&(this.langArrow.textContent="\u25B4")}closeLangDropdown(){this.langDropdownOpen=!1,this.langDropdown?.classList.remove("open"),this.langArrow&&(this.langArrow.textContent="\u25BE")}buildNoteSection(){let e=document.createElement("div");e.className="form-group";let t=document.createElement("label");t.className="form-label";let n=document.createElement("span");n.textContent="\u5907\u6CE8";let i=document.createElement("span");i.className="char-count",i.textContent=`${this.settings.playerNote.length}/50`,this.noteCounter=i,t.appendChild(n),t.appendChild(i),e.appendChild(t);let s=document.createElement("p");s.className="form-hint",s.textContent="\u5199\u4E0B\u4F60\u5BF9\u8FD9\u4E2A\u6E38\u620F\u7684\u5907\u6CE8\uFF0C\u4F1A\u663E\u793A\u5728\u5B58\u6863\u5217\u8868",e.appendChild(s);let o=document.createElement("textarea");return o.className="player-note-input",o.placeholder="\u5907\u6CE8",o.maxLength=50,o.rows=2,o.value=this.settings.playerNote,o.addEventListener("input",()=>{this.settings.playerNote=o.value,this.noteCounter&&(this.noteCounter.textContent=`${o.value.length}/50`)}),e.appendChild(o),e}buildSyncSection(){let e=document.createElement("div");e.className="form-group";let t=document.createElement("label");t.className="form-label",t.textContent="\u540C\u6B65\u6E38\u620F\u8BBE\u5B9A",e.appendChild(t);let n=document.createElement("p");n.className=`sync-hint${this.hasWorldUpdate?" visible":""}`,n.textContent="\u26A0 \u4F5C\u8005\u5DF2\u66F4\u65B0\u6E38\u620F\u5185\u5BB9\uFF0C\u5EFA\u8BAE\u70B9\u51FB\u540C\u6B65",this.syncHint=n,e.appendChild(n);let i=document.createElement("p");i.className="form-hint",i.textContent="\u5C06\u6700\u65B0\u6E38\u620F\u8BBE\u5B9A\u548C\u5F00\u5E55\u5C0F\u5267\u573A\u540C\u6B65\u5230\u5F53\u524D\u5BF9\u8BDD",e.appendChild(i);let s=document.createElement("button");return s.className="btn btn-sync",this.syncBtn=s,this.renderSyncBtn(),s.addEventListener("click",async()=>{if(this.syncState!=="loading"){this.setSyncState("loading");try{await this.callbacks.onSync(),this.setSyncState("success"),this.hasWorldUpdate=!1,this.fabDot&&this.fabDot.classList.remove("visible"),this.syncHint&&this.syncHint.classList.remove("visible"),setTimeout(()=>this.setSyncState("idle"),3e3)}catch{this.setSyncState("error"),setTimeout(()=>this.setSyncState("idle"),4e3)}}}),e.appendChild(s),e}setSyncState(e){this.syncState=e,this.renderSyncBtn()}renderSyncBtn(){if(!this.syncBtn)return;let e=this.syncState,t={idle:xe,loading:Ce,success:Ie,error:Ee},n={idle:"\u540C\u6B65\u6700\u65B0\u8BBE\u5B9A",loading:"\u540C\u6B65\u4E2D...",success:"\u5DF2\u540C\u6B65",error:"\u540C\u6B65\u5931\u8D25"};this.syncBtn.className=`btn btn-sync${e==="success"||e==="error"?` ${e}`:""}`,this.syncBtn.disabled=e==="loading",this.syncBtn.innerHTML=`${t[e]}<span>${n[e]}</span>`}async handleSave(){if(!(!this.saveBtn||this.saveBtn.disabled)){this.saveBtn.disabled=!0,this.saveBtn.innerHTML='<span class="spinner"></span>\u4FDD\u5B58\u4E2D...';try{if(this.pendingModelId&&this.pendingModelId!==this.selectedModelId){let e=this.models.find(t=>t.id===this.pendingModelId);if(e&&e.is_active!==!1){this.selectedModelId=this.pendingModelId,this.callbacks.onModelChange(this.pendingModelId);try{localStorage.setItem("storvia_model_id",this.pendingModelId)}catch{}}else this.pendingModelId=this.selectedModelId}await this.callbacks.onSettingsChange({temperature:this.settings.temperature,replyLength:this.settings.replyLength,replyLanguage:this.settings.replyLanguage,playerNote:this.settings.playerNote}),this.saveBtn&&(this.saveBtn.textContent="\u4FDD\u5B58",this.saveBtn.disabled=!1),this.closePanel()}catch{this.saveBtn&&(this.saveBtn.textContent="\u4FDD\u5B58\u5931\u8D25",setTimeout(()=>{this.saveBtn&&(this.saveBtn.textContent="\u4FDD\u5B58",this.saveBtn.disabled=!1)},2e3))}}}escapeHtml(e){return e.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t])}applyHostPosition(){this.host.style.left=`${this.fabX}px`,this.host.style.top=`${this.fabY}px`,this.host.style.right="auto",this.host.style.bottom="auto",this.applyPanelPosition()}isMobile(){return window.innerWidth<=768}applyPanelPosition(){if(!this.panel)return;if(this.isMobile()){this.panel.style.left="",this.panel.style.right="",this.panel.style.top="",this.panel.style.bottom="";return}let e=this.fabX+y/2<window.innerWidth/2,t=380;e?(this.panel.style.left="0",this.panel.style.right="auto"):(this.panel.style.left=`${y-t}px`,this.panel.style.right="auto"),this.fabY>500?(this.panel.style.bottom=`${y+8}px`,this.panel.style.top="auto"):(this.panel.style.top=`${y+8}px`,this.panel.style.bottom="auto")}togglePanel(){this.panel&&(this.panel.classList.contains("open")?this.closePanel():(this.applyPanelPosition(),this.panel.classList.add("open"),requestAnimationFrame(()=>{this.panel?.classList.contains("open")&&(this.fab&&(this.fab.style.visibility="hidden"),this.fabDot&&(this.fabDot.style.visibility="hidden"),this.fabWrap&&(this.fabWrap.style.pointerEvents="none"))}),this.isMobile()&&this.lockBodyScroll()))}closePanel(){if(this.panel&&this.panel.classList.remove("open"),this.fab&&(this.fab.style.visibility="visible"),this.fabDot&&(this.fabDot.style.visibility="visible"),this.fabWrap&&(this.fabWrap.style.pointerEvents=""),this.unlockBodyScroll(),this.pendingModelId!==this.selectedModelId){if(this.pendingModelId=this.selectedModelId,this.modelGrid){let e=this.getFilteredModels();this.modelGrid.querySelectorAll(".model-card").forEach((t,n)=>{t.classList.toggle("selected",e[n].id===this.pendingModelId)})}this.renderModelDetail()}}lockBodyScroll(){this.savedBodyOverflow===null&&(this.savedBodyOverflow=document.body.style.overflow||"",document.body.style.overflow="hidden")}unlockBodyScroll(){this.savedBodyOverflow!==null&&(document.body.style.overflow=this.savedBodyOverflow,this.savedBodyOverflow=null)}};var P=class{constructor(e,t,n,i,s=!1,o,a,d){this.http=e;this.getGameId=t;this.getConversationId=n;this.getModelId=i;this.isPreview=s;this.previewConfig=o,this.getSettings=a,this.getModelName=d}reqMeta(){let e=this.getModelName?.();return e?{modelName:e}:void 0}updatePreviewConfig(e){this.previewConfig=e}async send(e){if(this.isPreview)return this.sendPreview(e);let t={game_id:this.getGameId(),conversation_id:this.getConversationId(),model_id:this.getModelId(),message:e.message,topic:e.topic,scene_key:e.sceneKey,stream:e.stream??!1};if(e.stream){await this.http.stream("/chat",t,e.onChunk??(()=>{}),e.onDone??(()=>{}),this.reqMeta());return}return this.http.post("/chat",t,this.reqMeta())}async save(e){return this.isPreview?{id:`preview-${Date.now()}`}:this.http.post("/messages/save",{conversation_id:this.getConversationId(),role:e.role,content:e.content,topic:e.topic})}async generate(e){if(this.isPreview)return this.sendPreview({message:"",topic:e.topic,sceneKey:e.sceneKey,stream:e.stream,onChunk:e.onChunk,onDone:e.onDone});let t={conversation_id:this.getConversationId(),model_id:this.getModelId(),topic:e.topic,scene_key:e.sceneKey,stream:e.stream??!1};if(e.stream){await this.http.stream("/generate",t,e.onChunk??(()=>{}),e.onDone??(()=>{}),this.reqMeta());return}return this.http.post("/generate",t,this.reqMeta())}async retry(e={}){if(this.isPreview)throw new Error("Retry is not supported in preview mode");let t={conversation_id:this.getConversationId(),model_id:this.getModelId(),topic:e.topic,scene_key:e.sceneKey,stream:e.stream??!1};if(e.stream){await this.http.stream("/retry",t,e.onChunk??(()=>{}),e.onDone??(()=>{}),this.reqMeta());return}return this.http.post("/retry",t,this.reqMeta())}async messages(e){if(this.isPreview)return{data:[],hasMore:!1,nextCursor:null};let t={conversation_id:this.getConversationId(),order:e.order,limit:String(e.limit??20)};e.topic&&(t.topic=e.topic),e.cursor&&(t.cursor_uuid=e.cursor.uuid,t.cursor_created_at=e.cursor.createdAt);let n=await this.http.get("/messages",t);return{data:n.messages.map(i=>({uuid:i.uuid,role:i.role,content:i.content,topic:i.topic,status:i.status,model:i.model,createdAt:i.created_at})),hasMore:n.has_more,nextCursor:n.next_cursor?{uuid:n.next_cursor.cursor_uuid,createdAt:n.next_cursor.cursor_created_at}:null}}async sendPreview(e){let t={model_id:this.getModelId(),message:e.message,topic:e.topic,scene_key:e.sceneKey,history_messages:[]};this.previewConfig?t.prompt_config=this.previewConfig:t.game_id=this.getGameId();let n=this.getSettings?.();if(n&&(typeof n.temperature=="number"&&(t.temperature=n.temperature),n.replyLength&&(t.reply_length=n.replyLength),n.replyLanguage&&(t.reply_language=n.replyLanguage)),e.stream){await this.http.stream("/preview",t,e.onChunk??(()=>{}),e.onDone??(()=>{}),this.reqMeta());return}let i="";return await this.http.stream("/preview",t,s=>{i+=s},()=>{},this.reqMeta()),{id:"",content:i}}};var V=class{constructor(e,t,n=!1,i){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={};i&&(this.mem={...i})}setInitial(e){this.mem=e?{...e}:{}}async get(e,t){if(this.isPreview){let i=this.mem[e]||{};return t?{...i[t]||{}}:{...i}}let n=t?{group:t}:void 0;return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/state`,n)}async update(e,t,n){if(this.isPreview){let i=this.mem[e]||(this.mem[e]={});i[t]={...i[t]||{},...n};return}await this.http.patch(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/state`,{group:t,values:n})}},R=class{constructor(e,t,n=!1,i,s){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[];i&&(this.mem=i.map(ee)),this.state=new V(e,t,n,s)}setInitial(e,t){this.mem=e?e.map(ee):[],this.state.setInitial(t)}async list(){return this.isPreview?this.mem.map(te):this.http.get(`/conversations/${this.getConversationId()}/characters`)}async get(e){if(this.isPreview){let t=this.mem.find(n=>n.name===e);return t?te(t):{name:e}}return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}`)}async add(e){if(this.isPreview){this.mem.push({...e,isPreset:!1});return}await this.http.post(`/conversations/${this.getConversationId()}/characters`,e)}async update(e,t){if(this.isPreview){let n=this.mem.find(i=>i.name===e);n&&Object.assign(n,t);return}await this.http.patch(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}`,t)}async remove(e){if(this.isPreview){this.mem=this.mem.filter(t=>t.name!==e);return}await this.http.delete(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}`)}async detail(e){if(this.isPreview){let t=this.mem.find(n=>n.name===e);return{name:e,avatar:t?.avatar,description:t?.description,userDescription:t?.userDescription,...t?.gender?{gender:t.gender}:{},...t?.isPreset!==void 0?{isPreset:t.isPreset}:{},state:await this.state.get(e)}}return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/detail`)}async setPriority(e,t){let n=Math.max(0,Math.min(100,Math.round(t)));this.isPreview||await this.http.patch(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/state`,{priority:n})}};function ee(r){return{name:r.name,description:r.description,avatar:r.avatar,...r.gender?{gender:r.gender}:{},...r.userDescription!==void 0?{userDescription:r.userDescription}:{},...r.isPreset!==void 0?{isPreset:r.isPreset}:{}}}function te(r){return{name:r.name,avatar:r.avatar,description:r.description,...r.userDescription!==void 0?{userDescription:r.userDescription}:{},...r.gender?{gender:r.gender}:{},...r.isPreset!==void 0?{isPreset:r.isPreset}:{}}}var T=class{constructor(e,t,n=!1,i){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[];i&&(this.mem=i.map(s=>({...s})))}setInitial(e){this.mem=e?e.map(t=>({...t})):[]}async list(){return this.isPreview?[...this.mem]:this.http.get(`/conversations/${this.getConversationId()}/relationships`)}async get(e,t){if(this.isPreview){let n=this.mem.find(i=>i.from===e&&i.to===t);if(n)return{...n};throw new Error("Relationship not found")}return this.http.get(`/conversations/${this.getConversationId()}/relationships/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)}async add(e){if(this.isPreview){this.mem.push({...e});return}await this.http.post(`/conversations/${this.getConversationId()}/relationships`,e)}async update(e,t,n){if(this.isPreview){let i=this.mem.find(s=>s.from===e&&s.to===t);i?Object.assign(i,n):this.mem.push({from:e,to:t,...n});return}await this.http.patch(`/conversations/${this.getConversationId()}/relationships/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,n)}async remove(e,t){if(this.isPreview){this.mem=this.mem.filter(n=>!(n.from===e&&n.to===t));return}await this.http.delete(`/conversations/${this.getConversationId()}/relationships/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)}};function ne(r){let e={count:r.count};return r.desc!==void 0&&(e.desc=r.desc),r.icon_url!==void 0&&(e.iconUrl=r.icon_url),e}function W(r){let e={};if(!r)return e;for(let[t,n]of Object.entries(r)){let i={};for(let[s,o]of Object.entries(n))i[s]=ne(o);e[t]=i}return e}function Pe(r){let e={};if(!r)return e;for(let[t,n]of Object.entries(r))e[t]=ne(n);return e}var k=class{constructor(e,t,n=!1,i){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={};i&&(this.mem=W(i))}setInitial(e){this.mem=e?W(e):{}}async list(e){if(this.isPreview){if(e!==void 0)return{...this.mem[e]||{}};let n={};for(let[i,s]of Object.entries(this.mem))n[i]={...s};return n}if(e!==void 0){let n=await this.http.get(`/conversations/${this.getConversationId()}/inventory/${encodeURIComponent(e)}`);return Pe(n)}let t=await this.http.get(`/conversations/${this.getConversationId()}/inventory`);return W(t)}async add(e){let{group:t,name:n,count:i=1,desc:s,iconUrl:o}=e;if(this.isPreview){if(!this.mem[t])throw new Error(`Group "${t}" does not exist`);if(n in this.mem[t])throw new Error(`Item "${n}" already exists in group "${t}"`);let d={count:i};s!==void 0&&(d.desc=s),o!==void 0&&(d.iconUrl=o),this.mem[t][n]=d;return}let a={group:t,name:n,count:i};s!==void 0&&(a.desc=s),o!==void 0&&(a.icon_url=o),await this.http.post(`/conversations/${this.getConversationId()}/inventory`,a)}async update(e){let{group:t,name:n,count:i,desc:s,iconUrl:o}=e;if(this.isPreview){let d=this.mem[t];if(!d||!(n in d))throw new Error(`Item "${t}/${n}" not found`);let l=d[n];i!==void 0&&(l.count=i),s!==void 0&&(l.desc=s),o!==void 0&&(l.iconUrl=o);return}let a={};i!==void 0&&(a.count=i),s!==void 0&&(a.desc=s),o!==void 0&&(a.icon_url=o),await this.http.patch(`/conversations/${this.getConversationId()}/inventory/${encodeURIComponent(t)}/${encodeURIComponent(n)}`,a)}async remove(e){let{group:t,name:n}=e;if(this.isPreview){this.mem[t]&&delete this.mem[t][n];return}await this.http.delete(`/conversations/${this.getConversationId()}/inventory/${encodeURIComponent(t)}/${encodeURIComponent(n)}`)}async move(e){let{fromGroup:t,toGroup:n,name:i,newName:s}=e;if(this.isPreview){let o=this.mem[t];if(!o||!(i in o))throw new Error(`Source item "${t}/${i}" not found`);if(!this.mem[n])throw new Error(`Target group "${n}" does not exist`);let a=s||i;if(t===n&&a===i)return;if(a in this.mem[n])throw new Error(`Item "${a}" already exists in target group`);this.mem[n][a]=o[i],delete o[i];return}await this.http.post(`/conversations/${this.getConversationId()}/inventory/move`,{fromGroup:t,toGroup:n,name:i,newName:s})}async ensureGroup(e){if(this.isPreview){this.mem[e]||(this.mem[e]={});return}await this.http.post(`/conversations/${this.getConversationId()}/inventory/groups/${encodeURIComponent(e)}`,{})}async removeGroup(e,t){let n=t?.cascade??!1;if(this.isPreview){let s=this.mem[e];if(s&&Object.keys(s).length>0&&!n)throw new Error(`Group "${e}" is not empty, pass cascade: true to force delete`);delete this.mem[e];return}let i=n?"?cascade=true":"";await this.http.delete(`/conversations/${this.getConversationId()}/inventory/groups/${encodeURIComponent(e)}${i}`)}};var M=class{constructor(e,t,n=!1,i){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={};i&&(this.mem={...i})}setInitial(e){this.mem=e?{...e}:{}}async get(){return this.isPreview?{...this.mem}:this.http.get(`/conversations/${this.getConversationId()}/world`)}async update(e){if(this.isPreview){Object.assign(this.mem,e);return}await this.http.patch(`/conversations/${this.getConversationId()}/world`,e)}};var K=class{constructor(e,t,n=!1,i){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={};i&&(this.mem={...i})}setInitial(e){this.mem=e?{...e}:{}}async get(e){if(this.isPreview)return e?{...this.mem[e]||{}}:{...this.mem};let t=e?{group:e}:void 0;return this.http.get(`/conversations/${this.getConversationId()}/player/state`,t)}async update(e,t){if(this.isPreview){this.mem[e]={...this.mem[e]||{},...t};return}await this.http.patch(`/conversations/${this.getConversationId()}/player/state`,{group:e,values:t})}},O=class{constructor(e,t,n=!1,i,s){this.http=e;this.getConversationId=t;this.isPreview=n;this.memPersona={name:""};i&&(this.memPersona={...i}),this.state=new K(e,t,n,s)}setInitial(e,t){this.memPersona=e?{...e}:{name:""},this.state.setInitial(t)}async get(){return this.isPreview?{...this.memPersona}:this.http.get(`/conversations/${this.getConversationId()}/player`)}async update(e){if(this.isPreview){Object.assign(this.memPersona,e);return}await this.http.patch(`/conversations/${this.getConversationId()}/player`,e)}};var _=class{constructor(e,t,n=!1,i,s){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={};this.memInject={};i&&(this.mem=ie(i)),s&&(this.memInject={...s})}setInitial(e,t){this.mem=e?ie(e):{},this.memInject=t?{...t}:{}}async get(e){if(this.isPreview)return e!==void 0?this.mem[e]:{...this.mem};let t=await this.http.get(`/conversations/${this.getConversationId()}/custom`);return e!==void 0?t[e]:t}async set(e,t){if(this.isPreview){for(let[i,s]of Object.entries(e))typeof s=="object"&&s!==null&&typeof this.mem[i]=="object"&&this.mem[i]!==null?this.mem[i]={...this.mem[i],...s}:this.mem[i]=s,t?.inject!==void 0&&(this.memInject[i]=t.inject);return}let n=t?.inject!==void 0?{data:e,inject:t.inject}:e;await this.http.patch(`/conversations/${this.getConversationId()}/custom`,n)}async setInject(e,t){if(this.isPreview){this.memInject[e]=t;return}await this.http.patch(`/conversations/${this.getConversationId()}/custom/inject/${encodeURIComponent(e)}`,{inject:t})}getInject(){return{...this.memInject}}async delete(e){if(this.isPreview){delete this.mem[e],delete this.memInject[e];return}await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}`)}async setGroupField(e,t,n){if(this.isPreview){(!this.mem[e]||typeof this.mem[e]!="object")&&(this.mem[e]={}),this.mem[e][t]=n;return}await this.http.patch(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{value:n})}async deleteGroupField(e,t){if(this.isPreview){if(typeof this.mem[e]=="object"&&this.mem[e]!==null){let n=this.mem[e];delete n[t]}return}await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)}};function ie(r){let e={};for(let[t,n]of Object.entries(r))typeof n=="object"&&n!==null&&!Array.isArray(n)?e[t]={...n}:e[t]=n;return e}var D=class{constructor(e,t,n=!1,i){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={};i&&(this.mem={...i})}setInitial(e){this.mem=e?{...e}:{}}async get(){return this.isPreview?{...this.mem}:await this.http.get(`/conversations/${this.getConversationId()}/save`)}async set(e){if(this.isPreview){this.mem={...e};return}await this.http.put(`/conversations/${this.getConversationId()}/save`,e)}};var N=1;function U(r){if(!r||typeof r!="object")return!1;let e=r;return typeof e.protocol=="number"&&typeof e.type=="string"&&"payload"in e}function x(r,e,t){return{protocol:1,type:r,payload:e,...t?.id?{id:t.id}:{},...t?.ackId?{ackId:t.ackId}:{}}}var I=class{constructor(e){this.handlers=new Map;this.pendingAcks=new Map;this.listener=null;this.incoming=e.incoming,this.getOutgoing=e.outgoing,this.verifySource=e.verifySource??(()=>!0),this.validate=e.validate,this.debug=!!e.debug,this.getTransferables=e.transfer??(()=>{}),this.attach()}attach(){this.listener=e=>{if((this.incoming instanceof Window||this.incoming===window)&&!this.verifySource(e))return;let t=e.data;if(!U(t))return;if(t.protocol!==1){this.debug&&console.warn("[StorviaBus] protocol mismatch",{expected:1,got:t.protocol,type:t.type});return}if(this.validate&&!this.validate(t)){this.debug&&console.warn("[StorviaBus] validation failed",t);return}if(t.ackId){let i=this.pendingAcks.get(t.ackId);if(i){this.pendingAcks.delete(t.ackId),i(t);return}}let n=this.handlers.get(t.type);if(!n||n.size===0){this.debug&&console.debug("[StorviaBus] no handler for",t.type);return}n.forEach(i=>{try{i(t)}catch(s){console.error(`[StorviaBus] handler '${t.type}' threw:`,s)}})},this.incoming.addEventListener("message",this.listener),this.incoming instanceof MessagePort&&this.incoming.start()}on(e,t){let n=this.handlers.get(e);n||(n=new Set,this.handlers.set(e,n));let i=t;return n.add(i),()=>n.delete(i)}send(e){let t=this.getOutgoing();if(!t){this.debug&&console.warn("[StorviaBus] outgoing target unavailable, drop:",e.type);return}let n=e.protocol?e:x(e.type,e.payload,{id:e.id,ackId:e.ackId}),i=this.getTransferables(n);try{t instanceof MessagePort?t.postMessage(n,i??[]):t.postMessage(n,"*",i??[])}catch(s){console.error("[StorviaBus] postMessage failed:",s,{type:e.type})}}request(e,t=1e4){return new Promise((n,i)=>{let s=e.id??Re(),o=x(e.type,e.payload,{id:s}),a=setTimeout(()=>{this.pendingAcks.delete(s),i(new Error(`[StorviaBus] request '${e.type}' timed out after ${t}ms`))},t);this.pendingAcks.set(s,d=>{clearTimeout(a),n(d)}),this.send(o)})}destroy(){if(this.listener&&(this.incoming.removeEventListener("message",this.listener),this.listener=null),this.incoming instanceof MessagePort)try{this.incoming.close()}catch{}this.handlers.clear(),this.pendingAcks.clear()}};function Re(){return`bus-${Date.now()}-${Math.random().toString(36).slice(2,8)}`}var se="/functions/v1/world-engine/v1",Te="https://api.storvia.ai";function ke(){return window.__STORVIA__||{}}function Me(r,e=3e4){let t=ke();return t.apiBase?Promise.resolve(t):new Promise((n,i)=>{let s=setTimeout(()=>{o(),a(),i(new g("NOT_INITIALIZED","Timed out waiting for __STORVIA__ config from parent frame."))},e),o=r.on("init",l=>{l.payload?.apiBase&&d({apiBase:l.payload.apiBase,gameId:l.payload.gameId,accessToken:l.payload.accessToken,debug:l.payload.debug})}),a=r.on("preview-init",l=>{l.payload?.apiBase&&d(l.payload)});function d(l){clearTimeout(s),o(),a();let h=window;h.__STORVIA__=l,n(l)}r.send(x("ready",{}))})}var B=class{constructor(){this.baseUrl="";this.gameId="";this.conversationId="";this.modelId="";this.models=[];this.accessToken="";this.initialized=!1;this.isPreview=!1;this.previewConfig=void 0}async init(){if(this.initialized)return;this.bus=new I({incoming:window,outgoing:()=>window.parent,verifySource:c=>c.source===window.parent});let e=await Me(this.bus),t=e.apiBase;if(!t)throw new g("NOT_INITIALIZED","window.__STORVIA__.apiBase is not set. The platform must inject it before SDK init.");if(this.baseUrl=`${t}${se}`,this.isPreview=!!e.preview,this.previewConfig=e.previewConfig,!e.gameId)throw new g("GAME_NOT_FOUND","window.__STORVIA__.gameId is not set. The platform must inject it before SDK init.");if(this.gameId=e.gameId,!e.accessToken)throw new g("UNAUTHORIZED","window.__STORVIA__.accessToken is not set. The platform must inject the user token before SDK init.");if(this.accessToken=e.accessToken,this.http=new $(this.baseUrl,this.accessToken,!!e.debug),this.isPreview){this.conversationId="00000000-0000-0000-0000-000000000000";let[c,p]=await Promise.all([this.fetchModels(),this.fetchPreviewSnapshot()]);this.models=c;let m=this.getSavedModelId();this.modelId=e.selectedModelId||(m&&c.some(w=>w.id===m)?m:"")||c[0]?.id||"",this.settingsSheet=new S({onModelChange:w=>{this.modelId=w},onSettingsChange:()=>Promise.resolve(),onSync:()=>Promise.resolve()}),c.length>0&&this.settingsSheet.mount(c,this.modelId,{temperature:1,replyLength:"medium",replyLanguage:"zh-CN",playerNote:""},!1);let f=()=>this.gameId,v=()=>this.conversationId,L=()=>this.modelId,E=()=>this.models.find(w=>w.id===this.modelId)?.name;this.chat=new P(this.http,f,v,L,!0,this.previewConfig,()=>this.settingsSheet?.getSettings()??null,E),this.characters=new R(this.http,v,!0,p?.characters,p?.characterStates),this.relationships=new T(this.http,v,!0,p?.relationships),this.inventory=new k(this.http,v,!0,p?.inventory),this.world=new M(this.http,v,!0,p?.world),this.player=new O(this.http,v,!0,p?.player,p?.playerState),this.custom=new _(this.http,v,!0,p?.custom,p?.custom_inject),this.save=new D(this.http,v,!0,p?.save_data),this.initialized=!0,this.listenForPreviewMessages(),this.listenForTokenUpdate();return}let[n,i]=await Promise.all([this.authenticate(),this.fetchModels()]);this.conversationId=n.conversationId,this.models=i;let s=this.getSavedModelId();this.modelId=s&&i.some(c=>c.id===s)?s:i[0]?.id||"";let o=n.settings,a=o?{temperature:o.temperature??1,replyLength:o.reply_length??"medium",replyLanguage:o.reply_language??"zh-CN",playerNote:o.player_note??""}:{temperature:1,replyLength:"medium",replyLanguage:"zh-CN",playerNote:""};this.settingsSheet=new S({onModelChange:c=>{this.modelId=c},onSettingsChange:c=>this.saveSettings(c),onSync:()=>this.syncSettings()}),this.settingsSheet.mount(i,this.modelId,a,n.hasWorldUpdate??!1);let d=()=>this.gameId,l=()=>this.conversationId,h=()=>this.modelId,u=()=>this.models.find(c=>c.id===this.modelId)?.name;this.chat=new P(this.http,d,l,h,!1,void 0,void 0,u),this.characters=new R(this.http,l),this.relationships=new T(this.http,l),this.inventory=new k(this.http,l),this.world=new M(this.http,l),this.player=new O(this.http,l),this.custom=new _(this.http,l),this.save=new D(this.http,l),this.listenForTokenUpdate(),this.initialized=!0}listenForTokenUpdate(){this.bus.on("token-update",e=>{let t=e.payload?.accessToken;typeof t!="string"||!t||(this.accessToken=t,this.http?.setToken(t))})}listenForPreviewMessages(){this.bus.on("set-model",e=>{this.modelId=e.payload.modelId||""}),this.bus.on("config-update",e=>{this.previewConfig=e.payload.previewConfig,this.chat&&this.chat.updatePreviewConfig(this.previewConfig),this.refreshPreviewSnapshot().catch(t=>{console.warn("[Storvia SDK] refreshPreviewSnapshot failed:",t)})})}async fetchPreviewSnapshot(){try{let e={game_id:this.gameId};return this.previewConfig&&("game_config"in this.previewConfig&&(e.game_config=this.previewConfig.game_config),"game_state"in this.previewConfig&&(e.game_state_override=this.previewConfig.game_state)),await this.http.post("/preview/initial-snapshot",e)}catch(e){return console.warn("[Storvia SDK] fetchPreviewSnapshot failed:",e),null}}async refreshPreviewSnapshot(){let e=await this.fetchPreviewSnapshot();e&&(this.characters?.setInitial(e.characters,e.characterStates),this.player?.setInitial(e.player,e.playerState),this.inventory?.setInitial(e.inventory),this.relationships?.setInitial(e.relationships),this.world?.setInitial(e.world),this.custom?.setInitial(e.custom,e.custom_inject),this.save?.setInitial(e.save_data))}async saveSettings(e){let t={conversation_id:this.conversationId};e.temperature!==void 0&&(t.temperature=e.temperature),e.replyLength!==void 0&&(t.reply_length=e.replyLength),e.replyLanguage!==void 0&&(t.reply_language=e.replyLanguage),e.playerNote!==void 0&&(t.player_note=e.playerNote),await this.http.patch("/settings",t)}async syncSettings(){await this.http.post("/sync",{conversation_id:this.conversationId})}async fetchModels(){try{return await this.http.get("/models")}catch{}return[]}async authenticate(){let e=await fetch(`${this.baseUrl}/auth`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.accessToken}`},body:JSON.stringify({game_id:this.gameId})});if(!e.ok)throw e.status===401?new g("UNAUTHORIZED","User not authenticated"):e.status===404?new g("GAME_NOT_FOUND","Game not found or not published"):new g("INTERNAL_ERROR",`Auth failed: HTTP ${e.status}`);let t=await e.json();return t.data??t}getSavedModelId(){try{return localStorage.getItem("storvia_model_id")||""}catch{return""}}async initDev(e){if(this.initialized)return;this.baseUrl=`${Te}${se}`,this.gameId=e.gameId,this.isPreview=!0,this.http=new $(this.baseUrl,"",!1,e.apiKey);let[t,n]=await Promise.all([this.fetchModels(),this.fetchPreviewSnapshot()]);this.models=t;let i=this.getSavedModelId();this.modelId=(i&&t.some(l=>l.id===i)?i:"")||t[0]?.id||"",this.conversationId="00000000-0000-0000-0000-000000000000",this.settingsSheet=new S({onModelChange:l=>{this.modelId=l},onSettingsChange:()=>Promise.resolve(),onSync:()=>Promise.resolve()}),t.length>0&&this.settingsSheet.mount(t,this.modelId,{temperature:1,replyLength:"medium",replyLanguage:"zh-CN",playerNote:""},!1);let s=()=>this.gameId,o=()=>this.conversationId,a=()=>this.modelId,d=()=>this.models.find(l=>l.id===this.modelId)?.name;this.chat=new P(this.http,s,o,a,!0,void 0,()=>this.settingsSheet?.getSettings()??null,d),this.characters=new R(this.http,o,!0,n?.characters,n?.characterStates),this.relationships=new T(this.http,o,!0,n?.relationships),this.inventory=new k(this.http,o,!0,n?.inventory),this.world=new M(this.http,o,!0,n?.world),this.player=new O(this.http,o,!0,n?.player,n?.playerState),this.custom=new _(this.http,o,!0,n?.custom),this.save=new D(this.http,o,!0,n?.save_data),this.initialized=!0}};async function oe(r){let e=new B;return r?.dev?await e.initDev(r.dev):await e.init(),e}function Y(r){return typeof r=="object"&&r!==null&&"value"in r&&"type"in r&&(r.type==="number"||r.type==="text")}function re(r){return Y(r)?r.value:r}0&&(module.exports={PROTOCOL_VERSION,StorviaBus,StorviaError,StorviaSDK,createStorviaSDK,envelope,extractFieldValue,isProtocolEnvelope,isRichFieldValue,setToastEnabled,showToast});
package/dist/index.d.mts CHANGED
@@ -387,17 +387,26 @@ type CustomScalar = string | number;
387
387
  type CustomGroup = Record<string, CustomScalar>;
388
388
  /** 顶层值:scalar 或分组对象 */
389
389
  type CustomValue = CustomScalar | CustomGroup;
390
+ interface CustomSetOptions {
391
+ /** 这次写入的所有 key 都标记为对应的 inject 状态(true = 注入 AI,false = 不注入) */
392
+ inject?: boolean;
393
+ }
390
394
  declare class CustomModule {
391
395
  private http;
392
396
  private getConversationId;
393
397
  private isPreview;
394
398
  private mem;
395
- constructor(http: HttpClient, getConversationId: () => string, isPreview?: boolean, initialCustom?: Record<string, unknown>);
399
+ private memInject;
400
+ constructor(http: HttpClient, getConversationId: () => string, isPreview?: boolean, initialCustom?: Record<string, unknown>, initialInject?: Record<string, boolean>);
396
401
  /** 预览模式下重新灌入初始数据(previewConfig 变更时调用) */
397
- setInitial(initialCustom: Record<string, unknown> | undefined): void;
402
+ setInitial(initialCustom: Record<string, unknown> | undefined, initialInject?: Record<string, boolean>): void;
398
403
  get(): Promise<Record<string, unknown>>;
399
404
  get(key: string): Promise<unknown>;
400
- set(data: Record<string, CustomValue>): Promise<void>;
405
+ set(data: Record<string, CustomValue>, options?: CustomSetOptions): Promise<void>;
406
+ /** 单独切某个 key 的 AI 追踪状态(不修改值) */
407
+ setInject(key: string, inject: boolean): Promise<void>;
408
+ /** 读取当前所有 key 的 inject 状态(创作台预设 + SDK 写入合并后的运行时映射) */
409
+ getInject(): Record<string, boolean>;
401
410
  delete(key: string): Promise<void>;
402
411
  setGroupField(groupKey: string, fieldKey: string, value: CustomScalar): Promise<void>;
403
412
  deleteGroupField(groupKey: string, fieldKey: string): Promise<void>;
@@ -438,6 +447,7 @@ declare class StorviaSDK {
438
447
  private initialized;
439
448
  private isPreview;
440
449
  private previewConfig;
450
+ private bus;
441
451
  chat: ChatModule;
442
452
  characters: CharactersModule;
443
453
  relationships: RelationshipsModule;
@@ -448,15 +458,12 @@ declare class StorviaSDK {
448
458
  save: SaveModule;
449
459
  init(): Promise<void>;
450
460
  /**
451
- * 监听父页面发来的 token 刷新消息:
452
- * { type: 'storvia-token-update', accessToken: '<new jwt>' }
453
- *
454
- * Supabase JWT 默认 1h 过期,父页面 session 自动刷新后必须把新 token 同步进来,
455
- * 否则 iframe 内 SDK 一直用旧 token 请求会被服务端 401。
456
- * 预览模式和正式模式都需要。
461
+ * 监听父页面 token 刷新(envelope 'token-update')。
462
+ * Supabase JWT 默认 1h 过期,父页面 session 自动刷新后转发新 token 进来,
463
+ * 否则 SDK 会一直用旧 token 请求被服务端 401。
457
464
  */
458
465
  private listenForTokenUpdate;
459
- /** 监听父页面 postMessage(预览模式) */
466
+ /** 监听父页面发来的预览模式动态更新(envelope 'config-update' / 'set-model') */
460
467
  private listenForPreviewMessages;
461
468
  /**
462
469
  * 调用 POST /preview/initial-snapshot 拉取与正式发布等价的初始数据
@@ -494,4 +501,152 @@ type ToastType = 'success' | 'error' | 'warning' | 'info';
494
501
  declare function setToastEnabled(enabled: boolean): void;
495
502
  declare function showToast(message: string, type?: ToastType, duration?: number): void;
496
503
 
497
- export { type CharacterAddOptions, type CharacterDetail, type CharacterPersona, type CharacterUpdateOptions, type ChatGenerateOptions, type ChatMessage, type ChatMessageCursor, type ChatMessagesOptions, type ChatMessagesResponse, type ChatResponse, type ChatRetryOptions, type ChatSaveOptions, type ChatSendOptions, type FieldValue, type Gender, type InventoryAddOptions, type InventoryMoveOptions, type InventoryRemoveGroupOptions, type InventoryRemoveOptions, type InventoryState, type InventoryUpdateOptions, type ItemData, type PlayerPersona, type Relationship, type RichFieldValue, StorviaError, type StorviaErrorCode, StorviaSDK, createStorviaSDK, extractFieldValue, isRichFieldValue, setToastEnabled, showToast };
504
+ /**
505
+ * 父子 iframe postMessage 协议类型
506
+ *
507
+ * 设计要点:
508
+ * - 所有消息使用 ProtocolEnvelope 包裹,统一带 protocol 版本号
509
+ * - DownstreamMsg = 父 → 子;UpstreamMsg = 子 → 父
510
+ * - SDK 与主站共享同一份类型,避免字符串散落
511
+ *
512
+ * 协议版本:
513
+ * 1 = 握手 + 类型化 bus 首版(当前)
514
+ */
515
+ declare const PROTOCOL_VERSION = 1;
516
+ interface ProtocolEnvelope<T extends string, P> {
517
+ /** 协议版本,用于将来破坏性变更时双方判断 */
518
+ protocol: number;
519
+ /** 消息类型(union 区分) */
520
+ type: T;
521
+ /** 消息载荷 */
522
+ payload: P;
523
+ /** 用于 ack 的关联 id(可选) */
524
+ id?: string;
525
+ /** 这是对哪条消息的 ack(可选) */
526
+ ackId?: string;
527
+ }
528
+ /** 正式环境 init payload */
529
+ interface InitPayload {
530
+ apiBase: string;
531
+ gameId: string;
532
+ accessToken: string;
533
+ debug?: boolean;
534
+ }
535
+ interface PreviewConfig {
536
+ game_prompt?: string | null;
537
+ game_config?: Record<string, unknown>;
538
+ game_state?: Record<string, unknown> | null;
539
+ persona_settings?: Record<string, unknown>;
540
+ reply_length?: string;
541
+ reply_language?: string;
542
+ }
543
+ /** 预览环境 init payload —— 比 InitPayload 多 preview 配置 */
544
+ interface PreviewInitPayload {
545
+ apiBase: string;
546
+ gameId: string;
547
+ accessToken: string;
548
+ preview: true;
549
+ previewConfig?: PreviewConfig;
550
+ models?: Array<{
551
+ id: string;
552
+ name: string;
553
+ provider?: string;
554
+ }>;
555
+ selectedModelId?: string;
556
+ debug?: boolean;
557
+ }
558
+ interface TokenUpdatePayload {
559
+ accessToken: string;
560
+ }
561
+ interface ConfigUpdatePayload {
562
+ previewConfig: PreviewConfig;
563
+ }
564
+ interface SetModelPayload {
565
+ modelId: string;
566
+ }
567
+ interface OrientationPayload {
568
+ mode: 'landscape' | 'portrait';
569
+ }
570
+ interface ReadyPayload {
571
+ /** 标识 SDK 是否运行在预览模式(父侧据此选择 init 还是 preview-init) */
572
+ isPreview?: boolean;
573
+ }
574
+ interface SdkErrorPayload {
575
+ code: string;
576
+ message: string;
577
+ recoverable: boolean;
578
+ }
579
+ interface AckPayload {
580
+ ok: boolean;
581
+ error?: string;
582
+ }
583
+ type DownstreamMsg = ProtocolEnvelope<'init', InitPayload> | ProtocolEnvelope<'preview-init', PreviewInitPayload> | ProtocolEnvelope<'token-update', TokenUpdatePayload> | ProtocolEnvelope<'config-update', ConfigUpdatePayload> | ProtocolEnvelope<'set-model', SetModelPayload> | ProtocolEnvelope<'orientation', OrientationPayload> | ProtocolEnvelope<'ack', AckPayload>;
584
+ type UpstreamMsg = ProtocolEnvelope<'ready', ReadyPayload> | ProtocolEnvelope<'exit', Record<string, never>> | ProtocolEnvelope<'request-orientation', OrientationPayload> | ProtocolEnvelope<'error', SdkErrorPayload> | ProtocolEnvelope<'ack', AckPayload>;
585
+ declare function isProtocolEnvelope(data: unknown): data is ProtocolEnvelope<string, unknown>;
586
+ declare function envelope<T extends string, P>(type: T, payload: P, opts?: {
587
+ id?: string;
588
+ ackId?: string;
589
+ }): ProtocolEnvelope<T, P>;
590
+
591
+ /**
592
+ * StorviaBus —— 类型化的 postMessage 总线
593
+ *
594
+ * 同时支持两种 transport:
595
+ * - window.postMessage(默认 / fallback)
596
+ * - MessagePort(Phase 4 升级路径,由父侧握手时下发)
597
+ *
598
+ * 收到 envelope 时:
599
+ * 1. 校验 protocol 版本
600
+ * 2. 校验 source(防止任意 iframe 注入)
601
+ * 3. dispatch 到对应 type 的 handler
602
+ *
603
+ * 用法:
604
+ * const bus = new StorviaBus<DownstreamMsg, UpstreamMsg>({
605
+ * // 子侧:消息从父来;发回父
606
+ * incoming: window,
607
+ * outgoing: () => window.parent,
608
+ * verifySource: (e) => e.source === window.parent,
609
+ * })
610
+ * bus.on('init', (msg) => { ... msg.payload ... })
611
+ * bus.send({ type: 'ready', payload: { isPreview: false } })
612
+ */
613
+
614
+ type AnyEnvelope = ProtocolEnvelope<string, unknown>;
615
+ interface StorviaBusOptions<TIn extends AnyEnvelope> {
616
+ /** 监听消息的 EventTarget(通常是 window;也可以是 MessagePort) */
617
+ incoming: EventTarget | MessagePort;
618
+ /** 发送消息的目标。函数式,便于 iframe 还没渲染时也能挂 bus */
619
+ outgoing: () => Window | MessagePort | null | undefined;
620
+ /** 来源校验:父侧通常 e.source === iframe.contentWindow,子侧 e.source === window.parent */
621
+ verifySource?: (event: MessageEvent) => boolean;
622
+ /** 入站消息 schema 校验,返回 false 时静默丢弃 */
623
+ validate?: (data: unknown) => data is TIn;
624
+ /** 调试日志开关 */
625
+ debug?: boolean;
626
+ /** transferable objects 的回调(用于 Phase 4 MessageChannel) */
627
+ transfer?: (msg: AnyEnvelope) => Transferable[] | undefined;
628
+ }
629
+ declare class StorviaBus<TIn extends AnyEnvelope, TOut extends AnyEnvelope> {
630
+ private incoming;
631
+ private getOutgoing;
632
+ private verifySource;
633
+ private validate;
634
+ private debug;
635
+ private getTransferables;
636
+ private handlers;
637
+ private pendingAcks;
638
+ private listener;
639
+ constructor(opts: StorviaBusOptions<TIn>);
640
+ private attach;
641
+ /** 监听某类消息,返回取消订阅函数 */
642
+ on<K extends TIn['type']>(type: K, handler: (msg: Extract<TIn, {
643
+ type: K;
644
+ }>) => void): () => void;
645
+ /** 发出一条消息(不等 ack) */
646
+ send(msg: TOut): void;
647
+ /** 发出一条消息并等待 ack(默认 10s 超时) */
648
+ request(msg: TOut, timeoutMs?: number): Promise<TIn>;
649
+ destroy(): void;
650
+ }
651
+
652
+ export { type AckPayload, type CharacterAddOptions, type CharacterDetail, type CharacterPersona, type CharacterUpdateOptions, type ChatGenerateOptions, type ChatMessage, type ChatMessageCursor, type ChatMessagesOptions, type ChatMessagesResponse, type ChatResponse, type ChatRetryOptions, type ChatSaveOptions, type ChatSendOptions, type ConfigUpdatePayload, type DownstreamMsg, type FieldValue, type Gender, type InitPayload, type InventoryAddOptions, type InventoryMoveOptions, type InventoryRemoveGroupOptions, type InventoryRemoveOptions, type InventoryState, type InventoryUpdateOptions, type ItemData, type OrientationPayload, PROTOCOL_VERSION, type PlayerPersona, type PreviewConfig, type PreviewInitPayload, type ProtocolEnvelope, type ReadyPayload, type Relationship, type RichFieldValue, type SdkErrorPayload, type SetModelPayload, StorviaBus, type StorviaBusOptions, StorviaError, type StorviaErrorCode, StorviaSDK, type TokenUpdatePayload, type UpstreamMsg, createStorviaSDK, envelope, extractFieldValue, isProtocolEnvelope, isRichFieldValue, setToastEnabled, showToast };