create-fuzionx 0.1.54 → 0.1.56

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/index.js CHANGED
@@ -108,11 +108,6 @@ async function createApp(name, targetDir, type = 'spa') {
108
108
  const rendered = render(content, vars);
109
109
  const destName = entry.name.replace(/\.tpl$/, '');
110
110
  await fs.writeFile(path.join(dir, destName), rendered);
111
-
112
- // .env.example → .env 도 함께 생성
113
- if (destName === '.env.example') {
114
- await fs.writeFile(path.join(dir, '.env'), rendered);
115
- }
116
111
  }
117
112
  }
118
113
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-fuzionx",
3
- "version": "0.1.54",
3
+ "version": "0.1.56",
4
4
  "description": "Create a new FuzionX application — npx create-fuzionx my-app",
5
5
  "type": "module",
6
6
  "bin": {
@@ -5,12 +5,12 @@
5
5
  # ── Bridge (Rust 엔진) ──────────────────────────
6
6
  bridge:
7
7
  port: 49080
8
- workers: 0 # 0 = CPU 코어 수 자동
8
+ workers: 1 # 0 = CPU 코어 수 자동
9
9
  worker_timeout: 30 # 워커 요청 타임아웃 (초)
10
10
 
11
11
  # ── 보안: CORS ──
12
12
  cors:
13
- enabled: false
13
+ enabled: true
14
14
  origins:
15
15
  - "*"
16
16
 
@@ -32,7 +32,7 @@ bridge:
32
32
 
33
33
  # ── 보안: IP Filter ──
34
34
  ip_filter:
35
- enabled: false
35
+ enabled: true
36
36
  whitelist: [] # CIDR 형식
37
37
  blacklist: []
38
38
 
@@ -132,7 +132,7 @@ bridge:
132
132
 
133
133
  # ── ASP 암호화 ──
134
134
  asp:
135
- enabled: false
135
+ enabled: true
136
136
  master_secret: "${ASP_SECRET:change-me-in-production}"
137
137
  header_signal: Ruxy-Enc-Mode
138
138
 
@@ -9,8 +9,8 @@
9
9
  "test": "vitest run"
10
10
  },
11
11
  "dependencies": {
12
- "@fuzionx/framework": "^0.1.54",
13
- "@fuzionx/client": "^0.1.54",
12
+ "@fuzionx/framework": "^0.1.56",
13
+ "@fuzionx/client": "^0.1.56",
14
14
  "joi": "^18.1.1"
15
15
  },
16
16
  "devDependencies": {
@@ -4,7 +4,7 @@
4
4
  "description": "Vue.js 3 SPA + Tera SSR 하이브리드. WASM 암호화 통신.",
5
5
  "features": ["auth", "board", "i18n", "asp", "wasm"],
6
6
  "dependencies": {
7
- "@fuzionx/client": "^0.1.54"
7
+ "@fuzionx/client": "^0.1.56"
8
8
  },
9
9
  "devDependencies": {},
10
10
  "spaDevDependencies": {
@@ -9,7 +9,7 @@
9
9
  "preview": "vite preview"
10
10
  },
11
11
  "dependencies": {
12
- "@fuzionx/player": "^0.1.54",
12
+ "@fuzionx/player": "^0.1.56",
13
13
  "pinia": "^3.0.4",
14
14
  "vue": "^3.5.0",
15
15
  "vue-router": "^4.5.0"
@@ -0,0 +1,7 @@
1
+ var FuzionXPlayer=(()=>{var S=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var I=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var T=(h,e)=>{for(var t in e)S(h,t,{get:e[t],enumerable:!0})},R=(h,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of I(e))!k.call(h,o)&&o!==t&&S(h,o,{get:()=>e[o],enumerable:!(i=E(e,o))||i.enumerable});return h};var y=h=>R(S({},"__esModule",{value:!0}),h);var O={};T(O,{CODEC:()=>C,DEFAULT_ICE_SERVERS:()=>u,FuzionXPublisher:()=>g,FuzionXSignaling:()=>_,FuzionXViewer:()=>m,MAX_SLOTS:()=>f,RECONNECT:()=>p,SessionMode:()=>d,SignalType:()=>c});var u=[{urls:"stun:stun.l.google.com:19302"},{urls:"stun:stun1.l.google.com:19302"}],c={JOIN:"join",OFFER:"offer",ANSWER:"answer",CANDIDATE:"candidate",PLI:"pli",LEAVE:"leave",SLOT_INFO:"slot_info",CHAT:"chat",ERROR:"error"},d={BROADCAST:"broadcast",VIDEOCHAT:"videochat"},f={[d.BROADCAST]:1,[d.VIDEOCHAT]:9},p={MAX_RETRIES:5,BASE_DELAY_MS:1e3,MAX_DELAY_MS:3e4},C={VIDEO_MIME:"video/H264",AUDIO_MIME:"audio/opus",VIDEO_CLOCK:9e4,AUDIO_CLOCK:48e3};var _=class{constructor(e){this.url=e.url,this.onMessage=e.onMessage||(()=>{}),this.onOpen=e.onOpen||(()=>{}),this.onClose=e.onClose||(()=>{}),this.onError=e.onError||(()=>{}),this.autoReconnect=e.autoReconnect!==!1,this._ws=null,this._retryCount=0,this._reconnectTimer=null,this._intentionalClose=!1}connect(){this._intentionalClose=!1,this._doConnect()}_doConnect(){try{this._ws=new WebSocket(this.url)}catch(e){this.onError(e),this._scheduleReconnect();return}this._ws.onopen=()=>{this._retryCount=0,this.onOpen()},this._ws.onmessage=e=>{try{let t=JSON.parse(e.data);this.onMessage(t)}catch{console.warn("[FuzionX] Invalid JSON:",e.data)}},this._ws.onclose=e=>{this.onClose(e),!this._intentionalClose&&this.autoReconnect&&this._scheduleReconnect()},this._ws.onerror=e=>{this.onError(e)}}send(e){return this._ws&&this._ws.readyState===WebSocket.OPEN?(this._ws.send(JSON.stringify(e)),!0):!1}sendJoin(e,t,i={}){return this.send({type:c.JOIN,peer_id:e,channel_id:t,nickname:i.nickname||null,token:i.token||null,mode:i.mode||null})}sendOffer(e){return this.send({type:c.OFFER,sdp:e})}sendAnswer(e){return this.send({type:c.ANSWER,sdp:e})}sendCandidate(e){return this.send({type:c.CANDIDATE,candidate:e.candidate,sdp_mid:e.sdpMid,sdp_m_line_index:e.sdpMLineIndex})}sendChat(e,t){return this.send({type:c.CHAT,text:e,nickname:t||null,peer_id:null})}sendPLI(){return this.send({type:c.PLI})}sendLeave(){return this.send({type:c.LEAVE})}disconnect(){this._intentionalClose=!0,clearTimeout(this._reconnectTimer),this._ws&&(this._ws.close(),this._ws=null)}get connected(){return this._ws&&this._ws.readyState===WebSocket.OPEN}_scheduleReconnect(){if(this._retryCount>=p.MAX_RETRIES){console.error("[FuzionX] Max reconnect retries reached."),this.onError(new Error("Max reconnect retries"));return}let e=Math.min(p.BASE_DELAY_MS*Math.pow(2,this._retryCount),p.MAX_DELAY_MS);this._retryCount++,console.log(`[FuzionX] Reconnecting in ${e}ms (${this._retryCount}/${p.MAX_RETRIES})`),this._reconnectTimer=setTimeout(()=>this._doConnect(),e)}};var m=class h{constructor(e){this.url=e.url||null,this.hubUrl=e.hubUrl||null,this.channelId=e.channelId,this.mode=e.mode||d.BROADCAST,this.nickname=e.nickname||null,this.token=e.token||null,this.peerId=e.peerId||`viewer-${Math.random().toString(36).slice(2,10)}`,this.autoReconnect=e.autoReconnect!==!1,this.rtcConfig=e.rtcConfig||{iceServers:u,bundlePolicy:"max-bundle",rtcpMuxPolicy:"require"},this._signaling=null,this._pc=null,this._listeners={},this._slots=new Map,this._maxSlots=f[this.mode]||1,this._candidateQueue=[],this._connected=!1}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}_emit(e,...t){(this._listeners[e]||[]).forEach(i=>i(...t))}async connect(){if(!this.url&&this.hubUrl)try{let e=await fetch(`${this.hubUrl}/api/channels/${this.channelId}`);if(!e.ok)throw new Error(`Channel not found: ${this.channelId}`);let t=await e.json();if(t.ws_url){let i=this.hubUrl.startsWith("https");this.url=t.ws_url.replace(/^ws(s?):/,i?"wss:":"ws:")}else{let o=this.hubUrl.startsWith("https")?"wss":"ws";this.url=`${o}://${t.media_ip}:${t.webrtc_port}`}}catch(e){this._emit("error",e);return}if(!this.url){this._emit("error",new Error("url \uB610\uB294 hubUrl\uC744 \uC9C0\uC815\uD574\uC57C \uD569\uB2C8\uB2E4."));return}this._signaling=new _({url:this.url,autoReconnect:this.autoReconnect,onOpen:()=>this._onSignalingOpen(),onMessage:e=>this._onSignalingMessage(e),onClose:e=>this._onSignalingClose(e),onError:e=>this._emit("error",e)}),this._signaling.connect(),this._beforeUnloadHandler=()=>{this._signaling&&this._signaling.connected&&this._signaling.sendLeave(),this._closePeerConnection()},window.addEventListener("beforeunload",this._beforeUnloadHandler)}async disconnect(){this._beforeUnloadHandler&&(window.removeEventListener("beforeunload",this._beforeUnloadHandler),this._beforeUnloadHandler=null),this._signaling&&(this._signaling.sendLeave(),await new Promise(e=>setTimeout(e,100)),this._signaling.disconnect()),this._closePeerConnection(),this._slots.clear(),this._connected=!1}chat(e){this._signaling&&this._signaling.sendChat(e,this.nickname)}requestKeyframe(){this._signaling&&this._signaling.sendPLI()}get slots(){return this._slots}_onSignalingOpen(){this._signaling.sendJoin(this.peerId,this.channelId,{nickname:this.nickname,token:this.token,mode:this.mode}),this._createPeerConnection().catch(e=>this._emit("error",e))}_onSignalingMessage(e){switch(e.type){case c.ANSWER:this._handleAnswer(e);break;case c.CANDIDATE:this._handleCandidate(e);break;case c.SLOT_INFO:this._handleSlotInfo(e);break;case c.CHAT:this._emit("chat",{peerId:e.peer_id,nickname:e.nickname,text:e.text});break;case c.ERROR:this._emit("error",new Error(e.message));break}}_onSignalingClose(e){this._closePeerConnection(),this._connected=!1,this._emit("close",e)}async _handleAnswer(e){if(this._pc)try{await this._pc.setRemoteDescription(new RTCSessionDescription({type:"answer",sdp:e.sdp}));for(let t of this._candidateQueue)await this._pc.addIceCandidate(t);this._candidateQueue=[]}catch(t){this._emit("error",t)}}async _handleCandidate(e){let t=new RTCIceCandidate({candidate:e.candidate,sdpMid:e.sdp_mid,sdpMLineIndex:e.sdp_m_line_index});if(this._pc&&this._pc.remoteDescription)try{await this._pc.addIceCandidate(t)}catch(i){console.warn("[FuzionX] ICE candidate error:",i)}else this._candidateQueue.push(t)}_handleSlotInfo(e){let t=parseInt(e.stream_id.replace("stream_",""),10);if(!e.nickname||e.nickname===""){let o=this._slots.get(t);o&&this._slots.set(t,{slotIndex:t,stream:o.stream}),this._emit("slot_remove",{slotIndex:t,senderId:e.sender_id});return}let i=this._slots.get(t)||{};this._slots.set(t,{...i,slotIndex:t,streamId:e.stream_id,nickname:e.nickname,senderId:e.sender_id}),this._emit("slot",this._slots.get(t))}async _createPeerConnection(){this._pc=new RTCPeerConnection(this.rtcConfig);let e=0;this._pc.ontrack=o=>{let n=o.track;if(n.kind==="video"){let s=e++,r=o.streams[0];r||(r=new MediaStream,r.addTrack(n));let a=this._slots.get(s)||{slotIndex:s};a.stream=r,this._slots.set(s,a),this._emit("stream",r,s),this._connected||(this._connected=!0,this._emit("connected"),this._signaling&&this._signaling.sendPLI())}},this._pc.onconnectionstatechange=()=>{let o=this._pc?.connectionState;(o==="failed"||o==="disconnected")&&this._emit("error",new Error(`PeerConnection ${o}`))};for(let o=0;o<this._maxSlots;o++)this._pc.addTransceiver("video",{direction:"recvonly"}),this._pc.addTransceiver("audio",{direction:"recvonly"});let t=await this._pc.createOffer();t.sdp=h._forceCodecs(t.sdp),await this._pc.setLocalDescription(t),await this._waitForIceGathering();let i=this._pc.localDescription?.sdp;i&&this._signaling.sendOffer(i)}_waitForIceGathering(){return new Promise(e=>{if(this._pc.iceGatheringState==="complete")return e();let t=()=>{this._pc?.iceGatheringState==="complete"&&(this._pc.removeEventListener("icegatheringstatechange",t),e())};this._pc.addEventListener("icegatheringstatechange",t),setTimeout(()=>{this._pc&&this._pc.removeEventListener("icegatheringstatechange",t),e()},150)})}static _forceCodecs(e){let t=e.split(`\r
2
+ `),i=t.findIndex(n=>n.startsWith("m=video"));if(i!==-1){let n=[],s=new Map;if(t.forEach(r=>{let a=r.match(/a=rtpmap:(\d+) H264\/90000/);a&&(n.push(a[1]),s.set(a[1],0))}),t.forEach(r=>{if(r.startsWith("a=fmtp:")){let a=r.split(" ")[0].split(":")[1];s.has(a)&&(r.includes("profile-level-id=42e01f")?s.set(a,100):r.includes("profile-level-id=42001f")&&s.set(a,80),r.includes("packetization-mode=1")&&s.set(a,(s.get(a)||0)+10))}}),n.length>0){n.sort((l,w)=>s.get(w)-s.get(l));let r=t[i].split(" "),a=r.slice(3).filter(l=>!n.includes(l));t[i]=[...r.slice(0,3),...n,...a].join(" ")}}let o=t.findIndex(n=>n.startsWith("m=audio"));if(o!==-1){let n=[];if(t.forEach(s=>{let r=s.match(/a=rtpmap:(\d+) opus\/48000/);r&&n.push(r[1])}),n.length>0){let s=t[o].split(" "),r=s.slice(3).filter(a=>!n.includes(a));t[o]=[...s.slice(0,3),...n,...r].join(" ")}}return t.join(`\r
3
+ `)}_closePeerConnection(){this._pc&&(this._pc.close(),this._pc=null),this._candidateQueue=[]}};var g=class h{constructor(e){this.whipUrl=e.whipUrl||null,this.url=e.url||null,this.hubUrl=e.hubUrl||null,this.channelId=e.channelId||null,this.mode=e.mode||d.BROADCAST,this.nickname=e.nickname||null,this.token=e.token||null,this.peerId=e.peerId||`pub-${Math.random().toString(36).slice(2,10)}`,this.autoReconnect=e.autoReconnect!==!1,this.mediaConstraints=e.media||{video:!0,audio:!0},this._externalStream=e.stream||null,this.rtcConfig=e.rtcConfig||{iceServers:u,bundlePolicy:"max-bundle",rtcpMuxPolicy:"require"},this._signaling=null,this._pc=null,this._localStream=null,this._listeners={},this._candidateQueue=[],this._whipResourceUrl=null,this._maxSlots=f[this.mode]||1,this._slots=new Map,this._connected=!1}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}_emit(e,...t){(this._listeners[e]||[]).forEach(i=>i(...t))}async connect(){try{if(!this.url&&!this.whipUrl&&this.hubUrl&&this.channelId){let e=await fetch(`${this.hubUrl}/api/channels`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({channel_id:this.channelId,source_type:"webrtc"})}),t;if(e.status===409){let i=await fetch(`${this.hubUrl}/api/channels/${this.channelId}`);if(!i.ok)throw new Error(`Channel not found: ${this.channelId}`);t=await i.json()}else if(e.ok)t=await e.json();else throw new Error(`Failed to create channel: ${this.channelId}`);if(t.ws_url){let i=this.hubUrl.startsWith("https");this.url=t.ws_url.replace(/^ws(s?):/,i?"wss:":"ws:")}else{let o=this.hubUrl.startsWith("https")?"wss":"ws";this.url=`${o}://${t.media_ip}:${t.webrtc_port}`}}if(await this._acquireMedia(),this.whipUrl)await this._connectWhip();else if(this.url)this._connectWebSocket();else throw new Error("url, hubUrl, \uB610\uB294 whipUrl \uC911 \uD558\uB098\uB97C \uC9C0\uC815\uD574\uC57C \uD569\uB2C8\uB2E4.");this._beforeUnloadHandler=()=>{this._signaling&&this._signaling.connected&&this._signaling.sendLeave(),this._closePeerConnection(),this._stopMedia()},window.addEventListener("beforeunload",this._beforeUnloadHandler)}catch(e){this._emit("error",e)}}async disconnect(){if(this._beforeUnloadHandler&&(window.removeEventListener("beforeunload",this._beforeUnloadHandler),this._beforeUnloadHandler=null),this.whipUrl&&this._whipResourceUrl){try{let e=new URL(this.whipUrl).origin;await fetch(`${e}${this._whipResourceUrl}`,{method:"DELETE"})}catch(e){console.warn("[FuzionX] WHIP DELETE error:",e)}this._whipResourceUrl=null}this._signaling&&(this._signaling.sendLeave(),await new Promise(e=>setTimeout(e,100)),this._signaling.disconnect()),this._closePeerConnection(),this._stopMedia(),this._connected=!1}chat(e){this._signaling&&this._signaling.sendChat(e,this.nickname)}get localStream(){return this._localStream}get slots(){return this._slots}async _acquireMedia(){this._externalStream?this._localStream=this._externalStream:this._localStream=await navigator.mediaDevices.getUserMedia(this.mediaConstraints),this._emit("media",this._localStream)}_stopMedia(){this._localStream&&!this._externalStream&&this._localStream.getTracks().forEach(e=>e.stop()),this._localStream=null}async _connectWhip(){this._pc=new RTCPeerConnection(this.rtcConfig),this._localStream.getTracks().forEach(s=>{this._pc.addTrack(s,this._localStream)});let e=await this._pc.createOffer();e.sdp=h._forceCodecs(e.sdp),await this._pc.setLocalDescription(e),await new Promise(s=>{this._pc.iceGatheringState==="complete"?s():(this._pc.onicegatheringstatechange=()=>{this._pc.iceGatheringState==="complete"&&s()},setTimeout(s,150))});let t=this._pc.localDescription,i=this.whipUrl;this.token&&!i.includes("token=")&&(i+=(i.includes("?")?"&":"?")+`token=${this.token}`);let o=await fetch(i,{method:"POST",headers:{"Content-Type":"application/sdp"},body:t.sdp});if(o.status!==201)throw new Error(`WHIP failed: ${o.status} ${await o.text()}`);let n=await o.text();this._whipResourceUrl=o.headers.get("location"),await this._pc.setRemoteDescription(new RTCSessionDescription({type:"answer",sdp:n})),this._pc.onconnectionstatechange=()=>{let s=this._pc?.connectionState;s==="connected"?(this._connected=!0,this._emit("ready")):(s==="failed"||s==="disconnected")&&this._emit("error",new Error(`WHIP PeerConnection ${s}`))},this._emit("ready")}_connectWebSocket(){this._signaling=new _({url:this.url,autoReconnect:this.autoReconnect,onOpen:()=>this._onSignalingOpen(),onMessage:e=>this._onSignalingMessage(e),onClose:e=>{this._closePeerConnection(),this._connected=!1,this._emit("close",e)},onError:e=>this._emit("error",e)}),this._signaling.connect()}async _onSignalingOpen(){this._signaling.sendJoin(this.peerId,this.channelId,{nickname:this.nickname,token:this.token,mode:this.mode}),await this._createPeerConnection()}async _createPeerConnection(){if(this._pc=new RTCPeerConnection(this.rtcConfig),this._localStream.getTracks().forEach(i=>{this._pc.addTrack(i,this._localStream)}),this.mode===d.VIDEOCHAT){for(let n=0;n<this._maxSlots;n++)this._pc.addTransceiver("video",{direction:"recvonly"}),this._pc.addTransceiver("audio",{direction:"recvonly"});this._pc.getTransceivers().forEach(n=>{n.sender.track&&n.direction==="recvonly"&&(n.direction="sendrecv")});let o=0;this._pc.ontrack=n=>{let s=n.track;if(s.kind==="video"){let r=o++,a=n.streams[0];a||(a=new MediaStream,a.addTrack(s));let l=this._slots.get(r)||{slotIndex:r};l.stream=a,this._slots.set(r,l),this._emit("stream",a,r)}}}this._pc.onconnectionstatechange=()=>{let i=this._pc?.connectionState;i==="connected"&&!this._connected?(this._connected=!0,this._emit("ready")):(i==="failed"||i==="disconnected")&&this._emit("error",new Error(`PeerConnection ${i}`))};let e=await this._pc.createOffer();e.sdp=h._forceCodecs(e.sdp),await this._pc.setLocalDescription(e),await this._waitForIceGathering();let t=this._pc.localDescription?.sdp;t&&this._signaling.sendOffer(t)}_waitForIceGathering(){return new Promise(e=>{if(this._pc.iceGatheringState==="complete")return e();let t=()=>{this._pc?.iceGatheringState==="complete"&&(this._pc.removeEventListener("icegatheringstatechange",t),e())};this._pc.addEventListener("icegatheringstatechange",t),setTimeout(()=>{this._pc&&this._pc.removeEventListener("icegatheringstatechange",t),e()},150)})}static _forceCodecs(e){let t=e.split(`\r
4
+ `),i=t.findIndex(n=>n.startsWith("m=video"));if(i!==-1){let n=[],s=new Map;if(t.forEach(r=>{let a=r.match(/a=rtpmap:(\d+) H264\/90000/);a&&(n.push(a[1]),s.set(a[1],0))}),t.forEach(r=>{if(r.startsWith("a=fmtp:")){let a=r.split(" ")[0].split(":")[1];s.has(a)&&(r.includes("profile-level-id=42e01f")?s.set(a,100):r.includes("profile-level-id=42001f")&&s.set(a,80),r.includes("packetization-mode=1")&&s.set(a,(s.get(a)||0)+10))}}),n.length>0){n.sort((l,w)=>s.get(w)-s.get(l));let r=t[i].split(" "),a=r.slice(3).filter(l=>!n.includes(l));t[i]=[...r.slice(0,3),...n,...a].join(" ")}}let o=t.findIndex(n=>n.startsWith("m=audio"));if(o!==-1){let n=[];if(t.forEach(s=>{let r=s.match(/a=rtpmap:(\d+) opus\/48000/);r&&n.push(r[1])}),n.length>0){let s=t[o].split(" "),r=s.slice(3).filter(a=>!n.includes(a));t[o]=[...s.slice(0,3),...n,...r].join(" ")}}return t.join(`\r
5
+ `)}_onSignalingMessage(e){switch(e.type){case c.ANSWER:this._handleAnswer(e);break;case c.CANDIDATE:this._handleCandidate(e);break;case c.SLOT_INFO:this._handleSlotInfo(e);break;case c.CHAT:this._emit("chat",{peerId:e.peer_id,nickname:e.nickname,text:e.text});break;case c.ERROR:this._emit("error",new Error(e.message));break}}async _handleAnswer(e){if(this._pc)try{await this._pc.setRemoteDescription(new RTCSessionDescription({type:"answer",sdp:e.sdp}));for(let t of this._candidateQueue)await this._pc.addIceCandidate(t);this._candidateQueue=[]}catch(t){this._emit("error",t)}}async _handleCandidate(e){let t=new RTCIceCandidate({candidate:e.candidate,sdpMid:e.sdp_mid,sdpMLineIndex:e.sdp_m_line_index});if(this._pc&&this._pc.remoteDescription)try{await this._pc.addIceCandidate(t)}catch{}else this._candidateQueue.push(t)}_handleSlotInfo(e){if(e.sender_id===this.peerId)return;let t=parseInt(e.stream_id.replace("stream_",""),10);if(!e.nickname||e.nickname===""){let o=this._slots.get(t);o&&this._slots.set(t,{slotIndex:t,stream:o.stream}),this._emit("slot_remove",{slotIndex:t,senderId:e.sender_id});return}let i=this._slots.get(t)||{};this._slots.set(t,{...i,slotIndex:t,streamId:e.stream_id,nickname:e.nickname,senderId:e.sender_id}),this._emit("slot",this._slots.get(t))}_closePeerConnection(){this._pc&&(this._pc.close(),this._pc=null),this._candidateQueue=[]}};return y(O);})();
6
+ if(typeof module!=="undefined")module.exports=FuzionXPlayer;
7
+ //# sourceMappingURL=fx-player.umd.js.map
@@ -3,7 +3,7 @@
3
3
  {% block description %}FuzionX WebRTC video chat room. Up to 9 participants.{% endblock %}
4
4
 
5
5
  {% block head %}
6
- <script src="/public/js/fuzionx-player.umd.js"></script>
6
+ <script src="/public/js/fx-player.umd.js"></script>
7
7
  <style>
8
8
  .live-role-selector{display:flex;gap:1rem;}
9
9
  .live-role-btn{flex:1;display:flex;flex-direction:column;align-items:center;gap:.4rem;padding:1.25rem;border:2px solid var(--border-color,rgba(255,255,255,.08));border-radius:12px;background:transparent;cursor:pointer;transition:all .2s;}
@@ -3,7 +3,7 @@
3
3
  {% block description %}Watch live broadcast on FuzionX WebRTC.{% endblock %}
4
4
 
5
5
  {% block head %}
6
- <script src="/public/js/fuzionx-player.umd.js"></script>
6
+ <script src="/public/js/fx-player.umd.js"></script>
7
7
  <style>
8
8
  .live-watch-layout{display:flex;height:calc(100vh - 60px);overflow:hidden;}
9
9
  .live-watch-video{flex:1;display:flex;flex-direction:column;background:#000;}
@@ -1,16 +0,0 @@
1
- # .env — FuzionX App 환경 변수
2
-
3
- # ASP 암호화 (Bridge + WASM 공유)
4
- ASP_SECRET=change-me-in-production
5
-
6
- # Auth (JWT/세션)
7
- JWT_SECRET=change-me-in-production
8
-
9
- # Client Secret (설정값 암호화 → SPA 주입)
10
- CLIENT_SECRET=change-me-in-production
11
-
12
- # Database
13
- DB_NAME={{dbName}}
14
-
15
- # Redis (세션/큐 — 미사용 시 빈 값)
16
- REDIS_URL=