@fps-games/editor-deployment 0.2.3-beta.16 → 0.2.3-beta.17
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/licenses/THIRD_PARTY_NOTICES.txt +2 -2
- package/manifest.json +46 -46
- package/npm-shrinkwrap.json +2 -2
- package/package.json +6 -6
- package/public/assets/index-ChyK2lhc.js +1 -0
- package/public/assets/index-ChyK2lhc.js.br +0 -0
- package/public/assets/index-ChyK2lhc.js.gz +0 -0
- package/public/assets/playable-sdk-D42v8kWc.js +4 -0
- package/public/assets/playable-sdk-D42v8kWc.js.br +0 -0
- package/public/assets/playable-sdk-D42v8kWc.js.gz +0 -0
- package/public/assets/{playable-standard-project-Do0uyGjy.js → playable-standard-project-DgsY-0An.js} +66 -66
- package/public/assets/playable-standard-project-DgsY-0An.js.br +0 -0
- package/public/assets/playable-standard-project-DgsY-0An.js.gz +0 -0
- package/public/index.html +3 -3
- package/public/index.html.br +0 -0
- package/public/index.html.gz +0 -0
- package/runtime/editor-control-plane.mjs +4 -4
- package/worker/editor-service-worker.mjs +17 -17
- package/public/assets/index-Cv7z0zVA.js +0 -1
- package/public/assets/index-Cv7z0zVA.js.br +0 -0
- package/public/assets/index-Cv7z0zVA.js.gz +0 -0
- package/public/assets/playable-sdk-DO95mXOf.js +0 -4
- package/public/assets/playable-sdk-DO95mXOf.js.br +0 -0
- package/public/assets/playable-sdk-DO95mXOf.js.gz +0 -0
- package/public/assets/playable-standard-project-Do0uyGjy.js.br +0 -0
- package/public/assets/playable-standard-project-Do0uyGjy.js.gz +0 -0
|
Binary file
|
|
Binary file
|
package/public/index.html
CHANGED
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
html, body { width: 100%; height: 100%; margin: 0; overflow: hidden; background: #101018; }
|
|
11
11
|
#renderCanvas { width: 100%; height: 100%; display: block; outline: none; }
|
|
12
12
|
</style>
|
|
13
|
-
<script type="importmap">{"imports":{"@fps-games/editor/playable-sdk":"./assets/playable-sdk-
|
|
14
|
-
<script type="module" crossorigin src="./assets/index-
|
|
13
|
+
<script type="importmap">{"imports":{"@fps-games/editor/playable-sdk":"./assets/playable-sdk-D42v8kWc.js","@babylonjs/core":"./assets/babylon-core-DXA-HGqT.js","@fps-games/editor-core/plugin-host":"./assets/editor-core-plugin-host-94e73c63.js"}}</script>
|
|
14
|
+
<script type="module" crossorigin src="./assets/index-ChyK2lhc.js"></script>
|
|
15
15
|
<link rel="modulepreload" crossorigin href="./assets/hemisphericLight-C4swwL68.js">
|
|
16
|
-
<link rel="modulepreload" crossorigin href="./assets/playable-standard-project-
|
|
16
|
+
<link rel="modulepreload" crossorigin href="./assets/playable-standard-project-DgsY-0An.js">
|
|
17
17
|
</head>
|
|
18
18
|
<body>
|
|
19
19
|
</body>
|
package/public/index.html.br
CHANGED
|
Binary file
|
package/public/index.html.gz
CHANGED
|
Binary file
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{readFile as at}from"node:fs/promises";import ye from"node:path";import{createHash as Ae,randomBytes as He,randomUUID as Me}from"node:crypto";import{once as ue}from"node:events";import{createReadStream as We}from"node:fs";import{mkdir as Ge,open as fe,readFile as ne,realpath as oe,rm as me,stat as ae}from"node:fs/promises";import{createServer as Le}from"node:http";import{spawn as Ue}from"node:child_process";import y from"node:path";var R="/__fps_editor_authoring",Be=64*1024;async function ge(e){let o=await oe(e.projectRoot),a=e.projectEpoch?.trim()||Ae("sha256").update(o).digest("hex").slice(0,32),s=e.host?.trim()||"127.0.0.1",u=rt(e.port??3012),h=ot(s,u),v=y.resolve(o,e.workerEntry);if(Ie(o,v,"worker entry"),!(await ae(v).catch(()=>null))?.isFile())throw new Error(`Editor Project I/O worker entry is missing: ${v}`);let O=Ke(e.projectDefinition),m=ze(e.pluginSnapshots),_=new Map(e.builds.map(t=>[t.release,Ve(o,t)]));if(_.size===0||_.size!==e.builds.length)throw new Error("Editor Server requires uniquely named built Editor releases.");let g=e.activeRelease?.trim()||e.builds[0].release;if(!_.has(g))throw new Error(`Unknown active Editor release: ${g}`);let f=e.logger??console,L=Me(),ve=new Date().toISOString(),Q=e.testControl?e.controlToken?.trim()||He(32).toString("base64url"):null,X=e.runtimeUrl?.trim()||"http://127.0.0.1:3011",Se=K(e.workerReadyTimeoutMs,3e4),U=K(e.workerHeartbeatTimeoutMs,1e4),Re=K(e.workerRestartLimit,3),be=K(e.workerRestartWindowMs,6e4),se=Je(e.workerWatchdogMode),Y=y.join(o,".fps-editor/state/editor-server.owner"),ce=await Xe(Y,L),p=null,B=new WeakSet,Z=new WeakMap,N=!1,I="starting",j=0,A=null,H=null,q=0,D=[],ee=null,F=null,J=Date.now(),de=null,C=null,x=!1,te,M=null,S=null,$=Le((t,r)=>{Pe(t,r).catch(n=>{f.error?.(`[fps-editor-server] request failed: ${T(n)}`),r.headersSent?r.destroy(n instanceof Error?n:void 0):d(r,500,{ok:!1,error:T(n)})})});$.on("error",t=>f.error?.(`[fps-editor-server] ${T(t)}`));try{await new Promise((t,r)=>{$.once("error",r),$.listen(u,s,()=>{$.off("error",r),t()})}),await re().catch(t=>{f.error?.(`[fps-editor-server] initial Project I/O startup failed: ${T(t)}`)})}catch(t){throw await we($).catch(()=>{}),await _e(Y,ce).catch(()=>{}),t}J=Date.now(),M=setInterval(()=>{let t=Date.now(),r=t-J;if(J=t,r>U){de=r,C=t+U,x=!1,f.info?.(`[fps-editor-server] Supervisor resumed after a ${r}ms gap; granting Project I/O one heartbeat grace period.`);return}if(!(N||I!=="ready"||!F||!p)){if(t-Date.parse(F)<=U){C=null,x=!1;return}if(!(C!==null&&t<=C)){if(C=null,se==="observe"){x||(x=!0,f.warn?.("[fps-editor-server] Project I/O heartbeat timed out; observe mode left it running."));return}f.warn?.("[fps-editor-server] Project I/O heartbeat timed out; restarting worker."),x=!0,I="restarting",Z.set(p,"heartbeat-timeout"),p.kill("SIGKILL")}}},Math.min(1e3,Math.max(100,Math.floor(U/3)))),M.unref?.(),f.info?.(`[fps-editor-server] ready at ${h}`);function W(){return le(Date.now()),Object.freeze({status:I,ready:I==="ready",endpointBase:R,generation:j,pid:p?.pid??null,serviceInstanceId:A,restartCount:q,recentFailureCount:D.length,watchdogMode:se,lastSupervisorTickAt:new Date(J).toISOString(),lastSuspendGapMs:de,lastRestartReason:ee,lastHeartbeatAt:F,...te?{lastExit:te}:{}})}function z(){let t=_.get(g),r=W();return{ok:!0,authority:"browser",serverInstanceId:L,pid:process.pid,startedAt:ve,projectEpoch:a,host:s,port:u,projectIO:r,worker:r,editor:{activeRelease:g,artifactId:t.artifactId,build:t.build}}}async function re(){if(N)return;j+=1,I=j===1?"starting":"restarting",A=null,H=null,F=null,C=null,x=!1;let t=Ue(process.execPath,[v],{cwd:o,stdio:["ignore","inherit","inherit","ipc"],env:{...process.env,FPS_EDITOR_WORKER_GENERATION:String(j),FPS_EDITOR_WORKER_PROJECT_DEFINITION:JSON.stringify(O),FPS_EDITOR_WORKER_PLUGIN_SNAPSHOTS:JSON.stringify(m)}});p=t,t.on("message",i=>{Te(t,i).catch(c=>{f.error?.(`[fps-editor-server] invalid Project I/O worker message: ${T(c)}`),t.kill("SIGKILL")})}),t.once("exit",(i,c)=>{ke(t,i,c)});let r=Date.now()+Se,n=()=>I==="ready";for(;!N&&p===t&&!n()&&Date.now()<r;)await new Promise(i=>setTimeout(i,25));if(!n())throw p===t&&t.exitCode===null&&t.signalCode===null&&(I="restarting",Z.set(t,"worker-exit"),t.kill("SIGKILL")),new Error("Editor Project I/O worker did not become ready before the startup deadline.")}async function Te(t,r){if(t!==p||!Ze(r))return;if(r.type==="heartbeat"){r.serviceInstanceId===A&&(F=new Date().toISOString());return}let n=new URL(r.internalUrl);if(n.protocol!=="http:"||n.hostname!=="127.0.0.1")throw new Error("Editor Project I/O worker internal URL must use loopback HTTP.");A=r.serviceInstanceId,H=n.toString(),F=new Date().toISOString(),C=null,x=!1,I="ready"}async function ke(t,r,n){let i=B.has(t);B.delete(t),p===t&&(p=null);let c=Date.now();if(te={code:r,signal:n,at:new Date(c).toISOString()},H=null,A=null,N||i){I="stopped";return}if(ee=Z.get(t)??"worker-exit",q+=1,D.push(c),le(c),D.length>Re){I="fused",f.error?.("[fps-editor-server] Project I/O worker restart fuse opened.");return}I="restarting";let w=[100,500,2e3][Math.min(D.length-1,2)];S=setTimeout(()=>{S=null,re().catch(E=>{f.error?.(`[fps-editor-server] Project I/O worker restart failed: ${T(E)}`)})},w),S.unref?.()}function le(t){let r=t-be;D=D.filter(n=>n>=r)}async function Pe(t,r){let n=new URL(t.url??"/",h);if(et(r),t.method==="GET"&&n.pathname==="/__fps_editor/health"){d(r,200,z());return}if(t.method==="GET"&&n.pathname==="/__fps_editor/status"){d(r,200,z());return}if(t.method==="GET"&&n.pathname==="/__fps_editor/project-io/health"){let i=W();d(r,i.ready?200:503,{ok:i.ready,projectIO:i});return}if(t.method==="GET"&&n.pathname===`${R}/health`){let i=W();d(r,200,{schemaVersion:1,kind:"project-io",ready:i.ready,status:i.ready?"ready":"unavailable",generation:i.generation,serviceInstanceId:i.serviceInstanceId,...i.ready?{}:{reason:i.status}});return}if(t.method==="GET"&&n.pathname==="/__fps_editor/bootstrap.json"){let i=_.get(g),c=W();d(r,200,{ok:!0,schemaVersion:1,authority:"browser",serverInstanceId:L,projectEpoch:a,workerGeneration:j,authoringEndpointBase:R,projectDefinition:O,pluginSnapshots:m,projectIO:{endpointBase:c.endpointBase,status:c.ready?"ready":"unavailable",generation:c.generation,serviceInstanceId:c.serviceInstanceId,...c.ready?{}:{reason:c.status}},runtimeUrl:X,playUrl:X,build:i.build});return}if((t.method==="GET"||t.method==="HEAD")&&(n.pathname==="/"||n.pathname==="/index.html"||n.pathname==="/__fps_editor/document")){await je(r,n.searchParams.get("instanceId"),n.searchParams.get("release"),t.method==="HEAD");return}if((t.method==="GET"||t.method==="HEAD")&&n.pathname.startsWith("/__fps_editor/build/")){await De(t,r,n);return}if((t.method==="GET"||t.method==="HEAD")&&n.pathname.startsWith("/src/")){await Ce(t,r,n);return}if(t.method==="POST"&&n.pathname.startsWith("/__fps_editor/control/")){await Fe(t,r,n.pathname);return}if(n.pathname===R||n.pathname.startsWith(`${R}/`)){await xe(t,r,n);return}d(r,404,{ok:!1,error:"not_found"})}async function je(t,r,n,i=!1){let c=_.get(g);if(n?.trim()&&n.trim()!==g){d(t,409,{ok:!1,error:"editor_build_incompatible",activeRelease:g,requestedRelease:n.trim(),activeBuild:c.build});return}let w=await ne(y.join(c.rootPath,"index.html"),"utf8"),E=`/__fps_editor/build/${encodeURIComponent(c.artifactId)}/`,l=W(),b=[`<base href="${nt(E)}">`,"<script>","window.__FPS_EDITOR_HOSTED_SANDBOX__=true;",'window.__BOOT_MODE="edit";',`window.__FPS_EDITOR_SERVER__=${G({serverInstanceId:L,instanceId:r?.trim()||null,release:c.release,artifactId:c.artifactId,build:c.build})};`,`window.__FPS_EDITOR_PROJECT_IO__=${G({endpointBase:R,status:l.ready?"ready":"unavailable",generation:l.generation,serviceInstanceId:l.serviceInstanceId,...l.ready?{}:{reason:l.status}})};`,`window.__FPS_EDITOR_PROJECT_DEFINITION__=${G(O)};`,`window.__FPS_EDITOR_PLUGIN_SNAPSHOTS__=${G(m)};`,`window.__FPS_EDITOR_RUNTIME_URL__=${G(X)};`,"window.__FPS_EDITOR_PROJECT_IO_MONITOR__=setInterval(async()=>{",'try{const response=await fetch("/__fps_editor_authoring/health",{cache:"no-store"});','if(!response.ok)throw new Error("project-io-health-failed");const health=await response.json();const previous=window.__FPS_EDITOR_PROJECT_IO__;',`const next={endpointBase:"${R}",status:health.status,`,"generation:health.generation,serviceInstanceId:health.serviceInstanceId,reason:health.reason};","if(previous?.status===next.status&&previous?.generation===next.generation&&previous?.reason===next.reason)return;","window.__FPS_EDITOR_PROJECT_IO__=next;",'dispatchEvent(new CustomEvent("fps-editor:project-io-availability-changed",{detail:next}));',`}catch{const previous=window.__FPS_EDITOR_PROJECT_IO__;const next={endpointBase:"${R}",`,'status:"unavailable",generation:previous?.generation??0,serviceInstanceId:previous?.serviceInstanceId??null,','reason:"Project I/O health request failed."};',"if(previous?.status===next.status&&previous?.generation===next.generation&&previous?.reason===next.reason)return;","window.__FPS_EDITOR_PROJECT_IO__=next;",'dispatchEvent(new CustomEvent("fps-editor:project-io-availability-changed",{detail:next}));}',"},1000);",'addEventListener("pagehide",()=>clearInterval(window.__FPS_EDITOR_PROJECT_IO_MONITOR__),{once:true});',"</script>"].join(""),$e=/<head[^>]*>/i.test(w)?w.replace(/<head[^>]*>/i,Ne=>`${Ne}${b}`):`${b}${w}`;t.statusCode=200,t.setHeader("Cache-Control","no-store"),t.setHeader("Content-Type","text/html; charset=utf-8"),t.end(i?void 0:$e)}async function De(t,r,n){let i=n.pathname.split("/").filter(Boolean),c=decodeURIComponent(i[2]??""),w=[..._.values()].find(l=>l.artifactId===c);if(!w){d(r,404,{ok:!1,error:"editor_build_not_found"});return}let E=i.slice(3).map(decodeURIComponent).join("/");await pe(t,r,w.rootPath,E,!0)}async function Ce(t,r,n){let i=decodeURIComponent(n.pathname.slice(1));await pe(t,r,o,i,!1,n.searchParams.has("v"))}async function xe(t,r,n){if(!H||I!=="ready"){d(r,503,{ok:!1,error:"editor_project_io_unavailable",generation:j});return}let i;try{i=t.method==="GET"||t.method==="HEAD"?void 0:await qe(t,n.pathname===`${R}/asset-import`?Be:128*1024*1024)}catch(l){if(l?.code!=="asset_import_payload_too_large")throw l;d(r,413,{ok:!1,error:"asset_import_payload_too_large",code:"asset_import_payload_too_large",details:l.details});return}let c={};for(let l of["accept","content-type","if-none-match","range","origin","access-control-request-method","access-control-request-headers"]){let b=t.headers[l];typeof b=="string"&&(c[l]=b)}let w;try{w=await fetch(new URL(`${n.pathname}${n.search}`,H),{method:t.method,headers:c,...i?{body:new Uint8Array(i)}:{}})}catch(l){f.warn?.(`[fps-editor-server] Project I/O request failed: ${T(l)}`),d(r,503,{ok:!1,error:"editor_project_io_unavailable",generation:j});return}r.statusCode=w.status;for(let l of["content-type","content-length","etag","content-range","accept-ranges","server-timing","access-control-allow-origin","access-control-allow-methods","access-control-allow-headers","access-control-expose-headers","vary"]){let b=w.headers.get(l);b&&r.setHeader(l,b)}let E=t.method==="HEAD"?null:Buffer.from(await w.arrayBuffer());r.setHeader("Cache-Control","no-store"),r.end(E??void 0)}async function Fe(t,r,n){if(!Q||t.headers["x-fps-editor-control-token"]!==Q){d(r,404,{ok:!1,error:"not_found"});return}if(n==="/__fps_editor/control/worker/crash"){if(!p){d(r,409,{ok:!1,error:"worker_unavailable"});return}p.kill("SIGKILL"),d(r,202,{ok:!0});return}if(n==="/__fps_editor/control/worker/heartbeat/stop"||n==="/__fps_editor/control/worker/heartbeat/start"){if(!p?.connected){d(r,409,{ok:!1,error:"worker_unavailable"});return}p.send({type:n.endsWith("/stop")?"test.stop-heartbeat":"test.start-heartbeat"}),d(r,200,{ok:!0});return}let i="/__fps_editor/control/activate/",c=decodeURIComponent(n.slice(i.length));if(n.startsWith(i)&&_.has(c)){let w=g;if(g=c,q=0,D=[],ee=null,S&&(clearTimeout(S),S=null),p){let E=p;I="restarting",B.add(E);let l=ue(E,"exit");E.kill("SIGTERM"),await l}await re().catch(E=>{f.error?.(`[fps-editor-server] Project I/O activation restart failed: ${T(E)}`)}),d(r,200,{ok:!0,previousRelease:w,activeRelease:g,status:z()});return}d(r,404,{ok:!1,error:"control_not_found"})}let V=null;return Object.freeze({url:h,controlToken:Q,status:z,dispose(){return V||(V=(async()=>{N=!0,M&&clearInterval(M),S&&clearTimeout(S),M=null,S=null;let t=p;if(t){B.add(t);let r=ue(t,"exit").catch(()=>[]);t.kill("SIGTERM"),await Promise.race([r,new Promise(n=>setTimeout(n,5e3))]),t.exitCode===null&&t.signalCode===null&&t.kill("SIGKILL")}await we($),await _e(Y,ce)})(),V)}})}function Je(e){if(e===void 0||e==="restart")return"restart";if(e==="observe")return"observe";throw new Error(`Editor Project I/O watchdog mode must be restart or observe, got ${String(e)}.`)}function ze(e){if(e===void 0)return Object.freeze({});if(!e||typeof e!="object"||Array.isArray(e))throw new Error("Editor Server Plugin snapshots must be an object.");return Object.freeze(structuredClone(e))}function Ve(e,o){let a=y.resolve(e,o.rootPath);if(Ie(e,a,"built Editor root"),!o.release.trim()||!o.artifactId.trim())throw new Error("Editor build identity is incomplete.");return Object.freeze({...o,rootPath:a,build:Object.freeze({...o.build})})}function Ke(e){if(!e||typeof e!="object"||Array.isArray(e)||e.schemaVersion!==1||typeof e.projectId!="string"||typeof e.projectName!="string"||!e.authoring||!Array.isArray(e.plugins))throw new Error("Editor Server Project definition is invalid.");return structuredClone(e)}async function pe(e,o,a,s,u,h=!1){if(!s||s.includes("\\")||s.split("/").includes("..")){d(o,404,{ok:!1,error:"file_not_found"});return}let v=await oe(a).catch(()=>null),P=y.resolve(a,s),O=v?y.relative(v,P):"..";if(!v||!O||O===".."||O.startsWith(`..${y.sep}`)||y.isAbsolute(O)){d(o,404,{ok:!1,error:"file_not_found"});return}let m=await oe(P).catch(()=>null);if(!m||m!==P){d(o,404,{ok:!1,error:"file_not_found"});return}let _=await ae(m).catch(()=>null);if(!_?.isFile()){d(o,404,{ok:!1,error:"file_not_found"});return}let g=e.headers["accept-encoding"]??"",f=await Qe(m,g);o.statusCode=200,o.setHeader("Cache-Control",u||h?"public, max-age=31536000, immutable":"no-cache"),o.setHeader("Content-Type",tt(m)),o.setHeader("Content-Length",String(f?.stat.size??_.size)),f&&(o.setHeader("Content-Encoding",f.encoding),o.setHeader("Vary","Accept-Encoding")),e.method==="HEAD"?o.end():We(f?.path??m).pipe(o)}async function Qe(e,o){for(let a of he(o,"br")?[{suffix:".br",encoding:"br"},{suffix:".gz",encoding:"gzip"}]:[{suffix:".gz",encoding:"gzip"}]){if(a.encoding==="gzip"&&!he(o,"gzip"))continue;let s=`${e}${a.suffix}`,u=await ae(s).catch(()=>null);if(u?.isFile())return{path:s,encoding:a.encoding,stat:u}}return null}function he(e,o){let a=typeof e=="string"?e:e.join(","),s=null;for(let u of a.toLowerCase().split(",")){let[h="",...v]=u.split(";").map(_=>_.trim());if(h!==o&&h!=="*")continue;let P=v.find(_=>_.startsWith("q=")),O=P?Number(P.slice(2)):1,m=Number.isFinite(O)?O:0;if(h===o)return m>0;s=m}return(s??0)>0}async function Xe(e,o){await Ge(y.dirname(e),{recursive:!0,mode:448});let a={pid:process.pid,serverInstanceId:o,createdAt:new Date().toISOString()};try{let s=await fe(e,"wx",384);return await s.writeFile(`${JSON.stringify(a)}
|
|
2
|
-
`,"utf8"),await
|
|
3
|
-
`,"utf8"),await
|
|
4
|
-
`)}function
|
|
1
|
+
import{readFile as Tt}from"node:fs/promises";import Me from"node:path";import{createHash as qe,randomBytes as Ee,randomUUID as Oe}from"node:crypto";import{once as be}from"node:events";import{createReadStream as et}from"node:fs";import{mkdir as tt,open as Te,readFile as me,realpath as ue,rm as xe,stat as pe}from"node:fs/promises";import{createServer as rt}from"node:http";import{spawn as nt}from"node:child_process";import S from"node:path";var P="/__fps_editor_authoring",ot=64*1024,B="/__fps_editor/runtime-tuning/v1",it=16*1024,Re=15e3;async function De(e){let r=await ue(e.projectRoot),o=e.projectEpoch?.trim()||qe("sha256").update(r).digest("hex").slice(0,32),a=e.host?.trim()||"127.0.0.1",f=_t(e.port??3012),p=gt(a,f),O=S.resolve(r,e.workerEntry);if(Fe(r,O,"worker entry"),!(await pe(O).catch(()=>null))?.isFile())throw new Error(`Editor Project I/O worker entry is missing: ${O}`);let h=dt(e.projectDefinition),y=st(e.pluginSnapshots),_=new Map(e.builds.map(t=>[t.release,ct(r,t)]));if(_.size===0||_.size!==e.builds.length)throw new Error("Editor Server requires uniquely named built Editor releases.");let E=e.activeRelease?.trim()||e.builds[0].release;if(!_.has(E))throw new Error(`Unknown active Editor release: ${E}`);let m=e.logger??console,F=Oe(),re=new Date().toISOString(),ne=e.testControl?e.controlToken?.trim()||Ee(32).toString("base64url"):null,V=e.runtimeUrl?.trim()||"http://127.0.0.1:3011",K=new URL(V).origin,oe=Ee(32).toString("base64url"),T=new Map,w=null,Ue=te(e.workerReadyTimeoutMs,3e4),Q=te(e.workerHeartbeatTimeoutMs,1e4),ze=te(e.workerRestartLimit,3),Ge=te(e.workerRestartWindowMs,6e4),_e=at(e.workerWatchdogMode),ie=S.join(r,".fps-editor/state/editor-server.owner"),ge=await ut(ie,F),I=null,X=new WeakSet,ae=new WeakMap,U=!1,R="starting",A=0,z=null,G=null,se=0,x=[],ce=null,$=null,Z=Date.now(),we=null,D=null,N=!1,de,W=null,k=null,M=rt((t,n)=>{Be(t,n).catch(i=>{m.error?.(`[fps-editor-server] request failed: ${j(i)}`),n.headersSent?n.destroy(i instanceof Error?i:void 0):d(n,500,{ok:!1,error:j(i)})})});M.on("error",t=>m.error?.(`[fps-editor-server] ${j(t)}`));try{await new Promise((t,n)=>{M.once("error",n),M.listen(f,a,()=>{M.off("error",n),t()})}),await le().catch(t=>{m.error?.(`[fps-editor-server] initial Project I/O startup failed: ${j(t)}`)})}catch(t){throw await Pe(M).catch(()=>{}),await ke(ie,ge).catch(()=>{}),t}Z=Date.now(),W=setInterval(()=>{let t=Date.now(),n=t-Z;if(Z=t,n>Q){we=n,D=t+Q,N=!1,m.info?.(`[fps-editor-server] Supervisor resumed after a ${n}ms gap; granting Project I/O one heartbeat grace period.`);return}if(!(U||R!=="ready"||!$||!I)){if(t-Date.parse($)<=Q){D=null,N=!1;return}if(!(D!==null&&t<=D)){if(D=null,_e==="observe"){N||(N=!0,m.warn?.("[fps-editor-server] Project I/O heartbeat timed out; observe mode left it running."));return}m.warn?.("[fps-editor-server] Project I/O heartbeat timed out; restarting worker."),N=!0,R="restarting",ae.set(I,"heartbeat-timeout"),I.kill("SIGKILL")}}},Math.min(1e3,Math.max(100,Math.floor(Q/3)))),W.unref?.(),m.info?.(`[fps-editor-server] ready at ${p}`);function L(){return Ie(Date.now()),Object.freeze({status:R,ready:R==="ready",endpointBase:P,generation:A,pid:I?.pid??null,serviceInstanceId:z,restartCount:se,recentFailureCount:x.length,watchdogMode:_e,lastSupervisorTickAt:new Date(Z).toISOString(),lastSuspendGapMs:we,lastRestartReason:ce,lastHeartbeatAt:$,...de?{lastExit:de}:{}})}function Y(){let t=_.get(E),n=L();return{ok:!0,authority:"browser",serverInstanceId:F,pid:process.pid,startedAt:re,projectEpoch:o,host:a,port:f,projectIO:n,worker:n,editor:{activeRelease:E,artifactId:t.artifactId,build:t.build}}}async function le(){if(U)return;A+=1,R=A===1?"starting":"restarting",z=null,G=null,$=null,D=null,N=!1;let t=nt(process.execPath,[O],{cwd:r,stdio:["ignore","inherit","inherit","ipc"],env:{...process.env,FPS_EDITOR_WORKER_GENERATION:String(A),FPS_EDITOR_WORKER_PROJECT_DEFINITION:JSON.stringify(h),FPS_EDITOR_WORKER_PLUGIN_SNAPSHOTS:JSON.stringify(y)}});I=t,t.on("message",c=>{We(t,c).catch(l=>{m.error?.(`[fps-editor-server] invalid Project I/O worker message: ${j(l)}`),t.kill("SIGKILL")})}),t.once("exit",(c,l)=>{Le(t,c,l)});let n=Date.now()+Ue,i=()=>R==="ready";for(;!U&&I===t&&!i()&&Date.now()<n;)await new Promise(c=>setTimeout(c,25));if(!i())throw I===t&&t.exitCode===null&&t.signalCode===null&&(R="restarting",ae.set(t,"worker-exit"),t.kill("SIGKILL")),new Error("Editor Project I/O worker did not become ready before the startup deadline.")}async function We(t,n){if(t!==I||!mt(n))return;if(n.type==="heartbeat"){n.serviceInstanceId===z&&($=new Date().toISOString());return}let i=new URL(n.internalUrl);if(i.protocol!=="http:"||i.hostname!=="127.0.0.1")throw new Error("Editor Project I/O worker internal URL must use loopback HTTP.");z=n.serviceInstanceId,G=i.toString(),$=new Date().toISOString(),D=null,N=!1,R="ready"}async function Le(t,n,i){let c=X.has(t);X.delete(t),I===t&&(I=null);let l=Date.now();if(de={code:n,signal:i,at:new Date(l).toISOString()},G=null,z=null,U||c){R="stopped";return}if(ce=ae.get(t)??"worker-exit",se+=1,x.push(l),Ie(l),x.length>ze){R="fused",m.error?.("[fps-editor-server] Project I/O worker restart fuse opened.");return}R="restarting";let g=[100,500,2e3][Math.min(x.length-1,2)];k=setTimeout(()=>{k=null,le().catch(u=>{m.error?.(`[fps-editor-server] Project I/O worker restart failed: ${j(u)}`)})},g),k.unref?.()}function Ie(t){let n=t-Ge;x=x.filter(i=>i>=n)}async function Be(t,n){let i=new URL(t.url??"/",p);if(pt(n),t.method==="GET"&&i.pathname==="/__fps_editor/health"){d(n,200,Y());return}if(t.method==="GET"&&i.pathname==="/__fps_editor/status"){d(n,200,Y());return}if(t.method==="GET"&&i.pathname==="/__fps_editor/project-io/health"){let c=L();d(n,c.ready?200:503,{ok:c.ready,projectIO:c});return}if(t.method==="GET"&&i.pathname===`${P}/health`){let c=L();d(n,200,{schemaVersion:1,kind:"project-io",ready:c.ready,status:c.ready?"ready":"unavailable",generation:c.generation,serviceInstanceId:c.serviceInstanceId,...c.ready?{}:{reason:c.status}});return}if(t.method==="GET"&&i.pathname==="/__fps_editor/bootstrap.json"){let c=_.get(E),l=L();d(n,200,{ok:!0,schemaVersion:1,authority:"browser",serverInstanceId:F,projectEpoch:o,workerGeneration:A,authoringEndpointBase:P,projectDefinition:h,pluginSnapshots:y,projectIO:{endpointBase:l.endpointBase,status:l.ready?"ready":"unavailable",generation:l.generation,serviceInstanceId:l.serviceInstanceId,...l.ready?{}:{reason:l.status}},runtimeUrl:V,playUrl:V,build:c.build});return}if(i.pathname.startsWith(`${B}/`)){await Ve(t,n,i);return}if((t.method==="GET"||t.method==="HEAD")&&(i.pathname==="/"||i.pathname==="/index.html"||i.pathname==="/__fps_editor/document")){await Je(n,i.searchParams.get("instanceId"),i.searchParams.get("release"),t.method==="HEAD");return}if((t.method==="GET"||t.method==="HEAD")&&i.pathname.startsWith("/__fps_editor/build/")){await Ke(t,n,i);return}if((t.method==="GET"||t.method==="HEAD")&&i.pathname.startsWith("/src/")){await Qe(t,n,i);return}if(t.method==="POST"&&i.pathname.startsWith("/__fps_editor/control/")){await Ze(t,n,i.pathname);return}if(i.pathname===P||i.pathname.startsWith(`${P}/`)){await Xe(t,n,i);return}d(n,404,{ok:!1,error:"not_found"})}async function Je(t,n,i,c=!1){let l=_.get(E);if(i?.trim()&&i.trim()!==E){d(t,409,{ok:!1,error:"editor_build_incompatible",activeRelease:E,requestedRelease:i.trim(),activeBuild:l.build});return}let g=await me(S.join(l.rootPath,"index.html"),"utf8"),u=`/__fps_editor/build/${encodeURIComponent(l.artifactId)}/`,s=L(),v=[`<base href="${wt(u)}">`,"<script>","window.__FPS_EDITOR_HOSTED_SANDBOX__=true;",'window.__BOOT_MODE="edit";',`window.__FPS_EDITOR_SERVER__=${H({serverInstanceId:F,instanceId:n?.trim()||null,release:l.release,artifactId:l.artifactId,build:l.build})};`,`window.__FPS_EDITOR_PROJECT_IO__=${H({endpointBase:P,status:s.ready?"ready":"unavailable",generation:s.generation,serviceInstanceId:s.serviceInstanceId,...s.ready?{}:{reason:s.status}})};`,`window.__FPS_EDITOR_PROJECT_DEFINITION__=${H(h)};`,`window.__FPS_EDITOR_PLUGIN_SNAPSHOTS__=${H(y)};`,`window.__FPS_EDITOR_RUNTIME_URL__=${H(V)};`,`window.__FPS_EDITOR_RUNTIME_TUNING__=${H({endpointBase:B,token:oe,projectId:je(h)})};`,"window.__FPS_EDITOR_PROJECT_IO_MONITOR__=setInterval(async()=>{",'try{const response=await fetch("/__fps_editor_authoring/health",{cache:"no-store"});','if(!response.ok)throw new Error("project-io-health-failed");const health=await response.json();const previous=window.__FPS_EDITOR_PROJECT_IO__;',`const next={endpointBase:"${P}",status:health.status,`,"generation:health.generation,serviceInstanceId:health.serviceInstanceId,reason:health.reason};","if(previous?.status===next.status&&previous?.generation===next.generation&&previous?.reason===next.reason)return;","window.__FPS_EDITOR_PROJECT_IO__=next;",'dispatchEvent(new CustomEvent("fps-editor:project-io-availability-changed",{detail:next}));',`}catch{const previous=window.__FPS_EDITOR_PROJECT_IO__;const next={endpointBase:"${P}",`,'status:"unavailable",generation:previous?.generation??0,serviceInstanceId:previous?.serviceInstanceId??null,','reason:"Project I/O health request failed."};',"if(previous?.status===next.status&&previous?.generation===next.generation&&previous?.reason===next.reason)return;","window.__FPS_EDITOR_PROJECT_IO__=next;",'dispatchEvent(new CustomEvent("fps-editor:project-io-availability-changed",{detail:next}));}',"},1000);",'addEventListener("pagehide",()=>clearInterval(window.__FPS_EDITOR_PROJECT_IO_MONITOR__),{once:true});',"</script>"].join(""),ee=/<head[^>]*>/i.test(g)?g.replace(/<head[^>]*>/i,Ye=>`${Ye}${v}`):`${v}${g}`;t.statusCode=200,t.setHeader("Cache-Control","no-store"),t.setHeader("Content-Type","text/html; charset=utf-8"),t.end(c?void 0:ee)}async function Ve(t,n,i){let c=i.pathname;if(t.method==="OPTIONS"){if(t.headers.origin!==K)return d(n,404,{ok:!1,error:"not_found"});n.statusCode=204,n.setHeader("Access-Control-Allow-Origin",K),n.setHeader("Access-Control-Allow-Methods","POST"),n.setHeader("Access-Control-Allow-Headers","content-type"),n.setHeader("Vary","Origin"),n.end();return}if(c===`${B}/consumer/poll`){let u=Ae(t);if(t.method!=="POST"||t.headers["x-fps-editor-runtime-tuning-token"]!==oe||!u)return d(n,404,{ok:!1,error:"not_found"});if(T.has(u)){d(n,409,{ok:!1,error:"runtime_tuning_consumer_busy"});return}let s={id:u,response:n,delivered:!1,timer:setTimeout(()=>{T.get(u)===s&&T.delete(u),d(n,204,{})},Re)};T.set(u,s),n.once("close",()=>{!s.delivered&&T.get(u)===s&&(clearTimeout(s.timer),T.delete(u))}),w&&T.size===1&&ye(w);return}if(c===`${B}/consumer/result`){let u=Ae(t);if(t.method!=="POST"||t.headers["x-fps-editor-runtime-tuning-token"]!==oe||!u)return d(n,404,{ok:!1,error:"not_found"});let s=await Ce(t),v=typeof s.requestId=="string"?s.requestId:"";if(!w||v!==w.id||u!==w.consumerId)return d(n,409,{ok:!1,error:"runtime_tuning_stale_result"});let ee=w;w=null,T.delete(u),clearTimeout(ee.timer),ee.settle(Ot(s.result)),d(n,200,{ok:!0});return}if(c!==`${B}/submit`||t.method!=="POST"||t.headers.origin!==K||!t.headers["content-type"]?.toLowerCase().startsWith("application/json"))return d(n,404,{ok:!1,error:"not_found"});n.setHeader("Access-Control-Allow-Origin",K),n.setHeader("Vary","Origin");let l;try{l=It(await Ce(t),je(h))}catch(u){return d(n,400,{ok:!1,error:"runtime_tuning_invalid_intent",message:j(u).slice(0,240)})}if(T.size===0)return d(n,409,{ok:!1,error:"runtime_tuning_no_consumer"});if(T.size>1)return d(n,409,{ok:!1,error:"runtime_tuning_multiple_consumers",message:"\u68C0\u6D4B\u5230\u591A\u4E2A\u5F53\u524D\u9879\u76EE\u7F16\u8F91\u5668\u3002\u8BF7\u53EA\u4FDD\u7559\u4E00\u4E2A\u7F16\u8F91\u5668\u9875\u9762\u540E\u91CD\u8BD5\u3002"});if(w)return d(n,409,{ok:!1,error:"runtime_tuning_busy"});let g=await new Promise(u=>{let s={id:Oe(),intent:l,settle:u,consumerId:null,delivered:!1,timer:setTimeout(()=>{w===s&&(w=null),s.consumerId&&T.delete(s.consumerId),u({ok:!1,code:s.delivered?"runtime_tuning_outcome_unknown":"runtime_tuning_no_consumer",message:s.delivered?"\u7F16\u8F91\u5668\u5DF2\u6536\u5230\u8BF7\u6C42\uFF0C\u4F46\u7ED3\u679C\u5728\u9650\u5B9A\u65F6\u95F4\u5185\u672A\u77E5\u3002":"\u5F53\u524D\u6CA1\u6709\u53EF\u7528\u7684\u7F16\u8F91\u5668\u3002"})},Re)};w=s,ye(s)});d(n,g.ok===!0?200:409,g)}function ye(t){if(T.size!==1)return;let n=T.values().next().value;!n||n.delivered||(clearTimeout(n.timer),n.delivered=!0,t.consumerId=n.id,t.delivered=!0,d(n.response,200,{ok:!0,requestId:t.id,intent:t.intent}))}async function Ke(t,n,i){let c=i.pathname.split("/").filter(Boolean),l=decodeURIComponent(c[2]??""),g=[..._.values()].find(s=>s.artifactId===l);if(!g){d(n,404,{ok:!1,error:"editor_build_not_found"});return}let u=c.slice(3).map(decodeURIComponent).join("/");await Se(t,n,g.rootPath,u,!0)}async function Qe(t,n,i){let c=decodeURIComponent(i.pathname.slice(1));await Se(t,n,r,c,!1,i.searchParams.has("v"))}async function Xe(t,n,i){if(!G||R!=="ready"){d(n,503,{ok:!1,error:"editor_project_io_unavailable",generation:A});return}let c;try{c=t.method==="GET"||t.method==="HEAD"?void 0:await Ne(t,i.pathname===`${P}/asset-import`?ot:128*1024*1024)}catch(s){if(s?.code!=="asset_import_payload_too_large")throw s;d(n,413,{ok:!1,error:"asset_import_payload_too_large",code:"asset_import_payload_too_large",details:s.details});return}let l={};for(let s of["accept","content-type","if-none-match","range","origin","access-control-request-method","access-control-request-headers"]){let v=t.headers[s];typeof v=="string"&&(l[s]=v)}let g;try{g=await fetch(new URL(`${i.pathname}${i.search}`,G),{method:t.method,headers:l,...c?{body:new Uint8Array(c)}:{}})}catch(s){m.warn?.(`[fps-editor-server] Project I/O request failed: ${j(s)}`),d(n,503,{ok:!1,error:"editor_project_io_unavailable",generation:A});return}n.statusCode=g.status;for(let s of["content-type","content-length","etag","content-range","accept-ranges","server-timing","access-control-allow-origin","access-control-allow-methods","access-control-allow-headers","access-control-expose-headers","vary"]){let v=g.headers.get(s);v&&n.setHeader(s,v)}let u=t.method==="HEAD"?null:Buffer.from(await g.arrayBuffer());n.setHeader("Cache-Control","no-store"),n.end(u??void 0)}async function Ze(t,n,i){if(!ne||t.headers["x-fps-editor-control-token"]!==ne){d(n,404,{ok:!1,error:"not_found"});return}if(i==="/__fps_editor/control/worker/crash"){if(!I){d(n,409,{ok:!1,error:"worker_unavailable"});return}I.kill("SIGKILL"),d(n,202,{ok:!0});return}if(i==="/__fps_editor/control/worker/heartbeat/stop"||i==="/__fps_editor/control/worker/heartbeat/start"){if(!I?.connected){d(n,409,{ok:!1,error:"worker_unavailable"});return}I.send({type:i.endsWith("/stop")?"test.stop-heartbeat":"test.start-heartbeat"}),d(n,200,{ok:!0});return}let c="/__fps_editor/control/activate/",l=decodeURIComponent(i.slice(c.length));if(i.startsWith(c)&&_.has(l)){let g=E;if(E=l,se=0,x=[],ce=null,k&&(clearTimeout(k),k=null),I){let u=I;R="restarting",X.add(u);let s=be(u,"exit");u.kill("SIGTERM"),await s}await le().catch(u=>{m.error?.(`[fps-editor-server] Project I/O activation restart failed: ${j(u)}`)}),d(n,200,{ok:!0,previousRelease:g,activeRelease:E,status:Y()});return}d(n,404,{ok:!1,error:"control_not_found"})}let q=null;return Object.freeze({url:p,controlToken:ne,status:Y,dispose(){return q||(q=(async()=>{U=!0;for(let n of T.values())clearTimeout(n.timer),n.response.writableEnded||d(n.response,503,{ok:!1,code:"runtime_tuning_editor_unavailable",message:"\u7F16\u8F91\u5668\u670D\u52A1\u6B63\u5728\u5173\u95ED\u3002"});T.clear(),w&&(clearTimeout(w.timer),w.settle({ok:!1,code:w.delivered?"runtime_tuning_outcome_unknown":"runtime_tuning_editor_unavailable",message:w.delivered?"\u7F16\u8F91\u5668\u5DF2\u6536\u5230\u8BF7\u6C42\uFF0C\u4F46\u670D\u52A1\u5173\u95ED\u524D\u672A\u8FD4\u56DE\u53EF\u4FE1\u7ED3\u679C\u3002":"\u7F16\u8F91\u5668\u670D\u52A1\u6B63\u5728\u5173\u95ED\u3002"}),w=null),W&&clearInterval(W),k&&clearTimeout(k),W=null,k=null;let t=I;if(t){X.add(t);let n=be(t,"exit").catch(()=>[]);t.kill("SIGTERM"),await Promise.race([n,new Promise(i=>setTimeout(i,5e3))]),t.exitCode===null&&t.signalCode===null&&t.kill("SIGKILL")}await Pe(M),await ke(ie,ge)})(),q)}})}function at(e){if(e===void 0||e==="restart")return"restart";if(e==="observe")return"observe";throw new Error(`Editor Project I/O watchdog mode must be restart or observe, got ${String(e)}.`)}function st(e){if(e===void 0)return Object.freeze({});if(!e||typeof e!="object"||Array.isArray(e))throw new Error("Editor Server Plugin snapshots must be an object.");return Object.freeze(structuredClone(e))}function ct(e,r){let o=S.resolve(e,r.rootPath);if(Fe(e,o,"built Editor root"),!r.release.trim()||!r.artifactId.trim())throw new Error("Editor build identity is incomplete.");return Object.freeze({...r,rootPath:o,build:Object.freeze({...r.build})})}function dt(e){if(!e||typeof e!="object"||Array.isArray(e)||e.schemaVersion!==1||typeof e.projectId!="string"||typeof e.projectName!="string"||!e.authoring||!Array.isArray(e.plugins))throw new Error("Editor Server Project definition is invalid.");return structuredClone(e)}async function Se(e,r,o,a,f,p=!1){if(!a||a.includes("\\")||a.split("/").includes("..")){d(r,404,{ok:!1,error:"file_not_found"});return}let O=await ue(o).catch(()=>null),b=S.resolve(o,a),h=O?S.relative(O,b):"..";if(!O||!h||h===".."||h.startsWith(`..${S.sep}`)||S.isAbsolute(h)){d(r,404,{ok:!1,error:"file_not_found"});return}let y=await ue(b).catch(()=>null);if(!y||y!==b){d(r,404,{ok:!1,error:"file_not_found"});return}let _=await pe(y).catch(()=>null);if(!_?.isFile()){d(r,404,{ok:!1,error:"file_not_found"});return}let E=e.headers["accept-encoding"]??"",m=await lt(y,E);r.statusCode=200,r.setHeader("Cache-Control",f||p?"public, max-age=31536000, immutable":"no-cache"),r.setHeader("Content-Type",ht(y)),r.setHeader("Content-Length",String(m?.stat.size??_.size)),m&&(r.setHeader("Content-Encoding",m.encoding),r.setHeader("Vary","Accept-Encoding")),e.method==="HEAD"?r.end():et(m?.path??y).pipe(r)}async function lt(e,r){for(let o of ve(r,"br")?[{suffix:".br",encoding:"br"},{suffix:".gz",encoding:"gzip"}]:[{suffix:".gz",encoding:"gzip"}]){if(o.encoding==="gzip"&&!ve(r,"gzip"))continue;let a=`${e}${o.suffix}`,f=await pe(a).catch(()=>null);if(f?.isFile())return{path:a,encoding:o.encoding,stat:f}}return null}function ve(e,r){let o=typeof e=="string"?e:e.join(","),a=null;for(let f of o.toLowerCase().split(",")){let[p="",...O]=f.split(";").map(_=>_.trim());if(p!==r&&p!=="*")continue;let b=O.find(_=>_.startsWith("q=")),h=b?Number(b.slice(2)):1,y=Number.isFinite(h)?h:0;if(p===r)return y>0;a=y}return(a??0)>0}async function ut(e,r){await tt(S.dirname(e),{recursive:!0,mode:448});let o={pid:process.pid,serverInstanceId:r,createdAt:new Date().toISOString()};try{let a=await Te(e,"wx",384);return await a.writeFile(`${JSON.stringify(o)}
|
|
2
|
+
`,"utf8"),await a.close(),o}catch{let f=await me(e,"utf8").then(JSON.parse).catch(()=>null);if(typeof f?.pid=="number"&&ft(f.pid))throw new Error(`Editor Server project lock is already owned by PID ${f.pid}.`);await xe(e,{force:!0});let p=await Te(e,"wx",384);return await p.writeFile(`${JSON.stringify(o)}
|
|
3
|
+
`,"utf8"),await p.close(),o}}async function ke(e,r){(await me(e,"utf8").then(JSON.parse).catch(()=>null))?.serverInstanceId===r.serverInstanceId&&await xe(e,{force:!0})}function ft(e){try{return process.kill(e,0),!0}catch{return!1}}function mt(e){if(!e||typeof e!="object")return!1;let r=e;return r.type==="heartbeat"?typeof r.serviceInstanceId=="string":r.type==="ready"&&typeof r.serviceInstanceId=="string"&&typeof r.internalUrl=="string"}async function Ne(e,r){let o=[],a=0;for await(let f of e){let p=Buffer.isBuffer(f)?f:Buffer.from(f);if(a+=p.byteLength,a>r)throw Object.assign(new Error("asset_import_payload_too_large"),{code:"asset_import_payload_too_large",details:{maxBytes:r}});o.push(p)}return Buffer.concat(o)}function pt(e){e.setHeader("Access-Control-Allow-Origin","*"),e.setHeader("Access-Control-Expose-Headers","content-length, server-timing"),e.setHeader("Cross-Origin-Resource-Policy","cross-origin"),e.setHeader("Cross-Origin-Embedder-Policy","credentialless"),e.setHeader("X-Content-Type-Options","nosniff")}function d(e,r,o){e.statusCode=r,e.setHeader("Cache-Control","no-store"),e.setHeader("Content-Type","application/json; charset=utf-8"),e.end(`${JSON.stringify(o)}
|
|
4
|
+
`)}function ht(e){switch(S.extname(e).toLowerCase()){case".js":case".mjs":return"text/javascript; charset=utf-8";case".css":return"text/css; charset=utf-8";case".json":return"application/json; charset=utf-8";case".html":return"text/html; charset=utf-8";case".svg":return"image/svg+xml";case".png":return"image/png";case".jpg":case".jpeg":return"image/jpeg";case".webp":return"image/webp";case".glb":return"model/gltf-binary";case".gltf":return"model/gltf+json";default:return"application/octet-stream"}}function Fe(e,r,o){let a=S.relative(e,r);if(!a||a===".."||a.startsWith(`..${S.sep}`)||S.isAbsolute(a))throw new Error(`Editor Server ${o} must be inside the canonical project root.`)}function _t(e){if(!Number.isSafeInteger(e)||e<1||e>65535)throw new Error("Editor Server port is invalid.");return e}function te(e,r){return Number.isSafeInteger(e)&&e>0?e:r}function gt(e,r){return`http://${e==="0.0.0.0"?"127.0.0.1":e}:${r}`}function H(e){return JSON.stringify(e).replace(/</g,"\\u003c").replace(/>/g,"\\u003e")}function wt(e){return e.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<")}async function Pe(e){e.listening&&await new Promise((r,o)=>{e.close(a=>a?o(a):r())})}function j(e){return e instanceof Error?e.message:String(e)}function je(e){let r=e.projectId;return typeof r=="string"&&r.trim()?r.trim():"project"}async function Ce(e){let r=await Ne(e,it);if(!r||r.length===0)throw new Error("Runtime tuning body is required.");let o=JSON.parse(r.toString("utf8"));if(!o||typeof o!="object"||Array.isArray(o))throw new Error("Runtime tuning body must be a JSON object.");return o}function Ae(e){let r=e.headers["x-fps-editor-runtime-tuning-consumer"];return typeof r=="string"&&/^[a-zA-Z0-9_-]{8,96}$/u.test(r)?r:null}function It(e,r){if(!fe(e,["projectId","kind","targets"]))throw new Error("Runtime tuning envelope contains unsupported fields.");if(e.projectId!==r)throw new Error("Runtime tuning project identity does not match.");let o=e.kind,a=e.targets;if(o!=="camera"&&o!=="light"||!Array.isArray(a)||a.length!==(o==="camera"?1:2))throw new Error("Runtime tuning intent is outside the fixed Camera/Light schema.");let f=o==="camera"?new Set(["camera"]):new Set(["environment-light","directional-light"]),p=new Set;for(let O of a){if(!O||typeof O!="object"||Array.isArray(O))throw new Error("Runtime tuning target is invalid.");let b=O;if(!fe(b,["role","targetId","sourceId","changes"]))throw new Error("Runtime tuning target contains unsupported fields.");let h=typeof b.role=="string"?b.role:"";if(!f.has(h)||p.has(h))throw new Error("Runtime tuning target role is invalid.");p.add(h);let y=b.targetId,_=typeof y=="string"?y.trim():"",E=typeof b.sourceId=="string"?b.sourceId.trim():"",m=b.changes;if(!_||_.length>160||!E||E.length>160||!m||typeof m!="object"||Array.isArray(m)||Object.keys(m).length===0||Object.keys(m).length>24)throw new Error("Runtime tuning target is invalid.");for(let[F,re]of Object.entries(m))if(!Et(h,F,re))throw new Error("Runtime tuning intent contains an invalid field.")}if(p.size!==f.size)throw new Error("Runtime tuning target roles are incomplete.");return{projectId:r,kind:o,targets:a}}var yt=new Set(["camera.alpha","camera.beta","camera.radius","camera.orthoSize","camera.fov","camera.minZ","camera.maxZ","camera.inertia"]);function Et(e,r,o){if(e==="camera")return r==="camera.projection"?o==="orthographic"||o==="perspective":r==="camera.targetOffset"?J(o,["x","y","z"]):r==="camera.targetScreenOffset"?J(o,["x","y"]):yt.has(r)&&typeof o=="number"&&Number.isFinite(o);if(e==="environment-light")return r==="enabled"?typeof o=="boolean":r==="light.intensity"?typeof o=="number"&&Number.isFinite(o):r==="light.diffuseColor"||r==="light.groundColor"?J(o,["r","g","b"]):!1;if(e==="directional-light"){if(r==="enabled")return typeof o=="boolean";if(r==="light.intensity")return typeof o=="number"&&Number.isFinite(o);if(r==="light.diffuseColor")return J(o,["r","g","b"]);if(r==="transform.rotation")return J(o,["x","y","z"])}return!1}function J(e,r){if(!e||typeof e!="object"||Array.isArray(e))return!1;let o=e;return fe(o,r)&&r.every(a=>typeof o[a]=="number"&&Number.isFinite(o[a]))}function fe(e,r){let o=new Set(r);return Object.keys(e).every(a=>o.has(a))}function Ot(e){let r=e&&typeof e=="object"&&!Array.isArray(e)?e:{},o=r.receipt&&typeof r.receipt=="object"&&!Array.isArray(r.receipt)?r.receipt:null;return{ok:r.ok===!0,...typeof r.code=="string"?{code:r.code.slice(0,96)}:{},...typeof r.message=="string"?{message:bt(r.message)}:{},...r.phase==="apply"||r.phase==="save"?{phase:r.phase}:{},...typeof r.draftApplied=="boolean"?{draftApplied:r.draftApplied}:{},...typeof r.dirty=="boolean"?{dirty:r.dirty}:{},...o?{receipt:Object.fromEntries(Object.entries(o).filter(([a,f])=>["version","updatedAt","sceneUrl"].includes(a)&&(typeof f=="string"||typeof f=="number")))}:{}}}function bt(e){return e.replace(/\/(?:Users|home|private|var|tmp)(?:\/[^\s"'<>]+)+/giu,"[redacted-path]").replace(/\b([a-z-]*(?:token|secret|authorization)[a-z-]*)\s*[:=]\s*[^\s,;]+/giu,"$1=[redacted]").replace(/\b[A-Z]:\\(?:[^\s"'<>]+\\)*[^\s"'<>]+/gu,"[redacted-path]").slice(0,320)}Rt();var He=Me.resolve(process.cwd()),C=JSON.parse(await Tt(Me.join(He,".fps-editor/current.json"),"utf8").catch(e=>{throw new Error("Editor deployment is not prepared. Run npm run prepare:server first.",{cause:e})}));if(C.schemaVersion!==4||typeof C.workerEntry!="string"||!C.projectDefinition||!Array.isArray(C.builds))throw new Error("Editor deployment state is invalid. Run npm run prepare:server again.");var he=await De({projectRoot:He,workerEntry:C.workerEntry,projectDefinition:C.projectDefinition,pluginSnapshots:C.pluginSnapshots,builds:C.builds,activeRelease:process.env.FPS_EDITOR_RELEASE?.trim()||"a",host:process.env.FPS_EDITOR_SERVER_HOST?.trim()||"127.0.0.1",port:St(process.env.FPS_EDITOR_SERVER_PORT,3012),runtimeUrl:process.env.FPS_EDITOR_RUNTIME_URL?.trim()||"http://127.0.0.1:3011",workerReadyTimeoutMs:6e4,workerHeartbeatTimeoutMs:1e4,workerRestartLimit:3,workerRestartWindowMs:6e4,workerWatchdogMode:vt(process.env.FPS_EDITOR_WORKER_WATCHDOG),testControl:process.env.FPS_EDITOR_SERVER_TEST_CONTROL==="true",controlToken:process.env.FPS_EDITOR_SERVER_CONTROL_TOKEN});he.controlToken&&console.log(`[fps-editor-server] test control token: ${he.controlToken}`);var $e=!1;for(let e of["SIGINT","SIGTERM"])process.once(e,()=>{$e||($e=!0,he.dispose().finally(()=>{process.exitCode=e==="SIGINT"?130:143}))});function Rt(){let e=Number.parseInt(process.versions.node.split(".")[0]??"",10);if(!Number.isSafeInteger(e)||e<24||e>=27)throw new Error(`fps-editor-server requires Node.js >=24 <27; current version is ${process.versions.node}.`)}function St(e,r){if(!e?.trim())return r;let o=Number(e);if(!Number.isSafeInteger(o)||o<1||o>65535)throw new Error(`FPS_EDITOR_SERVER_PORT must be a valid port, got ${e}.`);return o}function vt(e){if(!e?.trim()||e.trim()==="restart")return"restart";if(e.trim()==="observe")return"observe";throw new Error(`FPS_EDITOR_WORKER_WATCHDOG must be restart or observe, got ${e}.`)}
|