var a=` .ks-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 10px; padding: 10px 0; } .ks-stat { background: var(--bg-input); border-radius: 10px; padding: 12px 14px; } .ks-stat-label { font-size: calc(11px + var(--fs-off, 0px)); color: var(--tx3); } .ks-stat-value { font-size: calc(20px + var(--fs-off, 0px)); font-weight: 600; color: var(--tx0); font-variant-numeric: tabular-nums; } .ks-log { max-height: 220px; overflow-y: auto; font-family: ui-monospace, monospace; font-size: calc(11px + var(--fs-off, 0px)); color: var(--tx2); background: var(--bg-input); border-radius: 8px; padding: 8px 10px; } .ks-log-line { white-space: pre-wrap; word-break: break-word; } .ks-log-line + .ks-log-line { margin-top: 3px; } `;function l(e){let n=document.createElement("div");return n.className="ks-log",e.appendChild(n),{append(t){let i=document.createElement("div");i.className="ks-log-line";let o=new Date().toLocaleTimeString();for(i.textContent=`${o} ${t}`,n.appendChild(i);n.childElementCount>200;)n.firstElementChild?.remove();n.scrollHeight-n.scrollTop-n.clientHeight<40&&(n.scrollTop=n.scrollHeight)},clear(){n.replaceChildren()}}}var u={watchGameLog:{kind:"boolean",label:"Follow the VRChat game log",description:"Streams player joins and world changes into the panel below.",default:!0},oscParameter:{kind:"string",label:"OSC parameter to pulse",description:"Sent to /avatar/parameters/ by the dashboard button.",default:"VRCEmote",placeholder:"VRCEmote"},oscValue:{kind:"number",label:"OSC value",default:1,min:0,max:255,step:1},verbosity:{kind:"select",label:"Log verbosity",default:"normal",options:[{value:"quiet",label:"Quiet"},{value:"normal",label:"Normal"},{value:"loud",label:"Everything"}]}},be={id:"kitchen-sink",settings:u,activate(e){let n={gameLogCount:0,oscParamCount:0,panel:void 0,log:t=>{e.settings.get("verbosity")!=="quiet"&&(e.logger.info(t),n.panel?.append(t))}};e.ui.injectCss(a),m(e),h(e,n),v(e,n),b(e,n),y(e,n),S(e,n),C(e,n),_(e,n),w(e,n),k(e,n),e.logger.info(`Kitchen Sink v${e.version} ready.`)},deactivate(){}};function m(e){e.disposables.add(e.settings.onChange(n=>{e.logger.debug(`Settings changed; verbosity is now ${n.verbosity}.`)}))}function h(e,n){e.events.on("friendTimelineEvent",t=>{n.log(`[friend] ${t.friendName} \u2192 ${t.type}`)}),e.events.on("vrcCurrentInstance",t=>{if(typeof t!="object"||t===null)return;let i=t.worldName;typeof i=="string"&&n.log(`[instance] now in ${i}`)}),e.events.onAny(t=>{e.settings.get("verbosity")==="loud"&&e.logger.debug(`event ${t.type}`)})}function v(e,n){e.gameLog.on(t=>{e.settings.get("watchGameLog")&&(n.gameLogCount+=1,n.log(`[gamelog] ${t.type}: ${t.message}`))}),e.gameLog.onType("gl_player_join",t=>{n.log(`[join] ${t.message}`)}),e.gameLog.history(e.signal).then(t=>{e.logger.info(`Game log backlog: ${String(t.length)} entries.`)}).catch(t=>{e.signal.aborted||e.logger.warn(`Could not read the game log: ${String(t)}`)})}function b(e,n){if(!e.osc.available){n.log("[osc] OSC is Windows-only in VRCNext; skipping.");return}e.osc.connect(),e.osc.onParam(t=>{n.oscParamCount+=1,e.settings.get("verbosity")==="loud"&&n.log(`[osc] ${t.name} = ${String(t.value)}`)}),e.osc.onAvatarChange(t=>{n.log(`[osc] avatar ${t.avatarId} with ${String(t.parameters.length)} parameters`)})}function c(e){if(!e.osc.available)return"OSC unavailable (Windows only)";let n=e.settings.get("oscParameter"),t=e.settings.get("oscValue");return e.osc.send(n,"int",t),`${n} = ${String(t)}`}function y(e,n){e.deepLinks.onPrefix("wrld",t=>{n.log(`[link] world ${t.id}`)}),e.deepLinks.on(t=>{n.log(`[link] ${t.prefix}:${t.id}${t.action?` (${t.action})`:""}`)})}function S(e,n){e.router.get("stats",()=>Response.json({gameLogEvents:n.gameLogCount,oscParams:n.oscParamCount,verbosity:e.settings.get("verbosity")})),e.router.get("greet/:name",t=>Response.json({hello:t.params.name??"world"})),e.router.post("osc/pulse",()=>Response.json({sent:c(e)})),e.logger.info(`Routes mounted at ${e.router.base.pathname}`)}function C(e,n){e.contextMenu.contribute(t=>{let i=[{kind:"divider"},{kind:"item",icon:"auto_awesome",label:"Kitchen Sink: log this element",onSelect:()=>{n.log(`[ctx] ${t.element.tagName.toLowerCase()}`)}},{kind:"submenu",icon:"tune",label:"Kitchen Sink: verbosity",items:()=>u.verbosity.options.map(o=>({kind:"item",icon:"adjust",label:o.label,checked:e.settings.get("verbosity")===o.value,onSelect:()=>{e.settings.set("verbosity",o.value)}}))}];if(t.entity!==void 0){let o=t.entity;i.push({kind:"item",icon:"content_copy",label:`Copy ${o.type} id`,onSelect:()=>{navigator.clipboard.writeText(o.id)}})}return i})}function _(e,n){e.gameLog.onType("gl_player_join",t=>{let i=t.message;e.notifications.toast({message:`${i} joined.`}),e.notifications.desktopAvailable?e.notifications.desktop({title:"Player joined",subtitle:i,accent:"info"}):n.log("[notify] desktop/VR notifications are Windows-only.")}),e.events.on("friendTimelineEvent",t=>{t.type==="online"&&e.notifications.notifToast({kind:"notification",sender:t.friendName,message:"came online"})})}async function w(e,n){if(!await e.native.ready){n.log(`[native] no companion at ${e.native.endpoint}; VR targets unavailable.`);return}let t=await e.native.targets();n.log(`[native] targets: ${t.map(o=>o.name).join(", ")||"none"}`),e.gameLog.onType("gl_player_join",o=>{let s=o.message;e.native.notify({title:"Player joined",content:s,timeoutSecs:4,icon:"user-available",overrides:{wayvr:{content:`${s} joined the instance`,height:200,opacity:.85,alwaysShow:!0}}})}),e.events.on("friendTimelineEvent",o=>{o.type==="online"&&e.native.notify({title:o.friendName,content:"came online",sinks:["wayvr"],timeoutSecs:3,opacity:.7})});let i=await e.native.describe();i!==void 0&&n.log(`[native] companion ${i.version}, services: ${Object.keys(i.services).join(", ")}`)}function k(e,n){e.ui.addDashboardCard({title:"Kitchen Sink",icon:"auto_awesome",order:10,render:t=>{let i=document.createElement("div");i.className="ks-grid",i.append(d("Game log events",()=>n.gameLogCount),d("OSC parameters",()=>n.oscParamCount)),t.appendChild(i);let o=document.createElement("button");o.textContent="Send OSC pulse",o.addEventListener("click",()=>{e.ui.toast({message:`Sent ${c(e)}.`})}),t.appendChild(o)}}),N(e,n),e.ui.addSettingsCard({title:"Kitchen Sink",icon:"auto_awesome",render:t=>{t.appendChild(e.ui.createToggleRow("Follow the VRChat game log",e.settings.get("watchGameLog"),o=>{e.settings.set("watchGameLog",o)}));let i=document.createElement("button");i.textContent="Reset settings",i.addEventListener("click",()=>{e.notifications.confirm({title:"Reset Kitchen Sink",message:"Restore every Kitchen Sink setting to its default?",confirmLabel:"Reset",icon:"restart_alt"}).then(async o=>{o&&(await e.settings.reset(),e.notifications.toast({message:"Kitchen Sink settings reset."}))})}),t.appendChild(i)}})}function N(e,n){e.ui.addNavTab({label:"Kitchen Sink",icon:"auto_awesome",render:t=>{let i=e.ui.kit,o=i.card({title:"Live activity",icon:"radar"});n.panel=l(o);let s=i.emptyState("No request yet.");t.append(i.layout(i.grid([i.card({title:"Counters",icon:"bolt",children:[i.stat({label:"Game log events",value:String(n.gameLogCount)}),i.stat({label:"OSC parameters",value:String(n.oscParamCount)})]}),i.card({title:"Capabilities",icon:"tune",children:[i.row({label:"OSC",value:e.osc.available?i.badge("ok","Ready"):i.badge("warn","Windows only"),detail:"Sent through VRCNext\u2019s own sockets."}),i.row({label:"Native companion",value:e.native.available?i.badge("ok","Connected"):i.badge("neutral","Not running"),detail:e.native.endpoint}),i.toggleRow({label:"Follow the game log",detail:"Mirrors VRChat log lines into the panel below.",value:e.settings.get("watchGameLog"),onChange:r=>{e.settings.set("watchGameLog",r)}})]}),i.card({title:"In-page routes",icon:"account_tree",children:[i.description("Plugin routes are reachable from this page only, never from curl."),i.buttonRow(i.button({label:"GET stats",icon:"download",onClick:()=>{e.router.fetch("stats").then(async r=>{s.textContent=await r.text()}).catch(r=>{s.textContent=String(r)})}})),s]})]),o))}})}function d(e,n){let t=document.createElement("div");t.className="ks-stat";let i=document.createElement("div");i.className="ks-stat-label",i.textContent=e;let o=document.createElement("div");return o.className="ks-stat-value",o.textContent=String(n()),new IntersectionObserver(r=>{for(let g of r)g.isIntersecting&&(o.textContent=String(n()))}).observe(t),t.append(i,o),t}export{be as default}; //# sourceMappingURL=kitchen-sink.js.map