@storvia/sdk 0.5.2 → 0.5.4
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 +11 -11
- package/dist/index.d.mts +186 -4
- package/dist/index.esm.js +11 -11
- package/dist/index.umd.js +11 -11
- package/package.json +1 -1
package/dist/index.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
#${
|
|
1
|
+
"use strict";var z=Object.defineProperty;var ae=Object.getOwnPropertyDescriptor;var de=Object.getOwnPropertyNames;var le=Object.prototype.hasOwnProperty;var ce=(o,e)=>{for(var t in e)z(o,t,{get:e[t],enumerable:!0})},pe=(o,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of de(e))!le.call(o,i)&&i!==t&&z(o,i,{get:()=>e[i],enumerable:!(n=ae(e,i))||n.enumerable});return o};var he=o=>pe(z({},"__esModule",{value:!0}),o);var Oe={};ce(Oe,{PROTOCOL_VERSION:()=>N,StorviaBus:()=>I,StorviaError:()=>g,StorviaSDK:()=>B,createStorviaSDK:()=>re,envelope:()=>x,extractFieldValue:()=>oe,isProtocolEnvelope:()=>U,isRichFieldValue:()=>Y,setToastEnabled:()=>Z,showToast:()=>V});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
|
-
`,
|
|
80
|
-
<span class="storvia-toast-icon">${
|
|
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(o){q=o}function ve(){if(typeof document>"u")return null;let o=document.getElementById(H);if(!o){if(!document.getElementById(X)){let e=document.createElement("style");e.id=X,e.textContent=ge,document.head.appendChild(e)}o=document.createElement("div"),o.id=H,document.body.appendChild(o)}return o}function V(o,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
|
|
83
|
-
`);for(let w of
|
|
82
|
+
`;let s=i.querySelector(".storvia-toast-msg");s&&(s.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 F(o,e){let t=me[o]||e||"\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5";V(t,o==="INSUFFICIENT_CREDITS"||o==="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:r,parsedData:a,error:d,durationMs:l,modelName:p}=e,u="%c[Storvia SDK]",c="color: #6366f1; font-weight: bold",h=l!==void 0?` (${l}ms)`:"",m=s!==void 0?` [${s}]`:"",f=p?` [model: ${p}]`:"";d?(console.groupCollapsed(`${u} %c${t} ${n}${m}${f}${h} %c\u2717`,c,"color: #e0e0e0","color: #ef4444"),i!==void 0&&console.log("Request:",i),r!==void 0&&console.log("Response (raw):",r),console.error("Error:",d),console.groupEnd()):(console.groupCollapsed(`${u} %c${t} ${n}${m}${f}${h} %c\u2713`,c,"color: #e0e0e0","color: #22c55e"),i!==void 0&&console.log("Request:",i),r!==void 0&&console.log("Response (raw):",r),a!==void 0&&a!==r&&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,r;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 r=d,this.log({method:"GET",path:e,body:t,status:s,rawResponse:r,parsedData:l,durationMs:Date.now()-i}),l}catch(a){throw this.log({method:"GET",path:e,body:t,status:s,rawResponse:r,error:a,durationMs:Date.now()-i}),this.maybeShowNetworkToast(a),a}}async post(e,t,n){let i=Date.now(),s,r;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 r=d,this.log({method:"POST",path:e,body:t,status:s,rawResponse:r,parsedData:l,durationMs:Date.now()-i,modelName:n?.modelName}),l}catch(a){throw this.log({method:"POST",path:e,body:t,status:s,rawResponse:r,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 r=await fetch(`${this.baseUrl}${e}`,{method:"PATCH",headers:this.buildHeaders(),body:t?JSON.stringify(t):void 0});i=r.status;let{raw:a,data:d}=await this.handleResponseWithRaw(r);return s=a,this.log({method:"PATCH",path:e,body:t,status:i,rawResponse:s,parsedData:d,durationMs:Date.now()-n}),d}catch(r){throw this.log({method:"PATCH",path:e,body:t,status:i,rawResponse:s,error:r,durationMs:Date.now()-n}),this.maybeShowNetworkToast(r),r}}async put(e,t){let n=Date.now(),i,s;try{let r=await fetch(`${this.baseUrl}${e}`,{method:"PUT",headers:this.buildHeaders(),body:t?JSON.stringify(t):void 0});i=r.status;let{raw:a,data:d}=await this.handleResponseWithRaw(r);return s=a,this.log({method:"PUT",path:e,body:t,status:i,rawResponse:s,parsedData:d,durationMs:Date.now()-n}),d}catch(r){throw this.log({method:"PUT",path:e,body:t,status:i,rawResponse:s,error:r,durationMs:Date.now()-n}),this.maybeShowNetworkToast(r),r}}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:r,data:a}=await this.handleResponseWithRaw(s);return i=r,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 r=Date.now(),a=s?.modelName?` [model: ${s.modelName}]`:"",d=[],l=f=>{this.debug&&d.push({t:Date.now()-r,event:f})},p=await fetch(`${this.baseUrl}${e}`,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(t)});if(!p.ok){let f=await p.text().catch(()=>""),v={};try{v=JSON.parse(f)}catch{}let L=v.code||"INTERNAL_ERROR",E=new g(L,v.message||`HTTP ${p.status}`);throw F(L,v.message),this.log({method:"STREAM",path:e,body:t,status:p.status,rawResponse:f,error:E,durationMs:Date.now()-r,modelName:s?.modelName}),E}let u=p.body?.getReader();if(!u)throw new g("INTERNAL_ERROR","No response body for stream");let c=new TextDecoder,h="",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} [${p.status}]${a} (${Date.now()-r}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:",h),console.log(`SSE events (${d.length}):`,d),console.groupEnd()),i(h);return}try{let C=JSON.parse(G);l(C),C.type==="done"&&C.id?h=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} [${p.status}]${a} (${Date.now()-r}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}h&&i(h)}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"},r=i.code||s[e.status]||"INTERNAL_ERROR",a=new g(r,i.message||`HTTP ${e.status}`);throw F(r,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
|
-
`,
|
|
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 r=document.createElement("div");r.className="panel",this.panel=r;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),r.appendChild(a);let p=document.createElement("div");p.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"),p.appendChild(this.modelTabBtn),p.appendChild(this.settingsTabBtn),r.appendChild(p);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),r.appendChild(u);let c=document.createElement("div");c.className="panel-footer";let h=document.createElement("button");h.className="btn btn-save",h.textContent="\u4FDD\u5B58",this.saveBtn=h,h.addEventListener("click",()=>this.handleSave()),c.appendChild(h),this.footer=c,r.appendChild(c),n.addEventListener("pointerdown",this.handlePointerDown);let m=document.createElement("div");m.appendChild(r),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 r=(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(p=>p.classList.remove("active")),l.classList.add("active"),this.renderModelGrid()}),l};s.appendChild(r("\u5168\u90E8",null)),t.forEach(a=>s.appendChild(r(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(r=>r.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="${
|
|
765
|
+
<img class="credits-icon" src="${ye}" alt="credits" />
|
|
766
766
|
<span class="credits-unit">/\u6B21</span>
|
|
767
767
|
</div>`:""}
|
|
768
|
-
${
|
|
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=[],K.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",K[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=N.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=[],N.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?Y:""}`,l.addEventListener("click",()=>{this.settings.replyLanguage=d.value,r.textContent=d.label,this.langOptions.forEach((h,m)=>{h.classList.toggle("active",N[m].value===d.value),h.innerHTML=`<span>${N[m].label}</span>${N[m].value===d.value?Y:""}`}),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:fe,loading:ve,success:be,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=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[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 H=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(X)),this.state=new H(e,t,n,r)}setInitial(e,t){this.mem=e?e.map(X):[],this.state.setInitial(t)}async list(){return this.isPreview?this.mem.map(q):this.http.get(`/conversations/${this.getConversationId()}/characters`)}async get(e){if(this.isPreview){let t=this.mem.find(n=>n.name===e);return t?q(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 X(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 q(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 Z(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 F(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]=Z(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]=Z(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=F(i))}setInitial(e){this.mem=e?F(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 F(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 G=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 G(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=J(i))}setInitial(e){this.mem=e?J(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&&!Array.isArray(n)&&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 J(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 Q="/functions/v1/world-engine/v1",Ce="https://api.storvia.ai";function Ie(){return window.__STORVIA__||{}}function Se(o=5e3){let e=Ie();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 _=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 Se(),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}${Q}`,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[c,p]=await Promise.all([this.fetchModels(),this.fetchPreviewSnapshot()]);this.models=c;let u=this.getSavedModelId();this.modelId=e.selectedModelId||(u&&c.some(w=>w.id===u)?u:"")||c[0]?.id||"",this.settingsSheet=new I({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,O=()=>this.modelId,C=()=>this.models.find(w=>w.id===this.modelId)?.name;this.chat=new S(this.http,f,v,O,!0,this.previewConfig,()=>this.settingsSheet?.getSettings()??null,C),this.characters=new E(this.http,v,!0,p?.characters,p?.characterStates),this.relationships=new R(this.http,v,!0,p?.relationships),this.inventory=new T(this.http,v,!0,p?.inventory),this.world=new k(this.http,v,!0,p?.world),this.player=new P(this.http,v,!0,p?.player,p?.playerState),this.custom=new M(this.http,v,!0,p?.custom),this.initialized=!0,this.listenForPreviewMessages();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(c=>c.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: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,m=()=>this.models.find(c=>c.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.initialized=!0}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))}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=`${Ce}${Q}`,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.initialized=!0}};async function ee(o){let e=new _;return o?.dev?await e.initDev(o.dev):await e.init(),e}function z(o){return typeof o=="object"&&o!==null&&"value"in o&&"type"in o&&(o.type==="number"||o.type==="text")}function te(o){return z(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>=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 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 r=document.createElement("input");r.type="range",r.className="slider",r.min="0",r.max="1",r.step="0.1",r.value=String(this.settings.temperature),r.addEventListener("input",()=>{let d=parseFloat(r.value);this.settings.temperature=d,this.tempValueEl&&(this.tempValueEl.textContent=d.toFixed(1))}),e.appendChild(r);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((r,a)=>{r.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 r=document.createElement("span");r.className="select-arrow",r.textContent="\u25BE",this.langArrow=r,i.appendChild(s),i.appendChild(r),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((p,u)=>{p.classList.toggle("active",A[u].value===d.value),p.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 r=document.createElement("textarea");return r.className="player-note-input",r.placeholder="\u5907\u6CE8",r.maxLength=50,r.rows=2,r.value=this.settings.playerNote,r.addEventListener("input",()=>{this.settings.playerNote=r.value,this.noteCounter&&(this.noteCounter.textContent=`${r.value.length}/50`)}),e.appendChild(r),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=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[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,r,a,d){this.http=e;this.getGameId=t;this.getConversationId=n;this.getModelId=i;this.isPreview=s;this.previewConfig=r,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 j=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 j(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(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 te(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 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(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 W(o){let e={};if(!o)return e;for(let[t,n]of Object.entries(o)){let i={};for(let[s,r]of Object.entries(n))i[s]=ne(r);e[t]=i}return e}function Pe(o){let e={};if(!o)return e;for(let[t,n]of Object.entries(o))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:r}=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),r!==void 0&&(d.iconUrl=r),this.mem[t][n]=d;return}let a={group:t,name:n,count:i};s!==void 0&&(a.desc=s),r!==void 0&&(a.icon_url=r),await this.http.post(`/conversations/${this.getConversationId()}/inventory`,a)}async update(e){let{group:t,name:n,count:i,desc:s,iconUrl:r}=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),r!==void 0&&(l.iconUrl=r);return}let a={};i!==void 0&&(a.count=i),s!==void 0&&(a.desc=s),r!==void 0&&(a.icon_url=r),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 r=this.mem[t];if(!r||!(i in r))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]=r[i],delete r[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){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={};i&&(this.mem=ie(i))}setInitial(e){this.mem=e?ie(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 ie(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 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(o){if(!o||typeof o!="object")return!1;let e=o;return typeof e.protocol=="number"&&typeof e.type=="string"&&"payload"in e}function x(o,e,t){return{protocol:1,type:o,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(),r=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(r)})}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(o,e=3e4){let t=ke();return t.apiBase?Promise.resolve(t):new Promise((n,i)=>{let s=setTimeout(()=>{r(),a(),i(new g("NOT_INITIALIZED","Timed out waiting for __STORVIA__ config from parent frame."))},e),r=o.on("init",l=>{l.payload?.apiBase&&d({apiBase:l.payload.apiBase,gameId:l.payload.gameId,accessToken:l.payload.accessToken,debug:l.payload.debug})}),a=o.on("preview-init",l=>{l.payload?.apiBase&&d(l.payload)});function d(l){clearTimeout(s),r(),a();let p=window;p.__STORVIA__=l,n(l)}o.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,h]=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,h?.characters,h?.characterStates),this.relationships=new T(this.http,v,!0,h?.relationships),this.inventory=new k(this.http,v,!0,h?.inventory),this.world=new M(this.http,v,!0,h?.world),this.player=new O(this.http,v,!0,h?.player,h?.playerState),this.custom=new _(this.http,v,!0,h?.custom),this.save=new D(this.http,v,!0,h?.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 r=n.settings,a=r?{temperature:r.temperature??1,replyLength:r.reply_length??"medium",replyLanguage:r.reply_language??"zh-CN",playerNote:r.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,p=()=>this.modelId,u=()=>this.models.find(c=>c.id===this.modelId)?.name;this.chat=new P(this.http,d,l,p,!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),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,r=()=>this.conversationId,a=()=>this.modelId,d=()=>this.models.find(l=>l.id===this.modelId)?.name;this.chat=new P(this.http,s,r,a,!0,void 0,()=>this.settingsSheet?.getSettings()??null,d),this.characters=new R(this.http,r,!0,n?.characters,n?.characterStates),this.relationships=new T(this.http,r,!0,n?.relationships),this.inventory=new k(this.http,r,!0,n?.inventory),this.world=new M(this.http,r,!0,n?.world),this.player=new O(this.http,r,!0,n?.player,n?.playerState),this.custom=new _(this.http,r,!0,n?.custom),this.save=new D(this.http,r,!0,n?.save_data),this.initialized=!0}};async function re(o){let e=new B;return o?.dev?await e.initDev(o.dev):await e.init(),e}function Y(o){return typeof o=="object"&&o!==null&&"value"in o&&"type"in o&&(o.type==="number"||o.type==="text")}function oe(o){return Y(o)?o.value:o}0&&(module.exports={PROTOCOL_VERSION,StorviaBus,StorviaError,StorviaSDK,createStorviaSDK,envelope,extractFieldValue,isProtocolEnvelope,isRichFieldValue,setToastEnabled,showToast});
|
package/dist/index.d.mts
CHANGED
|
@@ -20,6 +20,7 @@ declare class HttpClient {
|
|
|
20
20
|
modelName?: string;
|
|
21
21
|
}): Promise<T>;
|
|
22
22
|
patch<T>(path: string, body?: unknown): Promise<T>;
|
|
23
|
+
put<T>(path: string, body?: unknown): Promise<T>;
|
|
23
24
|
delete<T>(path: string): Promise<T>;
|
|
24
25
|
stream(path: string, body: unknown, onChunk: (text: string) => void, onDone: (id: string) => void, meta?: {
|
|
25
26
|
modelName?: string;
|
|
@@ -380,6 +381,12 @@ declare class PlayerModule {
|
|
|
380
381
|
update(data: Partial<PlayerPersona>): Promise<void>;
|
|
381
382
|
}
|
|
382
383
|
|
|
384
|
+
/** 字段值:文本或数值 */
|
|
385
|
+
type CustomScalar = string | number;
|
|
386
|
+
/** 分组:子字段全为 scalar */
|
|
387
|
+
type CustomGroup = Record<string, CustomScalar>;
|
|
388
|
+
/** 顶层值:scalar 或分组对象 */
|
|
389
|
+
type CustomValue = CustomScalar | CustomGroup;
|
|
383
390
|
declare class CustomModule {
|
|
384
391
|
private http;
|
|
385
392
|
private getConversationId;
|
|
@@ -390,12 +397,31 @@ declare class CustomModule {
|
|
|
390
397
|
setInitial(initialCustom: Record<string, unknown> | undefined): void;
|
|
391
398
|
get(): Promise<Record<string, unknown>>;
|
|
392
399
|
get(key: string): Promise<unknown>;
|
|
393
|
-
set(data: Record<string,
|
|
400
|
+
set(data: Record<string, CustomValue>): Promise<void>;
|
|
394
401
|
delete(key: string): Promise<void>;
|
|
395
|
-
setGroupField(groupKey: string, fieldKey: string, value:
|
|
402
|
+
setGroupField(groupKey: string, fieldKey: string, value: CustomScalar): Promise<void>;
|
|
396
403
|
deleteGroupField(groupKey: string, fieldKey: string): Promise<void>;
|
|
397
404
|
}
|
|
398
405
|
|
|
406
|
+
/**
|
|
407
|
+
* 游戏存档:作者自由读写的任意 JSON
|
|
408
|
+
* - 独立于 custom 的 40 字段配额
|
|
409
|
+
* - 永不注入 AI 提示词,AI 完全感知不到
|
|
410
|
+
* - 整体覆写语义(增量更新需自行 get → 修改 → set)
|
|
411
|
+
* - 序列化后上限 50KB
|
|
412
|
+
*/
|
|
413
|
+
declare class SaveModule {
|
|
414
|
+
private http;
|
|
415
|
+
private getConversationId;
|
|
416
|
+
private isPreview;
|
|
417
|
+
private mem;
|
|
418
|
+
constructor(http: HttpClient, getConversationId: () => string, isPreview?: boolean, initial?: Record<string, unknown>);
|
|
419
|
+
/** 预览模式下重新灌入初始数据(previewConfig 变更时调用) */
|
|
420
|
+
setInitial(initial: Record<string, unknown> | undefined): void;
|
|
421
|
+
get(): Promise<Record<string, unknown>>;
|
|
422
|
+
set(data: Record<string, unknown>): Promise<void>;
|
|
423
|
+
}
|
|
424
|
+
|
|
399
425
|
interface DevConfig {
|
|
400
426
|
apiKey: string;
|
|
401
427
|
gameId: string;
|
|
@@ -412,6 +438,7 @@ declare class StorviaSDK {
|
|
|
412
438
|
private initialized;
|
|
413
439
|
private isPreview;
|
|
414
440
|
private previewConfig;
|
|
441
|
+
private bus;
|
|
415
442
|
chat: ChatModule;
|
|
416
443
|
characters: CharactersModule;
|
|
417
444
|
relationships: RelationshipsModule;
|
|
@@ -419,8 +446,15 @@ declare class StorviaSDK {
|
|
|
419
446
|
world: WorldModule;
|
|
420
447
|
player: PlayerModule;
|
|
421
448
|
custom: CustomModule;
|
|
449
|
+
save: SaveModule;
|
|
422
450
|
init(): Promise<void>;
|
|
423
|
-
/**
|
|
451
|
+
/**
|
|
452
|
+
* 监听父页面 token 刷新(envelope 'token-update')。
|
|
453
|
+
* Supabase JWT 默认 1h 过期,父页面 session 自动刷新后转发新 token 进来,
|
|
454
|
+
* 否则 SDK 会一直用旧 token 请求被服务端 401。
|
|
455
|
+
*/
|
|
456
|
+
private listenForTokenUpdate;
|
|
457
|
+
/** 监听父页面发来的预览模式动态更新(envelope 'config-update' / 'set-model') */
|
|
424
458
|
private listenForPreviewMessages;
|
|
425
459
|
/**
|
|
426
460
|
* 调用 POST /preview/initial-snapshot 拉取与正式发布等价的初始数据
|
|
@@ -458,4 +492,152 @@ type ToastType = 'success' | 'error' | 'warning' | 'info';
|
|
|
458
492
|
declare function setToastEnabled(enabled: boolean): void;
|
|
459
493
|
declare function showToast(message: string, type?: ToastType, duration?: number): void;
|
|
460
494
|
|
|
461
|
-
|
|
495
|
+
/**
|
|
496
|
+
* 父子 iframe postMessage 协议类型
|
|
497
|
+
*
|
|
498
|
+
* 设计要点:
|
|
499
|
+
* - 所有消息使用 ProtocolEnvelope 包裹,统一带 protocol 版本号
|
|
500
|
+
* - DownstreamMsg = 父 → 子;UpstreamMsg = 子 → 父
|
|
501
|
+
* - SDK 与主站共享同一份类型,避免字符串散落
|
|
502
|
+
*
|
|
503
|
+
* 协议版本:
|
|
504
|
+
* 1 = 握手 + 类型化 bus 首版(当前)
|
|
505
|
+
*/
|
|
506
|
+
declare const PROTOCOL_VERSION = 1;
|
|
507
|
+
interface ProtocolEnvelope<T extends string, P> {
|
|
508
|
+
/** 协议版本,用于将来破坏性变更时双方判断 */
|
|
509
|
+
protocol: number;
|
|
510
|
+
/** 消息类型(union 区分) */
|
|
511
|
+
type: T;
|
|
512
|
+
/** 消息载荷 */
|
|
513
|
+
payload: P;
|
|
514
|
+
/** 用于 ack 的关联 id(可选) */
|
|
515
|
+
id?: string;
|
|
516
|
+
/** 这是对哪条消息的 ack(可选) */
|
|
517
|
+
ackId?: string;
|
|
518
|
+
}
|
|
519
|
+
/** 正式环境 init payload */
|
|
520
|
+
interface InitPayload {
|
|
521
|
+
apiBase: string;
|
|
522
|
+
gameId: string;
|
|
523
|
+
accessToken: string;
|
|
524
|
+
debug?: boolean;
|
|
525
|
+
}
|
|
526
|
+
interface PreviewConfig {
|
|
527
|
+
game_prompt?: string | null;
|
|
528
|
+
game_config?: Record<string, unknown>;
|
|
529
|
+
game_state?: Record<string, unknown> | null;
|
|
530
|
+
persona_settings?: Record<string, unknown>;
|
|
531
|
+
reply_length?: string;
|
|
532
|
+
reply_language?: string;
|
|
533
|
+
}
|
|
534
|
+
/** 预览环境 init payload —— 比 InitPayload 多 preview 配置 */
|
|
535
|
+
interface PreviewInitPayload {
|
|
536
|
+
apiBase: string;
|
|
537
|
+
gameId: string;
|
|
538
|
+
accessToken: string;
|
|
539
|
+
preview: true;
|
|
540
|
+
previewConfig?: PreviewConfig;
|
|
541
|
+
models?: Array<{
|
|
542
|
+
id: string;
|
|
543
|
+
name: string;
|
|
544
|
+
provider?: string;
|
|
545
|
+
}>;
|
|
546
|
+
selectedModelId?: string;
|
|
547
|
+
debug?: boolean;
|
|
548
|
+
}
|
|
549
|
+
interface TokenUpdatePayload {
|
|
550
|
+
accessToken: string;
|
|
551
|
+
}
|
|
552
|
+
interface ConfigUpdatePayload {
|
|
553
|
+
previewConfig: PreviewConfig;
|
|
554
|
+
}
|
|
555
|
+
interface SetModelPayload {
|
|
556
|
+
modelId: string;
|
|
557
|
+
}
|
|
558
|
+
interface OrientationPayload {
|
|
559
|
+
mode: 'landscape' | 'portrait';
|
|
560
|
+
}
|
|
561
|
+
interface ReadyPayload {
|
|
562
|
+
/** 标识 SDK 是否运行在预览模式(父侧据此选择 init 还是 preview-init) */
|
|
563
|
+
isPreview?: boolean;
|
|
564
|
+
}
|
|
565
|
+
interface SdkErrorPayload {
|
|
566
|
+
code: string;
|
|
567
|
+
message: string;
|
|
568
|
+
recoverable: boolean;
|
|
569
|
+
}
|
|
570
|
+
interface AckPayload {
|
|
571
|
+
ok: boolean;
|
|
572
|
+
error?: string;
|
|
573
|
+
}
|
|
574
|
+
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>;
|
|
575
|
+
type UpstreamMsg = ProtocolEnvelope<'ready', ReadyPayload> | ProtocolEnvelope<'exit', Record<string, never>> | ProtocolEnvelope<'request-orientation', OrientationPayload> | ProtocolEnvelope<'error', SdkErrorPayload> | ProtocolEnvelope<'ack', AckPayload>;
|
|
576
|
+
declare function isProtocolEnvelope(data: unknown): data is ProtocolEnvelope<string, unknown>;
|
|
577
|
+
declare function envelope<T extends string, P>(type: T, payload: P, opts?: {
|
|
578
|
+
id?: string;
|
|
579
|
+
ackId?: string;
|
|
580
|
+
}): ProtocolEnvelope<T, P>;
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* StorviaBus —— 类型化的 postMessage 总线
|
|
584
|
+
*
|
|
585
|
+
* 同时支持两种 transport:
|
|
586
|
+
* - window.postMessage(默认 / fallback)
|
|
587
|
+
* - MessagePort(Phase 4 升级路径,由父侧握手时下发)
|
|
588
|
+
*
|
|
589
|
+
* 收到 envelope 时:
|
|
590
|
+
* 1. 校验 protocol 版本
|
|
591
|
+
* 2. 校验 source(防止任意 iframe 注入)
|
|
592
|
+
* 3. dispatch 到对应 type 的 handler
|
|
593
|
+
*
|
|
594
|
+
* 用法:
|
|
595
|
+
* const bus = new StorviaBus<DownstreamMsg, UpstreamMsg>({
|
|
596
|
+
* // 子侧:消息从父来;发回父
|
|
597
|
+
* incoming: window,
|
|
598
|
+
* outgoing: () => window.parent,
|
|
599
|
+
* verifySource: (e) => e.source === window.parent,
|
|
600
|
+
* })
|
|
601
|
+
* bus.on('init', (msg) => { ... msg.payload ... })
|
|
602
|
+
* bus.send({ type: 'ready', payload: { isPreview: false } })
|
|
603
|
+
*/
|
|
604
|
+
|
|
605
|
+
type AnyEnvelope = ProtocolEnvelope<string, unknown>;
|
|
606
|
+
interface StorviaBusOptions<TIn extends AnyEnvelope> {
|
|
607
|
+
/** 监听消息的 EventTarget(通常是 window;也可以是 MessagePort) */
|
|
608
|
+
incoming: EventTarget | MessagePort;
|
|
609
|
+
/** 发送消息的目标。函数式,便于 iframe 还没渲染时也能挂 bus */
|
|
610
|
+
outgoing: () => Window | MessagePort | null | undefined;
|
|
611
|
+
/** 来源校验:父侧通常 e.source === iframe.contentWindow,子侧 e.source === window.parent */
|
|
612
|
+
verifySource?: (event: MessageEvent) => boolean;
|
|
613
|
+
/** 入站消息 schema 校验,返回 false 时静默丢弃 */
|
|
614
|
+
validate?: (data: unknown) => data is TIn;
|
|
615
|
+
/** 调试日志开关 */
|
|
616
|
+
debug?: boolean;
|
|
617
|
+
/** transferable objects 的回调(用于 Phase 4 MessageChannel) */
|
|
618
|
+
transfer?: (msg: AnyEnvelope) => Transferable[] | undefined;
|
|
619
|
+
}
|
|
620
|
+
declare class StorviaBus<TIn extends AnyEnvelope, TOut extends AnyEnvelope> {
|
|
621
|
+
private incoming;
|
|
622
|
+
private getOutgoing;
|
|
623
|
+
private verifySource;
|
|
624
|
+
private validate;
|
|
625
|
+
private debug;
|
|
626
|
+
private getTransferables;
|
|
627
|
+
private handlers;
|
|
628
|
+
private pendingAcks;
|
|
629
|
+
private listener;
|
|
630
|
+
constructor(opts: StorviaBusOptions<TIn>);
|
|
631
|
+
private attach;
|
|
632
|
+
/** 监听某类消息,返回取消订阅函数 */
|
|
633
|
+
on<K extends TIn['type']>(type: K, handler: (msg: Extract<TIn, {
|
|
634
|
+
type: K;
|
|
635
|
+
}>) => void): () => void;
|
|
636
|
+
/** 发出一条消息(不等 ack) */
|
|
637
|
+
send(msg: TOut): void;
|
|
638
|
+
/** 发出一条消息并等待 ack(默认 10s 超时) */
|
|
639
|
+
request(msg: TOut, timeoutMs?: number): Promise<TIn>;
|
|
640
|
+
destroy(): void;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
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 };
|