@storvia/sdk 0.1.0 → 0.1.3
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 +2 -2
- package/dist/index.esm.js +2 -2
- package/dist/index.umd.js +2 -2
- package/package.json +1 -1
- package/dist/index.cjs.js.map +0 -1
- package/dist/index.esm.js.map +0 -1
- package/dist/index.umd.js.map +0 -1
package/dist/index.cjs.js
CHANGED
|
@@ -427,5 +427,5 @@
|
|
|
427
427
|
to { transform: rotate(360deg); }
|
|
428
428
|
}
|
|
429
429
|
.spin { animation: spin 0.8s linear infinite; }
|
|
430
|
-
`,D='<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="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>',j='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>',z='<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>',G='<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>',F='<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>',v=class{constructor(e){this.selectedModelId="";this.models=[];this.modelPanel=null;this.settings={temperature:1,reply_length:"medium",reply_language:"zh-CN",player_note:""};this.hasWorldUpdate=!1;this.fabDot=null;this.syncHint=null;this.displayMode="phone";this.displayModeBtns=[];this.tempValueEl=null;this.tempSlider=null;this.segmentBtns=[];this.langSelect=null;this.noteInput=null;this.noteCounter=null;this.saveBtn=null;this.syncBtn=null;this.syncState="idle";this.panel=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,s=!1){this.models=e,this.selectedModelId=t,this.settings={...n},this.hasWorldUpdate=s;try{let i=localStorage.getItem("storvia_display_mode");(i==="phone"||i==="desktop")&&(this.displayMode=i)}catch{}document.body.appendChild(this.host),this.render()}unmount(){this.host.remove()}getSelectedModelId(){return this.selectedModelId}getSettings(){return{...this.settings}}render(){let e=document.createElement("style");e.textContent=U;let t=document.createElement("div"),n=document.createElement("div");n.className="fab-wrap";let s=document.createElement("button");s.className="fab",s.innerHTML=D,s.title="\u6E38\u620F\u8BBE\u7F6E";let i=document.createElement("div");i.className=`fab-dot${this.hasWorldUpdate?" visible":""}`,this.fabDot=i,n.appendChild(s),n.appendChild(i);let a=document.createElement("div");a.className="panel",this.panel=a;let o=document.createElement("div");o.className="panel-header";let d=document.createElement("div");d.className="panel-title",d.textContent="\u6E38\u620F\u8BBE\u7F6E";let p=document.createElement("button");p.className="close-btn",p.innerHTML="\u2715",p.addEventListener("click",()=>a.classList.remove("open")),o.appendChild(d),o.appendChild(p),a.appendChild(o);let r=document.createElement("div");r.className="panel-body",this.models.length>0&&(r.appendChild(this.buildModelSection()),r.appendChild(this.makeDivider())),r.appendChild(this.buildTemperatureSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildReplyLengthSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildReplyLanguageSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildNoteSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildDisplayModeSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildSyncSection());let m=document.createElement("div");m.className="save-row";let h=document.createElement("button");h.className="save-btn",h.textContent="\u4FDD\u5B58",this.saveBtn=h,h.addEventListener("click",()=>this.handleSave()),m.appendChild(h),r.appendChild(m),a.appendChild(r),s.addEventListener("click",()=>a.classList.toggle("open")),document.addEventListener("click",u=>{this.host.contains(u.target)||a.classList.remove("open")}),t.appendChild(a),t.appendChild(n),this.shadowRoot.appendChild(e),this.shadowRoot.appendChild(t)}buildModelSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="AI \u6A21\u578B",e.appendChild(t);let n=document.createElement("div");return n.className="model-list",this.modelPanel=n,this.models.forEach(s=>{let i=document.createElement("button");i.className=`model-option${s.id===this.selectedModelId?" active":""}`,i.innerHTML=`<span class="dot"></span><span>${s.name}</span>`,i.addEventListener("click",()=>{this.selectedModelId=s.id,this.callbacks.onModelChange(s.id);try{localStorage.setItem("storvia_model_id",s.id)}catch{}this.updateModelActive()}),n.appendChild(i)}),e.appendChild(n),e}buildTemperatureSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label";let n=document.createElement("span");n.textContent="\u6E29\u5EA6";let s=document.createElement("span");s.className="value",s.textContent=this.settings.temperature.toFixed(1),this.tempValueEl=s,t.appendChild(n),t.appendChild(s),e.appendChild(t);let i=document.createElement("div");i.className="section-desc",i.textContent="\u66F4\u4F4E\u7684\u6E29\u5EA6\u4F1A\u8BA9 AI \u56DE\u590D\u66F4\u7A33\u5B9A\u3001\u7406\u667A\uFF1B\u66F4\u9AD8\u7684\u6E29\u5EA6\u4F1A\u8BA9 AI \u7684\u56DE\u590D\u66F4\u5177\u591A\u6837\u6027\u548C\u968F\u673A\u6027",e.appendChild(i);let a=document.createElement("div");a.className="slider-wrap";let o=document.createElement("input");o.type="range",o.className="slider",o.min="0",o.max="2",o.step="0.1",o.value=String(this.settings.temperature),this.tempSlider=o,o.addEventListener("input",()=>{let p=parseFloat(o.value);this.settings.temperature=p,this.tempValueEl&&(this.tempValueEl.textContent=p.toFixed(1))}),a.appendChild(o);let d=document.createElement("div");return d.className="slider-labels",d.innerHTML="<span>\u7CBE\u786E</span><span>\u521B\u610F</span>",a.appendChild(d),e.appendChild(a),e}buildReplyLengthSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u56DE\u590D\u957F\u5EA6",e.appendChild(t);let n=document.createElement("div");return n.className="segment",this.segmentBtns=[],N.forEach(s=>{let i=document.createElement("button");i.className=`segment-btn${s.value===this.settings.reply_length?" active":""}`,i.textContent=s.label,i.addEventListener("click",()=>{this.settings.reply_length=s.value,this.segmentBtns.forEach((a,o)=>{a.classList.toggle("active",N[o].value===s.value)})}),this.segmentBtns.push(i),n.appendChild(i)}),e.appendChild(n),e}buildReplyLanguageSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u56DE\u590D\u8BED\u8A00",e.appendChild(t);let n=document.createElement("div");n.className="select-wrap";let s=document.createElement("select");s.className="select",this.langSelect=s,A.forEach(a=>{let o=document.createElement("option");o.value=a.value,o.textContent=a.label,a.value===this.settings.reply_language&&(o.selected=!0),s.appendChild(o)}),s.addEventListener("change",()=>{this.settings.reply_language=s.value});let i=document.createElement("span");return i.className="select-arrow",i.textContent="\u25BE",n.appendChild(s),n.appendChild(i),e.appendChild(n),e}buildNoteSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label";let n=document.createElement("span");n.textContent="\u5907\u6CE8";let s=document.createElement("span");s.textContent=`${this.settings.player_note.length}/50`,this.noteCounter=s,t.appendChild(n),t.appendChild(s),e.appendChild(t);let i=document.createElement("div");i.className="section-desc",i.textContent="\u5199\u4E0B\u4F60\u5BF9\u8FD9\u4E2A\u6E38\u620F\u7684\u5907\u6CE8\uFF0C\u4F1A\u663E\u793A\u5728\u5B58\u6863\u5217\u8868",e.appendChild(i);let a=document.createElement("div");a.className="note-wrap";let o=document.createElement("textarea");return o.className="note-input",o.placeholder="\u5907\u6CE8",o.maxLength=50,o.value=this.settings.player_note,this.noteInput=o,o.addEventListener("input",()=>{this.settings.player_note=o.value,this.noteCounter&&(this.noteCounter.textContent=`${o.value.length}/50`)}),a.appendChild(o),e.appendChild(a),e}buildDisplayModeSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u663E\u793A\u6A21\u5F0F",e.appendChild(t);let n=document.createElement("div");n.className="section-desc",n.textContent="\u7535\u8111\u6A21\u5F0F\u4F1A\u81EA\u52A8\u6A2A\u5C4F\u663E\u793A",e.appendChild(n);let s=document.createElement("div");s.className="segment",this.displayModeBtns=[];let i=[{value:"phone",label:"\u624B\u673A"},{value:"desktop",label:"\u7535\u8111"}];return i.forEach(a=>{let o=document.createElement("button");o.className=`segment-btn${a.value===this.displayMode?" active":""}`,o.textContent=a.label,o.addEventListener("click",()=>{this.displayMode=a.value;try{localStorage.setItem("storvia_display_mode",a.value)}catch{}this.displayModeBtns.forEach((d,p)=>{d.classList.toggle("active",i[p].value===a.value)});try{window.parent.postMessage({type:"storvia-orientation",mode:a.value==="desktop"?"landscape":"portrait"},"*")}catch{}}),this.displayModeBtns.push(o),s.appendChild(o)}),e.appendChild(s),e}buildSyncSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u540C\u6B65\u6E38\u620F\u8BBE\u5B9A",e.appendChild(t);let n=document.createElement("div");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 s=document.createElement("div");s.className="sync-desc",s.textContent="\u5982\u679C\u6E38\u620F\u4F5C\u8005\u66F4\u65B0\u4E86\u5185\u5BB9\uFF0C\u70B9\u51FB\u6B64\u6309\u94AE\u53EF\u5C06\u6700\u65B0\u7684\u6E38\u620F\u8BBE\u5B9A\u548C\u5F00\u5E55\u5C0F\u5267\u573A\u540C\u6B65\u5230\u5F53\u524D\u5BF9\u8BDD",e.appendChild(s);let i=document.createElement("button");return i.className="sync-btn",this.syncBtn=i,this.renderSyncBtn(),i.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(i),e}makeDivider(){let e=document.createElement("div");return e.className="divider",e}updateModelActive(){this.modelPanel&&this.modelPanel.querySelectorAll(".model-option").forEach((e,t)=>{e.classList.toggle("active",this.models[t].id===this.selectedModelId)})}setSyncState(e){this.syncState=e,this.renderSyncBtn()}renderSyncBtn(){if(!this.syncBtn)return;let e=this.syncState,t={idle:j,loading:z,success:G,error:F},n={idle:"\u540C\u6B65\u6700\u65B0\u8BBE\u5B9A",loading:"\u540C\u6B65\u4E2D...",success:"\u5DF2\u540C\u6B65",error:"\u540C\u6B65\u5931\u8D25"};this.syncBtn.className=`sync-btn${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.textContent="\u4FDD\u5B58\u4E2D...";try{await this.callbacks.onSettingsChange({temperature:this.settings.temperature,reply_length:this.settings.reply_length,reply_language:this.settings.reply_language,player_note:this.settings.player_note}),this.saveBtn.textContent="\u5DF2\u4FDD\u5B58",this.saveBtn.classList.add("saved"),setTimeout(()=>{this.saveBtn&&(this.saveBtn.textContent="\u4FDD\u5B58",this.saveBtn.classList.remove("saved"),this.saveBtn.disabled=!1)},2e3)}catch{this.saveBtn.textContent="\u4FDD\u5B58\u5931\u8D25",setTimeout(()=>{this.saveBtn&&(this.saveBtn.textContent="\u4FDD\u5B58",this.saveBtn.disabled=!1)},2e3)}}}};var f=class{constructor(e,t,n,s,i=!1,a){this.http=e;this.getGameId=t;this.getConversationId=n;this.getModelId=s;this.isPreview=i;this.previewConfig=a}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,context:e.context,stream:e.stream??!1};if(e.stream){await this.http.stream("/chat",t,e.onChunk??(()=>{}),e.onDone??(()=>{}));return}return this.http.post("/chat",t)}async save(e){return this.http.post("/messages/save",{conversation_id:this.getConversationId(),role:e.role,content:e.content,topic:e.topic})}async generate(e){let t={conversation_id:this.getConversationId(),model_id:this.getModelId(),topic:e.topic,context:e.context,stream:e.stream??!1,save:e.save??!0};if(e.stream){await this.http.stream("/generate",t,e.onChunk??(()=>{}),e.onDone??(()=>{}));return}return this.http.post("/generate",t)}async sendPreview(e){let t={model_id:this.getModelId(),message:e.message,topic:e.topic,context:e.context,prompt_config:this.previewConfig||{},history_messages:[]};if(e.stream){await this.http.stream("/preview",t,e.onChunk??(()=>{}),e.onDone??(()=>{}));return}let n="";return await this.http.stream("/preview",t,s=>{n+=s},()=>{}),{id:"",content:n}}};var R=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}async get(e){return this.isPreview?{...this.mem[e]||{}}:this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/state`)}async update(e,t){if(this.isPreview){this.mem[e]={...this.mem[e]||{},...t};return}await this.http.patch(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/state`,t)}},b=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[];this.state=new R(e,t,n)}async list(){return this.isPreview?this.mem.map(e=>({name:e.name,avatar:e.avatar})):this.http.get(`/conversations/${this.getConversationId()}/characters`)}async get(e){if(this.isPreview){let t=this.mem.find(n=>n.name===e);return{name:t?.name||e,avatar:t?.avatar}}return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}`)}async add(e){if(this.isPreview){this.mem.push(e);return}await this.http.post(`/conversations/${this.getConversationId()}/characters`,e)}async update(e,t){if(this.isPreview){let n=this.mem.find(s=>s.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,state:await this.state.get(e)}}return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/detail`)}};var w=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[]}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(s=>s.from===e&&s.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 s=this.mem.find(i=>i.from===e&&i.to===t);s?Object.assign(s,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)}`)}};var y=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[]}async list(e){if(this.isPreview)return e?this.mem.filter(n=>n.group===e):[...this.mem];let t=e?{group:e}:void 0;return this.http.get(`/conversations/${this.getConversationId()}/inventory`,t)}async add(e){if(this.isPreview){this.mem.push({...e});return}await this.http.post(`/conversations/${this.getConversationId()}/inventory`,e)}async update(e,t){if(this.isPreview){let n=this.mem.find(s=>s.name===e);n&&Object.assign(n,t);return}await this.http.patch(`/conversations/${this.getConversationId()}/inventory/${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()}/inventory/${encodeURIComponent(e)}`)}};var C=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}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 T=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}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})}},x=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.memPersona={name:""};this.state=new T(e,t,n)}async get(){return this.isPreview?{...this.memPersona}:this.http.get(`/conversations/${this.getConversationId()}/player`)}};var I=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}async get(e){if(this.isPreview)return e!==void 0?this.mem[e]:{...this.mem};let t=await this.http.get(`/conversations/${this.getConversationId()}/custom`);return e!==void 0?t[e]:t}async set(e){if(this.isPreview){for(let[t,n]of Object.entries(e))typeof n=="object"&&n!==null&&!Array.isArray(n)&&typeof this.mem[t]=="object"&&this.mem[t]!==null?this.mem[t]={...this.mem[t],...n}:this.mem[t]=n;return}await this.http.patch(`/conversations/${this.getConversationId()}/custom`,e)}async delete(e){if(this.isPreview){delete this.mem[e];return}await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}`)}async setGroupField(e,t,n){if(this.isPreview){(!this.mem[e]||typeof this.mem[e]!="object")&&(this.mem[e]={}),this.mem[e][t]=n;return}await this.http.patch(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{value:n})}async deleteGroupField(e,t){if(this.isPreview){if(typeof this.mem[e]=="object"&&this.mem[e]!==null){let n=this.mem[e];delete n[t],Object.keys(n).length===0&&delete this.mem[e]}return}await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)}};var V="/functions/v1/world-engine/v1";function W(){return window.__STORVIA__||{}}function J(l=5e3){let e=W();return e.apiBase?Promise.resolve(e):new Promise((t,n)=>{let s=setTimeout(()=>{window.removeEventListener("message",i),n(new c("NOT_INITIALIZED","Timed out waiting for __STORVIA__ config from parent frame."))},l);function i(a){let o=null;if(a.data?.type==="storvia-init"&&a.data.apiBase?o={apiBase:a.data.apiBase,gameId:a.data.gameId,accessToken:a.data.accessToken}:a.data?.type==="storvia-preview-init"&&a.data.config&&(o=a.data.config),o&&o.apiBase){clearTimeout(s),window.removeEventListener("message",i);let d=window;d.__STORVIA__=o,t(o)}}window.addEventListener("message",i)})}var k=class{constructor(){this.baseUrl="";this.gameId="";this.conversationId="";this.modelId="";this.accessToken="";this.initialized=!1;this.isPreview=!1;this.previewConfig=void 0}async init(){let e=await J(),t=e.apiBase;if(!t)throw new c("NOT_INITIALIZED","window.__STORVIA__.apiBase is not set. The platform must inject it before SDK init.");if(this.baseUrl=`${t}${V}`,this.isPreview=!!e.preview,this.previewConfig=e.previewConfig,!e.gameId)throw new c("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 c("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 S(this.baseUrl,this.accessToken,!!e.debug),this.isPreview){this.conversationId="00000000-0000-0000-0000-000000000000";let r=e.models||[];this.modelId=e.selectedModelId||r[0]?.id||"",this.settingsSheet=new v({onModelChange:E=>{this.modelId=E},onSettingsChange:()=>Promise.resolve(),onSync:()=>Promise.resolve()}),r.length>0&&this.settingsSheet.mount(r,this.modelId,{temperature:1,reply_length:"medium",reply_language:"zh-CN",player_note:""},!1);let m=()=>this.gameId,h=()=>this.conversationId,u=()=>this.modelId;this.chat=new f(this.http,m,h,u,!0,this.previewConfig),this.characters=new b(this.http,h,!0),this.relationships=new w(this.http,h,!0),this.inventory=new y(this.http,h,!0),this.world=new C(this.http,h,!0),this.player=new x(this.http,h,!0),this.custom=new I(this.http,h,!0),this.initialized=!0,this.listenForPreviewMessages();return}let n=await this.authenticate();this.conversationId=n.conversationId;let s=n.models||[],i=this.getSavedModelId();this.modelId=i&&s.some(r=>r.id===i)?i:s[0]?.id||"";let a=n.settings||{temperature:1,reply_length:"medium",reply_language:"zh-CN",player_note:""};this.settingsSheet=new v({onModelChange:r=>{this.modelId=r},onSettingsChange:r=>this.saveSettings(r),onSync:()=>this.syncSettings()}),this.settingsSheet.mount(s,this.modelId,a,n.hasWorldUpdate??!1);let o=()=>this.gameId,d=()=>this.conversationId,p=()=>this.modelId;this.chat=new f(this.http,o,d,p),this.characters=new b(this.http,d),this.relationships=new w(this.http,d),this.inventory=new y(this.http,d),this.world=new C(this.http,d),this.player=new x(this.http,d),this.custom=new I(this.http,d),this.initialized=!0}listenForPreviewMessages(){window.addEventListener("message",e=>{!e.data||e.data.type!=="storvia-preview"||(e.data.action==="set-model"&&(this.modelId=e.data.modelId||""),e.data.action==="update-config"&&(this.previewConfig=e.data.previewConfig,this.chat&&this.chat.updatePreviewConfig(this.previewConfig)))})}async saveSettings(e){await this.http.patch("/settings",{conversation_id:this.conversationId,...e})}async syncSettings(){await this.http.post("/sync",{conversation_id:this.conversationId})}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 c("UNAUTHORIZED","User not authenticated"):e.status===404?new c("GAME_NOT_FOUND","Game not found or not published"):new c("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""}}};0&&(module.exports={StorviaError,StorviaSDK});
|
|
431
|
-
//# sourceMappingURL=index.cjs.js.map
|
|
430
|
+
`,D='<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="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>',j='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>',z='<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>',G='<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>',F='<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>',v=class{constructor(e){this.selectedModelId="";this.models=[];this.modelPanel=null;this.settings={temperature:1,reply_length:"medium",reply_language:"zh-CN",player_note:""};this.hasWorldUpdate=!1;this.fabDot=null;this.syncHint=null;this.displayMode="phone";this.displayModeBtns=[];this.tempValueEl=null;this.tempSlider=null;this.segmentBtns=[];this.langSelect=null;this.noteInput=null;this.noteCounter=null;this.saveBtn=null;this.syncBtn=null;this.syncState="idle";this.panel=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,s=!1){this.models=e,this.selectedModelId=t,this.settings={...n},this.hasWorldUpdate=s;try{let i=localStorage.getItem("storvia_display_mode");(i==="phone"||i==="desktop")&&(this.displayMode=i)}catch{}document.body.appendChild(this.host),this.render()}unmount(){this.host.remove()}getSelectedModelId(){return this.selectedModelId}getSettings(){return{...this.settings}}render(){let e=document.createElement("style");e.textContent=U;let t=document.createElement("div"),n=document.createElement("div");n.className="fab-wrap";let s=document.createElement("button");s.className="fab",s.innerHTML=D,s.title="\u6E38\u620F\u8BBE\u7F6E";let i=document.createElement("div");i.className=`fab-dot${this.hasWorldUpdate?" visible":""}`,this.fabDot=i,n.appendChild(s),n.appendChild(i);let a=document.createElement("div");a.className="panel",this.panel=a;let o=document.createElement("div");o.className="panel-header";let d=document.createElement("div");d.className="panel-title",d.textContent="\u6E38\u620F\u8BBE\u7F6E";let p=document.createElement("button");p.className="close-btn",p.innerHTML="\u2715",p.addEventListener("click",()=>a.classList.remove("open")),o.appendChild(d),o.appendChild(p),a.appendChild(o);let r=document.createElement("div");r.className="panel-body",this.models.length>0&&(r.appendChild(this.buildModelSection()),r.appendChild(this.makeDivider())),r.appendChild(this.buildTemperatureSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildReplyLengthSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildReplyLanguageSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildNoteSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildDisplayModeSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildSyncSection());let m=document.createElement("div");m.className="save-row";let h=document.createElement("button");h.className="save-btn",h.textContent="\u4FDD\u5B58",this.saveBtn=h,h.addEventListener("click",()=>this.handleSave()),m.appendChild(h),r.appendChild(m),a.appendChild(r),s.addEventListener("click",()=>a.classList.toggle("open")),document.addEventListener("click",u=>{this.host.contains(u.target)||a.classList.remove("open")}),t.appendChild(a),t.appendChild(n),this.shadowRoot.appendChild(e),this.shadowRoot.appendChild(t)}buildModelSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="AI \u6A21\u578B",e.appendChild(t);let n=document.createElement("div");return n.className="model-list",this.modelPanel=n,this.models.forEach(s=>{let i=document.createElement("button");i.className=`model-option${s.id===this.selectedModelId?" active":""}`,i.innerHTML=`<span class="dot"></span><span>${s.name}</span>`,i.addEventListener("click",()=>{this.selectedModelId=s.id,this.callbacks.onModelChange(s.id);try{localStorage.setItem("storvia_model_id",s.id)}catch{}this.updateModelActive()}),n.appendChild(i)}),e.appendChild(n),e}buildTemperatureSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label";let n=document.createElement("span");n.textContent="\u6E29\u5EA6";let s=document.createElement("span");s.className="value",s.textContent=this.settings.temperature.toFixed(1),this.tempValueEl=s,t.appendChild(n),t.appendChild(s),e.appendChild(t);let i=document.createElement("div");i.className="section-desc",i.textContent="\u66F4\u4F4E\u7684\u6E29\u5EA6\u4F1A\u8BA9 AI \u56DE\u590D\u66F4\u7A33\u5B9A\u3001\u7406\u667A\uFF1B\u66F4\u9AD8\u7684\u6E29\u5EA6\u4F1A\u8BA9 AI \u7684\u56DE\u590D\u66F4\u5177\u591A\u6837\u6027\u548C\u968F\u673A\u6027",e.appendChild(i);let a=document.createElement("div");a.className="slider-wrap";let o=document.createElement("input");o.type="range",o.className="slider",o.min="0",o.max="2",o.step="0.1",o.value=String(this.settings.temperature),this.tempSlider=o,o.addEventListener("input",()=>{let p=parseFloat(o.value);this.settings.temperature=p,this.tempValueEl&&(this.tempValueEl.textContent=p.toFixed(1))}),a.appendChild(o);let d=document.createElement("div");return d.className="slider-labels",d.innerHTML="<span>\u7CBE\u786E</span><span>\u521B\u610F</span>",a.appendChild(d),e.appendChild(a),e}buildReplyLengthSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u56DE\u590D\u957F\u5EA6",e.appendChild(t);let n=document.createElement("div");return n.className="segment",this.segmentBtns=[],N.forEach(s=>{let i=document.createElement("button");i.className=`segment-btn${s.value===this.settings.reply_length?" active":""}`,i.textContent=s.label,i.addEventListener("click",()=>{this.settings.reply_length=s.value,this.segmentBtns.forEach((a,o)=>{a.classList.toggle("active",N[o].value===s.value)})}),this.segmentBtns.push(i),n.appendChild(i)}),e.appendChild(n),e}buildReplyLanguageSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u56DE\u590D\u8BED\u8A00",e.appendChild(t);let n=document.createElement("div");n.className="select-wrap";let s=document.createElement("select");s.className="select",this.langSelect=s,A.forEach(a=>{let o=document.createElement("option");o.value=a.value,o.textContent=a.label,a.value===this.settings.reply_language&&(o.selected=!0),s.appendChild(o)}),s.addEventListener("change",()=>{this.settings.reply_language=s.value});let i=document.createElement("span");return i.className="select-arrow",i.textContent="\u25BE",n.appendChild(s),n.appendChild(i),e.appendChild(n),e}buildNoteSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label";let n=document.createElement("span");n.textContent="\u5907\u6CE8";let s=document.createElement("span");s.textContent=`${this.settings.player_note.length}/50`,this.noteCounter=s,t.appendChild(n),t.appendChild(s),e.appendChild(t);let i=document.createElement("div");i.className="section-desc",i.textContent="\u5199\u4E0B\u4F60\u5BF9\u8FD9\u4E2A\u6E38\u620F\u7684\u5907\u6CE8\uFF0C\u4F1A\u663E\u793A\u5728\u5B58\u6863\u5217\u8868",e.appendChild(i);let a=document.createElement("div");a.className="note-wrap";let o=document.createElement("textarea");return o.className="note-input",o.placeholder="\u5907\u6CE8",o.maxLength=50,o.value=this.settings.player_note,this.noteInput=o,o.addEventListener("input",()=>{this.settings.player_note=o.value,this.noteCounter&&(this.noteCounter.textContent=`${o.value.length}/50`)}),a.appendChild(o),e.appendChild(a),e}buildDisplayModeSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u663E\u793A\u6A21\u5F0F",e.appendChild(t);let n=document.createElement("div");n.className="section-desc",n.textContent="\u7535\u8111\u6A21\u5F0F\u4F1A\u81EA\u52A8\u6A2A\u5C4F\u663E\u793A",e.appendChild(n);let s=document.createElement("div");s.className="segment",this.displayModeBtns=[];let i=[{value:"phone",label:"\u624B\u673A"},{value:"desktop",label:"\u7535\u8111"}];return i.forEach(a=>{let o=document.createElement("button");o.className=`segment-btn${a.value===this.displayMode?" active":""}`,o.textContent=a.label,o.addEventListener("click",()=>{this.displayMode=a.value;try{localStorage.setItem("storvia_display_mode",a.value)}catch{}this.displayModeBtns.forEach((d,p)=>{d.classList.toggle("active",i[p].value===a.value)});try{window.parent.postMessage({type:"storvia-orientation",mode:a.value==="desktop"?"landscape":"portrait"},"*")}catch{}}),this.displayModeBtns.push(o),s.appendChild(o)}),e.appendChild(s),e}buildSyncSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u540C\u6B65\u6E38\u620F\u8BBE\u5B9A",e.appendChild(t);let n=document.createElement("div");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 s=document.createElement("div");s.className="sync-desc",s.textContent="\u5982\u679C\u6E38\u620F\u4F5C\u8005\u66F4\u65B0\u4E86\u5185\u5BB9\uFF0C\u70B9\u51FB\u6B64\u6309\u94AE\u53EF\u5C06\u6700\u65B0\u7684\u6E38\u620F\u8BBE\u5B9A\u548C\u5F00\u5E55\u5C0F\u5267\u573A\u540C\u6B65\u5230\u5F53\u524D\u5BF9\u8BDD",e.appendChild(s);let i=document.createElement("button");return i.className="sync-btn",this.syncBtn=i,this.renderSyncBtn(),i.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(i),e}makeDivider(){let e=document.createElement("div");return e.className="divider",e}updateModelActive(){this.modelPanel&&this.modelPanel.querySelectorAll(".model-option").forEach((e,t)=>{e.classList.toggle("active",this.models[t].id===this.selectedModelId)})}setSyncState(e){this.syncState=e,this.renderSyncBtn()}renderSyncBtn(){if(!this.syncBtn)return;let e=this.syncState,t={idle:j,loading:z,success:G,error:F},n={idle:"\u540C\u6B65\u6700\u65B0\u8BBE\u5B9A",loading:"\u540C\u6B65\u4E2D...",success:"\u5DF2\u540C\u6B65",error:"\u540C\u6B65\u5931\u8D25"};this.syncBtn.className=`sync-btn${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.textContent="\u4FDD\u5B58\u4E2D...";try{await this.callbacks.onSettingsChange({temperature:this.settings.temperature,reply_length:this.settings.reply_length,reply_language:this.settings.reply_language,player_note:this.settings.player_note}),this.saveBtn.textContent="\u5DF2\u4FDD\u5B58",this.saveBtn.classList.add("saved"),setTimeout(()=>{this.saveBtn&&(this.saveBtn.textContent="\u4FDD\u5B58",this.saveBtn.classList.remove("saved"),this.saveBtn.disabled=!1)},2e3)}catch{this.saveBtn.textContent="\u4FDD\u5B58\u5931\u8D25",setTimeout(()=>{this.saveBtn&&(this.saveBtn.textContent="\u4FDD\u5B58",this.saveBtn.disabled=!1)},2e3)}}}};var f=class{constructor(e,t,n,s,i=!1,a){this.http=e;this.getGameId=t;this.getConversationId=n;this.getModelId=s;this.isPreview=i;this.previewConfig=a}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,context:e.context,stream:e.stream??!1};if(e.stream){await this.http.stream("/chat",t,e.onChunk??(()=>{}),e.onDone??(()=>{}));return}return this.http.post("/chat",t)}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,context:(e.context||"")+`
|
|
431
|
+
[\u6307\u4EE4] \u8BF7\u76F4\u63A5\u751F\u6210\u56DE\u590D\uFF0C\u65E0\u9700\u7528\u6237\u8F93\u5165`,stream:e.stream,onChunk:e.onChunk,onDone:e.onDone});let t={conversation_id:this.getConversationId(),model_id:this.getModelId(),topic:e.topic,context:e.context,stream:e.stream??!1,save:e.save??!0};if(e.stream){await this.http.stream("/generate",t,e.onChunk??(()=>{}),e.onDone??(()=>{}));return}return this.http.post("/generate",t)}async sendPreview(e){let t={model_id:this.getModelId(),message:e.message,topic:e.topic,context:e.context,prompt_config:this.previewConfig||{},history_messages:[]};if(e.stream){await this.http.stream("/preview",t,e.onChunk??(()=>{}),e.onDone??(()=>{}));return}let n="";return await this.http.stream("/preview",t,s=>{n+=s},()=>{}),{id:"",content:n}}};var R=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}async get(e){return this.isPreview?{...this.mem[e]||{}}:this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/state`)}async update(e,t){if(this.isPreview){this.mem[e]={...this.mem[e]||{},...t};return}await this.http.patch(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/state`,t)}},b=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[];this.state=new R(e,t,n)}async list(){return this.isPreview?this.mem.map(e=>({name:e.name,avatar:e.avatar})):this.http.get(`/conversations/${this.getConversationId()}/characters`)}async get(e){if(this.isPreview){let t=this.mem.find(n=>n.name===e);return{name:t?.name||e,avatar:t?.avatar}}return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}`)}async add(e){if(this.isPreview){this.mem.push(e);return}await this.http.post(`/conversations/${this.getConversationId()}/characters`,e)}async update(e,t){if(this.isPreview){let n=this.mem.find(s=>s.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,state:await this.state.get(e)}}return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/detail`)}};var w=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[]}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(s=>s.from===e&&s.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 s=this.mem.find(i=>i.from===e&&i.to===t);s?Object.assign(s,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)}`)}};var y=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[]}async list(e){if(this.isPreview)return e?this.mem.filter(n=>n.group===e):[...this.mem];let t=e?{group:e}:void 0;return this.http.get(`/conversations/${this.getConversationId()}/inventory`,t)}async add(e){if(this.isPreview){this.mem.push({...e});return}await this.http.post(`/conversations/${this.getConversationId()}/inventory`,e)}async update(e,t){if(this.isPreview){let n=this.mem.find(s=>s.name===e);n&&Object.assign(n,t);return}await this.http.patch(`/conversations/${this.getConversationId()}/inventory/${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()}/inventory/${encodeURIComponent(e)}`)}};var C=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}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 T=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}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})}},x=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.memPersona={name:""};this.state=new T(e,t,n)}async get(){return this.isPreview?{...this.memPersona}:this.http.get(`/conversations/${this.getConversationId()}/player`)}};var I=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}async get(e){if(this.isPreview)return e!==void 0?this.mem[e]:{...this.mem};let t=await this.http.get(`/conversations/${this.getConversationId()}/custom`);return e!==void 0?t[e]:t}async set(e){if(this.isPreview){for(let[t,n]of Object.entries(e))typeof n=="object"&&n!==null&&!Array.isArray(n)&&typeof this.mem[t]=="object"&&this.mem[t]!==null?this.mem[t]={...this.mem[t],...n}:this.mem[t]=n;return}await this.http.patch(`/conversations/${this.getConversationId()}/custom`,e)}async delete(e){if(this.isPreview){delete this.mem[e];return}await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}`)}async setGroupField(e,t,n){if(this.isPreview){(!this.mem[e]||typeof this.mem[e]!="object")&&(this.mem[e]={}),this.mem[e][t]=n;return}await this.http.patch(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{value:n})}async deleteGroupField(e,t){if(this.isPreview){if(typeof this.mem[e]=="object"&&this.mem[e]!==null){let n=this.mem[e];delete n[t],Object.keys(n).length===0&&delete this.mem[e]}return}await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)}};var V="/functions/v1/world-engine/v1";function W(){return window.__STORVIA__||{}}function J(l=5e3){let e=W();return e.apiBase?Promise.resolve(e):new Promise((t,n)=>{let s=setTimeout(()=>{window.removeEventListener("message",i),n(new c("NOT_INITIALIZED","Timed out waiting for __STORVIA__ config from parent frame."))},l);function i(a){let o=null;if(a.data?.type==="storvia-init"&&a.data.apiBase?o={apiBase:a.data.apiBase,gameId:a.data.gameId,accessToken:a.data.accessToken}:a.data?.type==="storvia-preview-init"&&a.data.config&&(o=a.data.config),o&&o.apiBase){clearTimeout(s),window.removeEventListener("message",i);let d=window;d.__STORVIA__=o,t(o)}}window.addEventListener("message",i)})}var k=class{constructor(){this.baseUrl="";this.gameId="";this.conversationId="";this.modelId="";this.accessToken="";this.initialized=!1;this.isPreview=!1;this.previewConfig=void 0}async init(){let e=await J(),t=e.apiBase;if(!t)throw new c("NOT_INITIALIZED","window.__STORVIA__.apiBase is not set. The platform must inject it before SDK init.");if(this.baseUrl=`${t}${V}`,this.isPreview=!!e.preview,this.previewConfig=e.previewConfig,!e.gameId)throw new c("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 c("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 S(this.baseUrl,this.accessToken,!!e.debug),this.isPreview){this.conversationId="00000000-0000-0000-0000-000000000000";let r=e.models||[];this.modelId=e.selectedModelId||r[0]?.id||"",this.settingsSheet=new v({onModelChange:E=>{this.modelId=E},onSettingsChange:()=>Promise.resolve(),onSync:()=>Promise.resolve()}),r.length>0&&this.settingsSheet.mount(r,this.modelId,{temperature:1,reply_length:"medium",reply_language:"zh-CN",player_note:""},!1);let m=()=>this.gameId,h=()=>this.conversationId,u=()=>this.modelId;this.chat=new f(this.http,m,h,u,!0,this.previewConfig),this.characters=new b(this.http,h,!0),this.relationships=new w(this.http,h,!0),this.inventory=new y(this.http,h,!0),this.world=new C(this.http,h,!0),this.player=new x(this.http,h,!0),this.custom=new I(this.http,h,!0),this.initialized=!0,this.listenForPreviewMessages();return}let n=await this.authenticate();this.conversationId=n.conversationId;let s=n.models||[],i=this.getSavedModelId();this.modelId=i&&s.some(r=>r.id===i)?i:s[0]?.id||"";let a=n.settings||{temperature:1,reply_length:"medium",reply_language:"zh-CN",player_note:""};this.settingsSheet=new v({onModelChange:r=>{this.modelId=r},onSettingsChange:r=>this.saveSettings(r),onSync:()=>this.syncSettings()}),this.settingsSheet.mount(s,this.modelId,a,n.hasWorldUpdate??!1);let o=()=>this.gameId,d=()=>this.conversationId,p=()=>this.modelId;this.chat=new f(this.http,o,d,p),this.characters=new b(this.http,d),this.relationships=new w(this.http,d),this.inventory=new y(this.http,d),this.world=new C(this.http,d),this.player=new x(this.http,d),this.custom=new I(this.http,d),this.initialized=!0}listenForPreviewMessages(){window.addEventListener("message",e=>{!e.data||e.data.type!=="storvia-preview"||(e.data.action==="set-model"&&(this.modelId=e.data.modelId||""),e.data.action==="update-config"&&(this.previewConfig=e.data.previewConfig,this.chat&&this.chat.updatePreviewConfig(this.previewConfig)))})}async saveSettings(e){await this.http.patch("/settings",{conversation_id:this.conversationId,...e})}async syncSettings(){await this.http.post("/sync",{conversation_id:this.conversationId})}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 c("UNAUTHORIZED","User not authenticated"):e.status===404?new c("GAME_NOT_FOUND","Game not found or not published"):new c("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""}}};0&&(module.exports={StorviaError,StorviaSDK});
|
package/dist/index.esm.js
CHANGED
|
@@ -427,5 +427,5 @@ var l=class extends Error{constructor(e,t){super(t),this.name="StorviaError",thi
|
|
|
427
427
|
to { transform: rotate(360deg); }
|
|
428
428
|
}
|
|
429
429
|
.spin { animation: spin 0.8s linear infinite; }
|
|
430
|
-
`,$='<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="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>',L='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>',H='<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>',O='<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>',B='<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>',v=class{constructor(e){this.selectedModelId="";this.models=[];this.modelPanel=null;this.settings={temperature:1,reply_length:"medium",reply_language:"zh-CN",player_note:""};this.hasWorldUpdate=!1;this.fabDot=null;this.syncHint=null;this.displayMode="phone";this.displayModeBtns=[];this.tempValueEl=null;this.tempSlider=null;this.segmentBtns=[];this.langSelect=null;this.noteInput=null;this.noteCounter=null;this.saveBtn=null;this.syncBtn=null;this.syncState="idle";this.panel=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,s=!1){this.models=e,this.selectedModelId=t,this.settings={...n},this.hasWorldUpdate=s;try{let i=localStorage.getItem("storvia_display_mode");(i==="phone"||i==="desktop")&&(this.displayMode=i)}catch{}document.body.appendChild(this.host),this.render()}unmount(){this.host.remove()}getSelectedModelId(){return this.selectedModelId}getSettings(){return{...this.settings}}render(){let e=document.createElement("style");e.textContent=M;let t=document.createElement("div"),n=document.createElement("div");n.className="fab-wrap";let s=document.createElement("button");s.className="fab",s.innerHTML=$,s.title="\u6E38\u620F\u8BBE\u7F6E";let i=document.createElement("div");i.className=`fab-dot${this.hasWorldUpdate?" visible":""}`,this.fabDot=i,n.appendChild(s),n.appendChild(i);let a=document.createElement("div");a.className="panel",this.panel=a;let o=document.createElement("div");o.className="panel-header";let d=document.createElement("div");d.className="panel-title",d.textContent="\u6E38\u620F\u8BBE\u7F6E";let p=document.createElement("button");p.className="close-btn",p.innerHTML="\u2715",p.addEventListener("click",()=>a.classList.remove("open")),o.appendChild(d),o.appendChild(p),a.appendChild(o);let r=document.createElement("div");r.className="panel-body",this.models.length>0&&(r.appendChild(this.buildModelSection()),r.appendChild(this.makeDivider())),r.appendChild(this.buildTemperatureSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildReplyLengthSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildReplyLanguageSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildNoteSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildDisplayModeSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildSyncSection());let m=document.createElement("div");m.className="save-row";let h=document.createElement("button");h.className="save-btn",h.textContent="\u4FDD\u5B58",this.saveBtn=h,h.addEventListener("click",()=>this.handleSave()),m.appendChild(h),r.appendChild(m),a.appendChild(r),s.addEventListener("click",()=>a.classList.toggle("open")),document.addEventListener("click",u=>{this.host.contains(u.target)||a.classList.remove("open")}),t.appendChild(a),t.appendChild(n),this.shadowRoot.appendChild(e),this.shadowRoot.appendChild(t)}buildModelSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="AI \u6A21\u578B",e.appendChild(t);let n=document.createElement("div");return n.className="model-list",this.modelPanel=n,this.models.forEach(s=>{let i=document.createElement("button");i.className=`model-option${s.id===this.selectedModelId?" active":""}`,i.innerHTML=`<span class="dot"></span><span>${s.name}</span>`,i.addEventListener("click",()=>{this.selectedModelId=s.id,this.callbacks.onModelChange(s.id);try{localStorage.setItem("storvia_model_id",s.id)}catch{}this.updateModelActive()}),n.appendChild(i)}),e.appendChild(n),e}buildTemperatureSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label";let n=document.createElement("span");n.textContent="\u6E29\u5EA6";let s=document.createElement("span");s.className="value",s.textContent=this.settings.temperature.toFixed(1),this.tempValueEl=s,t.appendChild(n),t.appendChild(s),e.appendChild(t);let i=document.createElement("div");i.className="section-desc",i.textContent="\u66F4\u4F4E\u7684\u6E29\u5EA6\u4F1A\u8BA9 AI \u56DE\u590D\u66F4\u7A33\u5B9A\u3001\u7406\u667A\uFF1B\u66F4\u9AD8\u7684\u6E29\u5EA6\u4F1A\u8BA9 AI \u7684\u56DE\u590D\u66F4\u5177\u591A\u6837\u6027\u548C\u968F\u673A\u6027",e.appendChild(i);let a=document.createElement("div");a.className="slider-wrap";let o=document.createElement("input");o.type="range",o.className="slider",o.min="0",o.max="2",o.step="0.1",o.value=String(this.settings.temperature),this.tempSlider=o,o.addEventListener("input",()=>{let p=parseFloat(o.value);this.settings.temperature=p,this.tempValueEl&&(this.tempValueEl.textContent=p.toFixed(1))}),a.appendChild(o);let d=document.createElement("div");return d.className="slider-labels",d.innerHTML="<span>\u7CBE\u786E</span><span>\u521B\u610F</span>",a.appendChild(d),e.appendChild(a),e}buildReplyLengthSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u56DE\u590D\u957F\u5EA6",e.appendChild(t);let n=document.createElement("div");return n.className="segment",this.segmentBtns=[],_.forEach(s=>{let i=document.createElement("button");i.className=`segment-btn${s.value===this.settings.reply_length?" active":""}`,i.textContent=s.label,i.addEventListener("click",()=>{this.settings.reply_length=s.value,this.segmentBtns.forEach((a,o)=>{a.classList.toggle("active",_[o].value===s.value)})}),this.segmentBtns.push(i),n.appendChild(i)}),e.appendChild(n),e}buildReplyLanguageSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u56DE\u590D\u8BED\u8A00",e.appendChild(t);let n=document.createElement("div");n.className="select-wrap";let s=document.createElement("select");s.className="select",this.langSelect=s,N.forEach(a=>{let o=document.createElement("option");o.value=a.value,o.textContent=a.label,a.value===this.settings.reply_language&&(o.selected=!0),s.appendChild(o)}),s.addEventListener("change",()=>{this.settings.reply_language=s.value});let i=document.createElement("span");return i.className="select-arrow",i.textContent="\u25BE",n.appendChild(s),n.appendChild(i),e.appendChild(n),e}buildNoteSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label";let n=document.createElement("span");n.textContent="\u5907\u6CE8";let s=document.createElement("span");s.textContent=`${this.settings.player_note.length}/50`,this.noteCounter=s,t.appendChild(n),t.appendChild(s),e.appendChild(t);let i=document.createElement("div");i.className="section-desc",i.textContent="\u5199\u4E0B\u4F60\u5BF9\u8FD9\u4E2A\u6E38\u620F\u7684\u5907\u6CE8\uFF0C\u4F1A\u663E\u793A\u5728\u5B58\u6863\u5217\u8868",e.appendChild(i);let a=document.createElement("div");a.className="note-wrap";let o=document.createElement("textarea");return o.className="note-input",o.placeholder="\u5907\u6CE8",o.maxLength=50,o.value=this.settings.player_note,this.noteInput=o,o.addEventListener("input",()=>{this.settings.player_note=o.value,this.noteCounter&&(this.noteCounter.textContent=`${o.value.length}/50`)}),a.appendChild(o),e.appendChild(a),e}buildDisplayModeSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u663E\u793A\u6A21\u5F0F",e.appendChild(t);let n=document.createElement("div");n.className="section-desc",n.textContent="\u7535\u8111\u6A21\u5F0F\u4F1A\u81EA\u52A8\u6A2A\u5C4F\u663E\u793A",e.appendChild(n);let s=document.createElement("div");s.className="segment",this.displayModeBtns=[];let i=[{value:"phone",label:"\u624B\u673A"},{value:"desktop",label:"\u7535\u8111"}];return i.forEach(a=>{let o=document.createElement("button");o.className=`segment-btn${a.value===this.displayMode?" active":""}`,o.textContent=a.label,o.addEventListener("click",()=>{this.displayMode=a.value;try{localStorage.setItem("storvia_display_mode",a.value)}catch{}this.displayModeBtns.forEach((d,p)=>{d.classList.toggle("active",i[p].value===a.value)});try{window.parent.postMessage({type:"storvia-orientation",mode:a.value==="desktop"?"landscape":"portrait"},"*")}catch{}}),this.displayModeBtns.push(o),s.appendChild(o)}),e.appendChild(s),e}buildSyncSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u540C\u6B65\u6E38\u620F\u8BBE\u5B9A",e.appendChild(t);let n=document.createElement("div");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 s=document.createElement("div");s.className="sync-desc",s.textContent="\u5982\u679C\u6E38\u620F\u4F5C\u8005\u66F4\u65B0\u4E86\u5185\u5BB9\uFF0C\u70B9\u51FB\u6B64\u6309\u94AE\u53EF\u5C06\u6700\u65B0\u7684\u6E38\u620F\u8BBE\u5B9A\u548C\u5F00\u5E55\u5C0F\u5267\u573A\u540C\u6B65\u5230\u5F53\u524D\u5BF9\u8BDD",e.appendChild(s);let i=document.createElement("button");return i.className="sync-btn",this.syncBtn=i,this.renderSyncBtn(),i.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(i),e}makeDivider(){let e=document.createElement("div");return e.className="divider",e}updateModelActive(){this.modelPanel&&this.modelPanel.querySelectorAll(".model-option").forEach((e,t)=>{e.classList.toggle("active",this.models[t].id===this.selectedModelId)})}setSyncState(e){this.syncState=e,this.renderSyncBtn()}renderSyncBtn(){if(!this.syncBtn)return;let e=this.syncState,t={idle:L,loading:H,success:O,error:B},n={idle:"\u540C\u6B65\u6700\u65B0\u8BBE\u5B9A",loading:"\u540C\u6B65\u4E2D...",success:"\u5DF2\u540C\u6B65",error:"\u540C\u6B65\u5931\u8D25"};this.syncBtn.className=`sync-btn${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.textContent="\u4FDD\u5B58\u4E2D...";try{await this.callbacks.onSettingsChange({temperature:this.settings.temperature,reply_length:this.settings.reply_length,reply_language:this.settings.reply_language,player_note:this.settings.player_note}),this.saveBtn.textContent="\u5DF2\u4FDD\u5B58",this.saveBtn.classList.add("saved"),setTimeout(()=>{this.saveBtn&&(this.saveBtn.textContent="\u4FDD\u5B58",this.saveBtn.classList.remove("saved"),this.saveBtn.disabled=!1)},2e3)}catch{this.saveBtn.textContent="\u4FDD\u5B58\u5931\u8D25",setTimeout(()=>{this.saveBtn&&(this.saveBtn.textContent="\u4FDD\u5B58",this.saveBtn.disabled=!1)},2e3)}}}};var f=class{constructor(e,t,n,s,i=!1,a){this.http=e;this.getGameId=t;this.getConversationId=n;this.getModelId=s;this.isPreview=i;this.previewConfig=a}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,context:e.context,stream:e.stream??!1};if(e.stream){await this.http.stream("/chat",t,e.onChunk??(()=>{}),e.onDone??(()=>{}));return}return this.http.post("/chat",t)}async save(e){return this.http.post("/messages/save",{conversation_id:this.getConversationId(),role:e.role,content:e.content,topic:e.topic})}async generate(e){let t={conversation_id:this.getConversationId(),model_id:this.getModelId(),topic:e.topic,context:e.context,stream:e.stream??!1,save:e.save??!0};if(e.stream){await this.http.stream("/generate",t,e.onChunk??(()=>{}),e.onDone??(()=>{}));return}return this.http.post("/generate",t)}async sendPreview(e){let t={model_id:this.getModelId(),message:e.message,topic:e.topic,context:e.context,prompt_config:this.previewConfig||{},history_messages:[]};if(e.stream){await this.http.stream("/preview",t,e.onChunk??(()=>{}),e.onDone??(()=>{}));return}let n="";return await this.http.stream("/preview",t,s=>{n+=s},()=>{}),{id:"",content:n}}};var k=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}async get(e){return this.isPreview?{...this.mem[e]||{}}:this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/state`)}async update(e,t){if(this.isPreview){this.mem[e]={...this.mem[e]||{},...t};return}await this.http.patch(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/state`,t)}},b=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[];this.state=new k(e,t,n)}async list(){return this.isPreview?this.mem.map(e=>({name:e.name,avatar:e.avatar})):this.http.get(`/conversations/${this.getConversationId()}/characters`)}async get(e){if(this.isPreview){let t=this.mem.find(n=>n.name===e);return{name:t?.name||e,avatar:t?.avatar}}return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}`)}async add(e){if(this.isPreview){this.mem.push(e);return}await this.http.post(`/conversations/${this.getConversationId()}/characters`,e)}async update(e,t){if(this.isPreview){let n=this.mem.find(s=>s.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,state:await this.state.get(e)}}return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/detail`)}};var w=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[]}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(s=>s.from===e&&s.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 s=this.mem.find(i=>i.from===e&&i.to===t);s?Object.assign(s,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)}`)}};var y=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[]}async list(e){if(this.isPreview)return e?this.mem.filter(n=>n.group===e):[...this.mem];let t=e?{group:e}:void 0;return this.http.get(`/conversations/${this.getConversationId()}/inventory`,t)}async add(e){if(this.isPreview){this.mem.push({...e});return}await this.http.post(`/conversations/${this.getConversationId()}/inventory`,e)}async update(e,t){if(this.isPreview){let n=this.mem.find(s=>s.name===e);n&&Object.assign(n,t);return}await this.http.patch(`/conversations/${this.getConversationId()}/inventory/${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()}/inventory/${encodeURIComponent(e)}`)}};var C=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}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 P=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}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})}},x=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.memPersona={name:""};this.state=new P(e,t,n)}async get(){return this.isPreview?{...this.memPersona}:this.http.get(`/conversations/${this.getConversationId()}/player`)}};var I=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}async get(e){if(this.isPreview)return e!==void 0?this.mem[e]:{...this.mem};let t=await this.http.get(`/conversations/${this.getConversationId()}/custom`);return e!==void 0?t[e]:t}async set(e){if(this.isPreview){for(let[t,n]of Object.entries(e))typeof n=="object"&&n!==null&&!Array.isArray(n)&&typeof this.mem[t]=="object"&&this.mem[t]!==null?this.mem[t]={...this.mem[t],...n}:this.mem[t]=n;return}await this.http.patch(`/conversations/${this.getConversationId()}/custom`,e)}async delete(e){if(this.isPreview){delete this.mem[e];return}await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}`)}async setGroupField(e,t,n){if(this.isPreview){(!this.mem[e]||typeof this.mem[e]!="object")&&(this.mem[e]={}),this.mem[e][t]=n;return}await this.http.patch(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{value:n})}async deleteGroupField(e,t){if(this.isPreview){if(typeof this.mem[e]=="object"&&this.mem[e]!==null){let n=this.mem[e];delete n[t],Object.keys(n).length===0&&delete this.mem[e]}return}await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)}};var A="/functions/v1/world-engine/v1";function U(){return window.__STORVIA__||{}}function D(c=5e3){let e=U();return e.apiBase?Promise.resolve(e):new Promise((t,n)=>{let s=setTimeout(()=>{window.removeEventListener("message",i),n(new l("NOT_INITIALIZED","Timed out waiting for __STORVIA__ config from parent frame."))},c);function i(a){let o=null;if(a.data?.type==="storvia-init"&&a.data.apiBase?o={apiBase:a.data.apiBase,gameId:a.data.gameId,accessToken:a.data.accessToken}:a.data?.type==="storvia-preview-init"&&a.data.config&&(o=a.data.config),o&&o.apiBase){clearTimeout(s),window.removeEventListener("message",i);let d=window;d.__STORVIA__=o,t(o)}}window.addEventListener("message",i)})}var R=class{constructor(){this.baseUrl="";this.gameId="";this.conversationId="";this.modelId="";this.accessToken="";this.initialized=!1;this.isPreview=!1;this.previewConfig=void 0}async init(){let e=await D(),t=e.apiBase;if(!t)throw new l("NOT_INITIALIZED","window.__STORVIA__.apiBase is not set. The platform must inject it before SDK init.");if(this.baseUrl=`${t}${A}`,this.isPreview=!!e.preview,this.previewConfig=e.previewConfig,!e.gameId)throw new l("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 l("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 S(this.baseUrl,this.accessToken,!!e.debug),this.isPreview){this.conversationId="00000000-0000-0000-0000-000000000000";let r=e.models||[];this.modelId=e.selectedModelId||r[0]?.id||"",this.settingsSheet=new v({onModelChange:E=>{this.modelId=E},onSettingsChange:()=>Promise.resolve(),onSync:()=>Promise.resolve()}),r.length>0&&this.settingsSheet.mount(r,this.modelId,{temperature:1,reply_length:"medium",reply_language:"zh-CN",player_note:""},!1);let m=()=>this.gameId,h=()=>this.conversationId,u=()=>this.modelId;this.chat=new f(this.http,m,h,u,!0,this.previewConfig),this.characters=new b(this.http,h,!0),this.relationships=new w(this.http,h,!0),this.inventory=new y(this.http,h,!0),this.world=new C(this.http,h,!0),this.player=new x(this.http,h,!0),this.custom=new I(this.http,h,!0),this.initialized=!0,this.listenForPreviewMessages();return}let n=await this.authenticate();this.conversationId=n.conversationId;let s=n.models||[],i=this.getSavedModelId();this.modelId=i&&s.some(r=>r.id===i)?i:s[0]?.id||"";let a=n.settings||{temperature:1,reply_length:"medium",reply_language:"zh-CN",player_note:""};this.settingsSheet=new v({onModelChange:r=>{this.modelId=r},onSettingsChange:r=>this.saveSettings(r),onSync:()=>this.syncSettings()}),this.settingsSheet.mount(s,this.modelId,a,n.hasWorldUpdate??!1);let o=()=>this.gameId,d=()=>this.conversationId,p=()=>this.modelId;this.chat=new f(this.http,o,d,p),this.characters=new b(this.http,d),this.relationships=new w(this.http,d),this.inventory=new y(this.http,d),this.world=new C(this.http,d),this.player=new x(this.http,d),this.custom=new I(this.http,d),this.initialized=!0}listenForPreviewMessages(){window.addEventListener("message",e=>{!e.data||e.data.type!=="storvia-preview"||(e.data.action==="set-model"&&(this.modelId=e.data.modelId||""),e.data.action==="update-config"&&(this.previewConfig=e.data.previewConfig,this.chat&&this.chat.updatePreviewConfig(this.previewConfig)))})}async saveSettings(e){await this.http.patch("/settings",{conversation_id:this.conversationId,...e})}async syncSettings(){await this.http.post("/sync",{conversation_id:this.conversationId})}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 l("UNAUTHORIZED","User not authenticated"):e.status===404?new l("GAME_NOT_FOUND","Game not found or not published"):new l("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""}}};export{l as StorviaError,R as StorviaSDK};
|
|
431
|
-
//# sourceMappingURL=index.esm.js.map
|
|
430
|
+
`,$='<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="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>',L='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>',H='<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>',O='<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>',B='<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>',v=class{constructor(e){this.selectedModelId="";this.models=[];this.modelPanel=null;this.settings={temperature:1,reply_length:"medium",reply_language:"zh-CN",player_note:""};this.hasWorldUpdate=!1;this.fabDot=null;this.syncHint=null;this.displayMode="phone";this.displayModeBtns=[];this.tempValueEl=null;this.tempSlider=null;this.segmentBtns=[];this.langSelect=null;this.noteInput=null;this.noteCounter=null;this.saveBtn=null;this.syncBtn=null;this.syncState="idle";this.panel=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,s=!1){this.models=e,this.selectedModelId=t,this.settings={...n},this.hasWorldUpdate=s;try{let i=localStorage.getItem("storvia_display_mode");(i==="phone"||i==="desktop")&&(this.displayMode=i)}catch{}document.body.appendChild(this.host),this.render()}unmount(){this.host.remove()}getSelectedModelId(){return this.selectedModelId}getSettings(){return{...this.settings}}render(){let e=document.createElement("style");e.textContent=M;let t=document.createElement("div"),n=document.createElement("div");n.className="fab-wrap";let s=document.createElement("button");s.className="fab",s.innerHTML=$,s.title="\u6E38\u620F\u8BBE\u7F6E";let i=document.createElement("div");i.className=`fab-dot${this.hasWorldUpdate?" visible":""}`,this.fabDot=i,n.appendChild(s),n.appendChild(i);let a=document.createElement("div");a.className="panel",this.panel=a;let o=document.createElement("div");o.className="panel-header";let d=document.createElement("div");d.className="panel-title",d.textContent="\u6E38\u620F\u8BBE\u7F6E";let p=document.createElement("button");p.className="close-btn",p.innerHTML="\u2715",p.addEventListener("click",()=>a.classList.remove("open")),o.appendChild(d),o.appendChild(p),a.appendChild(o);let r=document.createElement("div");r.className="panel-body",this.models.length>0&&(r.appendChild(this.buildModelSection()),r.appendChild(this.makeDivider())),r.appendChild(this.buildTemperatureSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildReplyLengthSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildReplyLanguageSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildNoteSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildDisplayModeSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildSyncSection());let m=document.createElement("div");m.className="save-row";let h=document.createElement("button");h.className="save-btn",h.textContent="\u4FDD\u5B58",this.saveBtn=h,h.addEventListener("click",()=>this.handleSave()),m.appendChild(h),r.appendChild(m),a.appendChild(r),s.addEventListener("click",()=>a.classList.toggle("open")),document.addEventListener("click",u=>{this.host.contains(u.target)||a.classList.remove("open")}),t.appendChild(a),t.appendChild(n),this.shadowRoot.appendChild(e),this.shadowRoot.appendChild(t)}buildModelSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="AI \u6A21\u578B",e.appendChild(t);let n=document.createElement("div");return n.className="model-list",this.modelPanel=n,this.models.forEach(s=>{let i=document.createElement("button");i.className=`model-option${s.id===this.selectedModelId?" active":""}`,i.innerHTML=`<span class="dot"></span><span>${s.name}</span>`,i.addEventListener("click",()=>{this.selectedModelId=s.id,this.callbacks.onModelChange(s.id);try{localStorage.setItem("storvia_model_id",s.id)}catch{}this.updateModelActive()}),n.appendChild(i)}),e.appendChild(n),e}buildTemperatureSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label";let n=document.createElement("span");n.textContent="\u6E29\u5EA6";let s=document.createElement("span");s.className="value",s.textContent=this.settings.temperature.toFixed(1),this.tempValueEl=s,t.appendChild(n),t.appendChild(s),e.appendChild(t);let i=document.createElement("div");i.className="section-desc",i.textContent="\u66F4\u4F4E\u7684\u6E29\u5EA6\u4F1A\u8BA9 AI \u56DE\u590D\u66F4\u7A33\u5B9A\u3001\u7406\u667A\uFF1B\u66F4\u9AD8\u7684\u6E29\u5EA6\u4F1A\u8BA9 AI \u7684\u56DE\u590D\u66F4\u5177\u591A\u6837\u6027\u548C\u968F\u673A\u6027",e.appendChild(i);let a=document.createElement("div");a.className="slider-wrap";let o=document.createElement("input");o.type="range",o.className="slider",o.min="0",o.max="2",o.step="0.1",o.value=String(this.settings.temperature),this.tempSlider=o,o.addEventListener("input",()=>{let p=parseFloat(o.value);this.settings.temperature=p,this.tempValueEl&&(this.tempValueEl.textContent=p.toFixed(1))}),a.appendChild(o);let d=document.createElement("div");return d.className="slider-labels",d.innerHTML="<span>\u7CBE\u786E</span><span>\u521B\u610F</span>",a.appendChild(d),e.appendChild(a),e}buildReplyLengthSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u56DE\u590D\u957F\u5EA6",e.appendChild(t);let n=document.createElement("div");return n.className="segment",this.segmentBtns=[],_.forEach(s=>{let i=document.createElement("button");i.className=`segment-btn${s.value===this.settings.reply_length?" active":""}`,i.textContent=s.label,i.addEventListener("click",()=>{this.settings.reply_length=s.value,this.segmentBtns.forEach((a,o)=>{a.classList.toggle("active",_[o].value===s.value)})}),this.segmentBtns.push(i),n.appendChild(i)}),e.appendChild(n),e}buildReplyLanguageSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u56DE\u590D\u8BED\u8A00",e.appendChild(t);let n=document.createElement("div");n.className="select-wrap";let s=document.createElement("select");s.className="select",this.langSelect=s,N.forEach(a=>{let o=document.createElement("option");o.value=a.value,o.textContent=a.label,a.value===this.settings.reply_language&&(o.selected=!0),s.appendChild(o)}),s.addEventListener("change",()=>{this.settings.reply_language=s.value});let i=document.createElement("span");return i.className="select-arrow",i.textContent="\u25BE",n.appendChild(s),n.appendChild(i),e.appendChild(n),e}buildNoteSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label";let n=document.createElement("span");n.textContent="\u5907\u6CE8";let s=document.createElement("span");s.textContent=`${this.settings.player_note.length}/50`,this.noteCounter=s,t.appendChild(n),t.appendChild(s),e.appendChild(t);let i=document.createElement("div");i.className="section-desc",i.textContent="\u5199\u4E0B\u4F60\u5BF9\u8FD9\u4E2A\u6E38\u620F\u7684\u5907\u6CE8\uFF0C\u4F1A\u663E\u793A\u5728\u5B58\u6863\u5217\u8868",e.appendChild(i);let a=document.createElement("div");a.className="note-wrap";let o=document.createElement("textarea");return o.className="note-input",o.placeholder="\u5907\u6CE8",o.maxLength=50,o.value=this.settings.player_note,this.noteInput=o,o.addEventListener("input",()=>{this.settings.player_note=o.value,this.noteCounter&&(this.noteCounter.textContent=`${o.value.length}/50`)}),a.appendChild(o),e.appendChild(a),e}buildDisplayModeSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u663E\u793A\u6A21\u5F0F",e.appendChild(t);let n=document.createElement("div");n.className="section-desc",n.textContent="\u7535\u8111\u6A21\u5F0F\u4F1A\u81EA\u52A8\u6A2A\u5C4F\u663E\u793A",e.appendChild(n);let s=document.createElement("div");s.className="segment",this.displayModeBtns=[];let i=[{value:"phone",label:"\u624B\u673A"},{value:"desktop",label:"\u7535\u8111"}];return i.forEach(a=>{let o=document.createElement("button");o.className=`segment-btn${a.value===this.displayMode?" active":""}`,o.textContent=a.label,o.addEventListener("click",()=>{this.displayMode=a.value;try{localStorage.setItem("storvia_display_mode",a.value)}catch{}this.displayModeBtns.forEach((d,p)=>{d.classList.toggle("active",i[p].value===a.value)});try{window.parent.postMessage({type:"storvia-orientation",mode:a.value==="desktop"?"landscape":"portrait"},"*")}catch{}}),this.displayModeBtns.push(o),s.appendChild(o)}),e.appendChild(s),e}buildSyncSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u540C\u6B65\u6E38\u620F\u8BBE\u5B9A",e.appendChild(t);let n=document.createElement("div");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 s=document.createElement("div");s.className="sync-desc",s.textContent="\u5982\u679C\u6E38\u620F\u4F5C\u8005\u66F4\u65B0\u4E86\u5185\u5BB9\uFF0C\u70B9\u51FB\u6B64\u6309\u94AE\u53EF\u5C06\u6700\u65B0\u7684\u6E38\u620F\u8BBE\u5B9A\u548C\u5F00\u5E55\u5C0F\u5267\u573A\u540C\u6B65\u5230\u5F53\u524D\u5BF9\u8BDD",e.appendChild(s);let i=document.createElement("button");return i.className="sync-btn",this.syncBtn=i,this.renderSyncBtn(),i.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(i),e}makeDivider(){let e=document.createElement("div");return e.className="divider",e}updateModelActive(){this.modelPanel&&this.modelPanel.querySelectorAll(".model-option").forEach((e,t)=>{e.classList.toggle("active",this.models[t].id===this.selectedModelId)})}setSyncState(e){this.syncState=e,this.renderSyncBtn()}renderSyncBtn(){if(!this.syncBtn)return;let e=this.syncState,t={idle:L,loading:H,success:O,error:B},n={idle:"\u540C\u6B65\u6700\u65B0\u8BBE\u5B9A",loading:"\u540C\u6B65\u4E2D...",success:"\u5DF2\u540C\u6B65",error:"\u540C\u6B65\u5931\u8D25"};this.syncBtn.className=`sync-btn${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.textContent="\u4FDD\u5B58\u4E2D...";try{await this.callbacks.onSettingsChange({temperature:this.settings.temperature,reply_length:this.settings.reply_length,reply_language:this.settings.reply_language,player_note:this.settings.player_note}),this.saveBtn.textContent="\u5DF2\u4FDD\u5B58",this.saveBtn.classList.add("saved"),setTimeout(()=>{this.saveBtn&&(this.saveBtn.textContent="\u4FDD\u5B58",this.saveBtn.classList.remove("saved"),this.saveBtn.disabled=!1)},2e3)}catch{this.saveBtn.textContent="\u4FDD\u5B58\u5931\u8D25",setTimeout(()=>{this.saveBtn&&(this.saveBtn.textContent="\u4FDD\u5B58",this.saveBtn.disabled=!1)},2e3)}}}};var f=class{constructor(e,t,n,s,i=!1,a){this.http=e;this.getGameId=t;this.getConversationId=n;this.getModelId=s;this.isPreview=i;this.previewConfig=a}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,context:e.context,stream:e.stream??!1};if(e.stream){await this.http.stream("/chat",t,e.onChunk??(()=>{}),e.onDone??(()=>{}));return}return this.http.post("/chat",t)}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,context:(e.context||"")+`
|
|
431
|
+
[\u6307\u4EE4] \u8BF7\u76F4\u63A5\u751F\u6210\u56DE\u590D\uFF0C\u65E0\u9700\u7528\u6237\u8F93\u5165`,stream:e.stream,onChunk:e.onChunk,onDone:e.onDone});let t={conversation_id:this.getConversationId(),model_id:this.getModelId(),topic:e.topic,context:e.context,stream:e.stream??!1,save:e.save??!0};if(e.stream){await this.http.stream("/generate",t,e.onChunk??(()=>{}),e.onDone??(()=>{}));return}return this.http.post("/generate",t)}async sendPreview(e){let t={model_id:this.getModelId(),message:e.message,topic:e.topic,context:e.context,prompt_config:this.previewConfig||{},history_messages:[]};if(e.stream){await this.http.stream("/preview",t,e.onChunk??(()=>{}),e.onDone??(()=>{}));return}let n="";return await this.http.stream("/preview",t,s=>{n+=s},()=>{}),{id:"",content:n}}};var k=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}async get(e){return this.isPreview?{...this.mem[e]||{}}:this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/state`)}async update(e,t){if(this.isPreview){this.mem[e]={...this.mem[e]||{},...t};return}await this.http.patch(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/state`,t)}},b=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[];this.state=new k(e,t,n)}async list(){return this.isPreview?this.mem.map(e=>({name:e.name,avatar:e.avatar})):this.http.get(`/conversations/${this.getConversationId()}/characters`)}async get(e){if(this.isPreview){let t=this.mem.find(n=>n.name===e);return{name:t?.name||e,avatar:t?.avatar}}return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}`)}async add(e){if(this.isPreview){this.mem.push(e);return}await this.http.post(`/conversations/${this.getConversationId()}/characters`,e)}async update(e,t){if(this.isPreview){let n=this.mem.find(s=>s.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,state:await this.state.get(e)}}return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/detail`)}};var w=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[]}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(s=>s.from===e&&s.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 s=this.mem.find(i=>i.from===e&&i.to===t);s?Object.assign(s,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)}`)}};var y=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[]}async list(e){if(this.isPreview)return e?this.mem.filter(n=>n.group===e):[...this.mem];let t=e?{group:e}:void 0;return this.http.get(`/conversations/${this.getConversationId()}/inventory`,t)}async add(e){if(this.isPreview){this.mem.push({...e});return}await this.http.post(`/conversations/${this.getConversationId()}/inventory`,e)}async update(e,t){if(this.isPreview){let n=this.mem.find(s=>s.name===e);n&&Object.assign(n,t);return}await this.http.patch(`/conversations/${this.getConversationId()}/inventory/${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()}/inventory/${encodeURIComponent(e)}`)}};var C=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}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 P=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}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})}},x=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.memPersona={name:""};this.state=new P(e,t,n)}async get(){return this.isPreview?{...this.memPersona}:this.http.get(`/conversations/${this.getConversationId()}/player`)}};var I=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}async get(e){if(this.isPreview)return e!==void 0?this.mem[e]:{...this.mem};let t=await this.http.get(`/conversations/${this.getConversationId()}/custom`);return e!==void 0?t[e]:t}async set(e){if(this.isPreview){for(let[t,n]of Object.entries(e))typeof n=="object"&&n!==null&&!Array.isArray(n)&&typeof this.mem[t]=="object"&&this.mem[t]!==null?this.mem[t]={...this.mem[t],...n}:this.mem[t]=n;return}await this.http.patch(`/conversations/${this.getConversationId()}/custom`,e)}async delete(e){if(this.isPreview){delete this.mem[e];return}await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}`)}async setGroupField(e,t,n){if(this.isPreview){(!this.mem[e]||typeof this.mem[e]!="object")&&(this.mem[e]={}),this.mem[e][t]=n;return}await this.http.patch(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{value:n})}async deleteGroupField(e,t){if(this.isPreview){if(typeof this.mem[e]=="object"&&this.mem[e]!==null){let n=this.mem[e];delete n[t],Object.keys(n).length===0&&delete this.mem[e]}return}await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)}};var A="/functions/v1/world-engine/v1";function U(){return window.__STORVIA__||{}}function D(c=5e3){let e=U();return e.apiBase?Promise.resolve(e):new Promise((t,n)=>{let s=setTimeout(()=>{window.removeEventListener("message",i),n(new l("NOT_INITIALIZED","Timed out waiting for __STORVIA__ config from parent frame."))},c);function i(a){let o=null;if(a.data?.type==="storvia-init"&&a.data.apiBase?o={apiBase:a.data.apiBase,gameId:a.data.gameId,accessToken:a.data.accessToken}:a.data?.type==="storvia-preview-init"&&a.data.config&&(o=a.data.config),o&&o.apiBase){clearTimeout(s),window.removeEventListener("message",i);let d=window;d.__STORVIA__=o,t(o)}}window.addEventListener("message",i)})}var R=class{constructor(){this.baseUrl="";this.gameId="";this.conversationId="";this.modelId="";this.accessToken="";this.initialized=!1;this.isPreview=!1;this.previewConfig=void 0}async init(){let e=await D(),t=e.apiBase;if(!t)throw new l("NOT_INITIALIZED","window.__STORVIA__.apiBase is not set. The platform must inject it before SDK init.");if(this.baseUrl=`${t}${A}`,this.isPreview=!!e.preview,this.previewConfig=e.previewConfig,!e.gameId)throw new l("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 l("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 S(this.baseUrl,this.accessToken,!!e.debug),this.isPreview){this.conversationId="00000000-0000-0000-0000-000000000000";let r=e.models||[];this.modelId=e.selectedModelId||r[0]?.id||"",this.settingsSheet=new v({onModelChange:E=>{this.modelId=E},onSettingsChange:()=>Promise.resolve(),onSync:()=>Promise.resolve()}),r.length>0&&this.settingsSheet.mount(r,this.modelId,{temperature:1,reply_length:"medium",reply_language:"zh-CN",player_note:""},!1);let m=()=>this.gameId,h=()=>this.conversationId,u=()=>this.modelId;this.chat=new f(this.http,m,h,u,!0,this.previewConfig),this.characters=new b(this.http,h,!0),this.relationships=new w(this.http,h,!0),this.inventory=new y(this.http,h,!0),this.world=new C(this.http,h,!0),this.player=new x(this.http,h,!0),this.custom=new I(this.http,h,!0),this.initialized=!0,this.listenForPreviewMessages();return}let n=await this.authenticate();this.conversationId=n.conversationId;let s=n.models||[],i=this.getSavedModelId();this.modelId=i&&s.some(r=>r.id===i)?i:s[0]?.id||"";let a=n.settings||{temperature:1,reply_length:"medium",reply_language:"zh-CN",player_note:""};this.settingsSheet=new v({onModelChange:r=>{this.modelId=r},onSettingsChange:r=>this.saveSettings(r),onSync:()=>this.syncSettings()}),this.settingsSheet.mount(s,this.modelId,a,n.hasWorldUpdate??!1);let o=()=>this.gameId,d=()=>this.conversationId,p=()=>this.modelId;this.chat=new f(this.http,o,d,p),this.characters=new b(this.http,d),this.relationships=new w(this.http,d),this.inventory=new y(this.http,d),this.world=new C(this.http,d),this.player=new x(this.http,d),this.custom=new I(this.http,d),this.initialized=!0}listenForPreviewMessages(){window.addEventListener("message",e=>{!e.data||e.data.type!=="storvia-preview"||(e.data.action==="set-model"&&(this.modelId=e.data.modelId||""),e.data.action==="update-config"&&(this.previewConfig=e.data.previewConfig,this.chat&&this.chat.updatePreviewConfig(this.previewConfig)))})}async saveSettings(e){await this.http.patch("/settings",{conversation_id:this.conversationId,...e})}async syncSettings(){await this.http.post("/sync",{conversation_id:this.conversationId})}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 l("UNAUTHORIZED","User not authenticated"):e.status===404?new l("GAME_NOT_FOUND","Game not found or not published"):new l("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""}}};export{l as StorviaError,R as StorviaSDK};
|
package/dist/index.umd.js
CHANGED
|
@@ -427,6 +427,6 @@
|
|
|
427
427
|
to { transform: rotate(360deg); }
|
|
428
428
|
}
|
|
429
429
|
.spin { animation: spin 0.8s linear infinite; }
|
|
430
|
-
`,D='<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="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>',j='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>',z='<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>',G='<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>',F='<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>',v=class{constructor(e){this.selectedModelId="";this.models=[];this.modelPanel=null;this.settings={temperature:1,reply_length:"medium",reply_language:"zh-CN",player_note:""};this.hasWorldUpdate=!1;this.fabDot=null;this.syncHint=null;this.displayMode="phone";this.displayModeBtns=[];this.tempValueEl=null;this.tempSlider=null;this.segmentBtns=[];this.langSelect=null;this.noteInput=null;this.noteCounter=null;this.saveBtn=null;this.syncBtn=null;this.syncState="idle";this.panel=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,s=!1){this.models=e,this.selectedModelId=t,this.settings={...n},this.hasWorldUpdate=s;try{let i=localStorage.getItem("storvia_display_mode");(i==="phone"||i==="desktop")&&(this.displayMode=i)}catch{}document.body.appendChild(this.host),this.render()}unmount(){this.host.remove()}getSelectedModelId(){return this.selectedModelId}getSettings(){return{...this.settings}}render(){let e=document.createElement("style");e.textContent=U;let t=document.createElement("div"),n=document.createElement("div");n.className="fab-wrap";let s=document.createElement("button");s.className="fab",s.innerHTML=D,s.title="\u6E38\u620F\u8BBE\u7F6E";let i=document.createElement("div");i.className=`fab-dot${this.hasWorldUpdate?" visible":""}`,this.fabDot=i,n.appendChild(s),n.appendChild(i);let a=document.createElement("div");a.className="panel",this.panel=a;let o=document.createElement("div");o.className="panel-header";let d=document.createElement("div");d.className="panel-title",d.textContent="\u6E38\u620F\u8BBE\u7F6E";let p=document.createElement("button");p.className="close-btn",p.innerHTML="\u2715",p.addEventListener("click",()=>a.classList.remove("open")),o.appendChild(d),o.appendChild(p),a.appendChild(o);let r=document.createElement("div");r.className="panel-body",this.models.length>0&&(r.appendChild(this.buildModelSection()),r.appendChild(this.makeDivider())),r.appendChild(this.buildTemperatureSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildReplyLengthSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildReplyLanguageSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildNoteSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildDisplayModeSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildSyncSection());let m=document.createElement("div");m.className="save-row";let h=document.createElement("button");h.className="save-btn",h.textContent="\u4FDD\u5B58",this.saveBtn=h,h.addEventListener("click",()=>this.handleSave()),m.appendChild(h),r.appendChild(m),a.appendChild(r),s.addEventListener("click",()=>a.classList.toggle("open")),document.addEventListener("click",u=>{this.host.contains(u.target)||a.classList.remove("open")}),t.appendChild(a),t.appendChild(n),this.shadowRoot.appendChild(e),this.shadowRoot.appendChild(t)}buildModelSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="AI \u6A21\u578B",e.appendChild(t);let n=document.createElement("div");return n.className="model-list",this.modelPanel=n,this.models.forEach(s=>{let i=document.createElement("button");i.className=`model-option${s.id===this.selectedModelId?" active":""}`,i.innerHTML=`<span class="dot"></span><span>${s.name}</span>`,i.addEventListener("click",()=>{this.selectedModelId=s.id,this.callbacks.onModelChange(s.id);try{localStorage.setItem("storvia_model_id",s.id)}catch{}this.updateModelActive()}),n.appendChild(i)}),e.appendChild(n),e}buildTemperatureSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label";let n=document.createElement("span");n.textContent="\u6E29\u5EA6";let s=document.createElement("span");s.className="value",s.textContent=this.settings.temperature.toFixed(1),this.tempValueEl=s,t.appendChild(n),t.appendChild(s),e.appendChild(t);let i=document.createElement("div");i.className="section-desc",i.textContent="\u66F4\u4F4E\u7684\u6E29\u5EA6\u4F1A\u8BA9 AI \u56DE\u590D\u66F4\u7A33\u5B9A\u3001\u7406\u667A\uFF1B\u66F4\u9AD8\u7684\u6E29\u5EA6\u4F1A\u8BA9 AI \u7684\u56DE\u590D\u66F4\u5177\u591A\u6837\u6027\u548C\u968F\u673A\u6027",e.appendChild(i);let a=document.createElement("div");a.className="slider-wrap";let o=document.createElement("input");o.type="range",o.className="slider",o.min="0",o.max="2",o.step="0.1",o.value=String(this.settings.temperature),this.tempSlider=o,o.addEventListener("input",()=>{let p=parseFloat(o.value);this.settings.temperature=p,this.tempValueEl&&(this.tempValueEl.textContent=p.toFixed(1))}),a.appendChild(o);let d=document.createElement("div");return d.className="slider-labels",d.innerHTML="<span>\u7CBE\u786E</span><span>\u521B\u610F</span>",a.appendChild(d),e.appendChild(a),e}buildReplyLengthSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u56DE\u590D\u957F\u5EA6",e.appendChild(t);let n=document.createElement("div");return n.className="segment",this.segmentBtns=[],N.forEach(s=>{let i=document.createElement("button");i.className=`segment-btn${s.value===this.settings.reply_length?" active":""}`,i.textContent=s.label,i.addEventListener("click",()=>{this.settings.reply_length=s.value,this.segmentBtns.forEach((a,o)=>{a.classList.toggle("active",N[o].value===s.value)})}),this.segmentBtns.push(i),n.appendChild(i)}),e.appendChild(n),e}buildReplyLanguageSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u56DE\u590D\u8BED\u8A00",e.appendChild(t);let n=document.createElement("div");n.className="select-wrap";let s=document.createElement("select");s.className="select",this.langSelect=s,A.forEach(a=>{let o=document.createElement("option");o.value=a.value,o.textContent=a.label,a.value===this.settings.reply_language&&(o.selected=!0),s.appendChild(o)}),s.addEventListener("change",()=>{this.settings.reply_language=s.value});let i=document.createElement("span");return i.className="select-arrow",i.textContent="\u25BE",n.appendChild(s),n.appendChild(i),e.appendChild(n),e}buildNoteSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label";let n=document.createElement("span");n.textContent="\u5907\u6CE8";let s=document.createElement("span");s.textContent=`${this.settings.player_note.length}/50`,this.noteCounter=s,t.appendChild(n),t.appendChild(s),e.appendChild(t);let i=document.createElement("div");i.className="section-desc",i.textContent="\u5199\u4E0B\u4F60\u5BF9\u8FD9\u4E2A\u6E38\u620F\u7684\u5907\u6CE8\uFF0C\u4F1A\u663E\u793A\u5728\u5B58\u6863\u5217\u8868",e.appendChild(i);let a=document.createElement("div");a.className="note-wrap";let o=document.createElement("textarea");return o.className="note-input",o.placeholder="\u5907\u6CE8",o.maxLength=50,o.value=this.settings.player_note,this.noteInput=o,o.addEventListener("input",()=>{this.settings.player_note=o.value,this.noteCounter&&(this.noteCounter.textContent=`${o.value.length}/50`)}),a.appendChild(o),e.appendChild(a),e}buildDisplayModeSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u663E\u793A\u6A21\u5F0F",e.appendChild(t);let n=document.createElement("div");n.className="section-desc",n.textContent="\u7535\u8111\u6A21\u5F0F\u4F1A\u81EA\u52A8\u6A2A\u5C4F\u663E\u793A",e.appendChild(n);let s=document.createElement("div");s.className="segment",this.displayModeBtns=[];let i=[{value:"phone",label:"\u624B\u673A"},{value:"desktop",label:"\u7535\u8111"}];return i.forEach(a=>{let o=document.createElement("button");o.className=`segment-btn${a.value===this.displayMode?" active":""}`,o.textContent=a.label,o.addEventListener("click",()=>{this.displayMode=a.value;try{localStorage.setItem("storvia_display_mode",a.value)}catch{}this.displayModeBtns.forEach((d,p)=>{d.classList.toggle("active",i[p].value===a.value)});try{window.parent.postMessage({type:"storvia-orientation",mode:a.value==="desktop"?"landscape":"portrait"},"*")}catch{}}),this.displayModeBtns.push(o),s.appendChild(o)}),e.appendChild(s),e}buildSyncSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u540C\u6B65\u6E38\u620F\u8BBE\u5B9A",e.appendChild(t);let n=document.createElement("div");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 s=document.createElement("div");s.className="sync-desc",s.textContent="\u5982\u679C\u6E38\u620F\u4F5C\u8005\u66F4\u65B0\u4E86\u5185\u5BB9\uFF0C\u70B9\u51FB\u6B64\u6309\u94AE\u53EF\u5C06\u6700\u65B0\u7684\u6E38\u620F\u8BBE\u5B9A\u548C\u5F00\u5E55\u5C0F\u5267\u573A\u540C\u6B65\u5230\u5F53\u524D\u5BF9\u8BDD",e.appendChild(s);let i=document.createElement("button");return i.className="sync-btn",this.syncBtn=i,this.renderSyncBtn(),i.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(i),e}makeDivider(){let e=document.createElement("div");return e.className="divider",e}updateModelActive(){this.modelPanel&&this.modelPanel.querySelectorAll(".model-option").forEach((e,t)=>{e.classList.toggle("active",this.models[t].id===this.selectedModelId)})}setSyncState(e){this.syncState=e,this.renderSyncBtn()}renderSyncBtn(){if(!this.syncBtn)return;let e=this.syncState,t={idle:j,loading:z,success:G,error:F},n={idle:"\u540C\u6B65\u6700\u65B0\u8BBE\u5B9A",loading:"\u540C\u6B65\u4E2D...",success:"\u5DF2\u540C\u6B65",error:"\u540C\u6B65\u5931\u8D25"};this.syncBtn.className=`sync-btn${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.textContent="\u4FDD\u5B58\u4E2D...";try{await this.callbacks.onSettingsChange({temperature:this.settings.temperature,reply_length:this.settings.reply_length,reply_language:this.settings.reply_language,player_note:this.settings.player_note}),this.saveBtn.textContent="\u5DF2\u4FDD\u5B58",this.saveBtn.classList.add("saved"),setTimeout(()=>{this.saveBtn&&(this.saveBtn.textContent="\u4FDD\u5B58",this.saveBtn.classList.remove("saved"),this.saveBtn.disabled=!1)},2e3)}catch{this.saveBtn.textContent="\u4FDD\u5B58\u5931\u8D25",setTimeout(()=>{this.saveBtn&&(this.saveBtn.textContent="\u4FDD\u5B58",this.saveBtn.disabled=!1)},2e3)}}}};var f=class{constructor(e,t,n,s,i=!1,a){this.http=e;this.getGameId=t;this.getConversationId=n;this.getModelId=s;this.isPreview=i;this.previewConfig=a}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,context:e.context,stream:e.stream??!1};if(e.stream){await this.http.stream("/chat",t,e.onChunk??(()=>{}),e.onDone??(()=>{}));return}return this.http.post("/chat",t)}async save(e){return this.http.post("/messages/save",{conversation_id:this.getConversationId(),role:e.role,content:e.content,topic:e.topic})}async generate(e){let t={conversation_id:this.getConversationId(),model_id:this.getModelId(),topic:e.topic,context:e.context,stream:e.stream??!1,save:e.save??!0};if(e.stream){await this.http.stream("/generate",t,e.onChunk??(()=>{}),e.onDone??(()=>{}));return}return this.http.post("/generate",t)}async sendPreview(e){let t={model_id:this.getModelId(),message:e.message,topic:e.topic,context:e.context,prompt_config:this.previewConfig||{},history_messages:[]};if(e.stream){await this.http.stream("/preview",t,e.onChunk??(()=>{}),e.onDone??(()=>{}));return}let n="";return await this.http.stream("/preview",t,s=>{n+=s},()=>{}),{id:"",content:n}}};var R=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}async get(e){return this.isPreview?{...this.mem[e]||{}}:this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/state`)}async update(e,t){if(this.isPreview){this.mem[e]={...this.mem[e]||{},...t};return}await this.http.patch(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/state`,t)}},b=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[];this.state=new R(e,t,n)}async list(){return this.isPreview?this.mem.map(e=>({name:e.name,avatar:e.avatar})):this.http.get(`/conversations/${this.getConversationId()}/characters`)}async get(e){if(this.isPreview){let t=this.mem.find(n=>n.name===e);return{name:t?.name||e,avatar:t?.avatar}}return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}`)}async add(e){if(this.isPreview){this.mem.push(e);return}await this.http.post(`/conversations/${this.getConversationId()}/characters`,e)}async update(e,t){if(this.isPreview){let n=this.mem.find(s=>s.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,state:await this.state.get(e)}}return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/detail`)}};var w=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[]}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(s=>s.from===e&&s.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 s=this.mem.find(i=>i.from===e&&i.to===t);s?Object.assign(s,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)}`)}};var y=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[]}async list(e){if(this.isPreview)return e?this.mem.filter(n=>n.group===e):[...this.mem];let t=e?{group:e}:void 0;return this.http.get(`/conversations/${this.getConversationId()}/inventory`,t)}async add(e){if(this.isPreview){this.mem.push({...e});return}await this.http.post(`/conversations/${this.getConversationId()}/inventory`,e)}async update(e,t){if(this.isPreview){let n=this.mem.find(s=>s.name===e);n&&Object.assign(n,t);return}await this.http.patch(`/conversations/${this.getConversationId()}/inventory/${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()}/inventory/${encodeURIComponent(e)}`)}};var C=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}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 T=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}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})}},x=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.memPersona={name:""};this.state=new T(e,t,n)}async get(){return this.isPreview?{...this.memPersona}:this.http.get(`/conversations/${this.getConversationId()}/player`)}};var I=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}async get(e){if(this.isPreview)return e!==void 0?this.mem[e]:{...this.mem};let t=await this.http.get(`/conversations/${this.getConversationId()}/custom`);return e!==void 0?t[e]:t}async set(e){if(this.isPreview){for(let[t,n]of Object.entries(e))typeof n=="object"&&n!==null&&!Array.isArray(n)&&typeof this.mem[t]=="object"&&this.mem[t]!==null?this.mem[t]={...this.mem[t],...n}:this.mem[t]=n;return}await this.http.patch(`/conversations/${this.getConversationId()}/custom`,e)}async delete(e){if(this.isPreview){delete this.mem[e];return}await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}`)}async setGroupField(e,t,n){if(this.isPreview){(!this.mem[e]||typeof this.mem[e]!="object")&&(this.mem[e]={}),this.mem[e][t]=n;return}await this.http.patch(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{value:n})}async deleteGroupField(e,t){if(this.isPreview){if(typeof this.mem[e]=="object"&&this.mem[e]!==null){let n=this.mem[e];delete n[t],Object.keys(n).length===0&&delete this.mem[e]}return}await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)}};var V="/functions/v1/world-engine/v1";function W(){return window.__STORVIA__||{}}function J(l=5e3){let e=W();return e.apiBase?Promise.resolve(e):new Promise((t,n)=>{let s=setTimeout(()=>{window.removeEventListener("message",i),n(new c("NOT_INITIALIZED","Timed out waiting for __STORVIA__ config from parent frame."))},l);function i(a){let o=null;if(a.data?.type==="storvia-init"&&a.data.apiBase?o={apiBase:a.data.apiBase,gameId:a.data.gameId,accessToken:a.data.accessToken}:a.data?.type==="storvia-preview-init"&&a.data.config&&(o=a.data.config),o&&o.apiBase){clearTimeout(s),window.removeEventListener("message",i);let d=window;d.__STORVIA__=o,t(o)}}window.addEventListener("message",i)})}var k=class{constructor(){this.baseUrl="";this.gameId="";this.conversationId="";this.modelId="";this.accessToken="";this.initialized=!1;this.isPreview=!1;this.previewConfig=void 0}async init(){let e=await J(),t=e.apiBase;if(!t)throw new c("NOT_INITIALIZED","window.__STORVIA__.apiBase is not set. The platform must inject it before SDK init.");if(this.baseUrl=`${t}${V}`,this.isPreview=!!e.preview,this.previewConfig=e.previewConfig,!e.gameId)throw new c("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 c("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 S(this.baseUrl,this.accessToken,!!e.debug),this.isPreview){this.conversationId="00000000-0000-0000-0000-000000000000";let r=e.models||[];this.modelId=e.selectedModelId||r[0]?.id||"",this.settingsSheet=new v({onModelChange:E=>{this.modelId=E},onSettingsChange:()=>Promise.resolve(),onSync:()=>Promise.resolve()}),r.length>0&&this.settingsSheet.mount(r,this.modelId,{temperature:1,reply_length:"medium",reply_language:"zh-CN",player_note:""},!1);let m=()=>this.gameId,h=()=>this.conversationId,u=()=>this.modelId;this.chat=new f(this.http,m,h,u,!0,this.previewConfig),this.characters=new b(this.http,h,!0),this.relationships=new w(this.http,h,!0),this.inventory=new y(this.http,h,!0),this.world=new C(this.http,h,!0),this.player=new x(this.http,h,!0),this.custom=new I(this.http,h,!0),this.initialized=!0,this.listenForPreviewMessages();return}let n=await this.authenticate();this.conversationId=n.conversationId;let s=n.models||[],i=this.getSavedModelId();this.modelId=i&&s.some(r=>r.id===i)?i:s[0]?.id||"";let a=n.settings||{temperature:1,reply_length:"medium",reply_language:"zh-CN",player_note:""};this.settingsSheet=new v({onModelChange:r=>{this.modelId=r},onSettingsChange:r=>this.saveSettings(r),onSync:()=>this.syncSettings()}),this.settingsSheet.mount(s,this.modelId,a,n.hasWorldUpdate??!1);let o=()=>this.gameId,d=()=>this.conversationId,p=()=>this.modelId;this.chat=new f(this.http,o,d,p),this.characters=new b(this.http,d),this.relationships=new w(this.http,d),this.inventory=new y(this.http,d),this.world=new C(this.http,d),this.player=new x(this.http,d),this.custom=new I(this.http,d),this.initialized=!0}listenForPreviewMessages(){window.addEventListener("message",e=>{!e.data||e.data.type!=="storvia-preview"||(e.data.action==="set-model"&&(this.modelId=e.data.modelId||""),e.data.action==="update-config"&&(this.previewConfig=e.data.previewConfig,this.chat&&this.chat.updatePreviewConfig(this.previewConfig)))})}async saveSettings(e){await this.http.patch("/settings",{conversation_id:this.conversationId,...e})}async syncSettings(){await this.http.post("/sync",{conversation_id:this.conversationId})}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 c("UNAUTHORIZED","User not authenticated"):e.status===404?new c("GAME_NOT_FOUND","Game not found or not published"):new c("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""}}};return B(Y);})();
|
|
430
|
+
`,D='<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="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>',j='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>',z='<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>',G='<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>',F='<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>',v=class{constructor(e){this.selectedModelId="";this.models=[];this.modelPanel=null;this.settings={temperature:1,reply_length:"medium",reply_language:"zh-CN",player_note:""};this.hasWorldUpdate=!1;this.fabDot=null;this.syncHint=null;this.displayMode="phone";this.displayModeBtns=[];this.tempValueEl=null;this.tempSlider=null;this.segmentBtns=[];this.langSelect=null;this.noteInput=null;this.noteCounter=null;this.saveBtn=null;this.syncBtn=null;this.syncState="idle";this.panel=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,s=!1){this.models=e,this.selectedModelId=t,this.settings={...n},this.hasWorldUpdate=s;try{let i=localStorage.getItem("storvia_display_mode");(i==="phone"||i==="desktop")&&(this.displayMode=i)}catch{}document.body.appendChild(this.host),this.render()}unmount(){this.host.remove()}getSelectedModelId(){return this.selectedModelId}getSettings(){return{...this.settings}}render(){let e=document.createElement("style");e.textContent=U;let t=document.createElement("div"),n=document.createElement("div");n.className="fab-wrap";let s=document.createElement("button");s.className="fab",s.innerHTML=D,s.title="\u6E38\u620F\u8BBE\u7F6E";let i=document.createElement("div");i.className=`fab-dot${this.hasWorldUpdate?" visible":""}`,this.fabDot=i,n.appendChild(s),n.appendChild(i);let a=document.createElement("div");a.className="panel",this.panel=a;let o=document.createElement("div");o.className="panel-header";let d=document.createElement("div");d.className="panel-title",d.textContent="\u6E38\u620F\u8BBE\u7F6E";let p=document.createElement("button");p.className="close-btn",p.innerHTML="\u2715",p.addEventListener("click",()=>a.classList.remove("open")),o.appendChild(d),o.appendChild(p),a.appendChild(o);let r=document.createElement("div");r.className="panel-body",this.models.length>0&&(r.appendChild(this.buildModelSection()),r.appendChild(this.makeDivider())),r.appendChild(this.buildTemperatureSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildReplyLengthSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildReplyLanguageSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildNoteSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildDisplayModeSection()),r.appendChild(this.makeDivider()),r.appendChild(this.buildSyncSection());let m=document.createElement("div");m.className="save-row";let h=document.createElement("button");h.className="save-btn",h.textContent="\u4FDD\u5B58",this.saveBtn=h,h.addEventListener("click",()=>this.handleSave()),m.appendChild(h),r.appendChild(m),a.appendChild(r),s.addEventListener("click",()=>a.classList.toggle("open")),document.addEventListener("click",u=>{this.host.contains(u.target)||a.classList.remove("open")}),t.appendChild(a),t.appendChild(n),this.shadowRoot.appendChild(e),this.shadowRoot.appendChild(t)}buildModelSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="AI \u6A21\u578B",e.appendChild(t);let n=document.createElement("div");return n.className="model-list",this.modelPanel=n,this.models.forEach(s=>{let i=document.createElement("button");i.className=`model-option${s.id===this.selectedModelId?" active":""}`,i.innerHTML=`<span class="dot"></span><span>${s.name}</span>`,i.addEventListener("click",()=>{this.selectedModelId=s.id,this.callbacks.onModelChange(s.id);try{localStorage.setItem("storvia_model_id",s.id)}catch{}this.updateModelActive()}),n.appendChild(i)}),e.appendChild(n),e}buildTemperatureSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label";let n=document.createElement("span");n.textContent="\u6E29\u5EA6";let s=document.createElement("span");s.className="value",s.textContent=this.settings.temperature.toFixed(1),this.tempValueEl=s,t.appendChild(n),t.appendChild(s),e.appendChild(t);let i=document.createElement("div");i.className="section-desc",i.textContent="\u66F4\u4F4E\u7684\u6E29\u5EA6\u4F1A\u8BA9 AI \u56DE\u590D\u66F4\u7A33\u5B9A\u3001\u7406\u667A\uFF1B\u66F4\u9AD8\u7684\u6E29\u5EA6\u4F1A\u8BA9 AI \u7684\u56DE\u590D\u66F4\u5177\u591A\u6837\u6027\u548C\u968F\u673A\u6027",e.appendChild(i);let a=document.createElement("div");a.className="slider-wrap";let o=document.createElement("input");o.type="range",o.className="slider",o.min="0",o.max="2",o.step="0.1",o.value=String(this.settings.temperature),this.tempSlider=o,o.addEventListener("input",()=>{let p=parseFloat(o.value);this.settings.temperature=p,this.tempValueEl&&(this.tempValueEl.textContent=p.toFixed(1))}),a.appendChild(o);let d=document.createElement("div");return d.className="slider-labels",d.innerHTML="<span>\u7CBE\u786E</span><span>\u521B\u610F</span>",a.appendChild(d),e.appendChild(a),e}buildReplyLengthSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u56DE\u590D\u957F\u5EA6",e.appendChild(t);let n=document.createElement("div");return n.className="segment",this.segmentBtns=[],N.forEach(s=>{let i=document.createElement("button");i.className=`segment-btn${s.value===this.settings.reply_length?" active":""}`,i.textContent=s.label,i.addEventListener("click",()=>{this.settings.reply_length=s.value,this.segmentBtns.forEach((a,o)=>{a.classList.toggle("active",N[o].value===s.value)})}),this.segmentBtns.push(i),n.appendChild(i)}),e.appendChild(n),e}buildReplyLanguageSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u56DE\u590D\u8BED\u8A00",e.appendChild(t);let n=document.createElement("div");n.className="select-wrap";let s=document.createElement("select");s.className="select",this.langSelect=s,A.forEach(a=>{let o=document.createElement("option");o.value=a.value,o.textContent=a.label,a.value===this.settings.reply_language&&(o.selected=!0),s.appendChild(o)}),s.addEventListener("change",()=>{this.settings.reply_language=s.value});let i=document.createElement("span");return i.className="select-arrow",i.textContent="\u25BE",n.appendChild(s),n.appendChild(i),e.appendChild(n),e}buildNoteSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label";let n=document.createElement("span");n.textContent="\u5907\u6CE8";let s=document.createElement("span");s.textContent=`${this.settings.player_note.length}/50`,this.noteCounter=s,t.appendChild(n),t.appendChild(s),e.appendChild(t);let i=document.createElement("div");i.className="section-desc",i.textContent="\u5199\u4E0B\u4F60\u5BF9\u8FD9\u4E2A\u6E38\u620F\u7684\u5907\u6CE8\uFF0C\u4F1A\u663E\u793A\u5728\u5B58\u6863\u5217\u8868",e.appendChild(i);let a=document.createElement("div");a.className="note-wrap";let o=document.createElement("textarea");return o.className="note-input",o.placeholder="\u5907\u6CE8",o.maxLength=50,o.value=this.settings.player_note,this.noteInput=o,o.addEventListener("input",()=>{this.settings.player_note=o.value,this.noteCounter&&(this.noteCounter.textContent=`${o.value.length}/50`)}),a.appendChild(o),e.appendChild(a),e}buildDisplayModeSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u663E\u793A\u6A21\u5F0F",e.appendChild(t);let n=document.createElement("div");n.className="section-desc",n.textContent="\u7535\u8111\u6A21\u5F0F\u4F1A\u81EA\u52A8\u6A2A\u5C4F\u663E\u793A",e.appendChild(n);let s=document.createElement("div");s.className="segment",this.displayModeBtns=[];let i=[{value:"phone",label:"\u624B\u673A"},{value:"desktop",label:"\u7535\u8111"}];return i.forEach(a=>{let o=document.createElement("button");o.className=`segment-btn${a.value===this.displayMode?" active":""}`,o.textContent=a.label,o.addEventListener("click",()=>{this.displayMode=a.value;try{localStorage.setItem("storvia_display_mode",a.value)}catch{}this.displayModeBtns.forEach((d,p)=>{d.classList.toggle("active",i[p].value===a.value)});try{window.parent.postMessage({type:"storvia-orientation",mode:a.value==="desktop"?"landscape":"portrait"},"*")}catch{}}),this.displayModeBtns.push(o),s.appendChild(o)}),e.appendChild(s),e}buildSyncSection(){let e=document.createElement("div");e.className="section";let t=document.createElement("div");t.className="section-label",t.textContent="\u540C\u6B65\u6E38\u620F\u8BBE\u5B9A",e.appendChild(t);let n=document.createElement("div");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 s=document.createElement("div");s.className="sync-desc",s.textContent="\u5982\u679C\u6E38\u620F\u4F5C\u8005\u66F4\u65B0\u4E86\u5185\u5BB9\uFF0C\u70B9\u51FB\u6B64\u6309\u94AE\u53EF\u5C06\u6700\u65B0\u7684\u6E38\u620F\u8BBE\u5B9A\u548C\u5F00\u5E55\u5C0F\u5267\u573A\u540C\u6B65\u5230\u5F53\u524D\u5BF9\u8BDD",e.appendChild(s);let i=document.createElement("button");return i.className="sync-btn",this.syncBtn=i,this.renderSyncBtn(),i.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(i),e}makeDivider(){let e=document.createElement("div");return e.className="divider",e}updateModelActive(){this.modelPanel&&this.modelPanel.querySelectorAll(".model-option").forEach((e,t)=>{e.classList.toggle("active",this.models[t].id===this.selectedModelId)})}setSyncState(e){this.syncState=e,this.renderSyncBtn()}renderSyncBtn(){if(!this.syncBtn)return;let e=this.syncState,t={idle:j,loading:z,success:G,error:F},n={idle:"\u540C\u6B65\u6700\u65B0\u8BBE\u5B9A",loading:"\u540C\u6B65\u4E2D...",success:"\u5DF2\u540C\u6B65",error:"\u540C\u6B65\u5931\u8D25"};this.syncBtn.className=`sync-btn${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.textContent="\u4FDD\u5B58\u4E2D...";try{await this.callbacks.onSettingsChange({temperature:this.settings.temperature,reply_length:this.settings.reply_length,reply_language:this.settings.reply_language,player_note:this.settings.player_note}),this.saveBtn.textContent="\u5DF2\u4FDD\u5B58",this.saveBtn.classList.add("saved"),setTimeout(()=>{this.saveBtn&&(this.saveBtn.textContent="\u4FDD\u5B58",this.saveBtn.classList.remove("saved"),this.saveBtn.disabled=!1)},2e3)}catch{this.saveBtn.textContent="\u4FDD\u5B58\u5931\u8D25",setTimeout(()=>{this.saveBtn&&(this.saveBtn.textContent="\u4FDD\u5B58",this.saveBtn.disabled=!1)},2e3)}}}};var f=class{constructor(e,t,n,s,i=!1,a){this.http=e;this.getGameId=t;this.getConversationId=n;this.getModelId=s;this.isPreview=i;this.previewConfig=a}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,context:e.context,stream:e.stream??!1};if(e.stream){await this.http.stream("/chat",t,e.onChunk??(()=>{}),e.onDone??(()=>{}));return}return this.http.post("/chat",t)}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,context:(e.context||"")+`
|
|
431
|
+
[\u6307\u4EE4] \u8BF7\u76F4\u63A5\u751F\u6210\u56DE\u590D\uFF0C\u65E0\u9700\u7528\u6237\u8F93\u5165`,stream:e.stream,onChunk:e.onChunk,onDone:e.onDone});let t={conversation_id:this.getConversationId(),model_id:this.getModelId(),topic:e.topic,context:e.context,stream:e.stream??!1,save:e.save??!0};if(e.stream){await this.http.stream("/generate",t,e.onChunk??(()=>{}),e.onDone??(()=>{}));return}return this.http.post("/generate",t)}async sendPreview(e){let t={model_id:this.getModelId(),message:e.message,topic:e.topic,context:e.context,prompt_config:this.previewConfig||{},history_messages:[]};if(e.stream){await this.http.stream("/preview",t,e.onChunk??(()=>{}),e.onDone??(()=>{}));return}let n="";return await this.http.stream("/preview",t,s=>{n+=s},()=>{}),{id:"",content:n}}};var R=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}async get(e){return this.isPreview?{...this.mem[e]||{}}:this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/state`)}async update(e,t){if(this.isPreview){this.mem[e]={...this.mem[e]||{},...t};return}await this.http.patch(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/state`,t)}},b=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[];this.state=new R(e,t,n)}async list(){return this.isPreview?this.mem.map(e=>({name:e.name,avatar:e.avatar})):this.http.get(`/conversations/${this.getConversationId()}/characters`)}async get(e){if(this.isPreview){let t=this.mem.find(n=>n.name===e);return{name:t?.name||e,avatar:t?.avatar}}return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}`)}async add(e){if(this.isPreview){this.mem.push(e);return}await this.http.post(`/conversations/${this.getConversationId()}/characters`,e)}async update(e,t){if(this.isPreview){let n=this.mem.find(s=>s.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,state:await this.state.get(e)}}return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(e)}/detail`)}};var w=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[]}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(s=>s.from===e&&s.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 s=this.mem.find(i=>i.from===e&&i.to===t);s?Object.assign(s,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)}`)}};var y=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem=[]}async list(e){if(this.isPreview)return e?this.mem.filter(n=>n.group===e):[...this.mem];let t=e?{group:e}:void 0;return this.http.get(`/conversations/${this.getConversationId()}/inventory`,t)}async add(e){if(this.isPreview){this.mem.push({...e});return}await this.http.post(`/conversations/${this.getConversationId()}/inventory`,e)}async update(e,t){if(this.isPreview){let n=this.mem.find(s=>s.name===e);n&&Object.assign(n,t);return}await this.http.patch(`/conversations/${this.getConversationId()}/inventory/${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()}/inventory/${encodeURIComponent(e)}`)}};var C=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}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 T=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}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})}},x=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.memPersona={name:""};this.state=new T(e,t,n)}async get(){return this.isPreview?{...this.memPersona}:this.http.get(`/conversations/${this.getConversationId()}/player`)}};var I=class{constructor(e,t,n=!1){this.http=e;this.getConversationId=t;this.isPreview=n;this.mem={}}async get(e){if(this.isPreview)return e!==void 0?this.mem[e]:{...this.mem};let t=await this.http.get(`/conversations/${this.getConversationId()}/custom`);return e!==void 0?t[e]:t}async set(e){if(this.isPreview){for(let[t,n]of Object.entries(e))typeof n=="object"&&n!==null&&!Array.isArray(n)&&typeof this.mem[t]=="object"&&this.mem[t]!==null?this.mem[t]={...this.mem[t],...n}:this.mem[t]=n;return}await this.http.patch(`/conversations/${this.getConversationId()}/custom`,e)}async delete(e){if(this.isPreview){delete this.mem[e];return}await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}`)}async setGroupField(e,t,n){if(this.isPreview){(!this.mem[e]||typeof this.mem[e]!="object")&&(this.mem[e]={}),this.mem[e][t]=n;return}await this.http.patch(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{value:n})}async deleteGroupField(e,t){if(this.isPreview){if(typeof this.mem[e]=="object"&&this.mem[e]!==null){let n=this.mem[e];delete n[t],Object.keys(n).length===0&&delete this.mem[e]}return}await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)}};var V="/functions/v1/world-engine/v1";function W(){return window.__STORVIA__||{}}function J(l=5e3){let e=W();return e.apiBase?Promise.resolve(e):new Promise((t,n)=>{let s=setTimeout(()=>{window.removeEventListener("message",i),n(new c("NOT_INITIALIZED","Timed out waiting for __STORVIA__ config from parent frame."))},l);function i(a){let o=null;if(a.data?.type==="storvia-init"&&a.data.apiBase?o={apiBase:a.data.apiBase,gameId:a.data.gameId,accessToken:a.data.accessToken}:a.data?.type==="storvia-preview-init"&&a.data.config&&(o=a.data.config),o&&o.apiBase){clearTimeout(s),window.removeEventListener("message",i);let d=window;d.__STORVIA__=o,t(o)}}window.addEventListener("message",i)})}var k=class{constructor(){this.baseUrl="";this.gameId="";this.conversationId="";this.modelId="";this.accessToken="";this.initialized=!1;this.isPreview=!1;this.previewConfig=void 0}async init(){let e=await J(),t=e.apiBase;if(!t)throw new c("NOT_INITIALIZED","window.__STORVIA__.apiBase is not set. The platform must inject it before SDK init.");if(this.baseUrl=`${t}${V}`,this.isPreview=!!e.preview,this.previewConfig=e.previewConfig,!e.gameId)throw new c("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 c("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 S(this.baseUrl,this.accessToken,!!e.debug),this.isPreview){this.conversationId="00000000-0000-0000-0000-000000000000";let r=e.models||[];this.modelId=e.selectedModelId||r[0]?.id||"",this.settingsSheet=new v({onModelChange:E=>{this.modelId=E},onSettingsChange:()=>Promise.resolve(),onSync:()=>Promise.resolve()}),r.length>0&&this.settingsSheet.mount(r,this.modelId,{temperature:1,reply_length:"medium",reply_language:"zh-CN",player_note:""},!1);let m=()=>this.gameId,h=()=>this.conversationId,u=()=>this.modelId;this.chat=new f(this.http,m,h,u,!0,this.previewConfig),this.characters=new b(this.http,h,!0),this.relationships=new w(this.http,h,!0),this.inventory=new y(this.http,h,!0),this.world=new C(this.http,h,!0),this.player=new x(this.http,h,!0),this.custom=new I(this.http,h,!0),this.initialized=!0,this.listenForPreviewMessages();return}let n=await this.authenticate();this.conversationId=n.conversationId;let s=n.models||[],i=this.getSavedModelId();this.modelId=i&&s.some(r=>r.id===i)?i:s[0]?.id||"";let a=n.settings||{temperature:1,reply_length:"medium",reply_language:"zh-CN",player_note:""};this.settingsSheet=new v({onModelChange:r=>{this.modelId=r},onSettingsChange:r=>this.saveSettings(r),onSync:()=>this.syncSettings()}),this.settingsSheet.mount(s,this.modelId,a,n.hasWorldUpdate??!1);let o=()=>this.gameId,d=()=>this.conversationId,p=()=>this.modelId;this.chat=new f(this.http,o,d,p),this.characters=new b(this.http,d),this.relationships=new w(this.http,d),this.inventory=new y(this.http,d),this.world=new C(this.http,d),this.player=new x(this.http,d),this.custom=new I(this.http,d),this.initialized=!0}listenForPreviewMessages(){window.addEventListener("message",e=>{!e.data||e.data.type!=="storvia-preview"||(e.data.action==="set-model"&&(this.modelId=e.data.modelId||""),e.data.action==="update-config"&&(this.previewConfig=e.data.previewConfig,this.chat&&this.chat.updatePreviewConfig(this.previewConfig)))})}async saveSettings(e){await this.http.patch("/settings",{conversation_id:this.conversationId,...e})}async syncSettings(){await this.http.post("/sync",{conversation_id:this.conversationId})}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 c("UNAUTHORIZED","User not authenticated"):e.status===404?new c("GAME_NOT_FOUND","Game not found or not published"):new c("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""}}};return B(Y);})();
|
|
431
432
|
if(typeof window!=="undefined"){window.StorviaSDK=StorviaSDK.StorviaSDK;}
|
|
432
|
-
//# sourceMappingURL=index.umd.js.map
|
package/package.json
CHANGED
package/dist/index.cjs.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/http.ts","../src/settings-sheet.ts","../src/modules/chat.ts","../src/modules/characters.ts","../src/modules/relationships.ts","../src/modules/inventory.ts","../src/modules/world.ts","../src/modules/player.ts","../src/modules/custom.ts","../src/StorviaSDK.ts"],"sourcesContent":["export { StorviaSDK } from './StorviaSDK'\nexport { StorviaError } from './errors'\nexport type {\n StorviaErrorCode,\n ChatSendOptions,\n ChatSaveOptions,\n ChatGenerateOptions,\n ChatResponse,\n CharacterPersona,\n CharacterDetail,\n Relationship,\n InventoryItemData,\n PlayerPersona,\n} from './types'\n","import type { StorviaErrorCode } from './types'\n\nexport class StorviaError extends Error {\n code: StorviaErrorCode\n\n constructor(code: StorviaErrorCode, message: string) {\n super(message)\n this.name = 'StorviaError'\n this.code = code\n }\n}\n","import { StorviaError } from './errors'\nimport type { StorviaErrorCode } from './types'\n\nexport class HttpClient {\n private baseUrl: string\n private token: string\n private debug: boolean\n\n constructor(baseUrl: string, token: string, debug = false) {\n this.baseUrl = baseUrl\n this.token = token\n this.debug = debug\n }\n\n setToken(token: string) {\n this.token = token\n }\n\n setDebug(enabled: boolean) {\n this.debug = enabled\n }\n\n private buildHeaders(): Record<string, string> {\n return {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.token}`,\n }\n }\n\n private log(method: string, path: string, body?: unknown, response?: unknown, error?: unknown) {\n if (!this.debug) return\n const tag = '%c[Storvia SDK]'\n const style = 'color: #6366f1; font-weight: bold'\n if (error) {\n console.groupCollapsed(`${tag} %c${method} ${path} %c✗`, style, 'color: #e0e0e0', 'color: #ef4444')\n if (body) console.log('Request:', body)\n console.error('Error:', error)\n console.groupEnd()\n } else {\n console.groupCollapsed(`${tag} %c${method} ${path} %c✓`, style, 'color: #e0e0e0', 'color: #22c55e')\n if (body) console.log('Request:', body)\n if (response !== undefined) console.log('Response:', response)\n console.groupEnd()\n }\n }\n\n async get<T>(path: string, params?: Record<string, string>): Promise<T> {\n const url = new URL(`${this.baseUrl}${path}`)\n if (params) {\n Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v))\n }\n\n try {\n const res = await fetch(url.toString(), {\n method: 'GET',\n headers: this.buildHeaders(),\n })\n const data = await this.handleResponse<T>(res)\n this.log('GET', path, params, data)\n return data\n } catch (e) {\n this.log('GET', path, params, undefined, e)\n throw e\n }\n }\n\n async post<T>(path: string, body?: unknown): Promise<T> {\n try {\n const res = await fetch(`${this.baseUrl}${path}`, {\n method: 'POST',\n headers: this.buildHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n })\n const data = await this.handleResponse<T>(res)\n this.log('POST', path, body, data)\n return data\n } catch (e) {\n this.log('POST', path, body, undefined, e)\n throw e\n }\n }\n\n async patch<T>(path: string, body?: unknown): Promise<T> {\n try {\n const res = await fetch(`${this.baseUrl}${path}`, {\n method: 'PATCH',\n headers: this.buildHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n })\n const data = await this.handleResponse<T>(res)\n this.log('PATCH', path, body, data)\n return data\n } catch (e) {\n this.log('PATCH', path, body, undefined, e)\n throw e\n }\n }\n\n async delete<T>(path: string): Promise<T> {\n try {\n const res = await fetch(`${this.baseUrl}${path}`, {\n method: 'DELETE',\n headers: this.buildHeaders(),\n })\n const data = await this.handleResponse<T>(res)\n this.log('DELETE', path, undefined, data)\n return data\n } catch (e) {\n this.log('DELETE', path, undefined, undefined, e)\n throw e\n }\n }\n\n async stream(\n path: string,\n body: unknown,\n onChunk: (text: string) => void,\n onDone: (id: string) => void\n ): Promise<void> {\n this.log('STREAM', path, body)\n\n const res = await fetch(`${this.baseUrl}${path}`, {\n method: 'POST',\n headers: this.buildHeaders(),\n body: JSON.stringify(body),\n })\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({}))\n const error = new StorviaError(\n (err.code as StorviaErrorCode) || 'INTERNAL_ERROR',\n err.message || `HTTP ${res.status}`\n )\n this.log('STREAM', path, body, undefined, error)\n throw error\n }\n\n const reader = res.body?.getReader()\n if (!reader) {\n throw new StorviaError('INTERNAL_ERROR', 'No response body for stream')\n }\n\n const decoder = new TextDecoder()\n let messageId = ''\n let accumulated = ''\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n const chunk = decoder.decode(value, { stream: true })\n const lines = chunk.split('\\n')\n\n for (const line of lines) {\n if (!line.startsWith('data: ')) continue\n const data = line.slice(6)\n\n if (data === '[DONE]') {\n if (this.debug) {\n this.log('STREAM', path + ' [done]', undefined, { id: messageId, contentLength: accumulated.length })\n }\n onDone(messageId)\n return\n }\n\n try {\n const parsed = JSON.parse(data)\n if (parsed.type === 'done' && parsed.id) {\n messageId = parsed.id\n } else if (parsed.content) {\n accumulated += parsed.content\n onChunk(parsed.content)\n }\n } catch {\n // non-JSON data line, ignore\n }\n }\n }\n\n if (messageId) onDone(messageId)\n }\n\n private async handleResponse<T>(res: Response): Promise<T> {\n if (!res.ok) {\n let err: { code?: string; message?: string } = {}\n try {\n err = await res.json()\n } catch {\n // ignore\n }\n\n const codeMap: Record<number, StorviaErrorCode> = {\n 401: 'UNAUTHORIZED',\n 402: 'INSUFFICIENT_BALANCE',\n 404: 'GAME_NOT_FOUND',\n 429: 'RATE_LIMITED',\n }\n\n const code =\n (err.code as StorviaErrorCode) || codeMap[res.status] || 'INTERNAL_ERROR'\n throw new StorviaError(code, err.message || `HTTP ${res.status}`)\n }\n\n const json = await res.json()\n // 解包 { success, data } 格式\n if (json && typeof json === 'object' && 'data' in json) {\n return json.data as T\n }\n return json as T\n }\n}\n","interface ModelOption {\n id: string\n name: string\n provider: string\n}\n\nexport interface GameSettings {\n temperature: number\n reply_length: string\n reply_language: string\n player_note: string\n}\n\ntype SyncState = 'idle' | 'loading' | 'success' | 'error'\n\ninterface SettingsCallbacks {\n onModelChange: (id: string) => void\n onSettingsChange: (settings: Partial<GameSettings>) => Promise<void>\n onSync: () => Promise<void>\n}\n\nconst LANGUAGES = [\n { value: 'zh-CN', label: '简体中文' },\n { value: 'zh-TW', label: '繁體中文' },\n { value: 'en', label: 'English' },\n { value: 'ja', label: '日本語' },\n { value: 'ko', label: '한국어' },\n]\n\nconst LENGTH_OPTIONS = [\n { value: 'low', label: '简短' },\n { value: 'medium', label: '适中' },\n { value: 'high', label: '详细' },\n]\n\nconst STYLES = `\n :host {\n position: fixed;\n bottom: 20px;\n right: 20px;\n z-index: 2147483647;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n\n .fab {\n width: 48px;\n height: 48px;\n border-radius: 50%;\n background: #6366f1;\n color: #fff;\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\n transition: transform 0.2s, box-shadow 0.2s;\n }\n\n .fab:hover {\n transform: scale(1.08);\n box-shadow: 0 6px 16px rgba(0,0,0,0.4);\n }\n\n .fab svg {\n width: 22px;\n height: 22px;\n }\n\n .panel {\n position: absolute;\n bottom: 60px;\n right: 0;\n width: 320px;\n max-height: 80vh;\n overflow-y: auto;\n background: #1e1e1e;\n border: 1px solid #333;\n border-radius: 16px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n display: none;\n }\n\n .panel.open {\n display: block;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 16px 8px;\n }\n\n .panel-title {\n font-size: 16px;\n font-weight: 600;\n color: #fff;\n }\n\n .close-btn {\n width: 28px;\n height: 28px;\n border-radius: 50%;\n border: none;\n background: transparent;\n color: #888;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n transition: background 0.15s;\n }\n\n .close-btn:hover {\n background: #2a2a2a;\n color: #fff;\n }\n\n .panel-body {\n padding: 4px 16px 16px;\n }\n\n .section {\n margin-bottom: 16px;\n }\n\n .section:last-child {\n margin-bottom: 0;\n }\n\n .section-label {\n font-size: 13px;\n font-weight: 500;\n color: #c0c0c0;\n margin-bottom: 6px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .section-label .value {\n color: #6366f1;\n font-weight: 600;\n }\n\n .section-desc {\n font-size: 11px;\n color: #666;\n margin-bottom: 8px;\n line-height: 1.4;\n }\n\n .divider {\n height: 1px;\n background: #2a2a2a;\n margin: 12px 0;\n }\n\n /* Model options */\n .model-list {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n\n .model-option {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px;\n border-radius: 8px;\n cursor: pointer;\n border: none;\n background: transparent;\n color: #e0e0e0;\n width: 100%;\n font-size: 13px;\n text-align: left;\n transition: background 0.15s;\n }\n\n .model-option:hover {\n background: #2a2a2a;\n }\n\n .model-option.active {\n background: #6366f1;\n color: #fff;\n }\n\n .model-option .dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #555;\n flex-shrink: 0;\n }\n\n .model-option.active .dot {\n background: #fff;\n }\n\n /* Slider */\n .slider-wrap {\n position: relative;\n padding: 0 2px;\n }\n\n .slider {\n -webkit-appearance: none;\n appearance: none;\n width: 100%;\n height: 4px;\n border-radius: 2px;\n background: #333;\n outline: none;\n }\n\n .slider::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: #6366f1;\n cursor: pointer;\n border: 2px solid #1e1e1e;\n box-shadow: 0 2px 4px rgba(0,0,0,0.3);\n }\n\n .slider::-moz-range-thumb {\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: #6366f1;\n cursor: pointer;\n border: 2px solid #1e1e1e;\n box-shadow: 0 2px 4px rgba(0,0,0,0.3);\n }\n\n .slider-labels {\n display: flex;\n justify-content: space-between;\n font-size: 11px;\n color: #666;\n margin-top: 4px;\n }\n\n /* Segment control (reply length) */\n .segment {\n display: flex;\n background: #2a2a2a;\n border-radius: 10px;\n padding: 3px;\n gap: 2px;\n }\n\n .segment-btn {\n flex: 1;\n padding: 8px 0;\n border: none;\n border-radius: 8px;\n background: transparent;\n color: #999;\n font-size: 13px;\n cursor: pointer;\n transition: all 0.2s;\n }\n\n .segment-btn.active {\n background: #6366f1;\n color: #fff;\n font-weight: 500;\n }\n\n .segment-btn:not(.active):hover {\n color: #ddd;\n }\n\n /* Select */\n .select-wrap {\n position: relative;\n }\n\n .select {\n width: 100%;\n padding: 10px 32px 10px 12px;\n border-radius: 10px;\n border: 1px solid #333;\n background: #2a2a2a;\n color: #e0e0e0;\n font-size: 13px;\n appearance: none;\n -webkit-appearance: none;\n cursor: pointer;\n outline: none;\n transition: border-color 0.15s;\n }\n\n .select:focus {\n border-color: #6366f1;\n }\n\n .select-arrow {\n position: absolute;\n right: 12px;\n top: 50%;\n transform: translateY(-50%);\n pointer-events: none;\n color: #666;\n font-size: 12px;\n }\n\n /* Textarea (note) */\n .note-wrap {\n position: relative;\n }\n\n .note-input {\n width: 100%;\n padding: 10px 12px;\n border-radius: 10px;\n border: 1px solid #333;\n background: #2a2a2a;\n color: #e0e0e0;\n font-size: 13px;\n font-family: inherit;\n resize: none;\n height: 64px;\n outline: none;\n transition: border-color 0.15s;\n box-sizing: border-box;\n }\n\n .note-input::placeholder {\n color: #555;\n }\n\n .note-input:focus {\n border-color: #6366f1;\n }\n\n .note-counter {\n text-align: right;\n font-size: 11px;\n color: #555;\n margin-top: 4px;\n }\n\n /* Sync section */\n .sync-desc {\n font-size: 11px;\n color: #666;\n margin-bottom: 8px;\n line-height: 1.4;\n }\n\n .sync-btn {\n width: 100%;\n padding: 10px 0;\n border-radius: 10px;\n border: 1px solid #333;\n background: #2a2a2a;\n color: #e0e0e0;\n font-size: 13px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n transition: background 0.15s;\n }\n\n .sync-btn:hover:not(:disabled) {\n background: #333;\n }\n\n .sync-btn:disabled {\n cursor: default;\n opacity: 0.6;\n }\n\n .sync-btn svg {\n width: 16px;\n height: 16px;\n }\n\n .sync-btn.success { color: #4ade80; border-color: #4ade80; }\n .sync-btn.error { color: #f87171; border-color: #f87171; }\n\n /* Save button */\n .save-row {\n display: flex;\n justify-content: flex-end;\n margin-top: 16px;\n }\n\n .save-btn {\n padding: 8px 24px;\n border-radius: 10px;\n border: none;\n background: #6366f1;\n color: #fff;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .save-btn:hover:not(:disabled) {\n background: #5558e6;\n }\n\n .save-btn:disabled {\n opacity: 0.6;\n cursor: default;\n }\n\n .save-btn.saved {\n background: #4ade80;\n }\n\n /* FAB red dot */\n .fab-dot {\n position: absolute;\n top: 2px;\n right: 2px;\n width: 10px;\n height: 10px;\n border-radius: 50%;\n background: #f87171;\n border: 2px solid #1e1e1e;\n display: none;\n }\n\n .fab-dot.visible {\n display: block;\n }\n\n .fab-wrap {\n position: relative;\n display: inline-block;\n }\n\n /* Sync update hint */\n .sync-hint {\n font-size: 11px;\n color: #f59e0b;\n margin-bottom: 6px;\n line-height: 1.4;\n display: none;\n }\n\n .sync-hint.visible {\n display: block;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n .spin { animation: spin 0.8s linear infinite; }\n`\n\nconst ICON_GEAR = `<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=\"3\"/><path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z\"/></svg>`\nconst ICON_SYNC = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"23 4 23 10 17 10\"/><polyline points=\"1 20 1 14 7 14\"/><path d=\"M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15\"/></svg>`\nconst ICON_SYNC_SPIN = `<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>`\nconst ICON_CHECK = `<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>`\nconst ICON_ERROR = `<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>`\n\nexport class SettingsSheet {\n private shadowRoot: ShadowRoot\n private host: HTMLElement\n private callbacks: SettingsCallbacks\n\n // Model state\n private selectedModelId = ''\n private models: ModelOption[] = []\n private modelPanel: HTMLElement | null = null\n\n // Settings state (local copy, saved on \"保存\")\n private settings: GameSettings = {\n temperature: 1.0,\n reply_length: 'medium',\n reply_language: 'zh-CN',\n player_note: '',\n }\n\n // World update state\n private hasWorldUpdate = false\n private fabDot: HTMLElement | null = null\n private syncHint: HTMLElement | null = null\n\n // Display mode state\n private displayMode: 'phone' | 'desktop' = 'phone'\n private displayModeBtns: HTMLButtonElement[] = []\n\n // UI refs\n private tempValueEl: HTMLElement | null = null\n private tempSlider: HTMLInputElement | null = null\n private segmentBtns: HTMLButtonElement[] = []\n private langSelect: HTMLSelectElement | null = null\n private noteInput: HTMLTextAreaElement | null = null\n private noteCounter: HTMLElement | null = null\n private saveBtn: HTMLButtonElement | null = null\n private syncBtn: HTMLButtonElement | null = null\n private syncState: SyncState = 'idle'\n private panel: HTMLElement | null = null\n\n constructor(callbacks: SettingsCallbacks) {\n this.callbacks = callbacks\n this.host = document.createElement('div')\n this.host.id = 'storvia-settings'\n this.shadowRoot = this.host.attachShadow({ mode: 'closed' })\n }\n\n mount(models: ModelOption[], defaultModelId: string, settings: GameSettings, hasWorldUpdate = false) {\n this.models = models\n this.selectedModelId = defaultModelId\n this.settings = { ...settings }\n this.hasWorldUpdate = hasWorldUpdate\n try {\n const saved = localStorage.getItem('storvia_display_mode')\n if (saved === 'phone' || saved === 'desktop') this.displayMode = saved\n } catch { /* ignore */ }\n document.body.appendChild(this.host)\n this.render()\n }\n\n unmount() {\n this.host.remove()\n }\n\n getSelectedModelId(): string {\n return this.selectedModelId\n }\n\n getSettings(): GameSettings {\n return { ...this.settings }\n }\n\n private render() {\n const style = document.createElement('style')\n style.textContent = STYLES\n\n const container = document.createElement('div')\n\n // FAB with red dot\n const fabWrap = document.createElement('div')\n fabWrap.className = 'fab-wrap'\n const fab = document.createElement('button')\n fab.className = 'fab'\n fab.innerHTML = ICON_GEAR\n fab.title = '游戏设置'\n const fabDot = document.createElement('div')\n fabDot.className = `fab-dot${this.hasWorldUpdate ? ' visible' : ''}`\n this.fabDot = fabDot\n fabWrap.appendChild(fab)\n fabWrap.appendChild(fabDot)\n\n // Panel\n const panel = document.createElement('div')\n panel.className = 'panel'\n this.panel = panel\n\n // Header\n const header = document.createElement('div')\n header.className = 'panel-header'\n const title = document.createElement('div')\n title.className = 'panel-title'\n title.textContent = '游戏设置'\n const closeBtn = document.createElement('button')\n closeBtn.className = 'close-btn'\n closeBtn.innerHTML = '✕'\n closeBtn.addEventListener('click', () => panel.classList.remove('open'))\n header.appendChild(title)\n header.appendChild(closeBtn)\n panel.appendChild(header)\n\n // Body\n const body = document.createElement('div')\n body.className = 'panel-body'\n\n // ── AI Model ──\n if (this.models.length > 0) {\n body.appendChild(this.buildModelSection())\n body.appendChild(this.makeDivider())\n }\n\n // ── Temperature ──\n body.appendChild(this.buildTemperatureSection())\n body.appendChild(this.makeDivider())\n\n // ── Reply Length ──\n body.appendChild(this.buildReplyLengthSection())\n body.appendChild(this.makeDivider())\n\n // ── Reply Language ──\n body.appendChild(this.buildReplyLanguageSection())\n body.appendChild(this.makeDivider())\n\n // ── Note ──\n body.appendChild(this.buildNoteSection())\n body.appendChild(this.makeDivider())\n\n // ── Display Mode ──\n body.appendChild(this.buildDisplayModeSection())\n body.appendChild(this.makeDivider())\n\n // ── Sync ──\n body.appendChild(this.buildSyncSection())\n\n // ── Save Button ──\n const saveRow = document.createElement('div')\n saveRow.className = 'save-row'\n const saveBtn = document.createElement('button')\n saveBtn.className = 'save-btn'\n saveBtn.textContent = '保存'\n this.saveBtn = saveBtn\n saveBtn.addEventListener('click', () => this.handleSave())\n saveRow.appendChild(saveBtn)\n body.appendChild(saveRow)\n\n panel.appendChild(body)\n\n // Toggle\n fab.addEventListener('click', () => panel.classList.toggle('open'))\n document.addEventListener('click', (e) => {\n if (!this.host.contains(e.target as Node)) panel.classList.remove('open')\n })\n\n container.appendChild(panel)\n container.appendChild(fabWrap)\n this.shadowRoot.appendChild(style)\n this.shadowRoot.appendChild(container)\n }\n\n // ── Build sections ──\n\n private buildModelSection(): HTMLElement {\n const section = document.createElement('div')\n section.className = 'section'\n\n const label = document.createElement('div')\n label.className = 'section-label'\n label.textContent = 'AI 模型'\n section.appendChild(label)\n\n const list = document.createElement('div')\n list.className = 'model-list'\n this.modelPanel = list\n\n this.models.forEach((model) => {\n const btn = document.createElement('button')\n btn.className = `model-option${model.id === this.selectedModelId ? ' active' : ''}`\n btn.innerHTML = `<span class=\"dot\"></span><span>${model.name}</span>`\n btn.addEventListener('click', () => {\n this.selectedModelId = model.id\n this.callbacks.onModelChange(model.id)\n try { localStorage.setItem('storvia_model_id', model.id) } catch { /* ignore */ }\n this.updateModelActive()\n })\n list.appendChild(btn)\n })\n\n section.appendChild(list)\n return section\n }\n\n private buildTemperatureSection(): HTMLElement {\n const section = document.createElement('div')\n section.className = 'section'\n\n const label = document.createElement('div')\n label.className = 'section-label'\n const labelText = document.createElement('span')\n labelText.textContent = '温度'\n const valueText = document.createElement('span')\n valueText.className = 'value'\n valueText.textContent = this.settings.temperature.toFixed(1)\n this.tempValueEl = valueText\n label.appendChild(labelText)\n label.appendChild(valueText)\n section.appendChild(label)\n\n const desc = document.createElement('div')\n desc.className = 'section-desc'\n desc.textContent = '更低的温度会让 AI 回复更稳定、理智;更高的温度会让 AI 的回复更具多样性和随机性'\n section.appendChild(desc)\n\n const wrap = document.createElement('div')\n wrap.className = 'slider-wrap'\n const slider = document.createElement('input')\n slider.type = 'range'\n slider.className = 'slider'\n slider.min = '0'\n slider.max = '2'\n slider.step = '0.1'\n slider.value = String(this.settings.temperature)\n this.tempSlider = slider\n slider.addEventListener('input', () => {\n const v = parseFloat(slider.value)\n this.settings.temperature = v\n if (this.tempValueEl) this.tempValueEl.textContent = v.toFixed(1)\n })\n wrap.appendChild(slider)\n\n const labels = document.createElement('div')\n labels.className = 'slider-labels'\n labels.innerHTML = '<span>精确</span><span>创意</span>'\n wrap.appendChild(labels)\n\n section.appendChild(wrap)\n return section\n }\n\n private buildReplyLengthSection(): HTMLElement {\n const section = document.createElement('div')\n section.className = 'section'\n\n const label = document.createElement('div')\n label.className = 'section-label'\n label.textContent = '回复长度'\n section.appendChild(label)\n\n const segment = document.createElement('div')\n segment.className = 'segment'\n this.segmentBtns = []\n\n LENGTH_OPTIONS.forEach((opt) => {\n const btn = document.createElement('button')\n btn.className = `segment-btn${opt.value === this.settings.reply_length ? ' active' : ''}`\n btn.textContent = opt.label\n btn.addEventListener('click', () => {\n this.settings.reply_length = opt.value\n this.segmentBtns.forEach((b, i) => {\n b.classList.toggle('active', LENGTH_OPTIONS[i].value === opt.value)\n })\n })\n this.segmentBtns.push(btn)\n segment.appendChild(btn)\n })\n\n section.appendChild(segment)\n return section\n }\n\n private buildReplyLanguageSection(): HTMLElement {\n const section = document.createElement('div')\n section.className = 'section'\n\n const label = document.createElement('div')\n label.className = 'section-label'\n label.textContent = '回复语言'\n section.appendChild(label)\n\n const wrap = document.createElement('div')\n wrap.className = 'select-wrap'\n const select = document.createElement('select')\n select.className = 'select'\n this.langSelect = select\n\n LANGUAGES.forEach((lang) => {\n const option = document.createElement('option')\n option.value = lang.value\n option.textContent = lang.label\n if (lang.value === this.settings.reply_language) option.selected = true\n select.appendChild(option)\n })\n\n select.addEventListener('change', () => {\n this.settings.reply_language = select.value\n })\n\n const arrow = document.createElement('span')\n arrow.className = 'select-arrow'\n arrow.textContent = '▾'\n wrap.appendChild(select)\n wrap.appendChild(arrow)\n\n section.appendChild(wrap)\n return section\n }\n\n private buildNoteSection(): HTMLElement {\n const section = document.createElement('div')\n section.className = 'section'\n\n const label = document.createElement('div')\n label.className = 'section-label'\n const labelText = document.createElement('span')\n labelText.textContent = '备注'\n const counter = document.createElement('span')\n counter.textContent = `${this.settings.player_note.length}/50`\n this.noteCounter = counter\n label.appendChild(labelText)\n label.appendChild(counter)\n section.appendChild(label)\n\n const desc = document.createElement('div')\n desc.className = 'section-desc'\n desc.textContent = '写下你对这个游戏的备注,会显示在存档列表'\n section.appendChild(desc)\n\n const wrap = document.createElement('div')\n wrap.className = 'note-wrap'\n const textarea = document.createElement('textarea')\n textarea.className = 'note-input'\n textarea.placeholder = '备注'\n textarea.maxLength = 50\n textarea.value = this.settings.player_note\n this.noteInput = textarea\n\n textarea.addEventListener('input', () => {\n this.settings.player_note = textarea.value\n if (this.noteCounter) {\n this.noteCounter.textContent = `${textarea.value.length}/50`\n }\n })\n\n wrap.appendChild(textarea)\n section.appendChild(wrap)\n return section\n }\n\n private buildDisplayModeSection(): HTMLElement {\n const section = document.createElement('div')\n section.className = 'section'\n\n const label = document.createElement('div')\n label.className = 'section-label'\n label.textContent = '显示模式'\n section.appendChild(label)\n\n const desc = document.createElement('div')\n desc.className = 'section-desc'\n desc.textContent = '电脑模式会自动横屏显示'\n section.appendChild(desc)\n\n const segment = document.createElement('div')\n segment.className = 'segment'\n this.displayModeBtns = []\n\n const DISPLAY_OPTIONS = [\n { value: 'phone' as const, label: '手机' },\n { value: 'desktop' as const, label: '电脑' },\n ]\n\n DISPLAY_OPTIONS.forEach((opt) => {\n const btn = document.createElement('button')\n btn.className = `segment-btn${opt.value === this.displayMode ? ' active' : ''}`\n btn.textContent = opt.label\n btn.addEventListener('click', () => {\n this.displayMode = opt.value\n try { localStorage.setItem('storvia_display_mode', opt.value) } catch { /* ignore */ }\n this.displayModeBtns.forEach((b, i) => {\n b.classList.toggle('active', DISPLAY_OPTIONS[i].value === opt.value)\n })\n // 通知父页面旋转\n try {\n window.parent.postMessage({\n type: 'storvia-orientation',\n mode: opt.value === 'desktop' ? 'landscape' : 'portrait',\n }, '*')\n } catch { /* ignore */ }\n })\n this.displayModeBtns.push(btn)\n segment.appendChild(btn)\n })\n\n section.appendChild(segment)\n return section\n }\n\n private buildSyncSection(): HTMLElement {\n const section = document.createElement('div')\n section.className = 'section'\n\n const label = document.createElement('div')\n label.className = 'section-label'\n label.textContent = '同步游戏设定'\n section.appendChild(label)\n\n // Update hint (only visible when hasWorldUpdate)\n const hint = document.createElement('div')\n hint.className = `sync-hint${this.hasWorldUpdate ? ' visible' : ''}`\n hint.textContent = '⚠ 作者已更新游戏内容,建议点击同步'\n this.syncHint = hint\n section.appendChild(hint)\n\n const desc = document.createElement('div')\n desc.className = 'sync-desc'\n desc.textContent = '如果游戏作者更新了内容,点击此按钮可将最新的游戏设定和开幕小剧场同步到当前对话'\n section.appendChild(desc)\n\n const syncBtn = document.createElement('button')\n syncBtn.className = 'sync-btn'\n this.syncBtn = syncBtn\n this.renderSyncBtn()\n\n syncBtn.addEventListener('click', async () => {\n if (this.syncState === 'loading') return\n this.setSyncState('loading')\n try {\n await this.callbacks.onSync()\n this.setSyncState('success')\n // Clear update indicators\n this.hasWorldUpdate = false\n if (this.fabDot) this.fabDot.classList.remove('visible')\n if (this.syncHint) this.syncHint.classList.remove('visible')\n setTimeout(() => this.setSyncState('idle'), 3000)\n } catch {\n this.setSyncState('error')\n setTimeout(() => this.setSyncState('idle'), 4000)\n }\n })\n\n section.appendChild(syncBtn)\n return section\n }\n\n // ── Helpers ──\n\n private makeDivider(): HTMLElement {\n const d = document.createElement('div')\n d.className = 'divider'\n return d\n }\n\n private updateModelActive() {\n if (!this.modelPanel) return\n this.modelPanel.querySelectorAll('.model-option').forEach((btn, i) => {\n btn.classList.toggle('active', this.models[i].id === this.selectedModelId)\n })\n }\n\n private setSyncState(state: SyncState) {\n this.syncState = state\n this.renderSyncBtn()\n }\n\n private renderSyncBtn() {\n if (!this.syncBtn) return\n const s = this.syncState\n const icons: Record<SyncState, string> = {\n idle: ICON_SYNC,\n loading: ICON_SYNC_SPIN,\n success: ICON_CHECK,\n error: ICON_ERROR,\n }\n const labels: Record<SyncState, string> = {\n idle: '同步最新设定',\n loading: '同步中...',\n success: '已同步',\n error: '同步失败',\n }\n this.syncBtn.className = `sync-btn${s === 'success' || s === 'error' ? ` ${s}` : ''}`\n this.syncBtn.disabled = s === 'loading'\n this.syncBtn.innerHTML = `${icons[s]}<span>${labels[s]}</span>`\n }\n\n private async handleSave() {\n if (!this.saveBtn || this.saveBtn.disabled) return\n this.saveBtn.disabled = true\n this.saveBtn.textContent = '保存中...'\n try {\n await this.callbacks.onSettingsChange({\n temperature: this.settings.temperature,\n reply_length: this.settings.reply_length,\n reply_language: this.settings.reply_language,\n player_note: this.settings.player_note,\n })\n this.saveBtn.textContent = '已保存'\n this.saveBtn.classList.add('saved')\n setTimeout(() => {\n if (this.saveBtn) {\n this.saveBtn.textContent = '保存'\n this.saveBtn.classList.remove('saved')\n this.saveBtn.disabled = false\n }\n }, 2000)\n } catch {\n this.saveBtn.textContent = '保存失败'\n setTimeout(() => {\n if (this.saveBtn) {\n this.saveBtn.textContent = '保存'\n this.saveBtn.disabled = false\n }\n }, 2000)\n }\n }\n}\n","import type { HttpClient } from '../http'\nimport type { ChatSendOptions, ChatSaveOptions, ChatGenerateOptions, ChatResponse } from '../types'\n\nexport class ChatModule {\n private previewConfig?: Record<string, unknown>\n\n constructor(\n private http: HttpClient,\n private getGameId: () => string,\n private getConversationId: () => string,\n private getModelId: () => string,\n private isPreview: boolean = false,\n previewConfig?: Record<string, unknown>,\n ) {\n this.previewConfig = previewConfig\n }\n\n /** 更新预览配置(由父页面 postMessage 触发) */\n updatePreviewConfig(config?: Record<string, unknown>): void {\n this.previewConfig = config\n }\n\n /**\n * 发送消息并获取 AI 回复(user 消息 + AI 回复一体化)\n * 适用于 1v1 对话场景\n */\n async send(options: ChatSendOptions): Promise<ChatResponse | void> {\n if (this.isPreview) {\n return this.sendPreview(options)\n }\n\n const body = {\n game_id: this.getGameId(),\n conversation_id: this.getConversationId(),\n model_id: this.getModelId(),\n message: options.message,\n topic: options.topic,\n context: options.context,\n stream: options.stream ?? false,\n }\n\n if (options.stream) {\n await this.http.stream(\n '/chat',\n body,\n options.onChunk ?? (() => {}),\n options.onDone ?? (() => {})\n )\n return\n }\n\n return this.http.post<ChatResponse>('/chat', body)\n }\n\n /**\n * 单独保存一条消息(不调 AI,不扣费)\n * 适用于群聊中先保存用户消息,再分别请求各 NPC 回复\n */\n async save(options: ChatSaveOptions): Promise<{ id: string }> {\n return this.http.post<{ id: string }>('/messages/save', {\n conversation_id: this.getConversationId(),\n role: options.role,\n content: options.content,\n topic: options.topic,\n })\n }\n\n /**\n * 基于 topic 历史 + context 请求 AI 生成回复(无需当前轮用户输入)\n * 适用于群聊 NPC 回复、NPC 自动发言、弹幕生成等\n */\n async generate(options: ChatGenerateOptions): Promise<ChatResponse | void> {\n const body = {\n conversation_id: this.getConversationId(),\n model_id: this.getModelId(),\n topic: options.topic,\n context: options.context,\n stream: options.stream ?? false,\n save: options.save ?? true,\n }\n\n if (options.stream) {\n await this.http.stream(\n '/generate',\n body,\n options.onChunk ?? (() => {}),\n options.onDone ?? (() => {})\n )\n return\n }\n\n return this.http.post<ChatResponse>('/generate', body)\n }\n\n /** 预览模式:发到 /preview 端点 */\n private async sendPreview(options: ChatSendOptions): Promise<ChatResponse | void> {\n const body = {\n model_id: this.getModelId(),\n message: options.message,\n topic: options.topic,\n context: options.context,\n prompt_config: this.previewConfig || {},\n history_messages: [],\n }\n\n if (options.stream) {\n await this.http.stream(\n '/preview',\n body,\n options.onChunk ?? (() => {}),\n options.onDone ?? (() => {})\n )\n return\n }\n\n let content = ''\n await this.http.stream(\n '/preview',\n body,\n (chunk) => { content += chunk },\n () => {}\n )\n return { id: '', content }\n }\n}\n","import type { HttpClient } from '../http'\nimport type { CharacterPersona, CharacterDetail } from '../types'\n\n/** 内部存储含 description(用于 add 传给后端),但不对外暴露 */\ninterface CharacterInternal {\n name: string\n description?: string\n avatar?: string\n}\n\nclass CharacterStateModule {\n private mem: Record<string, Record<string, string | number>> = {}\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {}\n\n async get(characterName: string): Promise<Record<string, string | number>> {\n if (this.isPreview) return { ...(this.mem[characterName] || {}) }\n return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(characterName)}/state`)\n }\n\n async update(characterName: string, values: Record<string, string | number>): Promise<void> {\n if (this.isPreview) {\n this.mem[characterName] = { ...(this.mem[characterName] || {}), ...values }\n return\n }\n await this.http.patch(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(characterName)}/state`, values)\n }\n}\n\nexport class CharactersModule {\n state: CharacterStateModule\n private mem: CharacterInternal[] = []\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {\n this.state = new CharacterStateModule(http, getConversationId, isPreview)\n }\n\n async list(): Promise<CharacterPersona[]> {\n if (this.isPreview) return this.mem.map(c => ({ name: c.name, avatar: c.avatar }))\n return this.http.get(`/conversations/${this.getConversationId()}/characters`)\n }\n\n async get(name: string): Promise<CharacterPersona> {\n if (this.isPreview) {\n const c = this.mem.find(c => c.name === name)\n return { name: c?.name || name, avatar: c?.avatar }\n }\n return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(name)}`)\n }\n\n async add(character: { name: string; description?: string; avatar?: string }): Promise<void> {\n if (this.isPreview) { this.mem.push(character); return }\n await this.http.post(`/conversations/${this.getConversationId()}/characters`, character)\n }\n\n async update(name: string, data: Partial<Omit<CharacterPersona, 'name'>>): Promise<void> {\n if (this.isPreview) { const c = this.mem.find(c => c.name === name); if (c) Object.assign(c, data); return }\n await this.http.patch(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(name)}`, data)\n }\n\n async remove(name: string): Promise<void> {\n if (this.isPreview) { this.mem = this.mem.filter(c => c.name !== name); return }\n await this.http.delete(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(name)}`)\n }\n\n async detail(name: string): Promise<CharacterDetail> {\n if (this.isPreview) {\n const c = this.mem.find(c => c.name === name)\n return { name, avatar: c?.avatar, state: await this.state.get(name) }\n }\n return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(name)}/detail`)\n }\n}\n","import type { HttpClient } from '../http'\nimport type { Relationship } from '../types'\n\nexport class RelationshipsModule {\n private mem: Relationship[] = []\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {}\n\n async list(): Promise<Relationship[]> {\n if (this.isPreview) return [...this.mem]\n return this.http.get(`/conversations/${this.getConversationId()}/relationships`)\n }\n\n async get(from: string, to: string): Promise<Relationship> {\n if (this.isPreview) {\n const r = this.mem.find(r => r.from === from && r.to === to)\n if (r) return { ...r }\n throw new Error('Relationship not found')\n }\n return this.http.get(`/conversations/${this.getConversationId()}/relationships/${encodeURIComponent(from)}/${encodeURIComponent(to)}`)\n }\n\n async add(relationship: Relationship): Promise<void> {\n if (this.isPreview) { this.mem.push({ ...relationship }); return }\n await this.http.post(`/conversations/${this.getConversationId()}/relationships`, relationship)\n }\n\n async update(from: string, to: string, data: Record<string, string | number>): Promise<void> {\n if (this.isPreview) {\n const r = this.mem.find(r => r.from === from && r.to === to)\n if (r) Object.assign(r, data)\n else this.mem.push({ from, to, ...data })\n return\n }\n await this.http.patch(`/conversations/${this.getConversationId()}/relationships/${encodeURIComponent(from)}/${encodeURIComponent(to)}`, data)\n }\n\n async remove(from: string, to: string): Promise<void> {\n if (this.isPreview) { this.mem = this.mem.filter(r => !(r.from === from && r.to === to)); return }\n await this.http.delete(`/conversations/${this.getConversationId()}/relationships/${encodeURIComponent(from)}/${encodeURIComponent(to)}`)\n }\n}\n","import type { HttpClient } from '../http'\nimport type { InventoryItemData } from '../types'\n\nexport class InventoryModule {\n private mem: InventoryItemData[] = []\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {}\n\n async list(group?: string): Promise<InventoryItemData[]> {\n if (this.isPreview) return group ? this.mem.filter(i => i.group === group) : [...this.mem]\n const params = group ? { group } : undefined\n return this.http.get(`/conversations/${this.getConversationId()}/inventory`, params)\n }\n\n async add(item: InventoryItemData): Promise<void> {\n if (this.isPreview) { this.mem.push({ ...item }); return }\n await this.http.post(`/conversations/${this.getConversationId()}/inventory`, item)\n }\n\n async update(name: string, data: Partial<Omit<InventoryItemData, 'name'>>): Promise<void> {\n if (this.isPreview) {\n const i = this.mem.find(i => i.name === name)\n if (i) Object.assign(i, data)\n return\n }\n await this.http.patch(`/conversations/${this.getConversationId()}/inventory/${encodeURIComponent(name)}`, data)\n }\n\n async remove(name: string): Promise<void> {\n if (this.isPreview) { this.mem = this.mem.filter(i => i.name !== name); return }\n await this.http.delete(`/conversations/${this.getConversationId()}/inventory/${encodeURIComponent(name)}`)\n }\n}\n","import type { HttpClient } from '../http'\n\nexport class WorldModule {\n private mem: Record<string, unknown> = {}\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {}\n\n async get(): Promise<Record<string, unknown>> {\n if (this.isPreview) return { ...this.mem }\n return this.http.get(`/conversations/${this.getConversationId()}/world`)\n }\n\n async update(data: Record<string, unknown>): Promise<void> {\n if (this.isPreview) { Object.assign(this.mem, data); return }\n await this.http.patch(`/conversations/${this.getConversationId()}/world`, data)\n }\n}\n","import type { HttpClient } from '../http'\nimport type { PlayerPersona } from '../types'\n\nclass PlayerStateModule {\n private mem: Record<string, Record<string, string | number>> = {}\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {}\n\n async get(): Promise<Record<string, Record<string, string | number>>>\n async get(group: string): Promise<Record<string, string | number>>\n async get(group?: string): Promise<Record<string, string | number> | Record<string, Record<string, string | number>>> {\n if (this.isPreview) {\n if (group) return { ...(this.mem[group] || {}) }\n return { ...this.mem }\n }\n const params = group ? { group } : undefined\n return this.http.get(`/conversations/${this.getConversationId()}/player/state`, params)\n }\n\n async update(group: string, values: Record<string, string | number>): Promise<void> {\n if (this.isPreview) {\n this.mem[group] = { ...(this.mem[group] || {}), ...values }\n return\n }\n await this.http.patch(`/conversations/${this.getConversationId()}/player/state`, { group, values })\n }\n}\n\nexport class PlayerModule {\n state: PlayerStateModule\n private memPersona: PlayerPersona = { name: '' }\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {\n this.state = new PlayerStateModule(http, getConversationId, isPreview)\n }\n\n async get(): Promise<PlayerPersona> {\n if (this.isPreview) return { ...this.memPersona }\n return this.http.get(`/conversations/${this.getConversationId()}/player`)\n }\n}\n","import type { HttpClient } from '../http'\n\nexport class CustomModule {\n private mem: Record<string, unknown> = {}\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {}\n\n async get(): Promise<Record<string, unknown>>\n async get(key: string): Promise<unknown>\n async get(key?: string): Promise<unknown> {\n if (this.isPreview) {\n if (key !== undefined) return this.mem[key]\n return { ...this.mem }\n }\n const data = await this.http.get<Record<string, unknown>>(\n `/conversations/${this.getConversationId()}/custom`\n )\n if (key !== undefined) return data[key]\n return data\n }\n\n async set(data: Record<string, unknown>): Promise<void> {\n if (this.isPreview) {\n // 深合并:分组对象合并子字段\n for (const [key, value] of Object.entries(data)) {\n if (typeof value === 'object' && value !== null && !Array.isArray(value)\n && typeof this.mem[key] === 'object' && this.mem[key] !== null) {\n this.mem[key] = { ...(this.mem[key] as Record<string, unknown>), ...value }\n } else {\n this.mem[key] = value\n }\n }\n return\n }\n await this.http.patch(`/conversations/${this.getConversationId()}/custom`, data)\n }\n\n async delete(key: string): Promise<void> {\n if (this.isPreview) { delete this.mem[key]; return }\n await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(key)}`)\n }\n\n async setGroupField(groupKey: string, fieldKey: string, value: unknown): Promise<void> {\n if (this.isPreview) {\n if (!this.mem[groupKey] || typeof this.mem[groupKey] !== 'object') {\n this.mem[groupKey] = {}\n }\n (this.mem[groupKey] as Record<string, unknown>)[fieldKey] = value\n return\n }\n await this.http.patch(\n `/conversations/${this.getConversationId()}/custom/${encodeURIComponent(groupKey)}/${encodeURIComponent(fieldKey)}`,\n { value }\n )\n }\n\n async deleteGroupField(groupKey: string, fieldKey: string): Promise<void> {\n if (this.isPreview) {\n if (typeof this.mem[groupKey] === 'object' && this.mem[groupKey] !== null) {\n const group = this.mem[groupKey] as Record<string, unknown>\n delete group[fieldKey]\n if (Object.keys(group).length === 0) delete this.mem[groupKey]\n }\n return\n }\n await this.http.delete(\n `/conversations/${this.getConversationId()}/custom/${encodeURIComponent(groupKey)}/${encodeURIComponent(fieldKey)}`\n )\n }\n}\n","import { HttpClient } from './http'\nimport { StorviaError } from './errors'\nimport { SettingsSheet } from './settings-sheet'\nimport type { GameSettings } from './settings-sheet'\nimport { ChatModule } from './modules/chat'\nimport { CharactersModule } from './modules/characters'\nimport { RelationshipsModule } from './modules/relationships'\nimport { InventoryModule } from './modules/inventory'\nimport { WorldModule } from './modules/world'\nimport { PlayerModule } from './modules/player'\nimport { CustomModule } from './modules/custom'\n\nconst API_PATH = '/functions/v1/world-engine/v1'\n\ninterface StorviaEnv {\n apiBase?: string\n gameId?: string\n accessToken?: string\n /** 预览模式标志:跳过 auth,chat 发到 /preview,其他模块内存模式 */\n preview?: boolean\n /** 预览模式下的 prompt 配置 */\n previewConfig?: {\n game_prompt?: string | null\n game_config?: Record<string, unknown>\n game_state?: Record<string, unknown>\n persona_settings?: Record<string, unknown>\n reply_length?: string\n reply_language?: string\n }\n /** 预览模式下由父页面传入的模型列表 */\n models?: { id: string; name: string; provider: string }[]\n /** 预览模式下由父页面传入的选中模型 ID */\n selectedModelId?: string\n /** 开启 debug 模式:打印所有请求/响应日志 */\n debug?: boolean\n}\n\nfunction getEnv(): StorviaEnv {\n return ((window as unknown as Record<string, StorviaEnv>).__STORVIA__) || {}\n}\n\n/**\n * 等待父页面通过 postMessage 注入 __STORVIA__ 配置\n * 支持两种消息格式:\n * 1. 正式环境 (World.vue): { type: 'storvia-init', apiBase, gameId, accessToken }\n * 2. 预览环境 (CreatePreviewModal): { type: 'storvia-preview-init', config: { apiBase, gameId, accessToken, preview, previewConfig } }\n * 如果 __STORVIA__ 已存在则立即返回\n */\nfunction waitForEnv(timeoutMs = 5000): Promise<StorviaEnv> {\n const existing = getEnv()\n if (existing.apiBase) return Promise.resolve(existing)\n\n return new Promise<StorviaEnv>((resolve, reject) => {\n const timer = setTimeout(() => {\n window.removeEventListener('message', handler)\n reject(new StorviaError('NOT_INITIALIZED', 'Timed out waiting for __STORVIA__ config from parent frame.'))\n }, timeoutMs)\n\n function handler(event: MessageEvent) {\n let env: StorviaEnv | null = null\n\n if (event.data?.type === 'storvia-init' && event.data.apiBase) {\n // 正式环境:World.vue 发送的扁平格式\n env = {\n apiBase: event.data.apiBase,\n gameId: event.data.gameId,\n accessToken: event.data.accessToken,\n }\n } else if (event.data?.type === 'storvia-preview-init' && event.data.config) {\n // 预览环境:CreatePreviewModal 发送的嵌套格式\n env = event.data.config\n }\n\n if (env && env.apiBase) {\n clearTimeout(timer)\n window.removeEventListener('message', handler)\n const w = window as unknown as Record<string, StorviaEnv>\n w.__STORVIA__ = env\n resolve(env)\n }\n }\n\n window.addEventListener('message', handler)\n })\n}\n\nexport class StorviaSDK {\n private http!: HttpClient\n private settingsSheet!: SettingsSheet\n private baseUrl = ''\n private gameId = ''\n private conversationId = ''\n private modelId = ''\n private accessToken = ''\n private initialized = false\n private isPreview = false\n private previewConfig: StorviaEnv['previewConfig'] = undefined\n\n chat!: ChatModule\n characters!: CharactersModule\n relationships!: RelationshipsModule\n inventory!: InventoryModule\n world!: WorldModule\n player!: PlayerModule\n custom!: CustomModule\n\n async init(): Promise<void> {\n // 尝试获取环境配置;如果不存在则等待父页面 postMessage 注入(预览场景)\n const env = await waitForEnv()\n\n const apiBase = env.apiBase\n if (!apiBase) {\n throw new StorviaError(\n 'NOT_INITIALIZED',\n 'window.__STORVIA__.apiBase is not set. The platform must inject it before SDK init.'\n )\n }\n this.baseUrl = `${apiBase}${API_PATH}`\n this.isPreview = !!env.preview\n this.previewConfig = env.previewConfig\n\n if (!env.gameId) {\n throw new StorviaError(\n 'GAME_NOT_FOUND',\n 'window.__STORVIA__.gameId is not set. The platform must inject it before SDK init.'\n )\n }\n this.gameId = env.gameId\n\n // 获取用户 access token(由主站通过 postMessage 注入到 __STORVIA__)\n if (!env.accessToken) {\n throw new StorviaError(\n 'UNAUTHORIZED',\n 'window.__STORVIA__.accessToken is not set. The platform must inject the user token before SDK init.'\n )\n }\n this.accessToken = env.accessToken\n\n this.http = new HttpClient(this.baseUrl, this.accessToken, !!env.debug)\n\n if (this.isPreview) {\n // ===== 预览模式:跳过 auth,使用占位 conversationId =====\n this.conversationId = '00000000-0000-0000-0000-000000000000'\n\n // 模型列表和选中模型由父页面传入\n const models = env.models || []\n this.modelId = env.selectedModelId || models[0]?.id || ''\n\n // 挂载设置面板(预览也需要模型选择和设置入口)\n this.settingsSheet = new SettingsSheet({\n onModelChange: (id) => { this.modelId = id },\n onSettingsChange: () => Promise.resolve(),\n onSync: () => Promise.resolve(),\n })\n if (models.length > 0) {\n this.settingsSheet.mount(models, this.modelId, {\n temperature: 1.0,\n reply_length: 'medium',\n reply_language: 'zh-CN',\n player_note: '',\n }, false)\n }\n\n const getGameId = () => this.gameId\n const getConversationId = () => this.conversationId\n const getModelId = () => this.modelId\n this.chat = new ChatModule(this.http, getGameId, getConversationId, getModelId, true, this.previewConfig as Record<string, unknown> | undefined)\n this.characters = new CharactersModule(this.http, getConversationId, true)\n this.relationships = new RelationshipsModule(this.http, getConversationId, true)\n this.inventory = new InventoryModule(this.http, getConversationId, true)\n this.world = new WorldModule(this.http, getConversationId, true)\n this.player = new PlayerModule(this.http, getConversationId, true)\n this.custom = new CustomModule(this.http, getConversationId, true)\n\n this.initialized = true\n\n // 监听父页面的配置更新(模型选择、prompt 变更等)\n this.listenForPreviewMessages()\n return\n }\n\n // ===== 正常模式 =====\n const authResult = await this.authenticate()\n this.conversationId = authResult.conversationId\n\n const models = authResult.models || []\n const savedModelId = this.getSavedModelId()\n this.modelId =\n savedModelId && models.some((m: { id: string }) => m.id === savedModelId)\n ? savedModelId\n : models[0]?.id || ''\n\n const settings: GameSettings = authResult.settings || {\n temperature: 1.0,\n reply_length: 'medium',\n reply_language: 'zh-CN',\n player_note: '',\n }\n\n this.settingsSheet = new SettingsSheet({\n onModelChange: (id) => { this.modelId = id },\n onSettingsChange: (s) => this.saveSettings(s),\n onSync: () => this.syncSettings(),\n })\n this.settingsSheet.mount(models, this.modelId, settings, authResult.hasWorldUpdate ?? false)\n\n const getGameId = () => this.gameId\n const getConversationId = () => this.conversationId\n const getModelId = () => this.modelId\n this.chat = new ChatModule(this.http, getGameId, getConversationId, getModelId)\n this.characters = new CharactersModule(this.http, getConversationId)\n this.relationships = new RelationshipsModule(this.http, getConversationId)\n this.inventory = new InventoryModule(this.http, getConversationId)\n this.world = new WorldModule(this.http, getConversationId)\n this.player = new PlayerModule(this.http, getConversationId)\n this.custom = new CustomModule(this.http, getConversationId)\n\n this.initialized = true\n }\n\n /** 监听父页面 postMessage(预览模式) */\n private listenForPreviewMessages(): void {\n window.addEventListener('message', (event: MessageEvent) => {\n if (!event.data || event.data.type !== 'storvia-preview') return\n\n if (event.data.action === 'set-model') {\n this.modelId = event.data.modelId || ''\n }\n\n if (event.data.action === 'update-config') {\n this.previewConfig = event.data.previewConfig\n // 更新 ChatModule 的 previewConfig\n if (this.chat) {\n this.chat.updatePreviewConfig(this.previewConfig as Record<string, unknown> | undefined)\n }\n }\n })\n }\n\n /** 保存设置到后端 */\n private async saveSettings(settings: Partial<GameSettings>): Promise<void> {\n await this.http.patch('/settings', {\n conversation_id: this.conversationId,\n ...settings,\n })\n }\n\n /** 同步最新游戏设定到当前存档 */\n async syncSettings(): Promise<void> {\n await this.http.post('/sync', { conversation_id: this.conversationId })\n }\n\n private async authenticate(): Promise<{\n conversationId: string\n models: { id: string; name: string; provider: string }[]\n settings?: GameSettings\n hasWorldUpdate?: boolean\n }> {\n const res = await fetch(`${this.baseUrl}/auth`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.accessToken}`,\n },\n body: JSON.stringify({ game_id: this.gameId }),\n })\n\n if (!res.ok) {\n if (res.status === 401) throw new StorviaError('UNAUTHORIZED', 'User not authenticated')\n if (res.status === 404) throw new StorviaError('GAME_NOT_FOUND', 'Game not found or not published')\n throw new StorviaError('INTERNAL_ERROR', `Auth failed: HTTP ${res.status}`)\n }\n\n const json = await res.json()\n return json.data ?? json\n }\n\n private getSavedModelId(): string {\n try {\n return localStorage.getItem('storvia_model_id') || ''\n } catch {\n return ''\n }\n }\n}\n"],"mappings":"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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA8aTC,EAAY,qxBACZC,EAAY,4RACZC,EAAiB,wLACjBC,EAAa,uKACbC,EAAa,oPAENC,EAAN,KAAoB,CAuCzB,YAAYC,EAA8B,CAjC1C,KAAQ,gBAAkB,GAC1B,KAAQ,OAAwB,CAAC,EACjC,KAAQ,WAAiC,KAGzC,KAAQ,SAAyB,CAC/B,YAAa,EACb,aAAc,SACd,eAAgB,QAChB,YAAa,EACf,EAGA,KAAQ,eAAiB,GACzB,KAAQ,OAA6B,KACrC,KAAQ,SAA+B,KAGvC,KAAQ,YAAmC,QAC3C,KAAQ,gBAAuC,CAAC,EAGhD,KAAQ,YAAkC,KAC1C,KAAQ,WAAsC,KAC9C,KAAQ,YAAmC,CAAC,EAC5C,KAAQ,WAAuC,KAC/C,KAAQ,UAAwC,KAChD,KAAQ,YAAkC,KAC1C,KAAQ,QAAoC,KAC5C,KAAQ,QAAoC,KAC5C,KAAQ,UAAuB,OAC/B,KAAQ,MAA4B,KAGlC,KAAK,UAAYA,EACjB,KAAK,KAAO,SAAS,cAAc,KAAK,EACxC,KAAK,KAAK,GAAK,mBACf,KAAK,WAAa,KAAK,KAAK,aAAa,CAAE,KAAM,QAAS,CAAC,CAC7D,CAEA,MAAMC,EAAuBC,EAAwBC,EAAwBC,EAAiB,GAAO,CACnG,KAAK,OAASH,EACd,KAAK,gBAAkBC,EACvB,KAAK,SAAW,CAAE,GAAGC,CAAS,EAC9B,KAAK,eAAiBC,EACtB,GAAI,CACF,IAAMC,EAAQ,aAAa,QAAQ,sBAAsB,GACrDA,IAAU,SAAWA,IAAU,aAAW,KAAK,YAAcA,EACnE,MAAQ,CAAe,CACvB,SAAS,KAAK,YAAY,KAAK,IAAI,EACnC,KAAK,OAAO,CACd,CAEA,SAAU,CACR,KAAK,KAAK,OAAO,CACnB,CAEA,oBAA6B,CAC3B,OAAO,KAAK,eACd,CAEA,aAA4B,CAC1B,MAAO,CAAE,GAAG,KAAK,QAAS,CAC5B,CAEQ,QAAS,CACf,IAAMC,EAAQ,SAAS,cAAc,OAAO,EAC5CA,EAAM,YAAcb,EAEpB,IAAMc,EAAY,SAAS,cAAc,KAAK,EAGxCC,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAY,WACpB,IAAMC,EAAM,SAAS,cAAc,QAAQ,EAC3CA,EAAI,UAAY,MAChBA,EAAI,UAAYf,EAChBe,EAAI,MAAQ,2BACZ,IAAMC,EAAS,SAAS,cAAc,KAAK,EAC3CA,EAAO,UAAY,UAAU,KAAK,eAAiB,WAAa,EAAE,GAClE,KAAK,OAASA,EACdF,EAAQ,YAAYC,CAAG,EACvBD,EAAQ,YAAYE,CAAM,EAG1B,IAAMC,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,QAClB,KAAK,MAAQA,EAGb,IAAMC,EAAS,SAAS,cAAc,KAAK,EAC3CA,EAAO,UAAY,eACnB,IAAMC,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,cAClBA,EAAM,YAAc,2BACpB,IAAMC,EAAW,SAAS,cAAc,QAAQ,EAChDA,EAAS,UAAY,YACrBA,EAAS,UAAY,SACrBA,EAAS,iBAAiB,QAAS,IAAMH,EAAM,UAAU,OAAO,MAAM,CAAC,EACvEC,EAAO,YAAYC,CAAK,EACxBD,EAAO,YAAYE,CAAQ,EAC3BH,EAAM,YAAYC,CAAM,EAGxB,IAAMG,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,aAGb,KAAK,OAAO,OAAS,IACvBA,EAAK,YAAY,KAAK,kBAAkB,CAAC,EACzCA,EAAK,YAAY,KAAK,YAAY,CAAC,GAIrCA,EAAK,YAAY,KAAK,wBAAwB,CAAC,EAC/CA,EAAK,YAAY,KAAK,YAAY,CAAC,EAGnCA,EAAK,YAAY,KAAK,wBAAwB,CAAC,EAC/CA,EAAK,YAAY,KAAK,YAAY,CAAC,EAGnCA,EAAK,YAAY,KAAK,0BAA0B,CAAC,EACjDA,EAAK,YAAY,KAAK,YAAY,CAAC,EAGnCA,EAAK,YAAY,KAAK,iBAAiB,CAAC,EACxCA,EAAK,YAAY,KAAK,YAAY,CAAC,EAGnCA,EAAK,YAAY,KAAK,wBAAwB,CAAC,EAC/CA,EAAK,YAAY,KAAK,YAAY,CAAC,EAGnCA,EAAK,YAAY,KAAK,iBAAiB,CAAC,EAGxC,IAAMC,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAY,WACpB,IAAMC,EAAU,SAAS,cAAc,QAAQ,EAC/CA,EAAQ,UAAY,WACpBA,EAAQ,YAAc,eACtB,KAAK,QAAUA,EACfA,EAAQ,iBAAiB,QAAS,IAAM,KAAK,WAAW,CAAC,EACzDD,EAAQ,YAAYC,CAAO,EAC3BF,EAAK,YAAYC,CAAO,EAExBL,EAAM,YAAYI,CAAI,EAGtBN,EAAI,iBAAiB,QAAS,IAAME,EAAM,UAAU,OAAO,MAAM,CAAC,EAClE,SAAS,iBAAiB,QAAUO,GAAM,CACnC,KAAK,KAAK,SAASA,EAAE,MAAc,GAAGP,EAAM,UAAU,OAAO,MAAM,CAC1E,CAAC,EAEDJ,EAAU,YAAYI,CAAK,EAC3BJ,EAAU,YAAYC,CAAO,EAC7B,KAAK,WAAW,YAAYF,CAAK,EACjC,KAAK,WAAW,YAAYC,CAAS,CACvC,CAIQ,mBAAiC,CACvC,IAAMY,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAY,UAEpB,IAAMC,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,gBAClBA,EAAM,YAAc,kBACpBD,EAAQ,YAAYC,CAAK,EAEzB,IAAMC,EAAO,SAAS,cAAc,KAAK,EACzC,OAAAA,EAAK,UAAY,aACjB,KAAK,WAAaA,EAElB,KAAK,OAAO,QAASC,GAAU,CAC7B,IAAMC,EAAM,SAAS,cAAc,QAAQ,EAC3CA,EAAI,UAAY,eAAeD,EAAM,KAAO,KAAK,gBAAkB,UAAY,EAAE,GACjFC,EAAI,UAAY,kCAAkCD,EAAM,IAAI,UAC5DC,EAAI,iBAAiB,QAAS,IAAM,CAClC,KAAK,gBAAkBD,EAAM,GAC7B,KAAK,UAAU,cAAcA,EAAM,EAAE,EACrC,GAAI,CAAE,aAAa,QAAQ,mBAAoBA,EAAM,EAAE,CAAE,MAAQ,CAAe,CAChF,KAAK,kBAAkB,CACzB,CAAC,EACDD,EAAK,YAAYE,CAAG,CACtB,CAAC,EAEDJ,EAAQ,YAAYE,CAAI,EACjBF,CACT,CAEQ,yBAAuC,CAC7C,IAAMA,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAY,UAEpB,IAAMC,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,gBAClB,IAAMI,EAAY,SAAS,cAAc,MAAM,EAC/CA,EAAU,YAAc,eACxB,IAAMC,EAAY,SAAS,cAAc,MAAM,EAC/CA,EAAU,UAAY,QACtBA,EAAU,YAAc,KAAK,SAAS,YAAY,QAAQ,CAAC,EAC3D,KAAK,YAAcA,EACnBL,EAAM,YAAYI,CAAS,EAC3BJ,EAAM,YAAYK,CAAS,EAC3BN,EAAQ,YAAYC,CAAK,EAEzB,IAAMM,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,eACjBA,EAAK,YAAc,6NACnBP,EAAQ,YAAYO,CAAI,EAExB,IAAMC,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,cACjB,IAAMC,EAAS,SAAS,cAAc,OAAO,EAC7CA,EAAO,KAAO,QACdA,EAAO,UAAY,SACnBA,EAAO,IAAM,IACbA,EAAO,IAAM,IACbA,EAAO,KAAO,MACdA,EAAO,MAAQ,OAAO,KAAK,SAAS,WAAW,EAC/C,KAAK,WAAaA,EAClBA,EAAO,iBAAiB,QAAS,IAAM,CACrC,IAAMC,EAAI,WAAWD,EAAO,KAAK,EACjC,KAAK,SAAS,YAAcC,EACxB,KAAK,cAAa,KAAK,YAAY,YAAcA,EAAE,QAAQ,CAAC,EAClE,CAAC,EACDF,EAAK,YAAYC,CAAM,EAEvB,IAAME,EAAS,SAAS,cAAc,KAAK,EAC3C,OAAAA,EAAO,UAAY,gBACnBA,EAAO,UAAY,qDACnBH,EAAK,YAAYG,CAAM,EAEvBX,EAAQ,YAAYQ,CAAI,EACjBR,CACT,CAEQ,yBAAuC,CAC7C,IAAMA,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAY,UAEpB,IAAMC,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,gBAClBA,EAAM,YAAc,2BACpBD,EAAQ,YAAYC,CAAK,EAEzB,IAAMW,EAAU,SAAS,cAAc,KAAK,EAC5C,OAAAA,EAAQ,UAAY,UACpB,KAAK,YAAc,CAAC,EAEpBvC,EAAe,QAASwC,GAAQ,CAC9B,IAAMT,EAAM,SAAS,cAAc,QAAQ,EAC3CA,EAAI,UAAY,cAAcS,EAAI,QAAU,KAAK,SAAS,aAAe,UAAY,EAAE,GACvFT,EAAI,YAAcS,EAAI,MACtBT,EAAI,iBAAiB,QAAS,IAAM,CAClC,KAAK,SAAS,aAAeS,EAAI,MACjC,KAAK,YAAY,QAAQ,CAACC,EAAGC,IAAM,CACjCD,EAAE,UAAU,OAAO,SAAUzC,EAAe0C,CAAC,EAAE,QAAUF,EAAI,KAAK,CACpE,CAAC,CACH,CAAC,EACD,KAAK,YAAY,KAAKT,CAAG,EACzBQ,EAAQ,YAAYR,CAAG,CACzB,CAAC,EAEDJ,EAAQ,YAAYY,CAAO,EACpBZ,CACT,CAEQ,2BAAyC,CAC/C,IAAMA,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAY,UAEpB,IAAMC,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,gBAClBA,EAAM,YAAc,2BACpBD,EAAQ,YAAYC,CAAK,EAEzB,IAAMO,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,cACjB,IAAMQ,EAAS,SAAS,cAAc,QAAQ,EAC9CA,EAAO,UAAY,SACnB,KAAK,WAAaA,EAElB5C,EAAU,QAAS6C,GAAS,CAC1B,IAAMC,EAAS,SAAS,cAAc,QAAQ,EAC9CA,EAAO,MAAQD,EAAK,MACpBC,EAAO,YAAcD,EAAK,MACtBA,EAAK,QAAU,KAAK,SAAS,iBAAgBC,EAAO,SAAW,IACnEF,EAAO,YAAYE,CAAM,CAC3B,CAAC,EAEDF,EAAO,iBAAiB,SAAU,IAAM,CACtC,KAAK,SAAS,eAAiBA,EAAO,KACxC,CAAC,EAED,IAAMG,EAAQ,SAAS,cAAc,MAAM,EAC3C,OAAAA,EAAM,UAAY,eAClBA,EAAM,YAAc,SACpBX,EAAK,YAAYQ,CAAM,EACvBR,EAAK,YAAYW,CAAK,EAEtBnB,EAAQ,YAAYQ,CAAI,EACjBR,CACT,CAEQ,kBAAgC,CACtC,IAAMA,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAY,UAEpB,IAAMC,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,gBAClB,IAAMI,EAAY,SAAS,cAAc,MAAM,EAC/CA,EAAU,YAAc,eACxB,IAAMe,EAAU,SAAS,cAAc,MAAM,EAC7CA,EAAQ,YAAc,GAAG,KAAK,SAAS,YAAY,MAAM,MACzD,KAAK,YAAcA,EACnBnB,EAAM,YAAYI,CAAS,EAC3BJ,EAAM,YAAYmB,CAAO,EACzBpB,EAAQ,YAAYC,CAAK,EAEzB,IAAMM,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,eACjBA,EAAK,YAAc,2HACnBP,EAAQ,YAAYO,CAAI,EAExB,IAAMC,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,YACjB,IAAMa,EAAW,SAAS,cAAc,UAAU,EAClD,OAAAA,EAAS,UAAY,aACrBA,EAAS,YAAc,eACvBA,EAAS,UAAY,GACrBA,EAAS,MAAQ,KAAK,SAAS,YAC/B,KAAK,UAAYA,EAEjBA,EAAS,iBAAiB,QAAS,IAAM,CACvC,KAAK,SAAS,YAAcA,EAAS,MACjC,KAAK,cACP,KAAK,YAAY,YAAc,GAAGA,EAAS,MAAM,MAAM,MAE3D,CAAC,EAEDb,EAAK,YAAYa,CAAQ,EACzBrB,EAAQ,YAAYQ,CAAI,EACjBR,CACT,CAEQ,yBAAuC,CAC7C,IAAMA,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAY,UAEpB,IAAMC,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,gBAClBA,EAAM,YAAc,2BACpBD,EAAQ,YAAYC,CAAK,EAEzB,IAAMM,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,eACjBA,EAAK,YAAc,qEACnBP,EAAQ,YAAYO,CAAI,EAExB,IAAMK,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAY,UACpB,KAAK,gBAAkB,CAAC,EAExB,IAAMU,EAAkB,CACtB,CAAE,MAAO,QAAkB,MAAO,cAAK,EACvC,CAAE,MAAO,UAAoB,MAAO,cAAK,CAC3C,EAEA,OAAAA,EAAgB,QAAST,GAAQ,CAC/B,IAAMT,EAAM,SAAS,cAAc,QAAQ,EAC3CA,EAAI,UAAY,cAAcS,EAAI,QAAU,KAAK,YAAc,UAAY,EAAE,GAC7ET,EAAI,YAAcS,EAAI,MACtBT,EAAI,iBAAiB,QAAS,IAAM,CAClC,KAAK,YAAcS,EAAI,MACvB,GAAI,CAAE,aAAa,QAAQ,uBAAwBA,EAAI,KAAK,CAAE,MAAQ,CAAe,CACrF,KAAK,gBAAgB,QAAQ,CAACC,EAAGC,IAAM,CACrCD,EAAE,UAAU,OAAO,SAAUQ,EAAgBP,CAAC,EAAE,QAAUF,EAAI,KAAK,CACrE,CAAC,EAED,GAAI,CACF,OAAO,OAAO,YAAY,CACxB,KAAM,sBACN,KAAMA,EAAI,QAAU,UAAY,YAAc,UAChD,EAAG,GAAG,CACR,MAAQ,CAAe,CACzB,CAAC,EACD,KAAK,gBAAgB,KAAKT,CAAG,EAC7BQ,EAAQ,YAAYR,CAAG,CACzB,CAAC,EAEDJ,EAAQ,YAAYY,CAAO,EACpBZ,CACT,CAEQ,kBAAgC,CACtC,IAAMA,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAY,UAEpB,IAAMC,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,gBAClBA,EAAM,YAAc,uCACpBD,EAAQ,YAAYC,CAAK,EAGzB,IAAMsB,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,YAAY,KAAK,eAAiB,WAAa,EAAE,GAClEA,EAAK,YAAc,0GACnB,KAAK,SAAWA,EAChBvB,EAAQ,YAAYuB,CAAI,EAExB,IAAMhB,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,YACjBA,EAAK,YAAc,6OACnBP,EAAQ,YAAYO,CAAI,EAExB,IAAMiB,EAAU,SAAS,cAAc,QAAQ,EAC/C,OAAAA,EAAQ,UAAY,WACpB,KAAK,QAAUA,EACf,KAAK,cAAc,EAEnBA,EAAQ,iBAAiB,QAAS,SAAY,CAC5C,GAAI,KAAK,YAAc,UACvB,MAAK,aAAa,SAAS,EAC3B,GAAI,CACF,MAAM,KAAK,UAAU,OAAO,EAC5B,KAAK,aAAa,SAAS,EAE3B,KAAK,eAAiB,GAClB,KAAK,QAAQ,KAAK,OAAO,UAAU,OAAO,SAAS,EACnD,KAAK,UAAU,KAAK,SAAS,UAAU,OAAO,SAAS,EAC3D,WAAW,IAAM,KAAK,aAAa,MAAM,EAAG,GAAI,CAClD,MAAQ,CACN,KAAK,aAAa,OAAO,EACzB,WAAW,IAAM,KAAK,aAAa,MAAM,EAAG,GAAI,CAClD,EACF,CAAC,EAEDxB,EAAQ,YAAYwB,CAAO,EACpBxB,CACT,CAIQ,aAA2B,CACjC,IAAMyB,EAAI,SAAS,cAAc,KAAK,EACtC,OAAAA,EAAE,UAAY,UACPA,CACT,CAEQ,mBAAoB,CACrB,KAAK,YACV,KAAK,WAAW,iBAAiB,eAAe,EAAE,QAAQ,CAACrB,EAAKW,IAAM,CACpEX,EAAI,UAAU,OAAO,SAAU,KAAK,OAAOW,CAAC,EAAE,KAAO,KAAK,eAAe,CAC3E,CAAC,CACH,CAEQ,aAAaW,EAAkB,CACrC,KAAK,UAAYA,EACjB,KAAK,cAAc,CACrB,CAEQ,eAAgB,CACtB,GAAI,CAAC,KAAK,QAAS,OACnB,IAAMC,EAAI,KAAK,UACTC,EAAmC,CACvC,KAAMpD,EACN,QAASC,EACT,QAASC,EACT,MAAOC,CACT,EACMgC,EAAoC,CACxC,KAAM,uCACN,QAAS,wBACT,QAAS,qBACT,MAAO,0BACT,EACA,KAAK,QAAQ,UAAY,WAAWgB,IAAM,WAAaA,IAAM,QAAU,IAAIA,CAAC,GAAK,EAAE,GACnF,KAAK,QAAQ,SAAWA,IAAM,UAC9B,KAAK,QAAQ,UAAY,GAAGC,EAAMD,CAAC,CAAC,SAAShB,EAAOgB,CAAC,CAAC,SACxD,CAEA,MAAc,YAAa,CACzB,GAAI,GAAC,KAAK,SAAW,KAAK,QAAQ,UAClC,MAAK,QAAQ,SAAW,GACxB,KAAK,QAAQ,YAAc,wBAC3B,GAAI,CACF,MAAM,KAAK,UAAU,iBAAiB,CACpC,YAAa,KAAK,SAAS,YAC3B,aAAc,KAAK,SAAS,aAC5B,eAAgB,KAAK,SAAS,eAC9B,YAAa,KAAK,SAAS,WAC7B,CAAC,EACD,KAAK,QAAQ,YAAc,qBAC3B,KAAK,QAAQ,UAAU,IAAI,OAAO,EAClC,WAAW,IAAM,CACX,KAAK,UACP,KAAK,QAAQ,YAAc,eAC3B,KAAK,QAAQ,UAAU,OAAO,OAAO,EACrC,KAAK,QAAQ,SAAW,GAE5B,EAAG,GAAI,CACT,MAAQ,CACN,KAAK,QAAQ,YAAc,2BAC3B,WAAW,IAAM,CACX,KAAK,UACP,KAAK,QAAQ,YAAc,eAC3B,KAAK,QAAQ,SAAW,GAE5B,EAAG,GAAI,CACT,EACF,CACF,EC79BO,IAAME,EAAN,KAAiB,CAGtB,YACUC,EACAC,EACAC,EACAC,EACAC,EAAqB,GAC7BC,EACA,CANQ,UAAAL,EACA,eAAAC,EACA,uBAAAC,EACA,gBAAAC,EACA,eAAAC,EAGR,KAAK,cAAgBC,CACvB,CAGA,oBAAoBC,EAAwC,CAC1D,KAAK,cAAgBA,CACvB,CAMA,MAAM,KAAKC,EAAwD,CACjE,GAAI,KAAK,UACP,OAAO,KAAK,YAAYA,CAAO,EAGjC,IAAMC,EAAO,CACX,QAAS,KAAK,UAAU,EACxB,gBAAiB,KAAK,kBAAkB,EACxC,SAAU,KAAK,WAAW,EAC1B,QAASD,EAAQ,QACjB,MAAOA,EAAQ,MACf,QAASA,EAAQ,QACjB,OAAQA,EAAQ,QAAU,EAC5B,EAEA,GAAIA,EAAQ,OAAQ,CAClB,MAAM,KAAK,KAAK,OACd,QACAC,EACAD,EAAQ,UAAY,IAAM,CAAC,GAC3BA,EAAQ,SAAW,IAAM,CAAC,EAC5B,EACA,MACF,CAEA,OAAO,KAAK,KAAK,KAAmB,QAASC,CAAI,CACnD,CAMA,MAAM,KAAKD,EAAmD,CAC5D,OAAO,KAAK,KAAK,KAAqB,iBAAkB,CACtD,gBAAiB,KAAK,kBAAkB,EACxC,KAAMA,EAAQ,KACd,QAASA,EAAQ,QACjB,MAAOA,EAAQ,KACjB,CAAC,CACH,CAMA,MAAM,SAASA,EAA4D,CACzE,IAAMC,EAAO,CACX,gBAAiB,KAAK,kBAAkB,EACxC,SAAU,KAAK,WAAW,EAC1B,MAAOD,EAAQ,MACf,QAASA,EAAQ,QACjB,OAAQA,EAAQ,QAAU,GAC1B,KAAMA,EAAQ,MAAQ,EACxB,EAEA,GAAIA,EAAQ,OAAQ,CAClB,MAAM,KAAK,KAAK,OACd,YACAC,EACAD,EAAQ,UAAY,IAAM,CAAC,GAC3BA,EAAQ,SAAW,IAAM,CAAC,EAC5B,EACA,MACF,CAEA,OAAO,KAAK,KAAK,KAAmB,YAAaC,CAAI,CACvD,CAGA,MAAc,YAAYD,EAAwD,CAChF,IAAMC,EAAO,CACX,SAAU,KAAK,WAAW,EAC1B,QAASD,EAAQ,QACjB,MAAOA,EAAQ,MACf,QAASA,EAAQ,QACjB,cAAe,KAAK,eAAiB,CAAC,EACtC,iBAAkB,CAAC,CACrB,EAEA,GAAIA,EAAQ,OAAQ,CAClB,MAAM,KAAK,KAAK,OACd,WACAC,EACAD,EAAQ,UAAY,IAAM,CAAC,GAC3BA,EAAQ,SAAW,IAAM,CAAC,EAC5B,EACA,MACF,CAEA,IAAIE,EAAU,GACd,aAAM,KAAK,KAAK,OACd,WACAD,EACCE,GAAU,CAAED,GAAWC,CAAM,EAC9B,IAAM,CAAC,CACT,EACO,CAAE,GAAI,GAAI,QAAAD,CAAQ,CAC3B,CACF,EClHA,IAAME,EAAN,KAA2B,CAGzB,YACUC,EACAC,EACAC,EAAqB,GAC7B,CAHQ,UAAAF,EACA,uBAAAC,EACA,eAAAC,EALV,KAAQ,IAAuD,CAAC,CAM7D,CAEH,MAAM,IAAIC,EAAiE,CACzE,OAAI,KAAK,UAAkB,CAAE,GAAI,KAAK,IAAIA,CAAa,GAAK,CAAC,CAAG,EACzD,KAAK,KAAK,IAAI,kBAAkB,KAAK,kBAAkB,CAAC,eAAe,mBAAmBA,CAAa,CAAC,QAAQ,CACzH,CAEA,MAAM,OAAOA,EAAuBC,EAAwD,CAC1F,GAAI,KAAK,UAAW,CAClB,KAAK,IAAID,CAAa,EAAI,CAAE,GAAI,KAAK,IAAIA,CAAa,GAAK,CAAC,EAAI,GAAGC,CAAO,EAC1E,MACF,CACA,MAAM,KAAK,KAAK,MAAM,kBAAkB,KAAK,kBAAkB,CAAC,eAAe,mBAAmBD,CAAa,CAAC,SAAUC,CAAM,CAClI,CACF,EAEaC,EAAN,KAAuB,CAI5B,YACUL,EACAC,EACAC,EAAqB,GAC7B,CAHQ,UAAAF,EACA,uBAAAC,EACA,eAAAC,EALV,KAAQ,IAA2B,CAAC,EAOlC,KAAK,MAAQ,IAAIH,EAAqBC,EAAMC,EAAmBC,CAAS,CAC1E,CAEA,MAAM,MAAoC,CACxC,OAAI,KAAK,UAAkB,KAAK,IAAI,IAAII,IAAM,CAAE,KAAMA,EAAE,KAAM,OAAQA,EAAE,MAAO,EAAE,EAC1E,KAAK,KAAK,IAAI,kBAAkB,KAAK,kBAAkB,CAAC,aAAa,CAC9E,CAEA,MAAM,IAAIC,EAAyC,CACjD,GAAI,KAAK,UAAW,CAClB,IAAMD,EAAI,KAAK,IAAI,KAAKA,GAAKA,EAAE,OAASC,CAAI,EAC5C,MAAO,CAAE,KAAMD,GAAG,MAAQC,EAAM,OAAQD,GAAG,MAAO,CACpD,CACA,OAAO,KAAK,KAAK,IAAI,kBAAkB,KAAK,kBAAkB,CAAC,eAAe,mBAAmBC,CAAI,CAAC,EAAE,CAC1G,CAEA,MAAM,IAAIC,EAAmF,CAC3F,GAAI,KAAK,UAAW,CAAE,KAAK,IAAI,KAAKA,CAAS,EAAG,MAAO,CACvD,MAAM,KAAK,KAAK,KAAK,kBAAkB,KAAK,kBAAkB,CAAC,cAAeA,CAAS,CACzF,CAEA,MAAM,OAAOD,EAAcE,EAA8D,CACvF,GAAI,KAAK,UAAW,CAAE,IAAMH,EAAI,KAAK,IAAI,KAAKA,GAAKA,EAAE,OAASC,CAAI,EAAOD,GAAG,OAAO,OAAOA,EAAGG,CAAI,EAAG,MAAO,CAC3G,MAAM,KAAK,KAAK,MAAM,kBAAkB,KAAK,kBAAkB,CAAC,eAAe,mBAAmBF,CAAI,CAAC,GAAIE,CAAI,CACjH,CAEA,MAAM,OAAOF,EAA6B,CACxC,GAAI,KAAK,UAAW,CAAE,KAAK,IAAM,KAAK,IAAI,OAAOD,GAAKA,EAAE,OAASC,CAAI,EAAG,MAAO,CAC/E,MAAM,KAAK,KAAK,OAAO,kBAAkB,KAAK,kBAAkB,CAAC,eAAe,mBAAmBA,CAAI,CAAC,EAAE,CAC5G,CAEA,MAAM,OAAOA,EAAwC,CACnD,GAAI,KAAK,UAAW,CAClB,IAAMD,EAAI,KAAK,IAAI,KAAKA,GAAKA,EAAE,OAASC,CAAI,EAC5C,MAAO,CAAE,KAAAA,EAAM,OAAQD,GAAG,OAAQ,MAAO,MAAM,KAAK,MAAM,IAAIC,CAAI,CAAE,CACtE,CACA,OAAO,KAAK,KAAK,IAAI,kBAAkB,KAAK,kBAAkB,CAAC,eAAe,mBAAmBA,CAAI,CAAC,SAAS,CACjH,CACF,EC7EO,IAAMG,EAAN,KAA0B,CAG/B,YACUC,EACAC,EACAC,EAAqB,GAC7B,CAHQ,UAAAF,EACA,uBAAAC,EACA,eAAAC,EALV,KAAQ,IAAsB,CAAC,CAM5B,CAEH,MAAM,MAAgC,CACpC,OAAI,KAAK,UAAkB,CAAC,GAAG,KAAK,GAAG,EAChC,KAAK,KAAK,IAAI,kBAAkB,KAAK,kBAAkB,CAAC,gBAAgB,CACjF,CAEA,MAAM,IAAIC,EAAcC,EAAmC,CACzD,GAAI,KAAK,UAAW,CAClB,IAAMC,EAAI,KAAK,IAAI,KAAKA,GAAKA,EAAE,OAASF,GAAQE,EAAE,KAAOD,CAAE,EAC3D,GAAIC,EAAG,MAAO,CAAE,GAAGA,CAAE,EACrB,MAAM,IAAI,MAAM,wBAAwB,CAC1C,CACA,OAAO,KAAK,KAAK,IAAI,kBAAkB,KAAK,kBAAkB,CAAC,kBAAkB,mBAAmBF,CAAI,CAAC,IAAI,mBAAmBC,CAAE,CAAC,EAAE,CACvI,CAEA,MAAM,IAAIE,EAA2C,CACnD,GAAI,KAAK,UAAW,CAAE,KAAK,IAAI,KAAK,CAAE,GAAGA,CAAa,CAAC,EAAG,MAAO,CACjE,MAAM,KAAK,KAAK,KAAK,kBAAkB,KAAK,kBAAkB,CAAC,iBAAkBA,CAAY,CAC/F,CAEA,MAAM,OAAOH,EAAcC,EAAYG,EAAsD,CAC3F,GAAI,KAAK,UAAW,CAClB,IAAMF,EAAI,KAAK,IAAI,KAAKA,GAAKA,EAAE,OAASF,GAAQE,EAAE,KAAOD,CAAE,EACvDC,EAAG,OAAO,OAAOA,EAAGE,CAAI,EACvB,KAAK,IAAI,KAAK,CAAE,KAAAJ,EAAM,GAAAC,EAAI,GAAGG,CAAK,CAAC,EACxC,MACF,CACA,MAAM,KAAK,KAAK,MAAM,kBAAkB,KAAK,kBAAkB,CAAC,kBAAkB,mBAAmBJ,CAAI,CAAC,IAAI,mBAAmBC,CAAE,CAAC,GAAIG,CAAI,CAC9I,CAEA,MAAM,OAAOJ,EAAcC,EAA2B,CACpD,GAAI,KAAK,UAAW,CAAE,KAAK,IAAM,KAAK,IAAI,OAAOC,GAAK,EAAEA,EAAE,OAASF,GAAQE,EAAE,KAAOD,EAAG,EAAG,MAAO,CACjG,MAAM,KAAK,KAAK,OAAO,kBAAkB,KAAK,kBAAkB,CAAC,kBAAkB,mBAAmBD,CAAI,CAAC,IAAI,mBAAmBC,CAAE,CAAC,EAAE,CACzI,CACF,EC1CO,IAAMI,EAAN,KAAsB,CAG3B,YACUC,EACAC,EACAC,EAAqB,GAC7B,CAHQ,UAAAF,EACA,uBAAAC,EACA,eAAAC,EALV,KAAQ,IAA2B,CAAC,CAMjC,CAEH,MAAM,KAAKC,EAA8C,CACvD,GAAI,KAAK,UAAW,OAAOA,EAAQ,KAAK,IAAI,OAAOC,GAAKA,EAAE,QAAUD,CAAK,EAAI,CAAC,GAAG,KAAK,GAAG,EACzF,IAAME,EAASF,EAAQ,CAAE,MAAAA,CAAM,EAAI,OACnC,OAAO,KAAK,KAAK,IAAI,kBAAkB,KAAK,kBAAkB,CAAC,aAAcE,CAAM,CACrF,CAEA,MAAM,IAAIC,EAAwC,CAChD,GAAI,KAAK,UAAW,CAAE,KAAK,IAAI,KAAK,CAAE,GAAGA,CAAK,CAAC,EAAG,MAAO,CACzD,MAAM,KAAK,KAAK,KAAK,kBAAkB,KAAK,kBAAkB,CAAC,aAAcA,CAAI,CACnF,CAEA,MAAM,OAAOC,EAAcC,EAA+D,CACxF,GAAI,KAAK,UAAW,CAClB,IAAMJ,EAAI,KAAK,IAAI,KAAKA,GAAKA,EAAE,OAASG,CAAI,EACxCH,GAAG,OAAO,OAAOA,EAAGI,CAAI,EAC5B,MACF,CACA,MAAM,KAAK,KAAK,MAAM,kBAAkB,KAAK,kBAAkB,CAAC,cAAc,mBAAmBD,CAAI,CAAC,GAAIC,CAAI,CAChH,CAEA,MAAM,OAAOD,EAA6B,CACxC,GAAI,KAAK,UAAW,CAAE,KAAK,IAAM,KAAK,IAAI,OAAOH,GAAKA,EAAE,OAASG,CAAI,EAAG,MAAO,CAC/E,MAAM,KAAK,KAAK,OAAO,kBAAkB,KAAK,kBAAkB,CAAC,cAAc,mBAAmBA,CAAI,CAAC,EAAE,CAC3G,CACF,EClCO,IAAME,EAAN,KAAkB,CAGvB,YACUC,EACAC,EACAC,EAAqB,GAC7B,CAHQ,UAAAF,EACA,uBAAAC,EACA,eAAAC,EALV,KAAQ,IAA+B,CAAC,CAMrC,CAEH,MAAM,KAAwC,CAC5C,OAAI,KAAK,UAAkB,CAAE,GAAG,KAAK,GAAI,EAClC,KAAK,KAAK,IAAI,kBAAkB,KAAK,kBAAkB,CAAC,QAAQ,CACzE,CAEA,MAAM,OAAOC,EAA8C,CACzD,GAAI,KAAK,UAAW,CAAE,OAAO,OAAO,KAAK,IAAKA,CAAI,EAAG,MAAO,CAC5D,MAAM,KAAK,KAAK,MAAM,kBAAkB,KAAK,kBAAkB,CAAC,SAAUA,CAAI,CAChF,CACF,ECjBA,IAAMC,EAAN,KAAwB,CAGtB,YACUC,EACAC,EACAC,EAAqB,GAC7B,CAHQ,UAAAF,EACA,uBAAAC,EACA,eAAAC,EALV,KAAQ,IAAuD,CAAC,CAM7D,CAIH,MAAM,IAAIC,EAA4G,CACpH,GAAI,KAAK,UACP,OAAIA,EAAc,CAAE,GAAI,KAAK,IAAIA,CAAK,GAAK,CAAC,CAAG,EACxC,CAAE,GAAG,KAAK,GAAI,EAEvB,IAAMC,EAASD,EAAQ,CAAE,MAAAA,CAAM,EAAI,OACnC,OAAO,KAAK,KAAK,IAAI,kBAAkB,KAAK,kBAAkB,CAAC,gBAAiBC,CAAM,CACxF,CAEA,MAAM,OAAOD,EAAeE,EAAwD,CAClF,GAAI,KAAK,UAAW,CAClB,KAAK,IAAIF,CAAK,EAAI,CAAE,GAAI,KAAK,IAAIA,CAAK,GAAK,CAAC,EAAI,GAAGE,CAAO,EAC1D,MACF,CACA,MAAM,KAAK,KAAK,MAAM,kBAAkB,KAAK,kBAAkB,CAAC,gBAAiB,CAAE,MAAAF,EAAO,OAAAE,CAAO,CAAC,CACpG,CACF,EAEaC,EAAN,KAAmB,CAIxB,YACUN,EACAC,EACAC,EAAqB,GAC7B,CAHQ,UAAAF,EACA,uBAAAC,EACA,eAAAC,EALV,KAAQ,WAA4B,CAAE,KAAM,EAAG,EAO7C,KAAK,MAAQ,IAAIH,EAAkBC,EAAMC,EAAmBC,CAAS,CACvE,CAEA,MAAM,KAA8B,CAClC,OAAI,KAAK,UAAkB,CAAE,GAAG,KAAK,UAAW,EACzC,KAAK,KAAK,IAAI,kBAAkB,KAAK,kBAAkB,CAAC,SAAS,CAC1E,CACF,EC9CO,IAAMK,EAAN,KAAmB,CAGxB,YACUC,EACAC,EACAC,EAAqB,GAC7B,CAHQ,UAAAF,EACA,uBAAAC,EACA,eAAAC,EALV,KAAQ,IAA+B,CAAC,CAMrC,CAIH,MAAM,IAAIC,EAAgC,CACxC,GAAI,KAAK,UACP,OAAIA,IAAQ,OAAkB,KAAK,IAAIA,CAAG,EACnC,CAAE,GAAG,KAAK,GAAI,EAEvB,IAAMC,EAAO,MAAM,KAAK,KAAK,IAC3B,kBAAkB,KAAK,kBAAkB,CAAC,SAC5C,EACA,OAAID,IAAQ,OAAkBC,EAAKD,CAAG,EAC/BC,CACT,CAEA,MAAM,IAAIA,EAA8C,CACtD,GAAI,KAAK,UAAW,CAElB,OAAW,CAACD,EAAKE,CAAK,IAAK,OAAO,QAAQD,CAAI,EACxC,OAAOC,GAAU,UAAYA,IAAU,MAAQ,CAAC,MAAM,QAAQA,CAAK,GAClE,OAAO,KAAK,IAAIF,CAAG,GAAM,UAAY,KAAK,IAAIA,CAAG,IAAM,KAC1D,KAAK,IAAIA,CAAG,EAAI,CAAE,GAAI,KAAK,IAAIA,CAAG,EAA+B,GAAGE,CAAM,EAE1E,KAAK,IAAIF,CAAG,EAAIE,EAGpB,MACF,CACA,MAAM,KAAK,KAAK,MAAM,kBAAkB,KAAK,kBAAkB,CAAC,UAAWD,CAAI,CACjF,CAEA,MAAM,OAAOD,EAA4B,CACvC,GAAI,KAAK,UAAW,CAAE,OAAO,KAAK,IAAIA,CAAG,EAAG,MAAO,CACnD,MAAM,KAAK,KAAK,OAAO,kBAAkB,KAAK,kBAAkB,CAAC,WAAW,mBAAmBA,CAAG,CAAC,EAAE,CACvG,CAEA,MAAM,cAAcG,EAAkBC,EAAkBF,EAA+B,CACrF,GAAI,KAAK,UAAW,EACd,CAAC,KAAK,IAAIC,CAAQ,GAAK,OAAO,KAAK,IAAIA,CAAQ,GAAM,YACvD,KAAK,IAAIA,CAAQ,EAAI,CAAC,GAEvB,KAAK,IAAIA,CAAQ,EAA8BC,CAAQ,EAAIF,EAC5D,MACF,CACA,MAAM,KAAK,KAAK,MACd,kBAAkB,KAAK,kBAAkB,CAAC,WAAW,mBAAmBC,CAAQ,CAAC,IAAI,mBAAmBC,CAAQ,CAAC,GACjH,CAAE,MAAAF,CAAM,CACV,CACF,CAEA,MAAM,iBAAiBC,EAAkBC,EAAiC,CACxE,GAAI,KAAK,UAAW,CAClB,GAAI,OAAO,KAAK,IAAID,CAAQ,GAAM,UAAY,KAAK,IAAIA,CAAQ,IAAM,KAAM,CACzE,IAAME,EAAQ,KAAK,IAAIF,CAAQ,EAC/B,OAAOE,EAAMD,CAAQ,EACjB,OAAO,KAAKC,CAAK,EAAE,SAAW,GAAG,OAAO,KAAK,IAAIF,CAAQ,CAC/D,CACA,MACF,CACA,MAAM,KAAK,KAAK,OACd,kBAAkB,KAAK,kBAAkB,CAAC,WAAW,mBAAmBA,CAAQ,CAAC,IAAI,mBAAmBC,CAAQ,CAAC,EACnH,CACF,CACF,EC7DA,IAAME,EAAW,gCAyBjB,SAASC,GAAqB,CAC5B,OAAS,OAAiD,aAAgB,CAAC,CAC7E,CASA,SAASC,EAAWC,EAAY,IAA2B,CACzD,IAAMC,EAAWH,EAAO,EACxB,OAAIG,EAAS,QAAgB,QAAQ,QAAQA,CAAQ,EAE9C,IAAI,QAAoB,CAACC,EAASC,IAAW,CAClD,IAAMC,EAAQ,WAAW,IAAM,CAC7B,OAAO,oBAAoB,UAAWC,CAAO,EAC7CF,EAAO,IAAIG,EAAa,kBAAmB,6DAA6D,CAAC,CAC3G,EAAGN,CAAS,EAEZ,SAASK,EAAQE,EAAqB,CACpC,IAAIC,EAAyB,KAc7B,GAZID,EAAM,MAAM,OAAS,gBAAkBA,EAAM,KAAK,QAEpDC,EAAM,CACJ,QAASD,EAAM,KAAK,QACpB,OAAQA,EAAM,KAAK,OACnB,YAAaA,EAAM,KAAK,WAC1B,EACSA,EAAM,MAAM,OAAS,wBAA0BA,EAAM,KAAK,SAEnEC,EAAMD,EAAM,KAAK,QAGfC,GAAOA,EAAI,QAAS,CACtB,aAAaJ,CAAK,EAClB,OAAO,oBAAoB,UAAWC,CAAO,EAC7C,IAAMI,EAAI,OACVA,EAAE,YAAcD,EAChBN,EAAQM,CAAG,CACb,CACF,CAEA,OAAO,iBAAiB,UAAWH,CAAO,CAC5C,CAAC,CACH,CAEO,IAAMK,EAAN,KAAiB,CAAjB,cAGL,KAAQ,QAAU,GAClB,KAAQ,OAAS,GACjB,KAAQ,eAAiB,GACzB,KAAQ,QAAU,GAClB,KAAQ,YAAc,GACtB,KAAQ,YAAc,GACtB,KAAQ,UAAY,GACpB,KAAQ,cAA6C,OAUrD,MAAM,MAAsB,CAE1B,IAAMF,EAAM,MAAMT,EAAW,EAEvBY,EAAUH,EAAI,QACpB,GAAI,CAACG,EACH,MAAM,IAAIL,EACR,kBACA,qFACF,EAMF,GAJA,KAAK,QAAU,GAAGK,CAAO,GAAGd,CAAQ,GACpC,KAAK,UAAY,CAAC,CAACW,EAAI,QACvB,KAAK,cAAgBA,EAAI,cAErB,CAACA,EAAI,OACP,MAAM,IAAIF,EACR,iBACA,oFACF,EAKF,GAHA,KAAK,OAASE,EAAI,OAGd,CAACA,EAAI,YACP,MAAM,IAAIF,EACR,eACA,qGACF,EAMF,GAJA,KAAK,YAAcE,EAAI,YAEvB,KAAK,KAAO,IAAII,EAAW,KAAK,QAAS,KAAK,YAAa,CAAC,CAACJ,EAAI,KAAK,EAElE,KAAK,UAAW,CAElB,KAAK,eAAiB,uCAGtB,IAAMK,EAASL,EAAI,QAAU,CAAC,EAC9B,KAAK,QAAUA,EAAI,iBAAmBK,EAAO,CAAC,GAAG,IAAM,GAGvD,KAAK,cAAgB,IAAIC,EAAc,CACrC,cAAgBC,GAAO,CAAE,KAAK,QAAUA,CAAG,EAC3C,iBAAkB,IAAM,QAAQ,QAAQ,EACxC,OAAQ,IAAM,QAAQ,QAAQ,CAChC,CAAC,EACGF,EAAO,OAAS,GAClB,KAAK,cAAc,MAAMA,EAAQ,KAAK,QAAS,CAC7C,YAAa,EACb,aAAc,SACd,eAAgB,QAChB,YAAa,EACf,EAAG,EAAK,EAGV,IAAMG,EAAY,IAAM,KAAK,OACvBC,EAAoB,IAAM,KAAK,eAC/BC,EAAa,IAAM,KAAK,QAC9B,KAAK,KAAO,IAAIC,EAAW,KAAK,KAAMH,EAAWC,EAAmBC,EAAY,GAAM,KAAK,aAAoD,EAC/I,KAAK,WAAa,IAAIE,EAAiB,KAAK,KAAMH,EAAmB,EAAI,EACzE,KAAK,cAAgB,IAAII,EAAoB,KAAK,KAAMJ,EAAmB,EAAI,EAC/E,KAAK,UAAY,IAAIK,EAAgB,KAAK,KAAML,EAAmB,EAAI,EACvE,KAAK,MAAQ,IAAIM,EAAY,KAAK,KAAMN,EAAmB,EAAI,EAC/D,KAAK,OAAS,IAAIO,EAAa,KAAK,KAAMP,EAAmB,EAAI,EACjE,KAAK,OAAS,IAAIQ,EAAa,KAAK,KAAMR,EAAmB,EAAI,EAEjE,KAAK,YAAc,GAGnB,KAAK,yBAAyB,EAC9B,MACF,CAGA,IAAMS,EAAa,MAAM,KAAK,aAAa,EAC3C,KAAK,eAAiBA,EAAW,eAEjC,IAAMb,EAASa,EAAW,QAAU,CAAC,EAC/BC,EAAe,KAAK,gBAAgB,EAC1C,KAAK,QACHA,GAAgBd,EAAO,KAAMe,GAAsBA,EAAE,KAAOD,CAAY,EACpEA,EACAd,EAAO,CAAC,GAAG,IAAM,GAEvB,IAAMgB,EAAyBH,EAAW,UAAY,CACpD,YAAa,EACb,aAAc,SACd,eAAgB,QAChB,YAAa,EACf,EAEA,KAAK,cAAgB,IAAIZ,EAAc,CACrC,cAAgBC,GAAO,CAAE,KAAK,QAAUA,CAAG,EAC3C,iBAAmBe,GAAM,KAAK,aAAaA,CAAC,EAC5C,OAAQ,IAAM,KAAK,aAAa,CAClC,CAAC,EACD,KAAK,cAAc,MAAMjB,EAAQ,KAAK,QAASgB,EAAUH,EAAW,gBAAkB,EAAK,EAE3F,IAAMV,EAAY,IAAM,KAAK,OACvBC,EAAoB,IAAM,KAAK,eAC/BC,EAAa,IAAM,KAAK,QAC9B,KAAK,KAAO,IAAIC,EAAW,KAAK,KAAMH,EAAWC,EAAmBC,CAAU,EAC9E,KAAK,WAAa,IAAIE,EAAiB,KAAK,KAAMH,CAAiB,EACnE,KAAK,cAAgB,IAAII,EAAoB,KAAK,KAAMJ,CAAiB,EACzE,KAAK,UAAY,IAAIK,EAAgB,KAAK,KAAML,CAAiB,EACjE,KAAK,MAAQ,IAAIM,EAAY,KAAK,KAAMN,CAAiB,EACzD,KAAK,OAAS,IAAIO,EAAa,KAAK,KAAMP,CAAiB,EAC3D,KAAK,OAAS,IAAIQ,EAAa,KAAK,KAAMR,CAAiB,EAE3D,KAAK,YAAc,EACrB,CAGQ,0BAAiC,CACvC,OAAO,iBAAiB,UAAYV,GAAwB,CACtD,CAACA,EAAM,MAAQA,EAAM,KAAK,OAAS,oBAEnCA,EAAM,KAAK,SAAW,cACxB,KAAK,QAAUA,EAAM,KAAK,SAAW,IAGnCA,EAAM,KAAK,SAAW,kBACxB,KAAK,cAAgBA,EAAM,KAAK,cAE5B,KAAK,MACP,KAAK,KAAK,oBAAoB,KAAK,aAAoD,GAG7F,CAAC,CACH,CAGA,MAAc,aAAasB,EAAgD,CACzE,MAAM,KAAK,KAAK,MAAM,YAAa,CACjC,gBAAiB,KAAK,eACtB,GAAGA,CACL,CAAC,CACH,CAGA,MAAM,cAA8B,CAClC,MAAM,KAAK,KAAK,KAAK,QAAS,CAAE,gBAAiB,KAAK,cAAe,CAAC,CACxE,CAEA,MAAc,cAKX,CACD,IAAME,EAAM,MAAM,MAAM,GAAG,KAAK,OAAO,QAAS,CAC9C,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,cAAe,UAAU,KAAK,WAAW,EAC3C,EACA,KAAM,KAAK,UAAU,CAAE,QAAS,KAAK,MAAO,CAAC,CAC/C,CAAC,EAED,GAAI,CAACA,EAAI,GACP,MAAIA,EAAI,SAAW,IAAW,IAAIzB,EAAa,eAAgB,wBAAwB,EACnFyB,EAAI,SAAW,IAAW,IAAIzB,EAAa,iBAAkB,iCAAiC,EAC5F,IAAIA,EAAa,iBAAkB,qBAAqByB,EAAI,MAAM,EAAE,EAG5E,IAAMC,EAAO,MAAMD,EAAI,KAAK,EAC5B,OAAOC,EAAK,MAAQA,CACtB,CAEQ,iBAA0B,CAChC,GAAI,CACF,OAAO,aAAa,QAAQ,kBAAkB,GAAK,EACrD,MAAQ,CACN,MAAO,EACT,CACF,CACF","names":["index_exports","__export","StorviaError","StorviaSDK","__toCommonJS","StorviaError","code","message","HttpClient","baseUrl","token","debug","enabled","method","path","body","response","error","tag","style","params","url","k","v","res","data","e","onChunk","onDone","err","StorviaError","reader","decoder","messageId","accumulated","done","value","lines","line","parsed","codeMap","code","json","LANGUAGES","LENGTH_OPTIONS","STYLES","ICON_GEAR","ICON_SYNC","ICON_SYNC_SPIN","ICON_CHECK","ICON_ERROR","SettingsSheet","callbacks","models","defaultModelId","settings","hasWorldUpdate","saved","style","container","fabWrap","fab","fabDot","panel","header","title","closeBtn","body","saveRow","saveBtn","e","section","label","list","model","btn","labelText","valueText","desc","wrap","slider","v","labels","segment","opt","b","i","select","lang","option","arrow","counter","textarea","DISPLAY_OPTIONS","hint","syncBtn","d","state","s","icons","ChatModule","http","getGameId","getConversationId","getModelId","isPreview","previewConfig","config","options","body","content","chunk","CharacterStateModule","http","getConversationId","isPreview","characterName","values","CharactersModule","c","name","character","data","RelationshipsModule","http","getConversationId","isPreview","from","to","r","relationship","data","InventoryModule","http","getConversationId","isPreview","group","i","params","item","name","data","WorldModule","http","getConversationId","isPreview","data","PlayerStateModule","http","getConversationId","isPreview","group","params","values","PlayerModule","CustomModule","http","getConversationId","isPreview","key","data","value","groupKey","fieldKey","group","API_PATH","getEnv","waitForEnv","timeoutMs","existing","resolve","reject","timer","handler","StorviaError","event","env","w","StorviaSDK","apiBase","HttpClient","models","SettingsSheet","id","getGameId","getConversationId","getModelId","ChatModule","CharactersModule","RelationshipsModule","InventoryModule","WorldModule","PlayerModule","CustomModule","authResult","savedModelId","m","settings","s","res","json"]}
|
package/dist/index.esm.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/settings-sheet.ts","../src/modules/chat.ts","../src/modules/characters.ts","../src/modules/relationships.ts","../src/modules/inventory.ts","../src/modules/world.ts","../src/modules/player.ts","../src/modules/custom.ts","../src/StorviaSDK.ts"],"sourcesContent":["import type { StorviaErrorCode } from './types'\n\nexport class StorviaError extends Error {\n code: StorviaErrorCode\n\n constructor(code: StorviaErrorCode, message: string) {\n super(message)\n this.name = 'StorviaError'\n this.code = code\n }\n}\n","import { StorviaError } from './errors'\nimport type { StorviaErrorCode } from './types'\n\nexport class HttpClient {\n private baseUrl: string\n private token: string\n private debug: boolean\n\n constructor(baseUrl: string, token: string, debug = false) {\n this.baseUrl = baseUrl\n this.token = token\n this.debug = debug\n }\n\n setToken(token: string) {\n this.token = token\n }\n\n setDebug(enabled: boolean) {\n this.debug = enabled\n }\n\n private buildHeaders(): Record<string, string> {\n return {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.token}`,\n }\n }\n\n private log(method: string, path: string, body?: unknown, response?: unknown, error?: unknown) {\n if (!this.debug) return\n const tag = '%c[Storvia SDK]'\n const style = 'color: #6366f1; font-weight: bold'\n if (error) {\n console.groupCollapsed(`${tag} %c${method} ${path} %c✗`, style, 'color: #e0e0e0', 'color: #ef4444')\n if (body) console.log('Request:', body)\n console.error('Error:', error)\n console.groupEnd()\n } else {\n console.groupCollapsed(`${tag} %c${method} ${path} %c✓`, style, 'color: #e0e0e0', 'color: #22c55e')\n if (body) console.log('Request:', body)\n if (response !== undefined) console.log('Response:', response)\n console.groupEnd()\n }\n }\n\n async get<T>(path: string, params?: Record<string, string>): Promise<T> {\n const url = new URL(`${this.baseUrl}${path}`)\n if (params) {\n Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v))\n }\n\n try {\n const res = await fetch(url.toString(), {\n method: 'GET',\n headers: this.buildHeaders(),\n })\n const data = await this.handleResponse<T>(res)\n this.log('GET', path, params, data)\n return data\n } catch (e) {\n this.log('GET', path, params, undefined, e)\n throw e\n }\n }\n\n async post<T>(path: string, body?: unknown): Promise<T> {\n try {\n const res = await fetch(`${this.baseUrl}${path}`, {\n method: 'POST',\n headers: this.buildHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n })\n const data = await this.handleResponse<T>(res)\n this.log('POST', path, body, data)\n return data\n } catch (e) {\n this.log('POST', path, body, undefined, e)\n throw e\n }\n }\n\n async patch<T>(path: string, body?: unknown): Promise<T> {\n try {\n const res = await fetch(`${this.baseUrl}${path}`, {\n method: 'PATCH',\n headers: this.buildHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n })\n const data = await this.handleResponse<T>(res)\n this.log('PATCH', path, body, data)\n return data\n } catch (e) {\n this.log('PATCH', path, body, undefined, e)\n throw e\n }\n }\n\n async delete<T>(path: string): Promise<T> {\n try {\n const res = await fetch(`${this.baseUrl}${path}`, {\n method: 'DELETE',\n headers: this.buildHeaders(),\n })\n const data = await this.handleResponse<T>(res)\n this.log('DELETE', path, undefined, data)\n return data\n } catch (e) {\n this.log('DELETE', path, undefined, undefined, e)\n throw e\n }\n }\n\n async stream(\n path: string,\n body: unknown,\n onChunk: (text: string) => void,\n onDone: (id: string) => void\n ): Promise<void> {\n this.log('STREAM', path, body)\n\n const res = await fetch(`${this.baseUrl}${path}`, {\n method: 'POST',\n headers: this.buildHeaders(),\n body: JSON.stringify(body),\n })\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({}))\n const error = new StorviaError(\n (err.code as StorviaErrorCode) || 'INTERNAL_ERROR',\n err.message || `HTTP ${res.status}`\n )\n this.log('STREAM', path, body, undefined, error)\n throw error\n }\n\n const reader = res.body?.getReader()\n if (!reader) {\n throw new StorviaError('INTERNAL_ERROR', 'No response body for stream')\n }\n\n const decoder = new TextDecoder()\n let messageId = ''\n let accumulated = ''\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n const chunk = decoder.decode(value, { stream: true })\n const lines = chunk.split('\\n')\n\n for (const line of lines) {\n if (!line.startsWith('data: ')) continue\n const data = line.slice(6)\n\n if (data === '[DONE]') {\n if (this.debug) {\n this.log('STREAM', path + ' [done]', undefined, { id: messageId, contentLength: accumulated.length })\n }\n onDone(messageId)\n return\n }\n\n try {\n const parsed = JSON.parse(data)\n if (parsed.type === 'done' && parsed.id) {\n messageId = parsed.id\n } else if (parsed.content) {\n accumulated += parsed.content\n onChunk(parsed.content)\n }\n } catch {\n // non-JSON data line, ignore\n }\n }\n }\n\n if (messageId) onDone(messageId)\n }\n\n private async handleResponse<T>(res: Response): Promise<T> {\n if (!res.ok) {\n let err: { code?: string; message?: string } = {}\n try {\n err = await res.json()\n } catch {\n // ignore\n }\n\n const codeMap: Record<number, StorviaErrorCode> = {\n 401: 'UNAUTHORIZED',\n 402: 'INSUFFICIENT_BALANCE',\n 404: 'GAME_NOT_FOUND',\n 429: 'RATE_LIMITED',\n }\n\n const code =\n (err.code as StorviaErrorCode) || codeMap[res.status] || 'INTERNAL_ERROR'\n throw new StorviaError(code, err.message || `HTTP ${res.status}`)\n }\n\n const json = await res.json()\n // 解包 { success, data } 格式\n if (json && typeof json === 'object' && 'data' in json) {\n return json.data as T\n }\n return json as T\n }\n}\n","interface ModelOption {\n id: string\n name: string\n provider: string\n}\n\nexport interface GameSettings {\n temperature: number\n reply_length: string\n reply_language: string\n player_note: string\n}\n\ntype SyncState = 'idle' | 'loading' | 'success' | 'error'\n\ninterface SettingsCallbacks {\n onModelChange: (id: string) => void\n onSettingsChange: (settings: Partial<GameSettings>) => Promise<void>\n onSync: () => Promise<void>\n}\n\nconst LANGUAGES = [\n { value: 'zh-CN', label: '简体中文' },\n { value: 'zh-TW', label: '繁體中文' },\n { value: 'en', label: 'English' },\n { value: 'ja', label: '日本語' },\n { value: 'ko', label: '한국어' },\n]\n\nconst LENGTH_OPTIONS = [\n { value: 'low', label: '简短' },\n { value: 'medium', label: '适中' },\n { value: 'high', label: '详细' },\n]\n\nconst STYLES = `\n :host {\n position: fixed;\n bottom: 20px;\n right: 20px;\n z-index: 2147483647;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n\n .fab {\n width: 48px;\n height: 48px;\n border-radius: 50%;\n background: #6366f1;\n color: #fff;\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\n transition: transform 0.2s, box-shadow 0.2s;\n }\n\n .fab:hover {\n transform: scale(1.08);\n box-shadow: 0 6px 16px rgba(0,0,0,0.4);\n }\n\n .fab svg {\n width: 22px;\n height: 22px;\n }\n\n .panel {\n position: absolute;\n bottom: 60px;\n right: 0;\n width: 320px;\n max-height: 80vh;\n overflow-y: auto;\n background: #1e1e1e;\n border: 1px solid #333;\n border-radius: 16px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n display: none;\n }\n\n .panel.open {\n display: block;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 16px 8px;\n }\n\n .panel-title {\n font-size: 16px;\n font-weight: 600;\n color: #fff;\n }\n\n .close-btn {\n width: 28px;\n height: 28px;\n border-radius: 50%;\n border: none;\n background: transparent;\n color: #888;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n transition: background 0.15s;\n }\n\n .close-btn:hover {\n background: #2a2a2a;\n color: #fff;\n }\n\n .panel-body {\n padding: 4px 16px 16px;\n }\n\n .section {\n margin-bottom: 16px;\n }\n\n .section:last-child {\n margin-bottom: 0;\n }\n\n .section-label {\n font-size: 13px;\n font-weight: 500;\n color: #c0c0c0;\n margin-bottom: 6px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .section-label .value {\n color: #6366f1;\n font-weight: 600;\n }\n\n .section-desc {\n font-size: 11px;\n color: #666;\n margin-bottom: 8px;\n line-height: 1.4;\n }\n\n .divider {\n height: 1px;\n background: #2a2a2a;\n margin: 12px 0;\n }\n\n /* Model options */\n .model-list {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n\n .model-option {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px;\n border-radius: 8px;\n cursor: pointer;\n border: none;\n background: transparent;\n color: #e0e0e0;\n width: 100%;\n font-size: 13px;\n text-align: left;\n transition: background 0.15s;\n }\n\n .model-option:hover {\n background: #2a2a2a;\n }\n\n .model-option.active {\n background: #6366f1;\n color: #fff;\n }\n\n .model-option .dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #555;\n flex-shrink: 0;\n }\n\n .model-option.active .dot {\n background: #fff;\n }\n\n /* Slider */\n .slider-wrap {\n position: relative;\n padding: 0 2px;\n }\n\n .slider {\n -webkit-appearance: none;\n appearance: none;\n width: 100%;\n height: 4px;\n border-radius: 2px;\n background: #333;\n outline: none;\n }\n\n .slider::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: #6366f1;\n cursor: pointer;\n border: 2px solid #1e1e1e;\n box-shadow: 0 2px 4px rgba(0,0,0,0.3);\n }\n\n .slider::-moz-range-thumb {\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: #6366f1;\n cursor: pointer;\n border: 2px solid #1e1e1e;\n box-shadow: 0 2px 4px rgba(0,0,0,0.3);\n }\n\n .slider-labels {\n display: flex;\n justify-content: space-between;\n font-size: 11px;\n color: #666;\n margin-top: 4px;\n }\n\n /* Segment control (reply length) */\n .segment {\n display: flex;\n background: #2a2a2a;\n border-radius: 10px;\n padding: 3px;\n gap: 2px;\n }\n\n .segment-btn {\n flex: 1;\n padding: 8px 0;\n border: none;\n border-radius: 8px;\n background: transparent;\n color: #999;\n font-size: 13px;\n cursor: pointer;\n transition: all 0.2s;\n }\n\n .segment-btn.active {\n background: #6366f1;\n color: #fff;\n font-weight: 500;\n }\n\n .segment-btn:not(.active):hover {\n color: #ddd;\n }\n\n /* Select */\n .select-wrap {\n position: relative;\n }\n\n .select {\n width: 100%;\n padding: 10px 32px 10px 12px;\n border-radius: 10px;\n border: 1px solid #333;\n background: #2a2a2a;\n color: #e0e0e0;\n font-size: 13px;\n appearance: none;\n -webkit-appearance: none;\n cursor: pointer;\n outline: none;\n transition: border-color 0.15s;\n }\n\n .select:focus {\n border-color: #6366f1;\n }\n\n .select-arrow {\n position: absolute;\n right: 12px;\n top: 50%;\n transform: translateY(-50%);\n pointer-events: none;\n color: #666;\n font-size: 12px;\n }\n\n /* Textarea (note) */\n .note-wrap {\n position: relative;\n }\n\n .note-input {\n width: 100%;\n padding: 10px 12px;\n border-radius: 10px;\n border: 1px solid #333;\n background: #2a2a2a;\n color: #e0e0e0;\n font-size: 13px;\n font-family: inherit;\n resize: none;\n height: 64px;\n outline: none;\n transition: border-color 0.15s;\n box-sizing: border-box;\n }\n\n .note-input::placeholder {\n color: #555;\n }\n\n .note-input:focus {\n border-color: #6366f1;\n }\n\n .note-counter {\n text-align: right;\n font-size: 11px;\n color: #555;\n margin-top: 4px;\n }\n\n /* Sync section */\n .sync-desc {\n font-size: 11px;\n color: #666;\n margin-bottom: 8px;\n line-height: 1.4;\n }\n\n .sync-btn {\n width: 100%;\n padding: 10px 0;\n border-radius: 10px;\n border: 1px solid #333;\n background: #2a2a2a;\n color: #e0e0e0;\n font-size: 13px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n transition: background 0.15s;\n }\n\n .sync-btn:hover:not(:disabled) {\n background: #333;\n }\n\n .sync-btn:disabled {\n cursor: default;\n opacity: 0.6;\n }\n\n .sync-btn svg {\n width: 16px;\n height: 16px;\n }\n\n .sync-btn.success { color: #4ade80; border-color: #4ade80; }\n .sync-btn.error { color: #f87171; border-color: #f87171; }\n\n /* Save button */\n .save-row {\n display: flex;\n justify-content: flex-end;\n margin-top: 16px;\n }\n\n .save-btn {\n padding: 8px 24px;\n border-radius: 10px;\n border: none;\n background: #6366f1;\n color: #fff;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .save-btn:hover:not(:disabled) {\n background: #5558e6;\n }\n\n .save-btn:disabled {\n opacity: 0.6;\n cursor: default;\n }\n\n .save-btn.saved {\n background: #4ade80;\n }\n\n /* FAB red dot */\n .fab-dot {\n position: absolute;\n top: 2px;\n right: 2px;\n width: 10px;\n height: 10px;\n border-radius: 50%;\n background: #f87171;\n border: 2px solid #1e1e1e;\n display: none;\n }\n\n .fab-dot.visible {\n display: block;\n }\n\n .fab-wrap {\n position: relative;\n display: inline-block;\n }\n\n /* Sync update hint */\n .sync-hint {\n font-size: 11px;\n color: #f59e0b;\n margin-bottom: 6px;\n line-height: 1.4;\n display: none;\n }\n\n .sync-hint.visible {\n display: block;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n .spin { animation: spin 0.8s linear infinite; }\n`\n\nconst ICON_GEAR = `<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=\"3\"/><path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z\"/></svg>`\nconst ICON_SYNC = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"23 4 23 10 17 10\"/><polyline points=\"1 20 1 14 7 14\"/><path d=\"M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15\"/></svg>`\nconst ICON_SYNC_SPIN = `<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>`\nconst ICON_CHECK = `<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>`\nconst ICON_ERROR = `<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>`\n\nexport class SettingsSheet {\n private shadowRoot: ShadowRoot\n private host: HTMLElement\n private callbacks: SettingsCallbacks\n\n // Model state\n private selectedModelId = ''\n private models: ModelOption[] = []\n private modelPanel: HTMLElement | null = null\n\n // Settings state (local copy, saved on \"保存\")\n private settings: GameSettings = {\n temperature: 1.0,\n reply_length: 'medium',\n reply_language: 'zh-CN',\n player_note: '',\n }\n\n // World update state\n private hasWorldUpdate = false\n private fabDot: HTMLElement | null = null\n private syncHint: HTMLElement | null = null\n\n // Display mode state\n private displayMode: 'phone' | 'desktop' = 'phone'\n private displayModeBtns: HTMLButtonElement[] = []\n\n // UI refs\n private tempValueEl: HTMLElement | null = null\n private tempSlider: HTMLInputElement | null = null\n private segmentBtns: HTMLButtonElement[] = []\n private langSelect: HTMLSelectElement | null = null\n private noteInput: HTMLTextAreaElement | null = null\n private noteCounter: HTMLElement | null = null\n private saveBtn: HTMLButtonElement | null = null\n private syncBtn: HTMLButtonElement | null = null\n private syncState: SyncState = 'idle'\n private panel: HTMLElement | null = null\n\n constructor(callbacks: SettingsCallbacks) {\n this.callbacks = callbacks\n this.host = document.createElement('div')\n this.host.id = 'storvia-settings'\n this.shadowRoot = this.host.attachShadow({ mode: 'closed' })\n }\n\n mount(models: ModelOption[], defaultModelId: string, settings: GameSettings, hasWorldUpdate = false) {\n this.models = models\n this.selectedModelId = defaultModelId\n this.settings = { ...settings }\n this.hasWorldUpdate = hasWorldUpdate\n try {\n const saved = localStorage.getItem('storvia_display_mode')\n if (saved === 'phone' || saved === 'desktop') this.displayMode = saved\n } catch { /* ignore */ }\n document.body.appendChild(this.host)\n this.render()\n }\n\n unmount() {\n this.host.remove()\n }\n\n getSelectedModelId(): string {\n return this.selectedModelId\n }\n\n getSettings(): GameSettings {\n return { ...this.settings }\n }\n\n private render() {\n const style = document.createElement('style')\n style.textContent = STYLES\n\n const container = document.createElement('div')\n\n // FAB with red dot\n const fabWrap = document.createElement('div')\n fabWrap.className = 'fab-wrap'\n const fab = document.createElement('button')\n fab.className = 'fab'\n fab.innerHTML = ICON_GEAR\n fab.title = '游戏设置'\n const fabDot = document.createElement('div')\n fabDot.className = `fab-dot${this.hasWorldUpdate ? ' visible' : ''}`\n this.fabDot = fabDot\n fabWrap.appendChild(fab)\n fabWrap.appendChild(fabDot)\n\n // Panel\n const panel = document.createElement('div')\n panel.className = 'panel'\n this.panel = panel\n\n // Header\n const header = document.createElement('div')\n header.className = 'panel-header'\n const title = document.createElement('div')\n title.className = 'panel-title'\n title.textContent = '游戏设置'\n const closeBtn = document.createElement('button')\n closeBtn.className = 'close-btn'\n closeBtn.innerHTML = '✕'\n closeBtn.addEventListener('click', () => panel.classList.remove('open'))\n header.appendChild(title)\n header.appendChild(closeBtn)\n panel.appendChild(header)\n\n // Body\n const body = document.createElement('div')\n body.className = 'panel-body'\n\n // ── AI Model ──\n if (this.models.length > 0) {\n body.appendChild(this.buildModelSection())\n body.appendChild(this.makeDivider())\n }\n\n // ── Temperature ──\n body.appendChild(this.buildTemperatureSection())\n body.appendChild(this.makeDivider())\n\n // ── Reply Length ──\n body.appendChild(this.buildReplyLengthSection())\n body.appendChild(this.makeDivider())\n\n // ── Reply Language ──\n body.appendChild(this.buildReplyLanguageSection())\n body.appendChild(this.makeDivider())\n\n // ── Note ──\n body.appendChild(this.buildNoteSection())\n body.appendChild(this.makeDivider())\n\n // ── Display Mode ──\n body.appendChild(this.buildDisplayModeSection())\n body.appendChild(this.makeDivider())\n\n // ── Sync ──\n body.appendChild(this.buildSyncSection())\n\n // ── Save Button ──\n const saveRow = document.createElement('div')\n saveRow.className = 'save-row'\n const saveBtn = document.createElement('button')\n saveBtn.className = 'save-btn'\n saveBtn.textContent = '保存'\n this.saveBtn = saveBtn\n saveBtn.addEventListener('click', () => this.handleSave())\n saveRow.appendChild(saveBtn)\n body.appendChild(saveRow)\n\n panel.appendChild(body)\n\n // Toggle\n fab.addEventListener('click', () => panel.classList.toggle('open'))\n document.addEventListener('click', (e) => {\n if (!this.host.contains(e.target as Node)) panel.classList.remove('open')\n })\n\n container.appendChild(panel)\n container.appendChild(fabWrap)\n this.shadowRoot.appendChild(style)\n this.shadowRoot.appendChild(container)\n }\n\n // ── Build sections ──\n\n private buildModelSection(): HTMLElement {\n const section = document.createElement('div')\n section.className = 'section'\n\n const label = document.createElement('div')\n label.className = 'section-label'\n label.textContent = 'AI 模型'\n section.appendChild(label)\n\n const list = document.createElement('div')\n list.className = 'model-list'\n this.modelPanel = list\n\n this.models.forEach((model) => {\n const btn = document.createElement('button')\n btn.className = `model-option${model.id === this.selectedModelId ? ' active' : ''}`\n btn.innerHTML = `<span class=\"dot\"></span><span>${model.name}</span>`\n btn.addEventListener('click', () => {\n this.selectedModelId = model.id\n this.callbacks.onModelChange(model.id)\n try { localStorage.setItem('storvia_model_id', model.id) } catch { /* ignore */ }\n this.updateModelActive()\n })\n list.appendChild(btn)\n })\n\n section.appendChild(list)\n return section\n }\n\n private buildTemperatureSection(): HTMLElement {\n const section = document.createElement('div')\n section.className = 'section'\n\n const label = document.createElement('div')\n label.className = 'section-label'\n const labelText = document.createElement('span')\n labelText.textContent = '温度'\n const valueText = document.createElement('span')\n valueText.className = 'value'\n valueText.textContent = this.settings.temperature.toFixed(1)\n this.tempValueEl = valueText\n label.appendChild(labelText)\n label.appendChild(valueText)\n section.appendChild(label)\n\n const desc = document.createElement('div')\n desc.className = 'section-desc'\n desc.textContent = '更低的温度会让 AI 回复更稳定、理智;更高的温度会让 AI 的回复更具多样性和随机性'\n section.appendChild(desc)\n\n const wrap = document.createElement('div')\n wrap.className = 'slider-wrap'\n const slider = document.createElement('input')\n slider.type = 'range'\n slider.className = 'slider'\n slider.min = '0'\n slider.max = '2'\n slider.step = '0.1'\n slider.value = String(this.settings.temperature)\n this.tempSlider = slider\n slider.addEventListener('input', () => {\n const v = parseFloat(slider.value)\n this.settings.temperature = v\n if (this.tempValueEl) this.tempValueEl.textContent = v.toFixed(1)\n })\n wrap.appendChild(slider)\n\n const labels = document.createElement('div')\n labels.className = 'slider-labels'\n labels.innerHTML = '<span>精确</span><span>创意</span>'\n wrap.appendChild(labels)\n\n section.appendChild(wrap)\n return section\n }\n\n private buildReplyLengthSection(): HTMLElement {\n const section = document.createElement('div')\n section.className = 'section'\n\n const label = document.createElement('div')\n label.className = 'section-label'\n label.textContent = '回复长度'\n section.appendChild(label)\n\n const segment = document.createElement('div')\n segment.className = 'segment'\n this.segmentBtns = []\n\n LENGTH_OPTIONS.forEach((opt) => {\n const btn = document.createElement('button')\n btn.className = `segment-btn${opt.value === this.settings.reply_length ? ' active' : ''}`\n btn.textContent = opt.label\n btn.addEventListener('click', () => {\n this.settings.reply_length = opt.value\n this.segmentBtns.forEach((b, i) => {\n b.classList.toggle('active', LENGTH_OPTIONS[i].value === opt.value)\n })\n })\n this.segmentBtns.push(btn)\n segment.appendChild(btn)\n })\n\n section.appendChild(segment)\n return section\n }\n\n private buildReplyLanguageSection(): HTMLElement {\n const section = document.createElement('div')\n section.className = 'section'\n\n const label = document.createElement('div')\n label.className = 'section-label'\n label.textContent = '回复语言'\n section.appendChild(label)\n\n const wrap = document.createElement('div')\n wrap.className = 'select-wrap'\n const select = document.createElement('select')\n select.className = 'select'\n this.langSelect = select\n\n LANGUAGES.forEach((lang) => {\n const option = document.createElement('option')\n option.value = lang.value\n option.textContent = lang.label\n if (lang.value === this.settings.reply_language) option.selected = true\n select.appendChild(option)\n })\n\n select.addEventListener('change', () => {\n this.settings.reply_language = select.value\n })\n\n const arrow = document.createElement('span')\n arrow.className = 'select-arrow'\n arrow.textContent = '▾'\n wrap.appendChild(select)\n wrap.appendChild(arrow)\n\n section.appendChild(wrap)\n return section\n }\n\n private buildNoteSection(): HTMLElement {\n const section = document.createElement('div')\n section.className = 'section'\n\n const label = document.createElement('div')\n label.className = 'section-label'\n const labelText = document.createElement('span')\n labelText.textContent = '备注'\n const counter = document.createElement('span')\n counter.textContent = `${this.settings.player_note.length}/50`\n this.noteCounter = counter\n label.appendChild(labelText)\n label.appendChild(counter)\n section.appendChild(label)\n\n const desc = document.createElement('div')\n desc.className = 'section-desc'\n desc.textContent = '写下你对这个游戏的备注,会显示在存档列表'\n section.appendChild(desc)\n\n const wrap = document.createElement('div')\n wrap.className = 'note-wrap'\n const textarea = document.createElement('textarea')\n textarea.className = 'note-input'\n textarea.placeholder = '备注'\n textarea.maxLength = 50\n textarea.value = this.settings.player_note\n this.noteInput = textarea\n\n textarea.addEventListener('input', () => {\n this.settings.player_note = textarea.value\n if (this.noteCounter) {\n this.noteCounter.textContent = `${textarea.value.length}/50`\n }\n })\n\n wrap.appendChild(textarea)\n section.appendChild(wrap)\n return section\n }\n\n private buildDisplayModeSection(): HTMLElement {\n const section = document.createElement('div')\n section.className = 'section'\n\n const label = document.createElement('div')\n label.className = 'section-label'\n label.textContent = '显示模式'\n section.appendChild(label)\n\n const desc = document.createElement('div')\n desc.className = 'section-desc'\n desc.textContent = '电脑模式会自动横屏显示'\n section.appendChild(desc)\n\n const segment = document.createElement('div')\n segment.className = 'segment'\n this.displayModeBtns = []\n\n const DISPLAY_OPTIONS = [\n { value: 'phone' as const, label: '手机' },\n { value: 'desktop' as const, label: '电脑' },\n ]\n\n DISPLAY_OPTIONS.forEach((opt) => {\n const btn = document.createElement('button')\n btn.className = `segment-btn${opt.value === this.displayMode ? ' active' : ''}`\n btn.textContent = opt.label\n btn.addEventListener('click', () => {\n this.displayMode = opt.value\n try { localStorage.setItem('storvia_display_mode', opt.value) } catch { /* ignore */ }\n this.displayModeBtns.forEach((b, i) => {\n b.classList.toggle('active', DISPLAY_OPTIONS[i].value === opt.value)\n })\n // 通知父页面旋转\n try {\n window.parent.postMessage({\n type: 'storvia-orientation',\n mode: opt.value === 'desktop' ? 'landscape' : 'portrait',\n }, '*')\n } catch { /* ignore */ }\n })\n this.displayModeBtns.push(btn)\n segment.appendChild(btn)\n })\n\n section.appendChild(segment)\n return section\n }\n\n private buildSyncSection(): HTMLElement {\n const section = document.createElement('div')\n section.className = 'section'\n\n const label = document.createElement('div')\n label.className = 'section-label'\n label.textContent = '同步游戏设定'\n section.appendChild(label)\n\n // Update hint (only visible when hasWorldUpdate)\n const hint = document.createElement('div')\n hint.className = `sync-hint${this.hasWorldUpdate ? ' visible' : ''}`\n hint.textContent = '⚠ 作者已更新游戏内容,建议点击同步'\n this.syncHint = hint\n section.appendChild(hint)\n\n const desc = document.createElement('div')\n desc.className = 'sync-desc'\n desc.textContent = '如果游戏作者更新了内容,点击此按钮可将最新的游戏设定和开幕小剧场同步到当前对话'\n section.appendChild(desc)\n\n const syncBtn = document.createElement('button')\n syncBtn.className = 'sync-btn'\n this.syncBtn = syncBtn\n this.renderSyncBtn()\n\n syncBtn.addEventListener('click', async () => {\n if (this.syncState === 'loading') return\n this.setSyncState('loading')\n try {\n await this.callbacks.onSync()\n this.setSyncState('success')\n // Clear update indicators\n this.hasWorldUpdate = false\n if (this.fabDot) this.fabDot.classList.remove('visible')\n if (this.syncHint) this.syncHint.classList.remove('visible')\n setTimeout(() => this.setSyncState('idle'), 3000)\n } catch {\n this.setSyncState('error')\n setTimeout(() => this.setSyncState('idle'), 4000)\n }\n })\n\n section.appendChild(syncBtn)\n return section\n }\n\n // ── Helpers ──\n\n private makeDivider(): HTMLElement {\n const d = document.createElement('div')\n d.className = 'divider'\n return d\n }\n\n private updateModelActive() {\n if (!this.modelPanel) return\n this.modelPanel.querySelectorAll('.model-option').forEach((btn, i) => {\n btn.classList.toggle('active', this.models[i].id === this.selectedModelId)\n })\n }\n\n private setSyncState(state: SyncState) {\n this.syncState = state\n this.renderSyncBtn()\n }\n\n private renderSyncBtn() {\n if (!this.syncBtn) return\n const s = this.syncState\n const icons: Record<SyncState, string> = {\n idle: ICON_SYNC,\n loading: ICON_SYNC_SPIN,\n success: ICON_CHECK,\n error: ICON_ERROR,\n }\n const labels: Record<SyncState, string> = {\n idle: '同步最新设定',\n loading: '同步中...',\n success: '已同步',\n error: '同步失败',\n }\n this.syncBtn.className = `sync-btn${s === 'success' || s === 'error' ? ` ${s}` : ''}`\n this.syncBtn.disabled = s === 'loading'\n this.syncBtn.innerHTML = `${icons[s]}<span>${labels[s]}</span>`\n }\n\n private async handleSave() {\n if (!this.saveBtn || this.saveBtn.disabled) return\n this.saveBtn.disabled = true\n this.saveBtn.textContent = '保存中...'\n try {\n await this.callbacks.onSettingsChange({\n temperature: this.settings.temperature,\n reply_length: this.settings.reply_length,\n reply_language: this.settings.reply_language,\n player_note: this.settings.player_note,\n })\n this.saveBtn.textContent = '已保存'\n this.saveBtn.classList.add('saved')\n setTimeout(() => {\n if (this.saveBtn) {\n this.saveBtn.textContent = '保存'\n this.saveBtn.classList.remove('saved')\n this.saveBtn.disabled = false\n }\n }, 2000)\n } catch {\n this.saveBtn.textContent = '保存失败'\n setTimeout(() => {\n if (this.saveBtn) {\n this.saveBtn.textContent = '保存'\n this.saveBtn.disabled = false\n }\n }, 2000)\n }\n }\n}\n","import type { HttpClient } from '../http'\nimport type { ChatSendOptions, ChatSaveOptions, ChatGenerateOptions, ChatResponse } from '../types'\n\nexport class ChatModule {\n private previewConfig?: Record<string, unknown>\n\n constructor(\n private http: HttpClient,\n private getGameId: () => string,\n private getConversationId: () => string,\n private getModelId: () => string,\n private isPreview: boolean = false,\n previewConfig?: Record<string, unknown>,\n ) {\n this.previewConfig = previewConfig\n }\n\n /** 更新预览配置(由父页面 postMessage 触发) */\n updatePreviewConfig(config?: Record<string, unknown>): void {\n this.previewConfig = config\n }\n\n /**\n * 发送消息并获取 AI 回复(user 消息 + AI 回复一体化)\n * 适用于 1v1 对话场景\n */\n async send(options: ChatSendOptions): Promise<ChatResponse | void> {\n if (this.isPreview) {\n return this.sendPreview(options)\n }\n\n const body = {\n game_id: this.getGameId(),\n conversation_id: this.getConversationId(),\n model_id: this.getModelId(),\n message: options.message,\n topic: options.topic,\n context: options.context,\n stream: options.stream ?? false,\n }\n\n if (options.stream) {\n await this.http.stream(\n '/chat',\n body,\n options.onChunk ?? (() => {}),\n options.onDone ?? (() => {})\n )\n return\n }\n\n return this.http.post<ChatResponse>('/chat', body)\n }\n\n /**\n * 单独保存一条消息(不调 AI,不扣费)\n * 适用于群聊中先保存用户消息,再分别请求各 NPC 回复\n */\n async save(options: ChatSaveOptions): Promise<{ id: string }> {\n return this.http.post<{ id: string }>('/messages/save', {\n conversation_id: this.getConversationId(),\n role: options.role,\n content: options.content,\n topic: options.topic,\n })\n }\n\n /**\n * 基于 topic 历史 + context 请求 AI 生成回复(无需当前轮用户输入)\n * 适用于群聊 NPC 回复、NPC 自动发言、弹幕生成等\n */\n async generate(options: ChatGenerateOptions): Promise<ChatResponse | void> {\n const body = {\n conversation_id: this.getConversationId(),\n model_id: this.getModelId(),\n topic: options.topic,\n context: options.context,\n stream: options.stream ?? false,\n save: options.save ?? true,\n }\n\n if (options.stream) {\n await this.http.stream(\n '/generate',\n body,\n options.onChunk ?? (() => {}),\n options.onDone ?? (() => {})\n )\n return\n }\n\n return this.http.post<ChatResponse>('/generate', body)\n }\n\n /** 预览模式:发到 /preview 端点 */\n private async sendPreview(options: ChatSendOptions): Promise<ChatResponse | void> {\n const body = {\n model_id: this.getModelId(),\n message: options.message,\n topic: options.topic,\n context: options.context,\n prompt_config: this.previewConfig || {},\n history_messages: [],\n }\n\n if (options.stream) {\n await this.http.stream(\n '/preview',\n body,\n options.onChunk ?? (() => {}),\n options.onDone ?? (() => {})\n )\n return\n }\n\n let content = ''\n await this.http.stream(\n '/preview',\n body,\n (chunk) => { content += chunk },\n () => {}\n )\n return { id: '', content }\n }\n}\n","import type { HttpClient } from '../http'\nimport type { CharacterPersona, CharacterDetail } from '../types'\n\n/** 内部存储含 description(用于 add 传给后端),但不对外暴露 */\ninterface CharacterInternal {\n name: string\n description?: string\n avatar?: string\n}\n\nclass CharacterStateModule {\n private mem: Record<string, Record<string, string | number>> = {}\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {}\n\n async get(characterName: string): Promise<Record<string, string | number>> {\n if (this.isPreview) return { ...(this.mem[characterName] || {}) }\n return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(characterName)}/state`)\n }\n\n async update(characterName: string, values: Record<string, string | number>): Promise<void> {\n if (this.isPreview) {\n this.mem[characterName] = { ...(this.mem[characterName] || {}), ...values }\n return\n }\n await this.http.patch(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(characterName)}/state`, values)\n }\n}\n\nexport class CharactersModule {\n state: CharacterStateModule\n private mem: CharacterInternal[] = []\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {\n this.state = new CharacterStateModule(http, getConversationId, isPreview)\n }\n\n async list(): Promise<CharacterPersona[]> {\n if (this.isPreview) return this.mem.map(c => ({ name: c.name, avatar: c.avatar }))\n return this.http.get(`/conversations/${this.getConversationId()}/characters`)\n }\n\n async get(name: string): Promise<CharacterPersona> {\n if (this.isPreview) {\n const c = this.mem.find(c => c.name === name)\n return { name: c?.name || name, avatar: c?.avatar }\n }\n return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(name)}`)\n }\n\n async add(character: { name: string; description?: string; avatar?: string }): Promise<void> {\n if (this.isPreview) { this.mem.push(character); return }\n await this.http.post(`/conversations/${this.getConversationId()}/characters`, character)\n }\n\n async update(name: string, data: Partial<Omit<CharacterPersona, 'name'>>): Promise<void> {\n if (this.isPreview) { const c = this.mem.find(c => c.name === name); if (c) Object.assign(c, data); return }\n await this.http.patch(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(name)}`, data)\n }\n\n async remove(name: string): Promise<void> {\n if (this.isPreview) { this.mem = this.mem.filter(c => c.name !== name); return }\n await this.http.delete(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(name)}`)\n }\n\n async detail(name: string): Promise<CharacterDetail> {\n if (this.isPreview) {\n const c = this.mem.find(c => c.name === name)\n return { name, avatar: c?.avatar, state: await this.state.get(name) }\n }\n return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(name)}/detail`)\n }\n}\n","import type { HttpClient } from '../http'\nimport type { Relationship } from '../types'\n\nexport class RelationshipsModule {\n private mem: Relationship[] = []\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {}\n\n async list(): Promise<Relationship[]> {\n if (this.isPreview) return [...this.mem]\n return this.http.get(`/conversations/${this.getConversationId()}/relationships`)\n }\n\n async get(from: string, to: string): Promise<Relationship> {\n if (this.isPreview) {\n const r = this.mem.find(r => r.from === from && r.to === to)\n if (r) return { ...r }\n throw new Error('Relationship not found')\n }\n return this.http.get(`/conversations/${this.getConversationId()}/relationships/${encodeURIComponent(from)}/${encodeURIComponent(to)}`)\n }\n\n async add(relationship: Relationship): Promise<void> {\n if (this.isPreview) { this.mem.push({ ...relationship }); return }\n await this.http.post(`/conversations/${this.getConversationId()}/relationships`, relationship)\n }\n\n async update(from: string, to: string, data: Record<string, string | number>): Promise<void> {\n if (this.isPreview) {\n const r = this.mem.find(r => r.from === from && r.to === to)\n if (r) Object.assign(r, data)\n else this.mem.push({ from, to, ...data })\n return\n }\n await this.http.patch(`/conversations/${this.getConversationId()}/relationships/${encodeURIComponent(from)}/${encodeURIComponent(to)}`, data)\n }\n\n async remove(from: string, to: string): Promise<void> {\n if (this.isPreview) { this.mem = this.mem.filter(r => !(r.from === from && r.to === to)); return }\n await this.http.delete(`/conversations/${this.getConversationId()}/relationships/${encodeURIComponent(from)}/${encodeURIComponent(to)}`)\n }\n}\n","import type { HttpClient } from '../http'\nimport type { InventoryItemData } from '../types'\n\nexport class InventoryModule {\n private mem: InventoryItemData[] = []\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {}\n\n async list(group?: string): Promise<InventoryItemData[]> {\n if (this.isPreview) return group ? this.mem.filter(i => i.group === group) : [...this.mem]\n const params = group ? { group } : undefined\n return this.http.get(`/conversations/${this.getConversationId()}/inventory`, params)\n }\n\n async add(item: InventoryItemData): Promise<void> {\n if (this.isPreview) { this.mem.push({ ...item }); return }\n await this.http.post(`/conversations/${this.getConversationId()}/inventory`, item)\n }\n\n async update(name: string, data: Partial<Omit<InventoryItemData, 'name'>>): Promise<void> {\n if (this.isPreview) {\n const i = this.mem.find(i => i.name === name)\n if (i) Object.assign(i, data)\n return\n }\n await this.http.patch(`/conversations/${this.getConversationId()}/inventory/${encodeURIComponent(name)}`, data)\n }\n\n async remove(name: string): Promise<void> {\n if (this.isPreview) { this.mem = this.mem.filter(i => i.name !== name); return }\n await this.http.delete(`/conversations/${this.getConversationId()}/inventory/${encodeURIComponent(name)}`)\n }\n}\n","import type { HttpClient } from '../http'\n\nexport class WorldModule {\n private mem: Record<string, unknown> = {}\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {}\n\n async get(): Promise<Record<string, unknown>> {\n if (this.isPreview) return { ...this.mem }\n return this.http.get(`/conversations/${this.getConversationId()}/world`)\n }\n\n async update(data: Record<string, unknown>): Promise<void> {\n if (this.isPreview) { Object.assign(this.mem, data); return }\n await this.http.patch(`/conversations/${this.getConversationId()}/world`, data)\n }\n}\n","import type { HttpClient } from '../http'\nimport type { PlayerPersona } from '../types'\n\nclass PlayerStateModule {\n private mem: Record<string, Record<string, string | number>> = {}\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {}\n\n async get(): Promise<Record<string, Record<string, string | number>>>\n async get(group: string): Promise<Record<string, string | number>>\n async get(group?: string): Promise<Record<string, string | number> | Record<string, Record<string, string | number>>> {\n if (this.isPreview) {\n if (group) return { ...(this.mem[group] || {}) }\n return { ...this.mem }\n }\n const params = group ? { group } : undefined\n return this.http.get(`/conversations/${this.getConversationId()}/player/state`, params)\n }\n\n async update(group: string, values: Record<string, string | number>): Promise<void> {\n if (this.isPreview) {\n this.mem[group] = { ...(this.mem[group] || {}), ...values }\n return\n }\n await this.http.patch(`/conversations/${this.getConversationId()}/player/state`, { group, values })\n }\n}\n\nexport class PlayerModule {\n state: PlayerStateModule\n private memPersona: PlayerPersona = { name: '' }\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {\n this.state = new PlayerStateModule(http, getConversationId, isPreview)\n }\n\n async get(): Promise<PlayerPersona> {\n if (this.isPreview) return { ...this.memPersona }\n return this.http.get(`/conversations/${this.getConversationId()}/player`)\n }\n}\n","import type { HttpClient } from '../http'\n\nexport class CustomModule {\n private mem: Record<string, unknown> = {}\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {}\n\n async get(): Promise<Record<string, unknown>>\n async get(key: string): Promise<unknown>\n async get(key?: string): Promise<unknown> {\n if (this.isPreview) {\n if (key !== undefined) return this.mem[key]\n return { ...this.mem }\n }\n const data = await this.http.get<Record<string, unknown>>(\n `/conversations/${this.getConversationId()}/custom`\n )\n if (key !== undefined) return data[key]\n return data\n }\n\n async set(data: Record<string, unknown>): Promise<void> {\n if (this.isPreview) {\n // 深合并:分组对象合并子字段\n for (const [key, value] of Object.entries(data)) {\n if (typeof value === 'object' && value !== null && !Array.isArray(value)\n && typeof this.mem[key] === 'object' && this.mem[key] !== null) {\n this.mem[key] = { ...(this.mem[key] as Record<string, unknown>), ...value }\n } else {\n this.mem[key] = value\n }\n }\n return\n }\n await this.http.patch(`/conversations/${this.getConversationId()}/custom`, data)\n }\n\n async delete(key: string): Promise<void> {\n if (this.isPreview) { delete this.mem[key]; return }\n await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(key)}`)\n }\n\n async setGroupField(groupKey: string, fieldKey: string, value: unknown): Promise<void> {\n if (this.isPreview) {\n if (!this.mem[groupKey] || typeof this.mem[groupKey] !== 'object') {\n this.mem[groupKey] = {}\n }\n (this.mem[groupKey] as Record<string, unknown>)[fieldKey] = value\n return\n }\n await this.http.patch(\n `/conversations/${this.getConversationId()}/custom/${encodeURIComponent(groupKey)}/${encodeURIComponent(fieldKey)}`,\n { value }\n )\n }\n\n async deleteGroupField(groupKey: string, fieldKey: string): Promise<void> {\n if (this.isPreview) {\n if (typeof this.mem[groupKey] === 'object' && this.mem[groupKey] !== null) {\n const group = this.mem[groupKey] as Record<string, unknown>\n delete group[fieldKey]\n if (Object.keys(group).length === 0) delete this.mem[groupKey]\n }\n return\n }\n await this.http.delete(\n `/conversations/${this.getConversationId()}/custom/${encodeURIComponent(groupKey)}/${encodeURIComponent(fieldKey)}`\n )\n }\n}\n","import { HttpClient } from './http'\nimport { StorviaError } from './errors'\nimport { SettingsSheet } from './settings-sheet'\nimport type { GameSettings } from './settings-sheet'\nimport { ChatModule } from './modules/chat'\nimport { CharactersModule } from './modules/characters'\nimport { RelationshipsModule } from './modules/relationships'\nimport { InventoryModule } from './modules/inventory'\nimport { WorldModule } from './modules/world'\nimport { PlayerModule } from './modules/player'\nimport { CustomModule } from './modules/custom'\n\nconst API_PATH = '/functions/v1/world-engine/v1'\n\ninterface StorviaEnv {\n apiBase?: string\n gameId?: string\n accessToken?: string\n /** 预览模式标志:跳过 auth,chat 发到 /preview,其他模块内存模式 */\n preview?: boolean\n /** 预览模式下的 prompt 配置 */\n previewConfig?: {\n game_prompt?: string | null\n game_config?: Record<string, unknown>\n game_state?: Record<string, unknown>\n persona_settings?: Record<string, unknown>\n reply_length?: string\n reply_language?: string\n }\n /** 预览模式下由父页面传入的模型列表 */\n models?: { id: string; name: string; provider: string }[]\n /** 预览模式下由父页面传入的选中模型 ID */\n selectedModelId?: string\n /** 开启 debug 模式:打印所有请求/响应日志 */\n debug?: boolean\n}\n\nfunction getEnv(): StorviaEnv {\n return ((window as unknown as Record<string, StorviaEnv>).__STORVIA__) || {}\n}\n\n/**\n * 等待父页面通过 postMessage 注入 __STORVIA__ 配置\n * 支持两种消息格式:\n * 1. 正式环境 (World.vue): { type: 'storvia-init', apiBase, gameId, accessToken }\n * 2. 预览环境 (CreatePreviewModal): { type: 'storvia-preview-init', config: { apiBase, gameId, accessToken, preview, previewConfig } }\n * 如果 __STORVIA__ 已存在则立即返回\n */\nfunction waitForEnv(timeoutMs = 5000): Promise<StorviaEnv> {\n const existing = getEnv()\n if (existing.apiBase) return Promise.resolve(existing)\n\n return new Promise<StorviaEnv>((resolve, reject) => {\n const timer = setTimeout(() => {\n window.removeEventListener('message', handler)\n reject(new StorviaError('NOT_INITIALIZED', 'Timed out waiting for __STORVIA__ config from parent frame.'))\n }, timeoutMs)\n\n function handler(event: MessageEvent) {\n let env: StorviaEnv | null = null\n\n if (event.data?.type === 'storvia-init' && event.data.apiBase) {\n // 正式环境:World.vue 发送的扁平格式\n env = {\n apiBase: event.data.apiBase,\n gameId: event.data.gameId,\n accessToken: event.data.accessToken,\n }\n } else if (event.data?.type === 'storvia-preview-init' && event.data.config) {\n // 预览环境:CreatePreviewModal 发送的嵌套格式\n env = event.data.config\n }\n\n if (env && env.apiBase) {\n clearTimeout(timer)\n window.removeEventListener('message', handler)\n const w = window as unknown as Record<string, StorviaEnv>\n w.__STORVIA__ = env\n resolve(env)\n }\n }\n\n window.addEventListener('message', handler)\n })\n}\n\nexport class StorviaSDK {\n private http!: HttpClient\n private settingsSheet!: SettingsSheet\n private baseUrl = ''\n private gameId = ''\n private conversationId = ''\n private modelId = ''\n private accessToken = ''\n private initialized = false\n private isPreview = false\n private previewConfig: StorviaEnv['previewConfig'] = undefined\n\n chat!: ChatModule\n characters!: CharactersModule\n relationships!: RelationshipsModule\n inventory!: InventoryModule\n world!: WorldModule\n player!: PlayerModule\n custom!: CustomModule\n\n async init(): Promise<void> {\n // 尝试获取环境配置;如果不存在则等待父页面 postMessage 注入(预览场景)\n const env = await waitForEnv()\n\n const apiBase = env.apiBase\n if (!apiBase) {\n throw new StorviaError(\n 'NOT_INITIALIZED',\n 'window.__STORVIA__.apiBase is not set. The platform must inject it before SDK init.'\n )\n }\n this.baseUrl = `${apiBase}${API_PATH}`\n this.isPreview = !!env.preview\n this.previewConfig = env.previewConfig\n\n if (!env.gameId) {\n throw new StorviaError(\n 'GAME_NOT_FOUND',\n 'window.__STORVIA__.gameId is not set. The platform must inject it before SDK init.'\n )\n }\n this.gameId = env.gameId\n\n // 获取用户 access token(由主站通过 postMessage 注入到 __STORVIA__)\n if (!env.accessToken) {\n throw new StorviaError(\n 'UNAUTHORIZED',\n 'window.__STORVIA__.accessToken is not set. The platform must inject the user token before SDK init.'\n )\n }\n this.accessToken = env.accessToken\n\n this.http = new HttpClient(this.baseUrl, this.accessToken, !!env.debug)\n\n if (this.isPreview) {\n // ===== 预览模式:跳过 auth,使用占位 conversationId =====\n this.conversationId = '00000000-0000-0000-0000-000000000000'\n\n // 模型列表和选中模型由父页面传入\n const models = env.models || []\n this.modelId = env.selectedModelId || models[0]?.id || ''\n\n // 挂载设置面板(预览也需要模型选择和设置入口)\n this.settingsSheet = new SettingsSheet({\n onModelChange: (id) => { this.modelId = id },\n onSettingsChange: () => Promise.resolve(),\n onSync: () => Promise.resolve(),\n })\n if (models.length > 0) {\n this.settingsSheet.mount(models, this.modelId, {\n temperature: 1.0,\n reply_length: 'medium',\n reply_language: 'zh-CN',\n player_note: '',\n }, false)\n }\n\n const getGameId = () => this.gameId\n const getConversationId = () => this.conversationId\n const getModelId = () => this.modelId\n this.chat = new ChatModule(this.http, getGameId, getConversationId, getModelId, true, this.previewConfig as Record<string, unknown> | undefined)\n this.characters = new CharactersModule(this.http, getConversationId, true)\n this.relationships = new RelationshipsModule(this.http, getConversationId, true)\n this.inventory = new InventoryModule(this.http, getConversationId, true)\n this.world = new WorldModule(this.http, getConversationId, true)\n this.player = new PlayerModule(this.http, getConversationId, true)\n this.custom = new CustomModule(this.http, getConversationId, true)\n\n this.initialized = true\n\n // 监听父页面的配置更新(模型选择、prompt 变更等)\n this.listenForPreviewMessages()\n return\n }\n\n // ===== 正常模式 =====\n const authResult = await this.authenticate()\n this.conversationId = authResult.conversationId\n\n const models = authResult.models || []\n const savedModelId = this.getSavedModelId()\n this.modelId =\n savedModelId && models.some((m: { id: string }) => m.id === savedModelId)\n ? savedModelId\n : models[0]?.id || ''\n\n const settings: GameSettings = authResult.settings || {\n temperature: 1.0,\n reply_length: 'medium',\n reply_language: 'zh-CN',\n player_note: '',\n }\n\n this.settingsSheet = new SettingsSheet({\n onModelChange: (id) => { this.modelId = id },\n onSettingsChange: (s) => this.saveSettings(s),\n onSync: () => this.syncSettings(),\n })\n this.settingsSheet.mount(models, this.modelId, settings, authResult.hasWorldUpdate ?? false)\n\n const getGameId = () => this.gameId\n const getConversationId = () => this.conversationId\n const getModelId = () => this.modelId\n this.chat = new ChatModule(this.http, getGameId, getConversationId, getModelId)\n this.characters = new CharactersModule(this.http, getConversationId)\n this.relationships = new RelationshipsModule(this.http, getConversationId)\n this.inventory = new InventoryModule(this.http, getConversationId)\n this.world = new WorldModule(this.http, getConversationId)\n this.player = new PlayerModule(this.http, getConversationId)\n this.custom = new CustomModule(this.http, getConversationId)\n\n this.initialized = true\n }\n\n /** 监听父页面 postMessage(预览模式) */\n private listenForPreviewMessages(): void {\n window.addEventListener('message', (event: MessageEvent) => {\n if (!event.data || event.data.type !== 'storvia-preview') return\n\n if (event.data.action === 'set-model') {\n this.modelId = event.data.modelId || ''\n }\n\n if (event.data.action === 'update-config') {\n this.previewConfig = event.data.previewConfig\n // 更新 ChatModule 的 previewConfig\n if (this.chat) {\n this.chat.updatePreviewConfig(this.previewConfig as Record<string, unknown> | undefined)\n }\n }\n })\n }\n\n /** 保存设置到后端 */\n private async saveSettings(settings: Partial<GameSettings>): Promise<void> {\n await this.http.patch('/settings', {\n conversation_id: this.conversationId,\n ...settings,\n })\n }\n\n /** 同步最新游戏设定到当前存档 */\n async syncSettings(): Promise<void> {\n await this.http.post('/sync', { conversation_id: this.conversationId })\n }\n\n private async authenticate(): Promise<{\n conversationId: string\n models: { id: string; name: string; provider: string }[]\n settings?: GameSettings\n hasWorldUpdate?: boolean\n }> {\n const res = await fetch(`${this.baseUrl}/auth`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.accessToken}`,\n },\n body: JSON.stringify({ game_id: this.gameId }),\n })\n\n if (!res.ok) {\n if (res.status === 401) throw new StorviaError('UNAUTHORIZED', 'User not authenticated')\n if (res.status === 404) throw new StorviaError('GAME_NOT_FOUND', 'Game not found or not published')\n throw new StorviaError('INTERNAL_ERROR', `Auth failed: HTTP ${res.status}`)\n }\n\n const json = await res.json()\n return json.data ?? json\n }\n\n private getSavedModelId(): string {\n try {\n return localStorage.getItem('storvia_model_id') || ''\n } catch {\n return ''\n }\n }\n}\n"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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","names":["StorviaError","code","message","HttpClient","baseUrl","token","debug","enabled","method","path","body","response","error","tag","style","params","url","k","v","res","data","e","onChunk","onDone","err","StorviaError","reader","decoder","messageId","accumulated","done","value","lines","line","parsed","codeMap","code","json","LANGUAGES","LENGTH_OPTIONS","STYLES","ICON_GEAR","ICON_SYNC","ICON_SYNC_SPIN","ICON_CHECK","ICON_ERROR","SettingsSheet","callbacks","models","defaultModelId","settings","hasWorldUpdate","saved","style","container","fabWrap","fab","fabDot","panel","header","title","closeBtn","body","saveRow","saveBtn","e","section","label","list","model","btn","labelText","valueText","desc","wrap","slider","v","labels","segment","opt","b","i","select","lang","option","arrow","counter","textarea","DISPLAY_OPTIONS","hint","syncBtn","d","state","s","icons","ChatModule","http","getGameId","getConversationId","getModelId","isPreview","previewConfig","config","options","body","content","chunk","CharacterStateModule","http","getConversationId","isPreview","characterName","values","CharactersModule","c","name","character","data","RelationshipsModule","http","getConversationId","isPreview","from","to","r","relationship","data","InventoryModule","http","getConversationId","isPreview","group","i","params","item","name","data","WorldModule","http","getConversationId","isPreview","data","PlayerStateModule","http","getConversationId","isPreview","group","params","values","PlayerModule","CustomModule","http","getConversationId","isPreview","key","data","value","groupKey","fieldKey","group","API_PATH","getEnv","waitForEnv","timeoutMs","existing","resolve","reject","timer","handler","StorviaError","event","env","w","StorviaSDK","apiBase","HttpClient","models","SettingsSheet","id","getGameId","getConversationId","getModelId","ChatModule","CharactersModule","RelationshipsModule","InventoryModule","WorldModule","PlayerModule","CustomModule","authResult","savedModelId","m","settings","s","res","json"]}
|
package/dist/index.umd.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/http.ts","../src/settings-sheet.ts","../src/modules/chat.ts","../src/modules/characters.ts","../src/modules/relationships.ts","../src/modules/inventory.ts","../src/modules/world.ts","../src/modules/player.ts","../src/modules/custom.ts","../src/StorviaSDK.ts"],"sourcesContent":["export { StorviaSDK } from './StorviaSDK'\nexport { StorviaError } from './errors'\nexport type {\n StorviaErrorCode,\n ChatSendOptions,\n ChatSaveOptions,\n ChatGenerateOptions,\n ChatResponse,\n CharacterPersona,\n CharacterDetail,\n Relationship,\n InventoryItemData,\n PlayerPersona,\n} from './types'\n","import type { StorviaErrorCode } from './types'\n\nexport class StorviaError extends Error {\n code: StorviaErrorCode\n\n constructor(code: StorviaErrorCode, message: string) {\n super(message)\n this.name = 'StorviaError'\n this.code = code\n }\n}\n","import { StorviaError } from './errors'\nimport type { StorviaErrorCode } from './types'\n\nexport class HttpClient {\n private baseUrl: string\n private token: string\n private debug: boolean\n\n constructor(baseUrl: string, token: string, debug = false) {\n this.baseUrl = baseUrl\n this.token = token\n this.debug = debug\n }\n\n setToken(token: string) {\n this.token = token\n }\n\n setDebug(enabled: boolean) {\n this.debug = enabled\n }\n\n private buildHeaders(): Record<string, string> {\n return {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.token}`,\n }\n }\n\n private log(method: string, path: string, body?: unknown, response?: unknown, error?: unknown) {\n if (!this.debug) return\n const tag = '%c[Storvia SDK]'\n const style = 'color: #6366f1; font-weight: bold'\n if (error) {\n console.groupCollapsed(`${tag} %c${method} ${path} %c✗`, style, 'color: #e0e0e0', 'color: #ef4444')\n if (body) console.log('Request:', body)\n console.error('Error:', error)\n console.groupEnd()\n } else {\n console.groupCollapsed(`${tag} %c${method} ${path} %c✓`, style, 'color: #e0e0e0', 'color: #22c55e')\n if (body) console.log('Request:', body)\n if (response !== undefined) console.log('Response:', response)\n console.groupEnd()\n }\n }\n\n async get<T>(path: string, params?: Record<string, string>): Promise<T> {\n const url = new URL(`${this.baseUrl}${path}`)\n if (params) {\n Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v))\n }\n\n try {\n const res = await fetch(url.toString(), {\n method: 'GET',\n headers: this.buildHeaders(),\n })\n const data = await this.handleResponse<T>(res)\n this.log('GET', path, params, data)\n return data\n } catch (e) {\n this.log('GET', path, params, undefined, e)\n throw e\n }\n }\n\n async post<T>(path: string, body?: unknown): Promise<T> {\n try {\n const res = await fetch(`${this.baseUrl}${path}`, {\n method: 'POST',\n headers: this.buildHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n })\n const data = await this.handleResponse<T>(res)\n this.log('POST', path, body, data)\n return data\n } catch (e) {\n this.log('POST', path, body, undefined, e)\n throw e\n }\n }\n\n async patch<T>(path: string, body?: unknown): Promise<T> {\n try {\n const res = await fetch(`${this.baseUrl}${path}`, {\n method: 'PATCH',\n headers: this.buildHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n })\n const data = await this.handleResponse<T>(res)\n this.log('PATCH', path, body, data)\n return data\n } catch (e) {\n this.log('PATCH', path, body, undefined, e)\n throw e\n }\n }\n\n async delete<T>(path: string): Promise<T> {\n try {\n const res = await fetch(`${this.baseUrl}${path}`, {\n method: 'DELETE',\n headers: this.buildHeaders(),\n })\n const data = await this.handleResponse<T>(res)\n this.log('DELETE', path, undefined, data)\n return data\n } catch (e) {\n this.log('DELETE', path, undefined, undefined, e)\n throw e\n }\n }\n\n async stream(\n path: string,\n body: unknown,\n onChunk: (text: string) => void,\n onDone: (id: string) => void\n ): Promise<void> {\n this.log('STREAM', path, body)\n\n const res = await fetch(`${this.baseUrl}${path}`, {\n method: 'POST',\n headers: this.buildHeaders(),\n body: JSON.stringify(body),\n })\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({}))\n const error = new StorviaError(\n (err.code as StorviaErrorCode) || 'INTERNAL_ERROR',\n err.message || `HTTP ${res.status}`\n )\n this.log('STREAM', path, body, undefined, error)\n throw error\n }\n\n const reader = res.body?.getReader()\n if (!reader) {\n throw new StorviaError('INTERNAL_ERROR', 'No response body for stream')\n }\n\n const decoder = new TextDecoder()\n let messageId = ''\n let accumulated = ''\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n const chunk = decoder.decode(value, { stream: true })\n const lines = chunk.split('\\n')\n\n for (const line of lines) {\n if (!line.startsWith('data: ')) continue\n const data = line.slice(6)\n\n if (data === '[DONE]') {\n if (this.debug) {\n this.log('STREAM', path + ' [done]', undefined, { id: messageId, contentLength: accumulated.length })\n }\n onDone(messageId)\n return\n }\n\n try {\n const parsed = JSON.parse(data)\n if (parsed.type === 'done' && parsed.id) {\n messageId = parsed.id\n } else if (parsed.content) {\n accumulated += parsed.content\n onChunk(parsed.content)\n }\n } catch {\n // non-JSON data line, ignore\n }\n }\n }\n\n if (messageId) onDone(messageId)\n }\n\n private async handleResponse<T>(res: Response): Promise<T> {\n if (!res.ok) {\n let err: { code?: string; message?: string } = {}\n try {\n err = await res.json()\n } catch {\n // ignore\n }\n\n const codeMap: Record<number, StorviaErrorCode> = {\n 401: 'UNAUTHORIZED',\n 402: 'INSUFFICIENT_BALANCE',\n 404: 'GAME_NOT_FOUND',\n 429: 'RATE_LIMITED',\n }\n\n const code =\n (err.code as StorviaErrorCode) || codeMap[res.status] || 'INTERNAL_ERROR'\n throw new StorviaError(code, err.message || `HTTP ${res.status}`)\n }\n\n const json = await res.json()\n // 解包 { success, data } 格式\n if (json && typeof json === 'object' && 'data' in json) {\n return json.data as T\n }\n return json as T\n }\n}\n","interface ModelOption {\n id: string\n name: string\n provider: string\n}\n\nexport interface GameSettings {\n temperature: number\n reply_length: string\n reply_language: string\n player_note: string\n}\n\ntype SyncState = 'idle' | 'loading' | 'success' | 'error'\n\ninterface SettingsCallbacks {\n onModelChange: (id: string) => void\n onSettingsChange: (settings: Partial<GameSettings>) => Promise<void>\n onSync: () => Promise<void>\n}\n\nconst LANGUAGES = [\n { value: 'zh-CN', label: '简体中文' },\n { value: 'zh-TW', label: '繁體中文' },\n { value: 'en', label: 'English' },\n { value: 'ja', label: '日本語' },\n { value: 'ko', label: '한국어' },\n]\n\nconst LENGTH_OPTIONS = [\n { value: 'low', label: '简短' },\n { value: 'medium', label: '适中' },\n { value: 'high', label: '详细' },\n]\n\nconst STYLES = `\n :host {\n position: fixed;\n bottom: 20px;\n right: 20px;\n z-index: 2147483647;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n\n .fab {\n width: 48px;\n height: 48px;\n border-radius: 50%;\n background: #6366f1;\n color: #fff;\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\n transition: transform 0.2s, box-shadow 0.2s;\n }\n\n .fab:hover {\n transform: scale(1.08);\n box-shadow: 0 6px 16px rgba(0,0,0,0.4);\n }\n\n .fab svg {\n width: 22px;\n height: 22px;\n }\n\n .panel {\n position: absolute;\n bottom: 60px;\n right: 0;\n width: 320px;\n max-height: 80vh;\n overflow-y: auto;\n background: #1e1e1e;\n border: 1px solid #333;\n border-radius: 16px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n display: none;\n }\n\n .panel.open {\n display: block;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 16px 8px;\n }\n\n .panel-title {\n font-size: 16px;\n font-weight: 600;\n color: #fff;\n }\n\n .close-btn {\n width: 28px;\n height: 28px;\n border-radius: 50%;\n border: none;\n background: transparent;\n color: #888;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n transition: background 0.15s;\n }\n\n .close-btn:hover {\n background: #2a2a2a;\n color: #fff;\n }\n\n .panel-body {\n padding: 4px 16px 16px;\n }\n\n .section {\n margin-bottom: 16px;\n }\n\n .section:last-child {\n margin-bottom: 0;\n }\n\n .section-label {\n font-size: 13px;\n font-weight: 500;\n color: #c0c0c0;\n margin-bottom: 6px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .section-label .value {\n color: #6366f1;\n font-weight: 600;\n }\n\n .section-desc {\n font-size: 11px;\n color: #666;\n margin-bottom: 8px;\n line-height: 1.4;\n }\n\n .divider {\n height: 1px;\n background: #2a2a2a;\n margin: 12px 0;\n }\n\n /* Model options */\n .model-list {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n\n .model-option {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px;\n border-radius: 8px;\n cursor: pointer;\n border: none;\n background: transparent;\n color: #e0e0e0;\n width: 100%;\n font-size: 13px;\n text-align: left;\n transition: background 0.15s;\n }\n\n .model-option:hover {\n background: #2a2a2a;\n }\n\n .model-option.active {\n background: #6366f1;\n color: #fff;\n }\n\n .model-option .dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #555;\n flex-shrink: 0;\n }\n\n .model-option.active .dot {\n background: #fff;\n }\n\n /* Slider */\n .slider-wrap {\n position: relative;\n padding: 0 2px;\n }\n\n .slider {\n -webkit-appearance: none;\n appearance: none;\n width: 100%;\n height: 4px;\n border-radius: 2px;\n background: #333;\n outline: none;\n }\n\n .slider::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: #6366f1;\n cursor: pointer;\n border: 2px solid #1e1e1e;\n box-shadow: 0 2px 4px rgba(0,0,0,0.3);\n }\n\n .slider::-moz-range-thumb {\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: #6366f1;\n cursor: pointer;\n border: 2px solid #1e1e1e;\n box-shadow: 0 2px 4px rgba(0,0,0,0.3);\n }\n\n .slider-labels {\n display: flex;\n justify-content: space-between;\n font-size: 11px;\n color: #666;\n margin-top: 4px;\n }\n\n /* Segment control (reply length) */\n .segment {\n display: flex;\n background: #2a2a2a;\n border-radius: 10px;\n padding: 3px;\n gap: 2px;\n }\n\n .segment-btn {\n flex: 1;\n padding: 8px 0;\n border: none;\n border-radius: 8px;\n background: transparent;\n color: #999;\n font-size: 13px;\n cursor: pointer;\n transition: all 0.2s;\n }\n\n .segment-btn.active {\n background: #6366f1;\n color: #fff;\n font-weight: 500;\n }\n\n .segment-btn:not(.active):hover {\n color: #ddd;\n }\n\n /* Select */\n .select-wrap {\n position: relative;\n }\n\n .select {\n width: 100%;\n padding: 10px 32px 10px 12px;\n border-radius: 10px;\n border: 1px solid #333;\n background: #2a2a2a;\n color: #e0e0e0;\n font-size: 13px;\n appearance: none;\n -webkit-appearance: none;\n cursor: pointer;\n outline: none;\n transition: border-color 0.15s;\n }\n\n .select:focus {\n border-color: #6366f1;\n }\n\n .select-arrow {\n position: absolute;\n right: 12px;\n top: 50%;\n transform: translateY(-50%);\n pointer-events: none;\n color: #666;\n font-size: 12px;\n }\n\n /* Textarea (note) */\n .note-wrap {\n position: relative;\n }\n\n .note-input {\n width: 100%;\n padding: 10px 12px;\n border-radius: 10px;\n border: 1px solid #333;\n background: #2a2a2a;\n color: #e0e0e0;\n font-size: 13px;\n font-family: inherit;\n resize: none;\n height: 64px;\n outline: none;\n transition: border-color 0.15s;\n box-sizing: border-box;\n }\n\n .note-input::placeholder {\n color: #555;\n }\n\n .note-input:focus {\n border-color: #6366f1;\n }\n\n .note-counter {\n text-align: right;\n font-size: 11px;\n color: #555;\n margin-top: 4px;\n }\n\n /* Sync section */\n .sync-desc {\n font-size: 11px;\n color: #666;\n margin-bottom: 8px;\n line-height: 1.4;\n }\n\n .sync-btn {\n width: 100%;\n padding: 10px 0;\n border-radius: 10px;\n border: 1px solid #333;\n background: #2a2a2a;\n color: #e0e0e0;\n font-size: 13px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n transition: background 0.15s;\n }\n\n .sync-btn:hover:not(:disabled) {\n background: #333;\n }\n\n .sync-btn:disabled {\n cursor: default;\n opacity: 0.6;\n }\n\n .sync-btn svg {\n width: 16px;\n height: 16px;\n }\n\n .sync-btn.success { color: #4ade80; border-color: #4ade80; }\n .sync-btn.error { color: #f87171; border-color: #f87171; }\n\n /* Save button */\n .save-row {\n display: flex;\n justify-content: flex-end;\n margin-top: 16px;\n }\n\n .save-btn {\n padding: 8px 24px;\n border-radius: 10px;\n border: none;\n background: #6366f1;\n color: #fff;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .save-btn:hover:not(:disabled) {\n background: #5558e6;\n }\n\n .save-btn:disabled {\n opacity: 0.6;\n cursor: default;\n }\n\n .save-btn.saved {\n background: #4ade80;\n }\n\n /* FAB red dot */\n .fab-dot {\n position: absolute;\n top: 2px;\n right: 2px;\n width: 10px;\n height: 10px;\n border-radius: 50%;\n background: #f87171;\n border: 2px solid #1e1e1e;\n display: none;\n }\n\n .fab-dot.visible {\n display: block;\n }\n\n .fab-wrap {\n position: relative;\n display: inline-block;\n }\n\n /* Sync update hint */\n .sync-hint {\n font-size: 11px;\n color: #f59e0b;\n margin-bottom: 6px;\n line-height: 1.4;\n display: none;\n }\n\n .sync-hint.visible {\n display: block;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n .spin { animation: spin 0.8s linear infinite; }\n`\n\nconst ICON_GEAR = `<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=\"3\"/><path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z\"/></svg>`\nconst ICON_SYNC = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"23 4 23 10 17 10\"/><polyline points=\"1 20 1 14 7 14\"/><path d=\"M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15\"/></svg>`\nconst ICON_SYNC_SPIN = `<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>`\nconst ICON_CHECK = `<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>`\nconst ICON_ERROR = `<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>`\n\nexport class SettingsSheet {\n private shadowRoot: ShadowRoot\n private host: HTMLElement\n private callbacks: SettingsCallbacks\n\n // Model state\n private selectedModelId = ''\n private models: ModelOption[] = []\n private modelPanel: HTMLElement | null = null\n\n // Settings state (local copy, saved on \"保存\")\n private settings: GameSettings = {\n temperature: 1.0,\n reply_length: 'medium',\n reply_language: 'zh-CN',\n player_note: '',\n }\n\n // World update state\n private hasWorldUpdate = false\n private fabDot: HTMLElement | null = null\n private syncHint: HTMLElement | null = null\n\n // Display mode state\n private displayMode: 'phone' | 'desktop' = 'phone'\n private displayModeBtns: HTMLButtonElement[] = []\n\n // UI refs\n private tempValueEl: HTMLElement | null = null\n private tempSlider: HTMLInputElement | null = null\n private segmentBtns: HTMLButtonElement[] = []\n private langSelect: HTMLSelectElement | null = null\n private noteInput: HTMLTextAreaElement | null = null\n private noteCounter: HTMLElement | null = null\n private saveBtn: HTMLButtonElement | null = null\n private syncBtn: HTMLButtonElement | null = null\n private syncState: SyncState = 'idle'\n private panel: HTMLElement | null = null\n\n constructor(callbacks: SettingsCallbacks) {\n this.callbacks = callbacks\n this.host = document.createElement('div')\n this.host.id = 'storvia-settings'\n this.shadowRoot = this.host.attachShadow({ mode: 'closed' })\n }\n\n mount(models: ModelOption[], defaultModelId: string, settings: GameSettings, hasWorldUpdate = false) {\n this.models = models\n this.selectedModelId = defaultModelId\n this.settings = { ...settings }\n this.hasWorldUpdate = hasWorldUpdate\n try {\n const saved = localStorage.getItem('storvia_display_mode')\n if (saved === 'phone' || saved === 'desktop') this.displayMode = saved\n } catch { /* ignore */ }\n document.body.appendChild(this.host)\n this.render()\n }\n\n unmount() {\n this.host.remove()\n }\n\n getSelectedModelId(): string {\n return this.selectedModelId\n }\n\n getSettings(): GameSettings {\n return { ...this.settings }\n }\n\n private render() {\n const style = document.createElement('style')\n style.textContent = STYLES\n\n const container = document.createElement('div')\n\n // FAB with red dot\n const fabWrap = document.createElement('div')\n fabWrap.className = 'fab-wrap'\n const fab = document.createElement('button')\n fab.className = 'fab'\n fab.innerHTML = ICON_GEAR\n fab.title = '游戏设置'\n const fabDot = document.createElement('div')\n fabDot.className = `fab-dot${this.hasWorldUpdate ? ' visible' : ''}`\n this.fabDot = fabDot\n fabWrap.appendChild(fab)\n fabWrap.appendChild(fabDot)\n\n // Panel\n const panel = document.createElement('div')\n panel.className = 'panel'\n this.panel = panel\n\n // Header\n const header = document.createElement('div')\n header.className = 'panel-header'\n const title = document.createElement('div')\n title.className = 'panel-title'\n title.textContent = '游戏设置'\n const closeBtn = document.createElement('button')\n closeBtn.className = 'close-btn'\n closeBtn.innerHTML = '✕'\n closeBtn.addEventListener('click', () => panel.classList.remove('open'))\n header.appendChild(title)\n header.appendChild(closeBtn)\n panel.appendChild(header)\n\n // Body\n const body = document.createElement('div')\n body.className = 'panel-body'\n\n // ── AI Model ──\n if (this.models.length > 0) {\n body.appendChild(this.buildModelSection())\n body.appendChild(this.makeDivider())\n }\n\n // ── Temperature ──\n body.appendChild(this.buildTemperatureSection())\n body.appendChild(this.makeDivider())\n\n // ── Reply Length ──\n body.appendChild(this.buildReplyLengthSection())\n body.appendChild(this.makeDivider())\n\n // ── Reply Language ──\n body.appendChild(this.buildReplyLanguageSection())\n body.appendChild(this.makeDivider())\n\n // ── Note ──\n body.appendChild(this.buildNoteSection())\n body.appendChild(this.makeDivider())\n\n // ── Display Mode ──\n body.appendChild(this.buildDisplayModeSection())\n body.appendChild(this.makeDivider())\n\n // ── Sync ──\n body.appendChild(this.buildSyncSection())\n\n // ── Save Button ──\n const saveRow = document.createElement('div')\n saveRow.className = 'save-row'\n const saveBtn = document.createElement('button')\n saveBtn.className = 'save-btn'\n saveBtn.textContent = '保存'\n this.saveBtn = saveBtn\n saveBtn.addEventListener('click', () => this.handleSave())\n saveRow.appendChild(saveBtn)\n body.appendChild(saveRow)\n\n panel.appendChild(body)\n\n // Toggle\n fab.addEventListener('click', () => panel.classList.toggle('open'))\n document.addEventListener('click', (e) => {\n if (!this.host.contains(e.target as Node)) panel.classList.remove('open')\n })\n\n container.appendChild(panel)\n container.appendChild(fabWrap)\n this.shadowRoot.appendChild(style)\n this.shadowRoot.appendChild(container)\n }\n\n // ── Build sections ──\n\n private buildModelSection(): HTMLElement {\n const section = document.createElement('div')\n section.className = 'section'\n\n const label = document.createElement('div')\n label.className = 'section-label'\n label.textContent = 'AI 模型'\n section.appendChild(label)\n\n const list = document.createElement('div')\n list.className = 'model-list'\n this.modelPanel = list\n\n this.models.forEach((model) => {\n const btn = document.createElement('button')\n btn.className = `model-option${model.id === this.selectedModelId ? ' active' : ''}`\n btn.innerHTML = `<span class=\"dot\"></span><span>${model.name}</span>`\n btn.addEventListener('click', () => {\n this.selectedModelId = model.id\n this.callbacks.onModelChange(model.id)\n try { localStorage.setItem('storvia_model_id', model.id) } catch { /* ignore */ }\n this.updateModelActive()\n })\n list.appendChild(btn)\n })\n\n section.appendChild(list)\n return section\n }\n\n private buildTemperatureSection(): HTMLElement {\n const section = document.createElement('div')\n section.className = 'section'\n\n const label = document.createElement('div')\n label.className = 'section-label'\n const labelText = document.createElement('span')\n labelText.textContent = '温度'\n const valueText = document.createElement('span')\n valueText.className = 'value'\n valueText.textContent = this.settings.temperature.toFixed(1)\n this.tempValueEl = valueText\n label.appendChild(labelText)\n label.appendChild(valueText)\n section.appendChild(label)\n\n const desc = document.createElement('div')\n desc.className = 'section-desc'\n desc.textContent = '更低的温度会让 AI 回复更稳定、理智;更高的温度会让 AI 的回复更具多样性和随机性'\n section.appendChild(desc)\n\n const wrap = document.createElement('div')\n wrap.className = 'slider-wrap'\n const slider = document.createElement('input')\n slider.type = 'range'\n slider.className = 'slider'\n slider.min = '0'\n slider.max = '2'\n slider.step = '0.1'\n slider.value = String(this.settings.temperature)\n this.tempSlider = slider\n slider.addEventListener('input', () => {\n const v = parseFloat(slider.value)\n this.settings.temperature = v\n if (this.tempValueEl) this.tempValueEl.textContent = v.toFixed(1)\n })\n wrap.appendChild(slider)\n\n const labels = document.createElement('div')\n labels.className = 'slider-labels'\n labels.innerHTML = '<span>精确</span><span>创意</span>'\n wrap.appendChild(labels)\n\n section.appendChild(wrap)\n return section\n }\n\n private buildReplyLengthSection(): HTMLElement {\n const section = document.createElement('div')\n section.className = 'section'\n\n const label = document.createElement('div')\n label.className = 'section-label'\n label.textContent = '回复长度'\n section.appendChild(label)\n\n const segment = document.createElement('div')\n segment.className = 'segment'\n this.segmentBtns = []\n\n LENGTH_OPTIONS.forEach((opt) => {\n const btn = document.createElement('button')\n btn.className = `segment-btn${opt.value === this.settings.reply_length ? ' active' : ''}`\n btn.textContent = opt.label\n btn.addEventListener('click', () => {\n this.settings.reply_length = opt.value\n this.segmentBtns.forEach((b, i) => {\n b.classList.toggle('active', LENGTH_OPTIONS[i].value === opt.value)\n })\n })\n this.segmentBtns.push(btn)\n segment.appendChild(btn)\n })\n\n section.appendChild(segment)\n return section\n }\n\n private buildReplyLanguageSection(): HTMLElement {\n const section = document.createElement('div')\n section.className = 'section'\n\n const label = document.createElement('div')\n label.className = 'section-label'\n label.textContent = '回复语言'\n section.appendChild(label)\n\n const wrap = document.createElement('div')\n wrap.className = 'select-wrap'\n const select = document.createElement('select')\n select.className = 'select'\n this.langSelect = select\n\n LANGUAGES.forEach((lang) => {\n const option = document.createElement('option')\n option.value = lang.value\n option.textContent = lang.label\n if (lang.value === this.settings.reply_language) option.selected = true\n select.appendChild(option)\n })\n\n select.addEventListener('change', () => {\n this.settings.reply_language = select.value\n })\n\n const arrow = document.createElement('span')\n arrow.className = 'select-arrow'\n arrow.textContent = '▾'\n wrap.appendChild(select)\n wrap.appendChild(arrow)\n\n section.appendChild(wrap)\n return section\n }\n\n private buildNoteSection(): HTMLElement {\n const section = document.createElement('div')\n section.className = 'section'\n\n const label = document.createElement('div')\n label.className = 'section-label'\n const labelText = document.createElement('span')\n labelText.textContent = '备注'\n const counter = document.createElement('span')\n counter.textContent = `${this.settings.player_note.length}/50`\n this.noteCounter = counter\n label.appendChild(labelText)\n label.appendChild(counter)\n section.appendChild(label)\n\n const desc = document.createElement('div')\n desc.className = 'section-desc'\n desc.textContent = '写下你对这个游戏的备注,会显示在存档列表'\n section.appendChild(desc)\n\n const wrap = document.createElement('div')\n wrap.className = 'note-wrap'\n const textarea = document.createElement('textarea')\n textarea.className = 'note-input'\n textarea.placeholder = '备注'\n textarea.maxLength = 50\n textarea.value = this.settings.player_note\n this.noteInput = textarea\n\n textarea.addEventListener('input', () => {\n this.settings.player_note = textarea.value\n if (this.noteCounter) {\n this.noteCounter.textContent = `${textarea.value.length}/50`\n }\n })\n\n wrap.appendChild(textarea)\n section.appendChild(wrap)\n return section\n }\n\n private buildDisplayModeSection(): HTMLElement {\n const section = document.createElement('div')\n section.className = 'section'\n\n const label = document.createElement('div')\n label.className = 'section-label'\n label.textContent = '显示模式'\n section.appendChild(label)\n\n const desc = document.createElement('div')\n desc.className = 'section-desc'\n desc.textContent = '电脑模式会自动横屏显示'\n section.appendChild(desc)\n\n const segment = document.createElement('div')\n segment.className = 'segment'\n this.displayModeBtns = []\n\n const DISPLAY_OPTIONS = [\n { value: 'phone' as const, label: '手机' },\n { value: 'desktop' as const, label: '电脑' },\n ]\n\n DISPLAY_OPTIONS.forEach((opt) => {\n const btn = document.createElement('button')\n btn.className = `segment-btn${opt.value === this.displayMode ? ' active' : ''}`\n btn.textContent = opt.label\n btn.addEventListener('click', () => {\n this.displayMode = opt.value\n try { localStorage.setItem('storvia_display_mode', opt.value) } catch { /* ignore */ }\n this.displayModeBtns.forEach((b, i) => {\n b.classList.toggle('active', DISPLAY_OPTIONS[i].value === opt.value)\n })\n // 通知父页面旋转\n try {\n window.parent.postMessage({\n type: 'storvia-orientation',\n mode: opt.value === 'desktop' ? 'landscape' : 'portrait',\n }, '*')\n } catch { /* ignore */ }\n })\n this.displayModeBtns.push(btn)\n segment.appendChild(btn)\n })\n\n section.appendChild(segment)\n return section\n }\n\n private buildSyncSection(): HTMLElement {\n const section = document.createElement('div')\n section.className = 'section'\n\n const label = document.createElement('div')\n label.className = 'section-label'\n label.textContent = '同步游戏设定'\n section.appendChild(label)\n\n // Update hint (only visible when hasWorldUpdate)\n const hint = document.createElement('div')\n hint.className = `sync-hint${this.hasWorldUpdate ? ' visible' : ''}`\n hint.textContent = '⚠ 作者已更新游戏内容,建议点击同步'\n this.syncHint = hint\n section.appendChild(hint)\n\n const desc = document.createElement('div')\n desc.className = 'sync-desc'\n desc.textContent = '如果游戏作者更新了内容,点击此按钮可将最新的游戏设定和开幕小剧场同步到当前对话'\n section.appendChild(desc)\n\n const syncBtn = document.createElement('button')\n syncBtn.className = 'sync-btn'\n this.syncBtn = syncBtn\n this.renderSyncBtn()\n\n syncBtn.addEventListener('click', async () => {\n if (this.syncState === 'loading') return\n this.setSyncState('loading')\n try {\n await this.callbacks.onSync()\n this.setSyncState('success')\n // Clear update indicators\n this.hasWorldUpdate = false\n if (this.fabDot) this.fabDot.classList.remove('visible')\n if (this.syncHint) this.syncHint.classList.remove('visible')\n setTimeout(() => this.setSyncState('idle'), 3000)\n } catch {\n this.setSyncState('error')\n setTimeout(() => this.setSyncState('idle'), 4000)\n }\n })\n\n section.appendChild(syncBtn)\n return section\n }\n\n // ── Helpers ──\n\n private makeDivider(): HTMLElement {\n const d = document.createElement('div')\n d.className = 'divider'\n return d\n }\n\n private updateModelActive() {\n if (!this.modelPanel) return\n this.modelPanel.querySelectorAll('.model-option').forEach((btn, i) => {\n btn.classList.toggle('active', this.models[i].id === this.selectedModelId)\n })\n }\n\n private setSyncState(state: SyncState) {\n this.syncState = state\n this.renderSyncBtn()\n }\n\n private renderSyncBtn() {\n if (!this.syncBtn) return\n const s = this.syncState\n const icons: Record<SyncState, string> = {\n idle: ICON_SYNC,\n loading: ICON_SYNC_SPIN,\n success: ICON_CHECK,\n error: ICON_ERROR,\n }\n const labels: Record<SyncState, string> = {\n idle: '同步最新设定',\n loading: '同步中...',\n success: '已同步',\n error: '同步失败',\n }\n this.syncBtn.className = `sync-btn${s === 'success' || s === 'error' ? ` ${s}` : ''}`\n this.syncBtn.disabled = s === 'loading'\n this.syncBtn.innerHTML = `${icons[s]}<span>${labels[s]}</span>`\n }\n\n private async handleSave() {\n if (!this.saveBtn || this.saveBtn.disabled) return\n this.saveBtn.disabled = true\n this.saveBtn.textContent = '保存中...'\n try {\n await this.callbacks.onSettingsChange({\n temperature: this.settings.temperature,\n reply_length: this.settings.reply_length,\n reply_language: this.settings.reply_language,\n player_note: this.settings.player_note,\n })\n this.saveBtn.textContent = '已保存'\n this.saveBtn.classList.add('saved')\n setTimeout(() => {\n if (this.saveBtn) {\n this.saveBtn.textContent = '保存'\n this.saveBtn.classList.remove('saved')\n this.saveBtn.disabled = false\n }\n }, 2000)\n } catch {\n this.saveBtn.textContent = '保存失败'\n setTimeout(() => {\n if (this.saveBtn) {\n this.saveBtn.textContent = '保存'\n this.saveBtn.disabled = false\n }\n }, 2000)\n }\n }\n}\n","import type { HttpClient } from '../http'\nimport type { ChatSendOptions, ChatSaveOptions, ChatGenerateOptions, ChatResponse } from '../types'\n\nexport class ChatModule {\n private previewConfig?: Record<string, unknown>\n\n constructor(\n private http: HttpClient,\n private getGameId: () => string,\n private getConversationId: () => string,\n private getModelId: () => string,\n private isPreview: boolean = false,\n previewConfig?: Record<string, unknown>,\n ) {\n this.previewConfig = previewConfig\n }\n\n /** 更新预览配置(由父页面 postMessage 触发) */\n updatePreviewConfig(config?: Record<string, unknown>): void {\n this.previewConfig = config\n }\n\n /**\n * 发送消息并获取 AI 回复(user 消息 + AI 回复一体化)\n * 适用于 1v1 对话场景\n */\n async send(options: ChatSendOptions): Promise<ChatResponse | void> {\n if (this.isPreview) {\n return this.sendPreview(options)\n }\n\n const body = {\n game_id: this.getGameId(),\n conversation_id: this.getConversationId(),\n model_id: this.getModelId(),\n message: options.message,\n topic: options.topic,\n context: options.context,\n stream: options.stream ?? false,\n }\n\n if (options.stream) {\n await this.http.stream(\n '/chat',\n body,\n options.onChunk ?? (() => {}),\n options.onDone ?? (() => {})\n )\n return\n }\n\n return this.http.post<ChatResponse>('/chat', body)\n }\n\n /**\n * 单独保存一条消息(不调 AI,不扣费)\n * 适用于群聊中先保存用户消息,再分别请求各 NPC 回复\n */\n async save(options: ChatSaveOptions): Promise<{ id: string }> {\n return this.http.post<{ id: string }>('/messages/save', {\n conversation_id: this.getConversationId(),\n role: options.role,\n content: options.content,\n topic: options.topic,\n })\n }\n\n /**\n * 基于 topic 历史 + context 请求 AI 生成回复(无需当前轮用户输入)\n * 适用于群聊 NPC 回复、NPC 自动发言、弹幕生成等\n */\n async generate(options: ChatGenerateOptions): Promise<ChatResponse | void> {\n const body = {\n conversation_id: this.getConversationId(),\n model_id: this.getModelId(),\n topic: options.topic,\n context: options.context,\n stream: options.stream ?? false,\n save: options.save ?? true,\n }\n\n if (options.stream) {\n await this.http.stream(\n '/generate',\n body,\n options.onChunk ?? (() => {}),\n options.onDone ?? (() => {})\n )\n return\n }\n\n return this.http.post<ChatResponse>('/generate', body)\n }\n\n /** 预览模式:发到 /preview 端点 */\n private async sendPreview(options: ChatSendOptions): Promise<ChatResponse | void> {\n const body = {\n model_id: this.getModelId(),\n message: options.message,\n topic: options.topic,\n context: options.context,\n prompt_config: this.previewConfig || {},\n history_messages: [],\n }\n\n if (options.stream) {\n await this.http.stream(\n '/preview',\n body,\n options.onChunk ?? (() => {}),\n options.onDone ?? (() => {})\n )\n return\n }\n\n let content = ''\n await this.http.stream(\n '/preview',\n body,\n (chunk) => { content += chunk },\n () => {}\n )\n return { id: '', content }\n }\n}\n","import type { HttpClient } from '../http'\nimport type { CharacterPersona, CharacterDetail } from '../types'\n\n/** 内部存储含 description(用于 add 传给后端),但不对外暴露 */\ninterface CharacterInternal {\n name: string\n description?: string\n avatar?: string\n}\n\nclass CharacterStateModule {\n private mem: Record<string, Record<string, string | number>> = {}\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {}\n\n async get(characterName: string): Promise<Record<string, string | number>> {\n if (this.isPreview) return { ...(this.mem[characterName] || {}) }\n return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(characterName)}/state`)\n }\n\n async update(characterName: string, values: Record<string, string | number>): Promise<void> {\n if (this.isPreview) {\n this.mem[characterName] = { ...(this.mem[characterName] || {}), ...values }\n return\n }\n await this.http.patch(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(characterName)}/state`, values)\n }\n}\n\nexport class CharactersModule {\n state: CharacterStateModule\n private mem: CharacterInternal[] = []\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {\n this.state = new CharacterStateModule(http, getConversationId, isPreview)\n }\n\n async list(): Promise<CharacterPersona[]> {\n if (this.isPreview) return this.mem.map(c => ({ name: c.name, avatar: c.avatar }))\n return this.http.get(`/conversations/${this.getConversationId()}/characters`)\n }\n\n async get(name: string): Promise<CharacterPersona> {\n if (this.isPreview) {\n const c = this.mem.find(c => c.name === name)\n return { name: c?.name || name, avatar: c?.avatar }\n }\n return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(name)}`)\n }\n\n async add(character: { name: string; description?: string; avatar?: string }): Promise<void> {\n if (this.isPreview) { this.mem.push(character); return }\n await this.http.post(`/conversations/${this.getConversationId()}/characters`, character)\n }\n\n async update(name: string, data: Partial<Omit<CharacterPersona, 'name'>>): Promise<void> {\n if (this.isPreview) { const c = this.mem.find(c => c.name === name); if (c) Object.assign(c, data); return }\n await this.http.patch(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(name)}`, data)\n }\n\n async remove(name: string): Promise<void> {\n if (this.isPreview) { this.mem = this.mem.filter(c => c.name !== name); return }\n await this.http.delete(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(name)}`)\n }\n\n async detail(name: string): Promise<CharacterDetail> {\n if (this.isPreview) {\n const c = this.mem.find(c => c.name === name)\n return { name, avatar: c?.avatar, state: await this.state.get(name) }\n }\n return this.http.get(`/conversations/${this.getConversationId()}/characters/${encodeURIComponent(name)}/detail`)\n }\n}\n","import type { HttpClient } from '../http'\nimport type { Relationship } from '../types'\n\nexport class RelationshipsModule {\n private mem: Relationship[] = []\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {}\n\n async list(): Promise<Relationship[]> {\n if (this.isPreview) return [...this.mem]\n return this.http.get(`/conversations/${this.getConversationId()}/relationships`)\n }\n\n async get(from: string, to: string): Promise<Relationship> {\n if (this.isPreview) {\n const r = this.mem.find(r => r.from === from && r.to === to)\n if (r) return { ...r }\n throw new Error('Relationship not found')\n }\n return this.http.get(`/conversations/${this.getConversationId()}/relationships/${encodeURIComponent(from)}/${encodeURIComponent(to)}`)\n }\n\n async add(relationship: Relationship): Promise<void> {\n if (this.isPreview) { this.mem.push({ ...relationship }); return }\n await this.http.post(`/conversations/${this.getConversationId()}/relationships`, relationship)\n }\n\n async update(from: string, to: string, data: Record<string, string | number>): Promise<void> {\n if (this.isPreview) {\n const r = this.mem.find(r => r.from === from && r.to === to)\n if (r) Object.assign(r, data)\n else this.mem.push({ from, to, ...data })\n return\n }\n await this.http.patch(`/conversations/${this.getConversationId()}/relationships/${encodeURIComponent(from)}/${encodeURIComponent(to)}`, data)\n }\n\n async remove(from: string, to: string): Promise<void> {\n if (this.isPreview) { this.mem = this.mem.filter(r => !(r.from === from && r.to === to)); return }\n await this.http.delete(`/conversations/${this.getConversationId()}/relationships/${encodeURIComponent(from)}/${encodeURIComponent(to)}`)\n }\n}\n","import type { HttpClient } from '../http'\nimport type { InventoryItemData } from '../types'\n\nexport class InventoryModule {\n private mem: InventoryItemData[] = []\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {}\n\n async list(group?: string): Promise<InventoryItemData[]> {\n if (this.isPreview) return group ? this.mem.filter(i => i.group === group) : [...this.mem]\n const params = group ? { group } : undefined\n return this.http.get(`/conversations/${this.getConversationId()}/inventory`, params)\n }\n\n async add(item: InventoryItemData): Promise<void> {\n if (this.isPreview) { this.mem.push({ ...item }); return }\n await this.http.post(`/conversations/${this.getConversationId()}/inventory`, item)\n }\n\n async update(name: string, data: Partial<Omit<InventoryItemData, 'name'>>): Promise<void> {\n if (this.isPreview) {\n const i = this.mem.find(i => i.name === name)\n if (i) Object.assign(i, data)\n return\n }\n await this.http.patch(`/conversations/${this.getConversationId()}/inventory/${encodeURIComponent(name)}`, data)\n }\n\n async remove(name: string): Promise<void> {\n if (this.isPreview) { this.mem = this.mem.filter(i => i.name !== name); return }\n await this.http.delete(`/conversations/${this.getConversationId()}/inventory/${encodeURIComponent(name)}`)\n }\n}\n","import type { HttpClient } from '../http'\n\nexport class WorldModule {\n private mem: Record<string, unknown> = {}\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {}\n\n async get(): Promise<Record<string, unknown>> {\n if (this.isPreview) return { ...this.mem }\n return this.http.get(`/conversations/${this.getConversationId()}/world`)\n }\n\n async update(data: Record<string, unknown>): Promise<void> {\n if (this.isPreview) { Object.assign(this.mem, data); return }\n await this.http.patch(`/conversations/${this.getConversationId()}/world`, data)\n }\n}\n","import type { HttpClient } from '../http'\nimport type { PlayerPersona } from '../types'\n\nclass PlayerStateModule {\n private mem: Record<string, Record<string, string | number>> = {}\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {}\n\n async get(): Promise<Record<string, Record<string, string | number>>>\n async get(group: string): Promise<Record<string, string | number>>\n async get(group?: string): Promise<Record<string, string | number> | Record<string, Record<string, string | number>>> {\n if (this.isPreview) {\n if (group) return { ...(this.mem[group] || {}) }\n return { ...this.mem }\n }\n const params = group ? { group } : undefined\n return this.http.get(`/conversations/${this.getConversationId()}/player/state`, params)\n }\n\n async update(group: string, values: Record<string, string | number>): Promise<void> {\n if (this.isPreview) {\n this.mem[group] = { ...(this.mem[group] || {}), ...values }\n return\n }\n await this.http.patch(`/conversations/${this.getConversationId()}/player/state`, { group, values })\n }\n}\n\nexport class PlayerModule {\n state: PlayerStateModule\n private memPersona: PlayerPersona = { name: '' }\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {\n this.state = new PlayerStateModule(http, getConversationId, isPreview)\n }\n\n async get(): Promise<PlayerPersona> {\n if (this.isPreview) return { ...this.memPersona }\n return this.http.get(`/conversations/${this.getConversationId()}/player`)\n }\n}\n","import type { HttpClient } from '../http'\n\nexport class CustomModule {\n private mem: Record<string, unknown> = {}\n\n constructor(\n private http: HttpClient,\n private getConversationId: () => string,\n private isPreview: boolean = false\n ) {}\n\n async get(): Promise<Record<string, unknown>>\n async get(key: string): Promise<unknown>\n async get(key?: string): Promise<unknown> {\n if (this.isPreview) {\n if (key !== undefined) return this.mem[key]\n return { ...this.mem }\n }\n const data = await this.http.get<Record<string, unknown>>(\n `/conversations/${this.getConversationId()}/custom`\n )\n if (key !== undefined) return data[key]\n return data\n }\n\n async set(data: Record<string, unknown>): Promise<void> {\n if (this.isPreview) {\n // 深合并:分组对象合并子字段\n for (const [key, value] of Object.entries(data)) {\n if (typeof value === 'object' && value !== null && !Array.isArray(value)\n && typeof this.mem[key] === 'object' && this.mem[key] !== null) {\n this.mem[key] = { ...(this.mem[key] as Record<string, unknown>), ...value }\n } else {\n this.mem[key] = value\n }\n }\n return\n }\n await this.http.patch(`/conversations/${this.getConversationId()}/custom`, data)\n }\n\n async delete(key: string): Promise<void> {\n if (this.isPreview) { delete this.mem[key]; return }\n await this.http.delete(`/conversations/${this.getConversationId()}/custom/${encodeURIComponent(key)}`)\n }\n\n async setGroupField(groupKey: string, fieldKey: string, value: unknown): Promise<void> {\n if (this.isPreview) {\n if (!this.mem[groupKey] || typeof this.mem[groupKey] !== 'object') {\n this.mem[groupKey] = {}\n }\n (this.mem[groupKey] as Record<string, unknown>)[fieldKey] = value\n return\n }\n await this.http.patch(\n `/conversations/${this.getConversationId()}/custom/${encodeURIComponent(groupKey)}/${encodeURIComponent(fieldKey)}`,\n { value }\n )\n }\n\n async deleteGroupField(groupKey: string, fieldKey: string): Promise<void> {\n if (this.isPreview) {\n if (typeof this.mem[groupKey] === 'object' && this.mem[groupKey] !== null) {\n const group = this.mem[groupKey] as Record<string, unknown>\n delete group[fieldKey]\n if (Object.keys(group).length === 0) delete this.mem[groupKey]\n }\n return\n }\n await this.http.delete(\n `/conversations/${this.getConversationId()}/custom/${encodeURIComponent(groupKey)}/${encodeURIComponent(fieldKey)}`\n )\n }\n}\n","import { HttpClient } from './http'\nimport { StorviaError } from './errors'\nimport { SettingsSheet } from './settings-sheet'\nimport type { GameSettings } from './settings-sheet'\nimport { ChatModule } from './modules/chat'\nimport { CharactersModule } from './modules/characters'\nimport { RelationshipsModule } from './modules/relationships'\nimport { InventoryModule } from './modules/inventory'\nimport { WorldModule } from './modules/world'\nimport { PlayerModule } from './modules/player'\nimport { CustomModule } from './modules/custom'\n\nconst API_PATH = '/functions/v1/world-engine/v1'\n\ninterface StorviaEnv {\n apiBase?: string\n gameId?: string\n accessToken?: string\n /** 预览模式标志:跳过 auth,chat 发到 /preview,其他模块内存模式 */\n preview?: boolean\n /** 预览模式下的 prompt 配置 */\n previewConfig?: {\n game_prompt?: string | null\n game_config?: Record<string, unknown>\n game_state?: Record<string, unknown>\n persona_settings?: Record<string, unknown>\n reply_length?: string\n reply_language?: string\n }\n /** 预览模式下由父页面传入的模型列表 */\n models?: { id: string; name: string; provider: string }[]\n /** 预览模式下由父页面传入的选中模型 ID */\n selectedModelId?: string\n /** 开启 debug 模式:打印所有请求/响应日志 */\n debug?: boolean\n}\n\nfunction getEnv(): StorviaEnv {\n return ((window as unknown as Record<string, StorviaEnv>).__STORVIA__) || {}\n}\n\n/**\n * 等待父页面通过 postMessage 注入 __STORVIA__ 配置\n * 支持两种消息格式:\n * 1. 正式环境 (World.vue): { type: 'storvia-init', apiBase, gameId, accessToken }\n * 2. 预览环境 (CreatePreviewModal): { type: 'storvia-preview-init', config: { apiBase, gameId, accessToken, preview, previewConfig } }\n * 如果 __STORVIA__ 已存在则立即返回\n */\nfunction waitForEnv(timeoutMs = 5000): Promise<StorviaEnv> {\n const existing = getEnv()\n if (existing.apiBase) return Promise.resolve(existing)\n\n return new Promise<StorviaEnv>((resolve, reject) => {\n const timer = setTimeout(() => {\n window.removeEventListener('message', handler)\n reject(new StorviaError('NOT_INITIALIZED', 'Timed out waiting for __STORVIA__ config from parent frame.'))\n }, timeoutMs)\n\n function handler(event: MessageEvent) {\n let env: StorviaEnv | null = null\n\n if (event.data?.type === 'storvia-init' && event.data.apiBase) {\n // 正式环境:World.vue 发送的扁平格式\n env = {\n apiBase: event.data.apiBase,\n gameId: event.data.gameId,\n accessToken: event.data.accessToken,\n }\n } else if (event.data?.type === 'storvia-preview-init' && event.data.config) {\n // 预览环境:CreatePreviewModal 发送的嵌套格式\n env = event.data.config\n }\n\n if (env && env.apiBase) {\n clearTimeout(timer)\n window.removeEventListener('message', handler)\n const w = window as unknown as Record<string, StorviaEnv>\n w.__STORVIA__ = env\n resolve(env)\n }\n }\n\n window.addEventListener('message', handler)\n })\n}\n\nexport class StorviaSDK {\n private http!: HttpClient\n private settingsSheet!: SettingsSheet\n private baseUrl = ''\n private gameId = ''\n private conversationId = ''\n private modelId = ''\n private accessToken = ''\n private initialized = false\n private isPreview = false\n private previewConfig: StorviaEnv['previewConfig'] = undefined\n\n chat!: ChatModule\n characters!: CharactersModule\n relationships!: RelationshipsModule\n inventory!: InventoryModule\n world!: WorldModule\n player!: PlayerModule\n custom!: CustomModule\n\n async init(): Promise<void> {\n // 尝试获取环境配置;如果不存在则等待父页面 postMessage 注入(预览场景)\n const env = await waitForEnv()\n\n const apiBase = env.apiBase\n if (!apiBase) {\n throw new StorviaError(\n 'NOT_INITIALIZED',\n 'window.__STORVIA__.apiBase is not set. The platform must inject it before SDK init.'\n )\n }\n this.baseUrl = `${apiBase}${API_PATH}`\n this.isPreview = !!env.preview\n this.previewConfig = env.previewConfig\n\n if (!env.gameId) {\n throw new StorviaError(\n 'GAME_NOT_FOUND',\n 'window.__STORVIA__.gameId is not set. The platform must inject it before SDK init.'\n )\n }\n this.gameId = env.gameId\n\n // 获取用户 access token(由主站通过 postMessage 注入到 __STORVIA__)\n if (!env.accessToken) {\n throw new StorviaError(\n 'UNAUTHORIZED',\n 'window.__STORVIA__.accessToken is not set. The platform must inject the user token before SDK init.'\n )\n }\n this.accessToken = env.accessToken\n\n this.http = new HttpClient(this.baseUrl, this.accessToken, !!env.debug)\n\n if (this.isPreview) {\n // ===== 预览模式:跳过 auth,使用占位 conversationId =====\n this.conversationId = '00000000-0000-0000-0000-000000000000'\n\n // 模型列表和选中模型由父页面传入\n const models = env.models || []\n this.modelId = env.selectedModelId || models[0]?.id || ''\n\n // 挂载设置面板(预览也需要模型选择和设置入口)\n this.settingsSheet = new SettingsSheet({\n onModelChange: (id) => { this.modelId = id },\n onSettingsChange: () => Promise.resolve(),\n onSync: () => Promise.resolve(),\n })\n if (models.length > 0) {\n this.settingsSheet.mount(models, this.modelId, {\n temperature: 1.0,\n reply_length: 'medium',\n reply_language: 'zh-CN',\n player_note: '',\n }, false)\n }\n\n const getGameId = () => this.gameId\n const getConversationId = () => this.conversationId\n const getModelId = () => this.modelId\n this.chat = new ChatModule(this.http, getGameId, getConversationId, getModelId, true, this.previewConfig as Record<string, unknown> | undefined)\n this.characters = new CharactersModule(this.http, getConversationId, true)\n this.relationships = new RelationshipsModule(this.http, getConversationId, true)\n this.inventory = new InventoryModule(this.http, getConversationId, true)\n this.world = new WorldModule(this.http, getConversationId, true)\n this.player = new PlayerModule(this.http, getConversationId, true)\n this.custom = new CustomModule(this.http, getConversationId, true)\n\n this.initialized = true\n\n // 监听父页面的配置更新(模型选择、prompt 变更等)\n this.listenForPreviewMessages()\n return\n }\n\n // ===== 正常模式 =====\n const authResult = await this.authenticate()\n this.conversationId = authResult.conversationId\n\n const models = authResult.models || []\n const savedModelId = this.getSavedModelId()\n this.modelId =\n savedModelId && models.some((m: { id: string }) => m.id === savedModelId)\n ? savedModelId\n : models[0]?.id || ''\n\n const settings: GameSettings = authResult.settings || {\n temperature: 1.0,\n reply_length: 'medium',\n reply_language: 'zh-CN',\n player_note: '',\n }\n\n this.settingsSheet = new SettingsSheet({\n onModelChange: (id) => { this.modelId = id },\n onSettingsChange: (s) => this.saveSettings(s),\n onSync: () => this.syncSettings(),\n })\n this.settingsSheet.mount(models, this.modelId, settings, authResult.hasWorldUpdate ?? false)\n\n const getGameId = () => this.gameId\n const getConversationId = () => this.conversationId\n const getModelId = () => this.modelId\n this.chat = new ChatModule(this.http, getGameId, getConversationId, getModelId)\n this.characters = new CharactersModule(this.http, getConversationId)\n this.relationships = new RelationshipsModule(this.http, getConversationId)\n this.inventory = new InventoryModule(this.http, getConversationId)\n this.world = new WorldModule(this.http, getConversationId)\n this.player = new PlayerModule(this.http, getConversationId)\n this.custom = new CustomModule(this.http, getConversationId)\n\n this.initialized = true\n }\n\n /** 监听父页面 postMessage(预览模式) */\n private listenForPreviewMessages(): void {\n window.addEventListener('message', (event: MessageEvent) => {\n if (!event.data || event.data.type !== 'storvia-preview') return\n\n if (event.data.action === 'set-model') {\n this.modelId = event.data.modelId || ''\n }\n\n if (event.data.action === 'update-config') {\n this.previewConfig = event.data.previewConfig\n // 更新 ChatModule 的 previewConfig\n if (this.chat) {\n this.chat.updatePreviewConfig(this.previewConfig as Record<string, unknown> | undefined)\n }\n }\n })\n }\n\n /** 保存设置到后端 */\n private async saveSettings(settings: Partial<GameSettings>): Promise<void> {\n await this.http.patch('/settings', {\n conversation_id: this.conversationId,\n ...settings,\n })\n }\n\n /** 同步最新游戏设定到当前存档 */\n async syncSettings(): Promise<void> {\n await this.http.post('/sync', { conversation_id: this.conversationId })\n }\n\n private async authenticate(): Promise<{\n conversationId: string\n models: { id: string; name: string; provider: string }[]\n settings?: GameSettings\n hasWorldUpdate?: boolean\n }> {\n const res = await fetch(`${this.baseUrl}/auth`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.accessToken}`,\n },\n body: JSON.stringify({ game_id: this.gameId }),\n })\n\n if (!res.ok) {\n if (res.status === 401) throw new StorviaError('UNAUTHORIZED', 'User not authenticated')\n if (res.status === 404) throw new StorviaError('GAME_NOT_FOUND', 'Game not found or not published')\n throw new StorviaError('INTERNAL_ERROR', `Auth failed: HTTP ${res.status}`)\n }\n\n const json = await res.json()\n return json.data ?? json\n }\n\n private getSavedModelId(): string {\n try {\n return localStorage.getItem('storvia_model_id') || ''\n } catch {\n return ''\n }\n }\n}\n"],"mappings":"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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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","names":["index_exports","__export","StorviaError","StorviaSDK","StorviaError","code","message","HttpClient","baseUrl","token","debug","enabled","method","path","body","response","error","tag","style","params","url","k","v","res","data","e","onChunk","onDone","err","StorviaError","reader","decoder","messageId","accumulated","done","value","lines","line","parsed","codeMap","code","json","LANGUAGES","LENGTH_OPTIONS","STYLES","ICON_GEAR","ICON_SYNC","ICON_SYNC_SPIN","ICON_CHECK","ICON_ERROR","SettingsSheet","callbacks","models","defaultModelId","settings","hasWorldUpdate","saved","style","container","fabWrap","fab","fabDot","panel","header","title","closeBtn","body","saveRow","saveBtn","e","section","label","list","model","btn","labelText","valueText","desc","wrap","slider","v","labels","segment","opt","b","i","select","lang","option","arrow","counter","textarea","DISPLAY_OPTIONS","hint","syncBtn","d","state","s","icons","ChatModule","http","getGameId","getConversationId","getModelId","isPreview","previewConfig","config","options","body","content","chunk","CharacterStateModule","http","getConversationId","isPreview","characterName","values","CharactersModule","c","name","character","data","RelationshipsModule","http","getConversationId","isPreview","from","to","r","relationship","data","InventoryModule","http","getConversationId","isPreview","group","i","params","item","name","data","WorldModule","http","getConversationId","isPreview","data","PlayerStateModule","http","getConversationId","isPreview","group","params","values","PlayerModule","CustomModule","http","getConversationId","isPreview","key","data","value","groupKey","fieldKey","group","API_PATH","getEnv","waitForEnv","timeoutMs","existing","resolve","reject","timer","handler","StorviaError","event","env","w","StorviaSDK","apiBase","HttpClient","models","SettingsSheet","id","getGameId","getConversationId","getModelId","ChatModule","CharactersModule","RelationshipsModule","InventoryModule","WorldModule","PlayerModule","CustomModule","authResult","savedModelId","m","settings","s","res","json"]}
|