@storvia/sdk 0.5.5 → 0.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs.js +10 -10
- package/dist/index.d.mts +117 -3
- package/dist/index.esm.js +10 -10
- package/dist/index.umd.js +10 -10
- 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 ce=Object.getOwnPropertyDescriptor;var pe=Object.getOwnPropertyNames;var he=Object.prototype.hasOwnProperty;var ge=(o,e)=>{for(var t in e)z(o,t,{get:e[t],enumerable:!0})},ue=(o,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of pe(e))!he.call(o,i)&&i!==t&&z(o,i,{get:()=>e[i],enumerable:!(n=ce(e,i))||n.enumerable});return o};var me=o=>ue(z({},"__esModule",{value:!0}),o);var Ne={};ge(Ne,{PROTOCOL_VERSION:()=>N,StorviaBus:()=>S,StorviaError:()=>m,StorviaSDK:()=>H,createStorviaSDK:()=>de,envelope:()=>I,extractFieldValue:()=>le,isProtocolEnvelope:()=>B,isRichFieldValue:()=>q,setToastEnabled:()=>ee,showToast:()=>W});module.exports=me(Ne);var m=class extends Error{constructor(e,t){super(t),this.name="StorviaError",this.code=e}};var J="storvia-sdk-toast-style",F="storvia-sdk-toast-stack",ve=`
|
|
2
|
+
#${F} {
|
|
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
|
+
#${F} {
|
|
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
|
+
`,fe={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>'},ye={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",NOT_SUPPORTED_IN_PREVIEW:"\u5F53\u524D\u63A5\u53E3\u5728\u9884\u89C8\u6A21\u5F0F\u4E0B\u4E0D\u53EF\u7528",NETWORK_ERROR:"\u7F51\u7EDC\u5F02\u5E38\uFF0C\u8BF7\u68C0\u67E5\u8FDE\u63A5"},Q=!0;function ee(o){Q=o}function be(){if(typeof document>"u")return null;let o=document.getElementById(F);if(!o){if(!document.getElementById(J)){let e=document.createElement("style");e.id=J,e.textContent=ve,document.head.appendChild(e)}o=document.createElement("div"),o.id=F,document.body.appendChild(o)}return o}function W(o,e="info",t=3500){if(!Q)return;let n=be();if(!n)return;let i=document.createElement("div");i.className=`storvia-toast ${e}`,i.innerHTML=`
|
|
80
|
+
<span class="storvia-toast-icon">${fe[e]}</span>
|
|
81
81
|
<span class="storvia-toast-msg"></span>
|
|
82
|
-
`;let s=i.querySelector(".storvia-toast-msg");s&&(s.textContent=
|
|
83
|
-
`);for(let
|
|
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 G(o,e){let t=ye[o]||e||"\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5";W(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 m||G("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:l,durationMs:d,modelName:g}=e,p="%c[Storvia SDK]",c="color: #6366f1; font-weight: bold",h=d!==void 0?` (${d}ms)`:"",v=s!==void 0?` [${s}]`:"",y=g?` [model: ${g}]`:"";l?(console.groupCollapsed(`${p} %c${t} ${n}${v}${y}${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:",l),console.groupEnd()):(console.groupCollapsed(`${p} %c${t} ${n}${v}${y}${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,l])=>n.searchParams.set(a,l));let i=Date.now(),s,r;try{let a=await fetch(n.toString(),{method:"GET",headers:this.buildHeaders()});s=a.status;let{raw:l,data:d}=await this.handleResponseWithRaw(a);return r=l,this.log({method:"GET",path:e,body:t,status:s,rawResponse:r,parsedData:d,durationMs:Date.now()-i}),d}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:l,data:d}=await this.handleResponseWithRaw(a);return r=l,this.log({method:"POST",path:e,body:t,status:s,rawResponse:r,parsedData:d,durationMs:Date.now()-i,modelName:n?.modelName}),d}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:l}=await this.handleResponseWithRaw(r);return s=a,this.log({method:"PATCH",path:e,body:t,status:i,rawResponse:s,parsedData:l,durationMs:Date.now()-n}),l}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:l}=await this.handleResponseWithRaw(r);return s=a,this.log({method:"PUT",path:e,body:t,status:i,rawResponse:s,parsedData:l,durationMs:Date.now()-n}),l}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,r){let a=Date.now(),l=s?.modelName?` [model: ${s.modelName}]`:"",d=[],g=u=>{this.debug&&d.push({t:Date.now()-a,event:u})},p=await fetch(`${this.baseUrl}${e}`,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(t)});if(!p.ok){let u=await p.text().catch(()=>""),x={};try{x=JSON.parse(u)}catch{}let L=x.code||"INTERNAL_ERROR",b=new m(L,x.message||`HTTP ${p.status}`);throw G(L,x.message),this.log({method:"STREAM",path:e,body:t,status:p.status,rawResponse:u,error:b,durationMs:Date.now()-a,modelName:s?.modelName}),b}let c=p.body?.getReader();if(!c)throw new m("INTERNAL_ERROR","No response body for stream");let h=new TextDecoder,v="",y="";try{for(;;){let{done:u,value:x}=await c.read();if(u)break;let b=h.decode(x,{stream:!0}).split(`
|
|
83
|
+
`);for(let Z of b){if(!Z.startsWith("data: "))continue;let V=Z.slice(6);if(V==="[DONE]"){g("[DONE]"),this.debug&&(console.groupCollapsed(`%c[Storvia SDK] %cSTREAM ${e} [${p.status}]${l} (${Date.now()-a}ms) %c\u2713`,"color: #6366f1; font-weight: bold","color: #e0e0e0","color: #22c55e"),console.log("Request:",t),console.log(`Accumulated content (${y.length} chars):`,y),console.log("Message ID:",v),console.log(`SSE events (${d.length}):`,d),console.groupEnd()),i(v);return}try{let w=JSON.parse(V);g(w),w.type==="done"&&w.id?v=w.id:w.type==="state"?r&&r(w.state,w.full??null):w.content&&(y+=w.content,n(w.content))}catch{g({raw:V})}}}}catch(u){throw this.debug&&(console.groupCollapsed(`%c[Storvia SDK] %cSTREAM ${e} [${p.status}]${l} (${Date.now()-a}ms) %c\u2717`,"color: #6366f1; font-weight: bold","color: #e0e0e0","color: #ef4444"),console.log("Request:",t),console.log(`Accumulated content (${y.length} chars):`,y),console.log(`SSE events (${d.length}):`,d),console.error("Stream error:",u),console.groupEnd()),u}v&&i(v)}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 m(r,i.message||`HTTP ${e.status}`);throw G(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"}],te=[{value:"low",label:"\u7B80\u77ED"},{value:"medium",label:"\u9002\u4E2D"},{value:"high",label:"\u8BE6\u7EC6"}],we="https://cdn.storvia.ai/default/logo.png",Ce="https://api.storvia.ai/storage/v1/object/public/storvia/default/credits.png",xe=`
|
|
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
|
+
`,Ie='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6L6 18M6 6l12 12"/></svg>',Se='<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>',Ee='<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>',Pe='<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>',Re='<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>',ne='<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>',f=48,C=16,ke=5,E=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)>ke&&(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+f/2<window.innerWidth/2;this.fabX=n?C:window.innerWidth-f-C,this.fabY=Math.max(C,Math.min(window.innerHeight-f-C,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(C,Math.min(window.innerWidth-f-C,this.fabX)),this.fabY=Math.max(C,Math.min(window.innerHeight-f-C,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-f-C,this.fabY=window.innerHeight-f-C,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=xe;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=we,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 l=document.createElement("h2");l.className="panel-title",l.textContent="\u6E38\u620F\u8BBE\u7F6E";let d=document.createElement("button");d.className="close-btn",d.innerHTML=Ie,d.addEventListener("click",()=>this.closePanel()),a.appendChild(l),a.appendChild(d),r.appendChild(a);let g=document.createElement("div");g.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"),g.appendChild(this.modelTabBtn),g.appendChild(this.settingsTabBtn),r.appendChild(g);let p=document.createElement("div");p.className="panel-body",this.modelBody=this.buildModelTab(),this.settingsBody=this.buildSettingsTab(),p.appendChild(this.modelBody),p.appendChild(this.settingsBody),r.appendChild(p);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 v=document.createElement("div");v.appendChild(r),v.appendChild(t),this.shadowRoot.appendChild(e),this.shadowRoot.appendChild(v),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,l)=>{let d=document.createElement("button");return d.className=`category-tab${this.selectedCategory===l?" active":""}`,d.textContent=a,d.addEventListener("click",()=>{this.selectedCategory=l,s.querySelectorAll(".category-tab").forEach(g=>g.classList.remove("active")),d.classList.add("active"),this.renderModelGrid()}),d};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="${Ce}" alt="credits" />
|
|
766
766
|
<span class="credits-unit">/\u6B21</span>
|
|
767
767
|
</div>`:""}
|
|
768
768
|
${s?`<div class="detail-description">${this.escapeHtml(s)}</div>`:""}
|
|
769
|
-
`}getStatusDotColor(e){if(e.is_active===!1)return"#6b7280";let t=e.success_rate??100;return t>=90?"#10b981":t>=80?"#3b82f6":t>=60?"#eab308":"#f97316"}getStatusClass(e){if(e.is_active===!1)return"inactive";let t=e.success_rate??100;return t>=90?"excellent":t>=80?"good":t>=60?"normal":"crowded"}getStatusText(e){if(e.is_active===!1)return"\u505C\u7528";let t=e.success_rate??100;return t>=90?"\u6D41\u7545":t>=80?"\u826F\u597D":t>=60?"\u4E00\u822C":"\u62E5\u6324"}getCreditsRange(e){let t=e.credits_config?.min??0,n=e.credits_config?.max??0;return t===0&&n===0?"":t===n?`${t}`:`${t}\uFF5E${n}`}buildSettingsTab(){let e=document.createElement("div"),t=document.createElement("div");return t.className="form-stack",t.appendChild(this.buildTemperatureSection()),t.appendChild(this.buildReplyLengthSection()),t.appendChild(this.buildReplyLanguageSection()),t.appendChild(this.buildNoteSection()),t.appendChild(this.buildSyncSection()),e.appendChild(t),e}buildTemperatureSection(){let e=document.createElement("div");e.className="form-group";let t=document.createElement("label");t.className="form-label";let n=document.createElement("span");n.textContent="\u6E29\u5EA6";let i=document.createElement("span");i.className="temperature-value",i.textContent=this.settings.temperature.toFixed(1),this.tempValueEl=i,t.appendChild(n),t.appendChild(i),e.appendChild(t);let s=document.createElement("p");s.className="form-hint",s.textContent="\u66F4\u4F4E\u8BA9 AI \u56DE\u590D\u66F4\u7A33\u5B9A\u7406\u667A\uFF0C\u66F4\u9AD8\u8BA9\u56DE\u590D\u66F4\u5177\u591A\u6837\u6027",e.appendChild(s);let o=document.createElement("input");o.type="range",o.className="slider",o.min="0",o.max="1",o.step="0.1",o.value=String(this.settings.temperature),o.addEventListener("input",()=>{let d=parseFloat(o.value);this.settings.temperature=d,this.tempValueEl&&(this.tempValueEl.textContent=d.toFixed(1))}),e.appendChild(o);let a=document.createElement("div");return a.className="slider-labels",a.innerHTML="<span>\u7CBE\u786E</span><span>\u521B\u610F</span>",e.appendChild(a),e}buildReplyLengthSection(){let e=document.createElement("div");e.className="form-group";let t=document.createElement("label");t.className="form-label",t.textContent="\u56DE\u590D\u957F\u5EA6",e.appendChild(t);let n=document.createElement("div");return n.className="segment-control",this.segmentBtns=[],J.forEach(i=>{let s=document.createElement("button");s.className=`segment-button${i.value===this.settings.replyLength?" active":""}`,s.textContent=i.label,s.addEventListener("click",()=>{this.settings.replyLength=i.value,this.segmentBtns.forEach((o,a)=>{o.classList.toggle("active",J[a].value===i.value)})}),this.segmentBtns.push(s),n.appendChild(s)}),e.appendChild(n),e}buildReplyLanguageSection(){let e=document.createElement("div");e.className="form-group";let t=document.createElement("label");t.className="form-label",t.textContent="\u56DE\u590D\u8BED\u8A00",e.appendChild(t);let n=document.createElement("div");n.className="custom-select";let i=document.createElement("button");i.className="select-trigger";let s=document.createElement("span");s.textContent=A.find(d=>d.value===this.settings.replyLanguage)?.label||"";let o=document.createElement("span");o.className="select-arrow",o.textContent="\u25BE",this.langArrow=o,i.appendChild(s),i.appendChild(o),i.addEventListener("click",d=>{d.stopPropagation(),this.toggleLangDropdown()}),n.appendChild(i);let a=document.createElement("div");return a.className="select-dropdown",this.langDropdown=a,this.langOptions=[],A.forEach(d=>{let l=document.createElement("button");l.className=`select-option${d.value===this.settings.replyLanguage?" active":""}`,l.innerHTML=`<span>${d.label}</span>${d.value===this.settings.replyLanguage?Q:""}`,l.addEventListener("click",()=>{this.settings.replyLanguage=d.value,s.textContent=d.label,this.langOptions.forEach((h,u)=>{h.classList.toggle("active",A[u].value===d.value),h.innerHTML=`<span>${A[u].label}</span>${A[u].value===d.value?Q:""}`}),this.closeLangDropdown()}),this.langOptions.push(l),a.appendChild(l)}),n.appendChild(a),e.appendChild(n),e}toggleLangDropdown(){this.langDropdownOpen?this.closeLangDropdown():this.openLangDropdown()}openLangDropdown(){this.langDropdownOpen=!0,this.langDropdown?.classList.add("open"),this.langArrow&&(this.langArrow.textContent="\u25B4")}closeLangDropdown(){this.langDropdownOpen=!1,this.langDropdown?.classList.remove("open"),this.langArrow&&(this.langArrow.textContent="\u25BE")}buildNoteSection(){let e=document.createElement("div");e.className="form-group";let t=document.createElement("label");t.className="form-label";let n=document.createElement("span");n.textContent="\u5907\u6CE8";let i=document.createElement("span");i.className="char-count",i.textContent=`${this.settings.playerNote.length}/50`,this.noteCounter=i,t.appendChild(n),t.appendChild(i),e.appendChild(t);let s=document.createElement("p");s.className="form-hint",s.textContent="\u5199\u4E0B\u4F60\u5BF9\u8FD9\u4E2A\u6E38\u620F\u7684\u5907\u6CE8\uFF0C\u4F1A\u663E\u793A\u5728\u5B58\u6863\u5217\u8868",e.appendChild(s);let o=document.createElement("textarea");return o.className="player-note-input",o.placeholder="\u5907\u6CE8",o.maxLength=50,o.rows=2,o.value=this.settings.playerNote,o.addEventListener("input",()=>{this.settings.playerNote=o.value,this.noteCounter&&(this.noteCounter.textContent=`${o.value.length}/50`)}),e.appendChild(o),e}buildSyncSection(){let e=document.createElement("div");e.className="form-group";let t=document.createElement("label");t.className="form-label",t.textContent="\u540C\u6B65\u6E38\u620F\u8BBE\u5B9A",e.appendChild(t);let n=document.createElement("p");n.className=`sync-hint${this.hasWorldUpdate?" visible":""}`,n.textContent="\u26A0 \u4F5C\u8005\u5DF2\u66F4\u65B0\u6E38\u620F\u5185\u5BB9\uFF0C\u5EFA\u8BAE\u70B9\u51FB\u540C\u6B65",this.syncHint=n,e.appendChild(n);let i=document.createElement("p");i.className="form-hint",i.textContent="\u5C06\u6700\u65B0\u6E38\u620F\u8BBE\u5B9A\u548C\u5F00\u5E55\u5C0F\u5267\u573A\u540C\u6B65\u5230\u5F53\u524D\u5BF9\u8BDD",e.appendChild(i);let s=document.createElement("button");return s.className="btn btn-sync",this.syncBtn=s,this.renderSyncBtn(),s.addEventListener("click",async()=>{if(this.syncState!=="loading"){this.setSyncState("loading");try{await this.callbacks.onSync(),this.setSyncState("success"),this.hasWorldUpdate=!1,this.fabDot&&this.fabDot.classList.remove("visible"),this.syncHint&&this.syncHint.classList.remove("visible"),setTimeout(()=>this.setSyncState("idle"),3e3)}catch{this.setSyncState("error"),setTimeout(()=>this.setSyncState("idle"),4e3)}}}),e.appendChild(s),e}setSyncState(e){this.syncState=e,this.renderSyncBtn()}renderSyncBtn(){if(!this.syncBtn)return;let e=this.syncState,t={idle:xe,loading:Ce,success:Ie,error:Ee},n={idle:"\u540C\u6B65\u6700\u65B0\u8BBE\u5B9A",loading:"\u540C\u6B65\u4E2D...",success:"\u5DF2\u540C\u6B65",error:"\u540C\u6B65\u5931\u8D25"};this.syncBtn.className=`btn btn-sync${e==="success"||e==="error"?` ${e}`:""}`,this.syncBtn.disabled=e==="loading",this.syncBtn.innerHTML=`${t[e]}<span>${n[e]}</span>`}async handleSave(){if(!(!this.saveBtn||this.saveBtn.disabled)){this.saveBtn.disabled=!0,this.saveBtn.innerHTML='<span class="spinner"></span>\u4FDD\u5B58\u4E2D...';try{if(this.pendingModelId&&this.pendingModelId!==this.selectedModelId){let e=this.models.find(t=>t.id===this.pendingModelId);if(e&&e.is_active!==!1){this.selectedModelId=this.pendingModelId,this.callbacks.onModelChange(this.pendingModelId);try{localStorage.setItem("storvia_model_id",this.pendingModelId)}catch{}}else this.pendingModelId=this.selectedModelId}await this.callbacks.onSettingsChange({temperature:this.settings.temperature,replyLength:this.settings.replyLength,replyLanguage:this.settings.replyLanguage,playerNote:this.settings.playerNote}),this.saveBtn&&(this.saveBtn.textContent="\u4FDD\u5B58",this.saveBtn.disabled=!1),this.closePanel()}catch{this.saveBtn&&(this.saveBtn.textContent="\u4FDD\u5B58\u5931\u8D25",setTimeout(()=>{this.saveBtn&&(this.saveBtn.textContent="\u4FDD\u5B58",this.saveBtn.disabled=!1)},2e3))}}}escapeHtml(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}applyHostPosition(){this.host.style.left=`${this.fabX}px`,this.host.style.top=`${this.fabY}px`,this.host.style.right="auto",this.host.style.bottom="auto",this.applyPanelPosition()}isMobile(){return window.innerWidth<=768}applyPanelPosition(){if(!this.panel)return;if(this.isMobile()){this.panel.style.left="",this.panel.style.right="",this.panel.style.top="",this.panel.style.bottom="";return}let e=this.fabX+y/2<window.innerWidth/2,t=380;e?(this.panel.style.left="0",this.panel.style.right="auto"):(this.panel.style.left=`${y-t}px`,this.panel.style.right="auto"),this.fabY>500?(this.panel.style.bottom=`${y+8}px`,this.panel.style.top="auto"):(this.panel.style.top=`${y+8}px`,this.panel.style.bottom="auto")}togglePanel(){this.panel&&(this.panel.classList.contains("open")?this.closePanel():(this.applyPanelPosition(),this.panel.classList.add("open"),requestAnimationFrame(()=>{this.panel?.classList.contains("open")&&(this.fab&&(this.fab.style.visibility="hidden"),this.fabDot&&(this.fabDot.style.visibility="hidden"),this.fabWrap&&(this.fabWrap.style.pointerEvents="none"))}),this.isMobile()&&this.lockBodyScroll()))}closePanel(){if(this.panel&&this.panel.classList.remove("open"),this.fab&&(this.fab.style.visibility="visible"),this.fabDot&&(this.fabDot.style.visibility="visible"),this.fabWrap&&(this.fabWrap.style.pointerEvents=""),this.unlockBodyScroll(),this.pendingModelId!==this.selectedModelId){if(this.pendingModelId=this.selectedModelId,this.modelGrid){let e=this.getFilteredModels();this.modelGrid.querySelectorAll(".model-card").forEach((t,n)=>{t.classList.toggle("selected",e[n].id===this.pendingModelId)})}this.renderModelDetail()}}lockBodyScroll(){this.savedBodyOverflow===null&&(this.savedBodyOverflow=document.body.style.overflow||"",document.body.style.overflow="hidden")}unlockBodyScroll(){this.savedBodyOverflow!==null&&(document.body.style.overflow=this.savedBodyOverflow,this.savedBodyOverflow=null)}};var P=class{constructor(e,t,n,i,s=!1,o,a,d){this.http=e;this.getGameId=t;this.getConversationId=n;this.getModelId=i;this.isPreview=s;this.previewConfig=o,this.getSettings=a,this.getModelName=d}reqMeta(){let e=this.getModelName?.();return e?{modelName:e}:void 0}updatePreviewConfig(e){this.previewConfig=e}async send(e){if(this.isPreview)return this.sendPreview(e);let t={game_id:this.getGameId(),conversation_id:this.getConversationId(),model_id:this.getModelId(),message:e.message,topic:e.topic,scene_key:e.sceneKey,stream:e.stream??!1};if(e.stream){await this.http.stream("/chat",t,e.onChunk??(()=>{}),e.onDone??(()=>{}),this.reqMeta());return}return this.http.post("/chat",t,this.reqMeta())}async save(e){return this.isPreview?{id:`preview-${Date.now()}`}:this.http.post("/messages/save",{conversation_id:this.getConversationId(),role:e.role,content:e.content,topic:e.topic})}async generate(e){if(this.isPreview)return this.sendPreview({message:"",topic:e.topic,sceneKey:e.sceneKey,stream:e.stream,onChunk:e.onChunk,onDone:e.onDone});let t={conversation_id:this.getConversationId(),model_id:this.getModelId(),topic:e.topic,scene_key:e.sceneKey,stream:e.stream??!1};if(e.stream){await this.http.stream("/generate",t,e.onChunk??(()=>{}),e.onDone??(()=>{}),this.reqMeta());return}return this.http.post("/generate",t,this.reqMeta())}async retry(e={}){if(this.isPreview)throw new Error("Retry is not supported in preview mode");let t={conversation_id:this.getConversationId(),model_id:this.getModelId(),topic:e.topic,scene_key:e.sceneKey,stream:e.stream??!1};if(e.stream){await this.http.stream("/retry",t,e.onChunk??(()=>{}),e.onDone??(()=>{}),this.reqMeta());return}return this.http.post("/retry",t,this.reqMeta())}async messages(e){if(this.isPreview)return{data:[],hasMore:!1,nextCursor:null};let t={conversation_id:this.getConversationId(),order:e.order,limit:String(e.limit??20)};e.topic&&(t.topic=e.topic),e.cursor&&(t.cursor_uuid=e.cursor.uuid,t.cursor_created_at=e.cursor.createdAt);let n=await this.http.get("/messages",t);return{data:n.messages.map(i=>({uuid:i.uuid,role:i.role,content:i.content,topic:i.topic,status:i.status,model:i.model,createdAt:i.created_at})),hasMore:n.has_more,nextCursor:n.next_cursor?{uuid:n.next_cursor.cursor_uuid,createdAt:n.next_cursor.cursor_created_at}:null}}async sendPreview(e){let t={model_id:this.getModelId(),message:e.message,topic:e.topic,scene_key:e.sceneKey,history_messages:[]};this.previewConfig?t.prompt_config=this.previewConfig:t.game_id=this.getGameId();let n=this.getSettings?.();if(n&&(typeof n.temperature=="number"&&(t.temperature=n.temperature),n.replyLength&&(t.reply_length=n.replyLength),n.replyLanguage&&(t.reply_language=n.replyLanguage)),e.stream){await this.http.stream("/preview",t,e.onChunk??(()=>{}),e.onDone??(()=>{}),this.reqMeta());return}let i="";return await this.http.stream("/preview",t,s=>{i+=s},()=>{},this.reqMeta()),{id:"",content:i}}};var V=class{constructor(e,t,n=!1,i){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={};i&&(this.mem={...i})}setInitial(e){this.mem=e?{...e}:{}}async get(e,t){if(this.isPreview){let i=this.mem[e]||{};return t?{...i[t]||{}}:{...i}}let n=t?{group:t}:void 0;return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/state`,n)}async update(e,t,n){if(this.isPreview){let i=this.mem[e]||(this.mem[e]={});i[t]={...i[t]||{},...n};return}await this.http.patch(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/state`,{group:t,values:n})}},R=class{constructor(e,t,n=!1,i,s){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[];i&&(this.mem=i.map(ee)),this.state=new V(e,t,n,s)}setInitial(e,t){this.mem=e?e.map(ee):[],this.state.setInitial(t)}async list(){return this.isPreview?this.mem.map(te):this.http.get(`/conversations/${this.getConversationId()}/characters`)}async get(e){if(this.isPreview){let t=this.mem.find(n=>n.name===e);return t?te(t):{name:e}}return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}`)}async add(e){if(this.isPreview){this.mem.push({...e,isPreset:!1});return}await this.http.post(`/conversations/${this.getConversationId()}/characters`,e)}async update(e,t){if(this.isPreview){let n=this.mem.find(i=>i.name===e);n&&Object.assign(n,t);return}await this.http.patch(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}`,t)}async remove(e){if(this.isPreview){this.mem=this.mem.filter(t=>t.name!==e);return}await this.http.delete(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}`)}async detail(e){if(this.isPreview){let t=this.mem.find(n=>n.name===e);return{name:e,avatar:t?.avatar,description:t?.description,userDescription:t?.userDescription,...t?.gender?{gender:t.gender}:{},...t?.isPreset!==void 0?{isPreset:t.isPreset}:{},state:await this.state.get(e)}}return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/detail`)}async setPriority(e,t){let n=Math.max(0,Math.min(100,Math.round(t)));this.isPreview||await this.http.patch(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/state`,{priority:n})}};function ee(r){return{name:r.name,description:r.description,avatar:r.avatar,...r.gender?{gender:r.gender}:{},...r.userDescription!==void 0?{userDescription:r.userDescription}:{},...r.isPreset!==void 0?{isPreset:r.isPreset}:{}}}function te(r){return{name:r.name,avatar:r.avatar,description:r.description,...r.userDescription!==void 0?{userDescription:r.userDescription}:{},...r.gender?{gender:r.gender}:{},...r.isPreset!==void 0?{isPreset:r.isPreset}:{}}}var T=class{constructor(e,t,n=!1,i){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[];i&&(this.mem=i.map(s=>({...s})))}setInitial(e){this.mem=e?e.map(t=>({...t})):[]}async list(){return this.isPreview?[...this.mem]:this.http.get(`/conversations/${this.getConversationId()}/relationships`)}async get(e,t){if(this.isPreview){let n=this.mem.find(i=>i.from===e&&i.to===t);if(n)return{...n};throw new Error("Relationship not found")}return this.http.get(`/conversations/${this.getConversationId()}/relationships/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)}async add(e){if(this.isPreview){this.mem.push({...e});return}await this.http.post(`/conversations/${this.getConversationId()}/relationships`,e)}async update(e,t,n){if(this.isPreview){let i=this.mem.find(s=>s.from===e&&s.to===t);i?Object.assign(i,n):this.mem.push({from:e,to:t,...n});return}await this.http.patch(`/conversations/${this.getConversationId()}/relationships/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,n)}async remove(e,t){if(this.isPreview){this.mem=this.mem.filter(n=>!(n.from===e&&n.to===t));return}await this.http.delete(`/conversations/${this.getConversationId()}/relationships/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)}};function ne(r){let e={count:r.count};return r.desc!==void 0&&(e.desc=r.desc),r.icon_url!==void 0&&(e.iconUrl=r.icon_url),e}function W(r){let e={};if(!r)return e;for(let[t,n]of Object.entries(r)){let i={};for(let[s,o]of Object.entries(n))i[s]=ne(o);e[t]=i}return e}function Pe(r){let e={};if(!r)return e;for(let[t,n]of Object.entries(r))e[t]=ne(n);return e}var k=class{constructor(e,t,n=!1,i){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={};i&&(this.mem=W(i))}setInitial(e){this.mem=e?W(e):{}}async list(e){if(this.isPreview){if(e!==void 0)return{...this.mem[e]||{}};let n={};for(let[i,s]of Object.entries(this.mem))n[i]={...s};return n}if(e!==void 0){let n=await this.http.get(`/conversations/${this.getConversationId()}/inventory/${encodeURIComponent(e)}`);return Pe(n)}let t=await this.http.get(`/conversations/${this.getConversationId()}/inventory`);return W(t)}async add(e){let{group:t,name:n,count:i=1,desc:s,iconUrl:o}=e;if(this.isPreview){if(!this.mem[t])throw new Error(`Group "${t}" does not exist`);if(n in this.mem[t])throw new Error(`Item "${n}" already exists in group "${t}"`);let d={count:i};s!==void 0&&(d.desc=s),o!==void 0&&(d.iconUrl=o),this.mem[t][n]=d;return}let a={group:t,name:n,count:i};s!==void 0&&(a.desc=s),o!==void 0&&(a.icon_url=o),await this.http.post(`/conversations/${this.getConversationId()}/inventory`,a)}async update(e){let{group:t,name:n,count:i,desc:s,iconUrl:o}=e;if(this.isPreview){let d=this.mem[t];if(!d||!(n in d))throw new Error(`Item "${t}/${n}" not found`);let l=d[n];i!==void 0&&(l.count=i),s!==void 0&&(l.desc=s),o!==void 0&&(l.iconUrl=o);return}let a={};i!==void 0&&(a.count=i),s!==void 0&&(a.desc=s),o!==void 0&&(a.icon_url=o),await this.http.patch(`/conversations/${this.getConversationId()}/inventory/${encodeURIComponent(t)}/${encodeURIComponent(n)}`,a)}async remove(e){let{group:t,name:n}=e;if(this.isPreview){this.mem[t]&&delete this.mem[t][n];return}await this.http.delete(`/conversations/${this.getConversationId()}/inventory/${encodeURIComponent(t)}/${encodeURIComponent(n)}`)}async move(e){let{fromGroup:t,toGroup:n,name:i,newName:s}=e;if(this.isPreview){let o=this.mem[t];if(!o||!(i in o))throw new Error(`Source item "${t}/${i}" not found`);if(!this.mem[n])throw new Error(`Target group "${n}" does not exist`);let a=s||i;if(t===n&&a===i)return;if(a in this.mem[n])throw new Error(`Item "${a}" already exists in target group`);this.mem[n][a]=o[i],delete o[i];return}await this.http.post(`/conversations/${this.getConversationId()}/inventory/move`,{fromGroup:t,toGroup:n,name:i,newName:s})}async ensureGroup(e){if(this.isPreview){this.mem[e]||(this.mem[e]={});return}await this.http.post(`/conversations/${this.getConversationId()}/inventory/groups/${encodeURIComponent(e)}`,{})}async removeGroup(e,t){let n=t?.cascade??!1;if(this.isPreview){let s=this.mem[e];if(s&&Object.keys(s).length>0&&!n)throw new Error(`Group "${e}" is not empty, pass cascade: true to force delete`);delete this.mem[e];return}let i=n?"?cascade=true":"";await this.http.delete(`/conversations/${this.getConversationId()}/inventory/groups/${encodeURIComponent(e)}${i}`)}};var M=class{constructor(e,t,n=!1,i){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={};i&&(this.mem={...i})}setInitial(e){this.mem=e?{...e}:{}}async get(){return this.isPreview?{...this.mem}:this.http.get(`/conversations/${this.getConversationId()}/world`)}async update(e){if(this.isPreview){Object.assign(this.mem,e);return}await this.http.patch(`/conversations/${this.getConversationId()}/world`,e)}};var K=class{constructor(e,t,n=!1,i){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={};i&&(this.mem={...i})}setInitial(e){this.mem=e?{...e}:{}}async get(e){if(this.isPreview)return e?{...this.mem[e]||{}}:{...this.mem};let t=e?{group:e}:void 0;return this.http.get(`/conversations/${this.getConversationId()}/player/state`,t)}async update(e,t){if(this.isPreview){this.mem[e]={...this.mem[e]||{},...t};return}await this.http.patch(`/conversations/${this.getConversationId()}/player/state`,{group:e,values:t})}},O=class{constructor(e,t,n=!1,i,s){this.http=e;this.getConversationId=t;this.isPreview=n;this.memPersona={name:""};i&&(this.memPersona={...i}),this.state=new K(e,t,n,s)}setInitial(e,t){this.memPersona=e?{...e}:{name:""},this.state.setInitial(t)}async get(){return this.isPreview?{...this.memPersona}:this.http.get(`/conversations/${this.getConversationId()}/player`)}async update(e){if(this.isPreview){Object.assign(this.memPersona,e);return}await this.http.patch(`/conversations/${this.getConversationId()}/player`,e)}};var _=class{constructor(e,t,n=!1,i,s){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={};this.memInject={};i&&(this.mem=ie(i)),s&&(this.memInject={...s})}setInitial(e,t){this.mem=e?ie(e):{},this.memInject=t?{...t}:{}}async get(e){if(this.isPreview)return e!==void 0?this.mem[e]:{...this.mem};let t=await this.http.get(`/conversations/${this.getConversationId()}/custom`);return e!==void 0?t[e]:t}async set(e,t){if(this.isPreview){for(let[i,s]of Object.entries(e))typeof s=="object"&&s!==null&&typeof this.mem[i]=="object"&&this.mem[i]!==null?this.mem[i]={...this.mem[i],...s}:this.mem[i]=s,t?.inject!==void 0&&(this.memInject[i]=t.inject);return}let n=t?.inject!==void 0?{data:e,inject:t.inject}:e;await this.http.patch(`/conversations/${this.getConversationId()}/custom`,n)}async setInject(e,t){if(this.isPreview){this.memInject[e]=t;return}await this.http.patch(`/conversations/${this.getConversationId()}/custom/inject/${encodeURIComponent(e)}`,{inject:t})}getInject(){return{...this.memInject}}async delete(e){if(this.isPreview){delete this.mem[e],delete this.memInject[e];return}await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}`)}async setGroupField(e,t,n){if(this.isPreview){(!this.mem[e]||typeof this.mem[e]!="object")&&(this.mem[e]={}),this.mem[e][t]=n;return}await this.http.patch(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{value:n})}async deleteGroupField(e,t){if(this.isPreview){if(typeof this.mem[e]=="object"&&this.mem[e]!==null){let n=this.mem[e];delete n[t]}return}await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)}};function ie(r){let e={};for(let[t,n]of Object.entries(r))typeof n=="object"&&n!==null&&!Array.isArray(n)?e[t]={...n}:e[t]=n;return e}var D=class{constructor(e,t,n=!1,i){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={};i&&(this.mem={...i})}setInitial(e){this.mem=e?{...e}:{}}async get(){return this.isPreview?{...this.mem}:await this.http.get(`/conversations/${this.getConversationId()}/save`)}async set(e){if(this.isPreview){this.mem={...e};return}await this.http.put(`/conversations/${this.getConversationId()}/save`,e)}};var N=1;function U(r){if(!r||typeof r!="object")return!1;let e=r;return typeof e.protocol=="number"&&typeof e.type=="string"&&"payload"in e}function x(r,e,t){return{protocol:1,type:r,payload:e,...t?.id?{id:t.id}:{},...t?.ackId?{ackId:t.ackId}:{}}}var I=class{constructor(e){this.handlers=new Map;this.pendingAcks=new Map;this.listener=null;this.incoming=e.incoming,this.getOutgoing=e.outgoing,this.verifySource=e.verifySource??(()=>!0),this.validate=e.validate,this.debug=!!e.debug,this.getTransferables=e.transfer??(()=>{}),this.attach()}attach(){this.listener=e=>{if((this.incoming instanceof Window||this.incoming===window)&&!this.verifySource(e))return;let t=e.data;if(!U(t))return;if(t.protocol!==1){this.debug&&console.warn("[StorviaBus] protocol mismatch",{expected:1,got:t.protocol,type:t.type});return}if(this.validate&&!this.validate(t)){this.debug&&console.warn("[StorviaBus] validation failed",t);return}if(t.ackId){let i=this.pendingAcks.get(t.ackId);if(i){this.pendingAcks.delete(t.ackId),i(t);return}}let n=this.handlers.get(t.type);if(!n||n.size===0){this.debug&&console.debug("[StorviaBus] no handler for",t.type);return}n.forEach(i=>{try{i(t)}catch(s){console.error(`[StorviaBus] handler '${t.type}' threw:`,s)}})},this.incoming.addEventListener("message",this.listener),this.incoming instanceof MessagePort&&this.incoming.start()}on(e,t){let n=this.handlers.get(e);n||(n=new Set,this.handlers.set(e,n));let i=t;return n.add(i),()=>n.delete(i)}send(e){let t=this.getOutgoing();if(!t){this.debug&&console.warn("[StorviaBus] outgoing target unavailable, drop:",e.type);return}let n=e.protocol?e:x(e.type,e.payload,{id:e.id,ackId:e.ackId}),i=this.getTransferables(n);try{t instanceof MessagePort?t.postMessage(n,i??[]):t.postMessage(n,"*",i??[])}catch(s){console.error("[StorviaBus] postMessage failed:",s,{type:e.type})}}request(e,t=1e4){return new Promise((n,i)=>{let s=e.id??Re(),o=x(e.type,e.payload,{id:s}),a=setTimeout(()=>{this.pendingAcks.delete(s),i(new Error(`[StorviaBus] request '${e.type}' timed out after ${t}ms`))},t);this.pendingAcks.set(s,d=>{clearTimeout(a),n(d)}),this.send(o)})}destroy(){if(this.listener&&(this.incoming.removeEventListener("message",this.listener),this.listener=null),this.incoming instanceof MessagePort)try{this.incoming.close()}catch{}this.handlers.clear(),this.pendingAcks.clear()}};function Re(){return`bus-${Date.now()}-${Math.random().toString(36).slice(2,8)}`}var se="/functions/v1/world-engine/v1",Te="https://api.storvia.ai";function ke(){return window.__STORVIA__||{}}function Me(r,e=3e4){let t=ke();return t.apiBase?Promise.resolve(t):new Promise((n,i)=>{let s=setTimeout(()=>{o(),a(),i(new g("NOT_INITIALIZED","Timed out waiting for __STORVIA__ config from parent frame."))},e),o=r.on("init",l=>{l.payload?.apiBase&&d({apiBase:l.payload.apiBase,gameId:l.payload.gameId,accessToken:l.payload.accessToken,debug:l.payload.debug})}),a=r.on("preview-init",l=>{l.payload?.apiBase&&d(l.payload)});function d(l){clearTimeout(s),o(),a();let h=window;h.__STORVIA__=l,n(l)}r.send(x("ready",{}))})}var B=class{constructor(){this.baseUrl="";this.gameId="";this.conversationId="";this.modelId="";this.models=[];this.accessToken="";this.initialized=!1;this.isPreview=!1;this.previewConfig=void 0}async init(){if(this.initialized)return;this.bus=new I({incoming:window,outgoing:()=>window.parent,verifySource:c=>c.source===window.parent});let e=await Me(this.bus),t=e.apiBase;if(!t)throw new g("NOT_INITIALIZED","window.__STORVIA__.apiBase is not set. The platform must inject it before SDK init.");if(this.baseUrl=`${t}${se}`,this.isPreview=!!e.preview,this.previewConfig=e.previewConfig,!e.gameId)throw new g("GAME_NOT_FOUND","window.__STORVIA__.gameId is not set. The platform must inject it before SDK init.");if(this.gameId=e.gameId,!e.accessToken)throw new g("UNAUTHORIZED","window.__STORVIA__.accessToken is not set. The platform must inject the user token before SDK init.");if(this.accessToken=e.accessToken,this.http=new $(this.baseUrl,this.accessToken,!!e.debug),this.isPreview){this.conversationId="00000000-0000-0000-0000-000000000000";let[c,p]=await Promise.all([this.fetchModels(),this.fetchPreviewSnapshot()]);this.models=c;let m=this.getSavedModelId();this.modelId=e.selectedModelId||(m&&c.some(w=>w.id===m)?m:"")||c[0]?.id||"",this.settingsSheet=new S({onModelChange:w=>{this.modelId=w},onSettingsChange:()=>Promise.resolve(),onSync:()=>Promise.resolve()}),c.length>0&&this.settingsSheet.mount(c,this.modelId,{temperature:1,replyLength:"medium",replyLanguage:"zh-CN",playerNote:""},!1);let f=()=>this.gameId,v=()=>this.conversationId,L=()=>this.modelId,E=()=>this.models.find(w=>w.id===this.modelId)?.name;this.chat=new P(this.http,f,v,L,!0,this.previewConfig,()=>this.settingsSheet?.getSettings()??null,E),this.characters=new R(this.http,v,!0,p?.characters,p?.characterStates),this.relationships=new T(this.http,v,!0,p?.relationships),this.inventory=new k(this.http,v,!0,p?.inventory),this.world=new M(this.http,v,!0,p?.world),this.player=new O(this.http,v,!0,p?.player,p?.playerState),this.custom=new _(this.http,v,!0,p?.custom,p?.custom_inject),this.save=new D(this.http,v,!0,p?.save_data),this.initialized=!0,this.listenForPreviewMessages(),this.listenForTokenUpdate();return}let[n,i]=await Promise.all([this.authenticate(),this.fetchModels()]);this.conversationId=n.conversationId,this.models=i;let s=this.getSavedModelId();this.modelId=s&&i.some(c=>c.id===s)?s:i[0]?.id||"";let o=n.settings,a=o?{temperature:o.temperature??1,replyLength:o.reply_length??"medium",replyLanguage:o.reply_language??"zh-CN",playerNote:o.player_note??""}:{temperature:1,replyLength:"medium",replyLanguage:"zh-CN",playerNote:""};this.settingsSheet=new S({onModelChange:c=>{this.modelId=c},onSettingsChange:c=>this.saveSettings(c),onSync:()=>this.syncSettings()}),this.settingsSheet.mount(i,this.modelId,a,n.hasWorldUpdate??!1);let d=()=>this.gameId,l=()=>this.conversationId,h=()=>this.modelId,u=()=>this.models.find(c=>c.id===this.modelId)?.name;this.chat=new P(this.http,d,l,h,!1,void 0,void 0,u),this.characters=new R(this.http,l),this.relationships=new T(this.http,l),this.inventory=new k(this.http,l),this.world=new M(this.http,l),this.player=new O(this.http,l),this.custom=new _(this.http,l),this.save=new D(this.http,l),this.listenForTokenUpdate(),this.initialized=!0}listenForTokenUpdate(){this.bus.on("token-update",e=>{let t=e.payload?.accessToken;typeof t!="string"||!t||(this.accessToken=t,this.http?.setToken(t))})}listenForPreviewMessages(){this.bus.on("set-model",e=>{this.modelId=e.payload.modelId||""}),this.bus.on("config-update",e=>{this.previewConfig=e.payload.previewConfig,this.chat&&this.chat.updatePreviewConfig(this.previewConfig),this.refreshPreviewSnapshot().catch(t=>{console.warn("[Storvia SDK] refreshPreviewSnapshot failed:",t)})})}async fetchPreviewSnapshot(){try{let e={game_id:this.gameId};return this.previewConfig&&("game_config"in this.previewConfig&&(e.game_config=this.previewConfig.game_config),"game_state"in this.previewConfig&&(e.game_state_override=this.previewConfig.game_state)),await this.http.post("/preview/initial-snapshot",e)}catch(e){return console.warn("[Storvia SDK] fetchPreviewSnapshot failed:",e),null}}async refreshPreviewSnapshot(){let e=await this.fetchPreviewSnapshot();e&&(this.characters?.setInitial(e.characters,e.characterStates),this.player?.setInitial(e.player,e.playerState),this.inventory?.setInitial(e.inventory),this.relationships?.setInitial(e.relationships),this.world?.setInitial(e.world),this.custom?.setInitial(e.custom,e.custom_inject),this.save?.setInitial(e.save_data))}async saveSettings(e){let t={conversation_id:this.conversationId};e.temperature!==void 0&&(t.temperature=e.temperature),e.replyLength!==void 0&&(t.reply_length=e.replyLength),e.replyLanguage!==void 0&&(t.reply_language=e.replyLanguage),e.playerNote!==void 0&&(t.player_note=e.playerNote),await this.http.patch("/settings",t)}async syncSettings(){await this.http.post("/sync",{conversation_id:this.conversationId})}async fetchModels(){try{return await this.http.get("/models")}catch{}return[]}async authenticate(){let e=await fetch(`${this.baseUrl}/auth`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.accessToken}`},body:JSON.stringify({game_id:this.gameId})});if(!e.ok)throw e.status===401?new g("UNAUTHORIZED","User not authenticated"):e.status===404?new g("GAME_NOT_FOUND","Game not found or not published"):new g("INTERNAL_ERROR",`Auth failed: HTTP ${e.status}`);let t=await e.json();return t.data??t}getSavedModelId(){try{return localStorage.getItem("storvia_model_id")||""}catch{return""}}async initDev(e){if(this.initialized)return;this.baseUrl=`${Te}${se}`,this.gameId=e.gameId,this.isPreview=!0,this.http=new $(this.baseUrl,"",!1,e.apiKey);let[t,n]=await Promise.all([this.fetchModels(),this.fetchPreviewSnapshot()]);this.models=t;let i=this.getSavedModelId();this.modelId=(i&&t.some(l=>l.id===i)?i:"")||t[0]?.id||"",this.conversationId="00000000-0000-0000-0000-000000000000",this.settingsSheet=new S({onModelChange:l=>{this.modelId=l},onSettingsChange:()=>Promise.resolve(),onSync:()=>Promise.resolve()}),t.length>0&&this.settingsSheet.mount(t,this.modelId,{temperature:1,replyLength:"medium",replyLanguage:"zh-CN",playerNote:""},!1);let s=()=>this.gameId,o=()=>this.conversationId,a=()=>this.modelId,d=()=>this.models.find(l=>l.id===this.modelId)?.name;this.chat=new P(this.http,s,o,a,!0,void 0,()=>this.settingsSheet?.getSettings()??null,d),this.characters=new R(this.http,o,!0,n?.characters,n?.characterStates),this.relationships=new T(this.http,o,!0,n?.relationships),this.inventory=new k(this.http,o,!0,n?.inventory),this.world=new M(this.http,o,!0,n?.world),this.player=new O(this.http,o,!0,n?.player,n?.playerState),this.custom=new _(this.http,o,!0,n?.custom),this.save=new D(this.http,o,!0,n?.save_data),this.initialized=!0}};async function oe(r){let e=new B;return r?.dev?await e.initDev(r.dev):await e.init(),e}function Y(r){return typeof r=="object"&&r!==null&&"value"in r&&"type"in r&&(r.type==="number"||r.type==="text")}function re(r){return Y(r)?r.value:r}0&&(module.exports={PROTOCOL_VERSION,StorviaBus,StorviaError,StorviaSDK,createStorviaSDK,envelope,extractFieldValue,isProtocolEnvelope,isRichFieldValue,setToastEnabled,showToast});
|
|
769
|
+
`}getStatusDotColor(e){if(e.is_active===!1)return"#6b7280";let t=e.success_rate??100;return t>=90?"#10b981":t>=80?"#3b82f6":t>=60?"#eab308":"#f97316"}getStatusClass(e){if(e.is_active===!1)return"inactive";let t=e.success_rate??100;return t>=90?"excellent":t>=80?"good":t>=60?"normal":"crowded"}getStatusText(e){if(e.is_active===!1)return"\u505C\u7528";let t=e.success_rate??100;return t>=90?"\u6D41\u7545":t>=80?"\u826F\u597D":t>=60?"\u4E00\u822C":"\u62E5\u6324"}getCreditsRange(e){let t=e.credits_config?.min??0,n=e.credits_config?.max??0;return t===0&&n===0?"":t===n?`${t}`:`${t}\uFF5E${n}`}buildSettingsTab(){let e=document.createElement("div"),t=document.createElement("div");return t.className="form-stack",t.appendChild(this.buildTemperatureSection()),t.appendChild(this.buildReplyLengthSection()),t.appendChild(this.buildReplyLanguageSection()),t.appendChild(this.buildNoteSection()),t.appendChild(this.buildSyncSection()),e.appendChild(t),e}buildTemperatureSection(){let e=document.createElement("div");e.className="form-group";let t=document.createElement("label");t.className="form-label";let n=document.createElement("span");n.textContent="\u6E29\u5EA6";let i=document.createElement("span");i.className="temperature-value",i.textContent=this.settings.temperature.toFixed(1),this.tempValueEl=i,t.appendChild(n),t.appendChild(i),e.appendChild(t);let s=document.createElement("p");s.className="form-hint",s.textContent="\u66F4\u4F4E\u8BA9 AI \u56DE\u590D\u66F4\u7A33\u5B9A\u7406\u667A\uFF0C\u66F4\u9AD8\u8BA9\u56DE\u590D\u66F4\u5177\u591A\u6837\u6027",e.appendChild(s);let 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 l=parseFloat(r.value);this.settings.temperature=l,this.tempValueEl&&(this.tempValueEl.textContent=l.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=[],te.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",te[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(l=>l.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",l=>{l.stopPropagation(),this.toggleLangDropdown()}),n.appendChild(i);let a=document.createElement("div");return a.className="select-dropdown",this.langDropdown=a,this.langOptions=[],A.forEach(l=>{let d=document.createElement("button");d.className=`select-option${l.value===this.settings.replyLanguage?" active":""}`,d.innerHTML=`<span>${l.label}</span>${l.value===this.settings.replyLanguage?ne:""}`,d.addEventListener("click",()=>{this.settings.replyLanguage=l.value,s.textContent=l.label,this.langOptions.forEach((g,p)=>{g.classList.toggle("active",A[p].value===l.value),g.innerHTML=`<span>${A[p].label}</span>${A[p].value===l.value?ne:""}`}),this.closeLangDropdown()}),this.langOptions.push(d),a.appendChild(d)}),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:Se,loading:Ee,success:Pe,error:Re},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+f/2<window.innerWidth/2,t=380;e?(this.panel.style.left="0",this.panel.style.right="auto"):(this.panel.style.left=`${f-t}px`,this.panel.style.right="auto"),this.fabY>500?(this.panel.style.bottom=`${f+8}px`,this.panel.style.top="auto"):(this.panel.style.top=`${f+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,l){this.http=e;this.getGameId=t;this.getConversationId=n;this.getModelId=i;this.isPreview=s;this.previewConfig=r,this.getSettings=a,this.getModelName=l}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(),j(e.onState));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,onState:e.onState});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(),j(e.onState));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(),j(e.onState));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(),j(e.onState));return}let i="",s=null,r=null;await this.http.stream("/preview",t,l=>{i+=l},()=>{},this.reqMeta(),(l,d)=>{s=l,r=d,e.onState&&e.onState(s,r)});let a={id:"",content:i};return s&&(a.state=s,r&&(a.full=r)),a}};function j(o){if(o)return(e,t)=>o(e,t)}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,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(ie)),this.state=new K(e,t,n,s)}setInitial(e,t){this.mem=e?e.map(ie):[],this.state.setInitial(t)}async list(){return this.isPreview?this.mem.map(se):this.http.get(`/conversations/${this.getConversationId()}/characters`)}async get(e){if(this.isPreview){let t=this.mem.find(n=>n.name===e);return t?se(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 ie(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 se(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 k=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 re(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 Y(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]=re(r);e[t]=i}return e}function Te(o){let e={};if(!o)return e;for(let[t,n]of Object.entries(o))e[t]=re(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=Y(i))}setInitial(e){this.mem=e?Y(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 Te(n)}let t=await this.http.get(`/conversations/${this.getConversationId()}/inventory`);return Y(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 l={count:i};s!==void 0&&(l.desc=s),r!==void 0&&(l.iconUrl=r),this.mem[t][n]=l;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 l=this.mem[t];if(!l||!(n in l))throw new Error(`Item "${t}/${n}" not found`);let d=l[n];i!==void 0&&(d.count=i),s!==void 0&&(d.desc=s),r!==void 0&&(d.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 X=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 X(e,t,n,s)}setInitial(e,t){this.memPersona=e?{...e}:{name:""},this.state.setInitial(t)}async get(){return this.isPreview?{...this.memPersona}:this.http.get(`/conversations/${this.getConversationId()}/player`)}async update(e){if(this.isPreview){Object.assign(this.memPersona,e);return}await this.http.patch(`/conversations/${this.getConversationId()}/player`,e)}};var _=class{constructor(e,t,n=!1,i,s){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={};this.memInject={};i&&(this.mem=oe(i)),s&&(this.memInject={...s})}setInitial(e,t){this.mem=e?oe(e):{},this.memInject=t?{...t}:{}}async get(e){if(this.isPreview)return e!==void 0?this.mem[e]:{...this.mem};let t=await this.http.get(`/conversations/${this.getConversationId()}/custom`);return e!==void 0?t[e]:t}async set(e,t){if(this.isPreview){for(let[i,s]of Object.entries(e))typeof s=="object"&&s!==null&&typeof this.mem[i]=="object"&&this.mem[i]!==null?this.mem[i]={...this.mem[i],...s}:this.mem[i]=s,t?.inject!==void 0&&(this.memInject[i]=t.inject);return}let n=t?.inject!==void 0?{data:e,inject:t.inject}:e;await this.http.patch(`/conversations/${this.getConversationId()}/custom`,n)}async setInject(e,t){if(this.isPreview){this.memInject[e]=t;return}await this.http.patch(`/conversations/${this.getConversationId()}/custom/inject/${encodeURIComponent(e)}`,{inject:t})}getInject(){return{...this.memInject}}async delete(e){if(this.isPreview){delete this.mem[e],delete this.memInject[e];return}await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}`)}async setGroupField(e,t,n){if(this.isPreview){(!this.mem[e]||typeof this.mem[e]!="object")&&(this.mem[e]={}),this.mem[e][t]=n;return}await this.http.patch(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{value:n})}async deleteGroupField(e,t){if(this.isPreview){if(typeof this.mem[e]=="object"&&this.mem[e]!==null){let n=this.mem[e];delete n[t]}return}await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)}};function oe(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 U=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n}async get(){if(this.isPreview)throw new m("NOT_SUPPORTED_IN_PREVIEW","storvia.state.get() is not available in preview mode. Use per-module get() instead.");return this.http.get(`/conversations/${this.getConversationId()}/state`)}};var N=1;function B(o){if(!o||typeof o!="object")return!1;let e=o;return typeof e.protocol=="number"&&typeof e.type=="string"&&"payload"in e}function I(o,e,t){return{protocol:1,type:o,payload:e,...t?.id?{id:t.id}:{},...t?.ackId?{ackId:t.ackId}:{}}}var S=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(!B(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:I(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??Me(),r=I(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,l=>{clearTimeout(a),n(l)}),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 Me(){return`bus-${Date.now()}-${Math.random().toString(36).slice(2,8)}`}var ae="/functions/v1/world-engine/v1",Oe="https://api.storvia.ai";function _e(){return window.__STORVIA__||{}}function De(o,e=3e4){let t=_e();return t.apiBase?Promise.resolve(t):new Promise((n,i)=>{let s=setTimeout(()=>{r(),a(),i(new m("NOT_INITIALIZED","Timed out waiting for __STORVIA__ config from parent frame."))},e),r=o.on("init",d=>{d.payload?.apiBase&&l({apiBase:d.payload.apiBase,gameId:d.payload.gameId,accessToken:d.payload.accessToken,debug:d.payload.debug})}),a=o.on("preview-init",d=>{d.payload?.apiBase&&l(d.payload)});function l(d){clearTimeout(s),r(),a();let g=window;g.__STORVIA__=d,n(d)}o.send(I("ready",{}))})}var H=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 S({incoming:window,outgoing:()=>window.parent,verifySource:c=>c.source===window.parent});let e=await De(this.bus),t=e.apiBase;if(!t)throw new m("NOT_INITIALIZED","window.__STORVIA__.apiBase is not set. The platform must inject it before SDK init.");if(this.baseUrl=`${t}${ae}`,this.isPreview=!!e.preview,this.previewConfig=e.previewConfig,!e.gameId)throw new m("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 m("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 v=this.getSavedModelId();this.modelId=e.selectedModelId||(v&&c.some(b=>b.id===v)?v:"")||c[0]?.id||"",this.settingsSheet=new E({onModelChange:b=>{this.modelId=b},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 y=()=>this.gameId,u=()=>this.conversationId,x=()=>this.modelId,L=()=>this.models.find(b=>b.id===this.modelId)?.name;this.chat=new P(this.http,y,u,x,!0,this.previewConfig,()=>this.settingsSheet?.getSettings()??null,L),this.characters=new R(this.http,u,!0,h?.characters,h?.characterStates),this.relationships=new k(this.http,u,!0,h?.relationships),this.inventory=new T(this.http,u,!0,h?.inventory),this.world=new M(this.http,u,!0,h?.world),this.player=new O(this.http,u,!0,h?.player,h?.playerState),this.custom=new _(this.http,u,!0,h?.custom,h?.custom_inject),this.save=new D(this.http,u,!0,h?.save_data),this.state=new U(this.http,u,!0),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 E({onModelChange:c=>{this.modelId=c},onSettingsChange:c=>this.saveSettings(c),onSync:()=>this.syncSettings()}),this.settingsSheet.mount(i,this.modelId,a,n.hasWorldUpdate??!1);let l=()=>this.gameId,d=()=>this.conversationId,g=()=>this.modelId,p=()=>this.models.find(c=>c.id===this.modelId)?.name;this.chat=new P(this.http,l,d,g,!1,void 0,void 0,p),this.characters=new R(this.http,d),this.relationships=new k(this.http,d),this.inventory=new T(this.http,d),this.world=new M(this.http,d),this.player=new O(this.http,d),this.custom=new _(this.http,d),this.save=new D(this.http,d),this.state=new U(this.http,d),this.listenForTokenUpdate(),this.initialized=!0}listenForTokenUpdate(){this.bus.on("token-update",e=>{let t=e.payload?.accessToken;typeof t!="string"||!t||(this.accessToken=t,this.http?.setToken(t))})}listenForPreviewMessages(){this.bus.on("set-model",e=>{this.modelId=e.payload.modelId||""}),this.bus.on("config-update",e=>{this.previewConfig=e.payload.previewConfig,this.chat&&this.chat.updatePreviewConfig(this.previewConfig),this.refreshPreviewSnapshot().catch(t=>{console.warn("[Storvia SDK] refreshPreviewSnapshot failed:",t)})})}async fetchPreviewSnapshot(){try{let e={game_id:this.gameId};return this.previewConfig&&("game_config"in this.previewConfig&&(e.game_config=this.previewConfig.game_config),"game_state"in this.previewConfig&&(e.game_state_override=this.previewConfig.game_state)),await this.http.post("/preview/initial-snapshot",e)}catch(e){return console.warn("[Storvia SDK] fetchPreviewSnapshot failed:",e),null}}async refreshPreviewSnapshot(){let e=await this.fetchPreviewSnapshot();e&&(this.characters?.setInitial(e.characters,e.characterStates),this.player?.setInitial(e.player,e.playerState),this.inventory?.setInitial(e.inventory),this.relationships?.setInitial(e.relationships),this.world?.setInitial(e.world),this.custom?.setInitial(e.custom,e.custom_inject),this.save?.setInitial(e.save_data))}async saveSettings(e){let t={conversation_id:this.conversationId};e.temperature!==void 0&&(t.temperature=e.temperature),e.replyLength!==void 0&&(t.reply_length=e.replyLength),e.replyLanguage!==void 0&&(t.reply_language=e.replyLanguage),e.playerNote!==void 0&&(t.player_note=e.playerNote),await this.http.patch("/settings",t)}async syncSettings(){await this.http.post("/sync",{conversation_id:this.conversationId})}async fetchModels(){try{return await this.http.get("/models")}catch{}return[]}async authenticate(){let e=await fetch(`${this.baseUrl}/auth`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.accessToken}`},body:JSON.stringify({game_id:this.gameId})});if(!e.ok)throw e.status===401?new m("UNAUTHORIZED","User not authenticated"):e.status===404?new m("GAME_NOT_FOUND","Game not found or not published"):new m("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=`${Oe}${ae}`,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(d=>d.id===i)?i:"")||t[0]?.id||"",this.conversationId="00000000-0000-0000-0000-000000000000",this.settingsSheet=new E({onModelChange:d=>{this.modelId=d},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,l=()=>this.models.find(d=>d.id===this.modelId)?.name;this.chat=new P(this.http,s,r,a,!0,void 0,()=>this.settingsSheet?.getSettings()??null,l),this.characters=new R(this.http,r,!0,n?.characters,n?.characterStates),this.relationships=new k(this.http,r,!0,n?.relationships),this.inventory=new T(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 de(o){let e=new H;return o?.dev?await e.initDev(o.dev):await e.init(),e}function q(o){return typeof o=="object"&&o!==null&&"value"in o&&"type"in o&&(o.type==="number"||o.type==="text")}function le(o){return q(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
|
@@ -24,7 +24,7 @@ declare class HttpClient {
|
|
|
24
24
|
delete<T>(path: string): Promise<T>;
|
|
25
25
|
stream(path: string, body: unknown, onChunk: (text: string) => void, onDone: (id: string) => void, meta?: {
|
|
26
26
|
modelName?: string;
|
|
27
|
-
}): Promise<void>;
|
|
27
|
+
}, onState?: (state: unknown, full: unknown) => void): Promise<void>;
|
|
28
28
|
/**
|
|
29
29
|
* 读取完整响应文本,解析为 JSON 并返回 `{ raw, data }`:
|
|
30
30
|
* - `raw` 是后端返回的整体(用于 debug 完整打印,含 success/code/message 等包装字段)
|
|
@@ -33,7 +33,48 @@ declare class HttpClient {
|
|
|
33
33
|
private handleResponseWithRaw;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
type StorviaErrorCode = 'UNAUTHORIZED' | 'INSUFFICIENT_CREDITS' | 'VIOLATION_WORD_DETECTED' | 'MESSAGE_TOO_LONG' | 'CONTENT_FILTERED' | 'MODEL_REFUSAL' | 'STREAM_INTERRUPTED' | 'RATE_LIMITED' | 'MODEL_NOT_FOUND' | 'GAME_NOT_FOUND' | 'INVALID_REQUEST' | 'INTERNAL_ERROR' | 'NOT_INITIALIZED' | 'NETWORK_ERROR';
|
|
36
|
+
type StorviaErrorCode = 'UNAUTHORIZED' | 'INSUFFICIENT_CREDITS' | 'VIOLATION_WORD_DETECTED' | 'MESSAGE_TOO_LONG' | 'CONTENT_FILTERED' | 'MODEL_REFUSAL' | 'STREAM_INTERRUPTED' | 'RATE_LIMITED' | 'MODEL_NOT_FOUND' | 'GAME_NOT_FOUND' | 'INVALID_REQUEST' | 'INTERNAL_ERROR' | 'NOT_INITIALIZED' | 'NOT_SUPPORTED_IN_PREVIEW' | 'NETWORK_ERROR';
|
|
37
|
+
/** AI 本轮的属性变更(仅包含发生改变的字段) */
|
|
38
|
+
interface StateChanges {
|
|
39
|
+
/** 世界状态变更(扁平 KV) */
|
|
40
|
+
world: Record<string, string> | null;
|
|
41
|
+
/** 玩家状态变更(扁平 KV) */
|
|
42
|
+
player: Record<string, string | number | boolean> | null;
|
|
43
|
+
/** 角色变更 */
|
|
44
|
+
characters: Array<{
|
|
45
|
+
id: string;
|
|
46
|
+
op: 'add' | 'update' | 'remove';
|
|
47
|
+
attrs: Record<string, string | number | boolean>;
|
|
48
|
+
}>;
|
|
49
|
+
/** 物品变更 */
|
|
50
|
+
items: Array<{
|
|
51
|
+
name: string;
|
|
52
|
+
op: 'add' | 'update' | 'remove';
|
|
53
|
+
count?: number;
|
|
54
|
+
[key: string]: unknown;
|
|
55
|
+
}>;
|
|
56
|
+
/** 关系变更 */
|
|
57
|
+
relations: Array<{
|
|
58
|
+
from: string;
|
|
59
|
+
to: string;
|
|
60
|
+
op: 'add' | 'update' | 'remove';
|
|
61
|
+
[key: string]: unknown;
|
|
62
|
+
}>;
|
|
63
|
+
/** 地点(仅 add) */
|
|
64
|
+
locations: Array<{
|
|
65
|
+
name: string;
|
|
66
|
+
op: 'add';
|
|
67
|
+
region?: string;
|
|
68
|
+
description?: string;
|
|
69
|
+
connections?: string[];
|
|
70
|
+
}>;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* State 事件回调:AI 本轮产生属性变更时触发。
|
|
74
|
+
* @param state 本轮的不同(仅包含变更字段)
|
|
75
|
+
* @param full 合并后的完整状态快照(结构同 storvia.state.get());首次对话或无 previous 时部分字段可能为 null
|
|
76
|
+
*/
|
|
77
|
+
type ChatStateCallback = (state: StateChanges, full: State | null) => void;
|
|
37
78
|
interface ChatSendOptions {
|
|
38
79
|
message: string;
|
|
39
80
|
topic?: string;
|
|
@@ -41,6 +82,8 @@ interface ChatSendOptions {
|
|
|
41
82
|
stream?: boolean;
|
|
42
83
|
onChunk?: (text: string) => void;
|
|
43
84
|
onDone?: (id: string) => void;
|
|
85
|
+
/** AI 本轮有属性变更时触发;非流式调用通过 ChatResponse.state/full 获取,无需此回调 */
|
|
86
|
+
onState?: ChatStateCallback;
|
|
44
87
|
}
|
|
45
88
|
interface ChatSaveOptions {
|
|
46
89
|
role: 'user' | 'assistant';
|
|
@@ -53,6 +96,8 @@ interface ChatGenerateOptions {
|
|
|
53
96
|
stream?: boolean;
|
|
54
97
|
onChunk?: (text: string) => void;
|
|
55
98
|
onDone?: (id: string) => void;
|
|
99
|
+
/** AI 本轮有属性变更时触发;非流式调用通过 ChatResponse.state/full 获取,无需此回调 */
|
|
100
|
+
onState?: ChatStateCallback;
|
|
56
101
|
}
|
|
57
102
|
interface ChatRetryOptions {
|
|
58
103
|
topic?: string;
|
|
@@ -60,10 +105,16 @@ interface ChatRetryOptions {
|
|
|
60
105
|
stream?: boolean;
|
|
61
106
|
onChunk?: (text: string) => void;
|
|
62
107
|
onDone?: (id: string) => void;
|
|
108
|
+
/** AI 本轮有属性变更时触发;非流式调用通过 ChatResponse.state/full 获取,无需此回调 */
|
|
109
|
+
onState?: ChatStateCallback;
|
|
63
110
|
}
|
|
64
111
|
interface ChatResponse {
|
|
65
112
|
id: string;
|
|
66
113
|
content: string;
|
|
114
|
+
/** AI 本轮的属性变更,仅在有变更时出现 */
|
|
115
|
+
state?: StateChanges;
|
|
116
|
+
/** 合并后的完整状态快照,仅在有变更时出现;结构同 storvia.state.get() */
|
|
117
|
+
full?: State;
|
|
67
118
|
}
|
|
68
119
|
interface ChatMessageCursor {
|
|
69
120
|
uuid: string;
|
|
@@ -191,6 +242,43 @@ interface PlayerPersona {
|
|
|
191
242
|
description?: string;
|
|
192
243
|
avatar?: string;
|
|
193
244
|
}
|
|
245
|
+
/** 当前活跃的所有模块数据 */
|
|
246
|
+
interface CurrentState {
|
|
247
|
+
world: Record<string, FieldValue>;
|
|
248
|
+
player: {
|
|
249
|
+
attributes: Record<string, Record<string, FieldValue>>;
|
|
250
|
+
};
|
|
251
|
+
characters: Record<string, {
|
|
252
|
+
isPreset?: boolean;
|
|
253
|
+
priority?: number;
|
|
254
|
+
avatar?: string;
|
|
255
|
+
gender?: Gender;
|
|
256
|
+
attributes: Record<string, Record<string, FieldValue>>;
|
|
257
|
+
}>;
|
|
258
|
+
inventory: Record<string, Record<string, {
|
|
259
|
+
count: number;
|
|
260
|
+
desc?: string;
|
|
261
|
+
icon_url?: string;
|
|
262
|
+
}>>;
|
|
263
|
+
relationships: Array<Record<string, unknown>>;
|
|
264
|
+
}
|
|
265
|
+
/** 因角色数量超出上限被移入休眠区的数据 */
|
|
266
|
+
interface DormantState {
|
|
267
|
+
characters: Record<string, {
|
|
268
|
+
isPreset?: boolean;
|
|
269
|
+
priority?: number;
|
|
270
|
+
avatar?: string;
|
|
271
|
+
gender?: Gender;
|
|
272
|
+
attributes: Record<string, Record<string, FieldValue>>;
|
|
273
|
+
}>;
|
|
274
|
+
relationships: Array<Record<string, unknown>>;
|
|
275
|
+
}
|
|
276
|
+
/** 完整游戏状态:跨所有模块的合并快照 */
|
|
277
|
+
interface State {
|
|
278
|
+
current: CurrentState;
|
|
279
|
+
previous: CurrentState | null;
|
|
280
|
+
dormant: DormantState;
|
|
281
|
+
}
|
|
194
282
|
|
|
195
283
|
interface GameSettings {
|
|
196
284
|
temperature: number;
|
|
@@ -431,6 +519,31 @@ declare class SaveModule {
|
|
|
431
519
|
set(data: Record<string, unknown>): Promise<void>;
|
|
432
520
|
}
|
|
433
521
|
|
|
522
|
+
/**
|
|
523
|
+
* 完整游戏状态(跨所有模块的合并快照)。
|
|
524
|
+
*
|
|
525
|
+
* 用于一次性拿到当前会话的完整状态对象(current + previous + dormant),
|
|
526
|
+
* 适合渲染整体 UI 面板或调试。单模块读取请用 `storvia.world` / `storvia.player` /
|
|
527
|
+
* `storvia.characters` 等对应模块的 `get()` 方法。
|
|
528
|
+
*/
|
|
529
|
+
declare class StateModule {
|
|
530
|
+
private http;
|
|
531
|
+
private getConversationId;
|
|
532
|
+
private isPreview;
|
|
533
|
+
constructor(http: HttpClient, getConversationId: () => string, isPreview?: boolean);
|
|
534
|
+
/**
|
|
535
|
+
* 读取当前会话的完整游戏状态。
|
|
536
|
+
*
|
|
537
|
+
* 返回 `{ current, previous, dormant }`:
|
|
538
|
+
* - `current`:当前所有活跃模块(world / player / characters / inventory / relationships)的合并快照
|
|
539
|
+
* - `previous`:上一轮的 current(用于做 before/after 对比)
|
|
540
|
+
* - `dormant`:因角色数量超出上限被移入休眠区的 characters / relationships
|
|
541
|
+
*
|
|
542
|
+
* 预览模式下不可用——预览会话没有持久化的 game_state,请使用各模块的 `get()`。
|
|
543
|
+
*/
|
|
544
|
+
get(): Promise<State | null>;
|
|
545
|
+
}
|
|
546
|
+
|
|
434
547
|
interface DevConfig {
|
|
435
548
|
apiKey: string;
|
|
436
549
|
gameId: string;
|
|
@@ -456,6 +569,7 @@ declare class StorviaSDK {
|
|
|
456
569
|
player: PlayerModule;
|
|
457
570
|
custom: CustomModule;
|
|
458
571
|
save: SaveModule;
|
|
572
|
+
state: StateModule;
|
|
459
573
|
init(): Promise<void>;
|
|
460
574
|
/**
|
|
461
575
|
* 监听父页面 token 刷新(envelope 'token-update')。
|
|
@@ -649,4 +763,4 @@ declare class StorviaBus<TIn extends AnyEnvelope, TOut extends AnyEnvelope> {
|
|
|
649
763
|
destroy(): void;
|
|
650
764
|
}
|
|
651
765
|
|
|
652
|
-
export { type AckPayload, type CharacterAddOptions, type CharacterDetail, type CharacterPersona, type CharacterUpdateOptions, type ChatGenerateOptions, type ChatMessage, type ChatMessageCursor, type ChatMessagesOptions, type ChatMessagesResponse, type ChatResponse, type ChatRetryOptions, type ChatSaveOptions, type ChatSendOptions, type ConfigUpdatePayload, type DownstreamMsg, type FieldValue, type Gender, type InitPayload, type InventoryAddOptions, type InventoryMoveOptions, type InventoryRemoveGroupOptions, type InventoryRemoveOptions, type InventoryState, type InventoryUpdateOptions, type ItemData, type OrientationPayload, PROTOCOL_VERSION, type PlayerPersona, type PreviewConfig, type PreviewInitPayload, type ProtocolEnvelope, type ReadyPayload, type Relationship, type RichFieldValue, type SdkErrorPayload, type SetModelPayload, StorviaBus, type StorviaBusOptions, StorviaError, type StorviaErrorCode, StorviaSDK, type TokenUpdatePayload, type UpstreamMsg, createStorviaSDK, envelope, extractFieldValue, isProtocolEnvelope, isRichFieldValue, setToastEnabled, showToast };
|
|
766
|
+
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 ChatStateCallback, type ConfigUpdatePayload, type CurrentState, type DormantState, 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, type State, type StateChanges, StorviaBus, type StorviaBusOptions, StorviaError, type StorviaErrorCode, StorviaSDK, type TokenUpdatePayload, type UpstreamMsg, createStorviaSDK, envelope, extractFieldValue, isProtocolEnvelope, isRichFieldValue, setToastEnabled, showToast };
|