club-security: self detection via currentVrcUser, settle window after own join
This commit is contained in:
1 parent
485d29af9c
commit
db2e9786f1
2 files changed
+6
-6
No files matched your search
Vendored
+3
-3
@@ -1,4 +1,4 @@
|
||||
function f(n){return typeof n=="object"&&n!==null?n:void 0}function d(n){return typeof n=="string"?n:""}function G(n){return Array.isArray(n)?n.filter(e=>typeof e=="string"):[]}function J(n){return/~group\((grp_[0-9a-f-]+)\)/i.exec(n)?.[1]??""}function q(n){let e=f(n);if(e===void 0)return;let t=d(e.id),r=d(e.displayName);if(!(t===""&&r===""))return{id:t,displayName:r,ageVerified:e.ageVerified===!0,ageVerificationStatus:d(e.ageVerificationStatus),platform:d(e.platform),tags:G(e.tags),lastLogin:d(e.lastLogin),avatarId:d(e.avatarId),avatarName:d(e.avatarName)}}function N(n){let e=f(n);if(e===void 0)return;let t=d(e.location);if(t==="")return;let r=Array.isArray(e.users)?e.users:[];return{location:t,worldId:d(e.worldId),worldName:d(e.worldName),instanceType:d(e.instanceType),groupId:J(t),users:r.flatMap(i=>{let s=q(i);return s===void 0?[]:[s]})}}function C(n){return n.ageVerificationStatus!==""||n.tags.length>0||n.lastLogin!==""}function L(n){let e=f(n);if(e===void 0)return;let t=d(e.userId);if(t==="")return;let r=Array.isArray(e.groups)?e.groups:[];return{userId:t,groupIds:r.flatMap(i=>{let s=d(f(i)?.id);return s===""?[]:[s]})}}function R(n){let e=f(n);if(e===void 0)return;let t=d(e.userId);if(t!=="")return{userId:t,avatarId:d(e.avatarId),avatarName:d(e.avatarName)}}function A(n){let e=f(n);if(e===void 0)return;let t=d(e.id);if(t!=="")return{avatarId:t,name:d(e.name),pc:d(e.pcPerf),quest:d(e.questPerf)}}function $(n){return d(f(n)?.id)}function y(n,e,t,r){return new Promise(i=>{let s=!1,a=l=>{s||(s=!0,clearTimeout(u),c(),r.signal.removeEventListener("abort",o),i(l))},o=()=>{a(void 0)},u=setTimeout(()=>{a(void 0)},r.ms),c=n.on(e,l=>{let p=t(l);p!==void 0&&a(p)});r.signal.addEventListener("abort",o,{once:!0})})}function _(n,e){return n.users.find(t=>e.userId!==""?t.id===e.userId:t.displayName===e.name)}function W(){let n=document.getElementById("modalAvatarDetail");return n!==null&&n.offsetParent!==null}var h=class{#e;#n;#t=new Map;constructor(e){this.#e=e,e.events.on("vrcCurrentInstance",t=>{let r=N(t);r!==void 0&&(this.#n=r)}),e.events.on("vrcAvatarDetail",t=>{let r=A(t);r!==void 0&&this.#t.set(r.avatarId,{name:r.name,pc:r.pc,quest:r.quest})})}get instance(){return this.#n}async collect(e,t,r){let i=this.#e.signal,[s,a,o]=await Promise.all([this.#r(e,r,i),t===""?Promise.resolve(void 0):this.#i(e,t,r,i),this.#s(e,r,i)]);return{ageVerified:s===void 0?void 0:s.ageVerified,ageStatus:s?.ageVerificationStatus??"",platform:s?.platform??"",avatar:o,inGroup:a}}async#r(e,t,r){let i=this.#n===void 0?void 0:_(this.#n,e);return i!==void 0&&C(i)?i:await y(this.#e.events,"vrcCurrentInstance",a=>{let o=N(a),u=o===void 0?void 0:_(o,e);return u!==void 0&&C(u)?u:void 0},{ms:t,signal:r})??i}async#i(e,t,r,i){if(e.userId==="")return;let s=t.toLowerCase(),a=y(this.#e.events,"vrcGroupsForNetwork",u=>{let c=L(u);return c?.userId===e.userId?c.groupIds:void 0},{ms:r,signal:i});this.#e.bridge.send("vrcGetGroupsForNetwork",{userId:e.userId});let o=await a;return o===void 0?void 0:o.some(u=>u.toLowerCase()===s)}async#s(e,t,r){if(e.userId==="")return;let i=Date.now(),s=()=>Math.max(1e3,t-(Date.now()-i)),a=this.#n===void 0?"":_(this.#n,e)?.avatarId??"",o="";if(a===""){let p=y(this.#e.events,"vrcInstanceAvatarFound",O=>{let E=R(O);return E?.userId===e.userId?E:void 0},{ms:s(),signal:r});this.#e.bridge.send("vrcGetInstanceAvatars",{userIds:[e.userId]});let g=await p;if(g===void 0)return;a=g.avatarId,o=g.avatarName}if(a==="")return o===""?void 0:{name:o,pc:"",quest:""};let u=this.#t.get(a);if(u!==void 0)return u;if(W())return this.#e.logger.debug("Avatar modal is open; not fetching performance ranks behind it."),{name:o,pc:"",quest:""};let c=y(this.#e.events,"vrcAvatarDetail",p=>{let g=A(p);return g?.avatarId===a?g:void 0},{ms:s(),signal:r});this.#e.bridge.send("vrcGetAvatarDetail",{avatarId:a});let l=await c;return l===void 0?{name:o,pc:"",quest:""}:{name:l.name===""?o:l.name,pc:l.pc,quest:l.quest}}};function F(n){return n.split(/[,\s]+/).map(e=>e.trim().toLowerCase()).filter(e=>e.length>0)}function m(n){return{instanceTypes:F(n.instanceTypes),groupId:n.groupId.trim().toLowerCase(),worldIds:F(n.worldIds)}}function K(n,e){if(n.length===0)return!0;let t=e.toLowerCase();return n.some(r=>r===t||r==="group"&&t.startsWith("group"))}function I(n,e){if(!K(n.instanceTypes,e.instanceType))return!1;let t=n.groupId.toLowerCase();if(t!==""&&e.groupId.toLowerCase()!==t)return!1;let r=n.worldIds.map(i=>i.toLowerCase());return!(r.length>0&&!r.includes(e.worldId.toLowerCase()))}function V(n){let e=[];return n.instanceTypes.length>0&&e.push(`types: ${n.instanceTypes.join(", ")}`),n.groupId!==""&&e.push(`group: ${n.groupId}`),n.worldIds.length>0&&e.push(`worlds: ${String(n.worldIds.length)}`),e.length===0?"every instance":e.join(" \xB7 ")}function Y(n){try{let e=JSON.parse(n);if(typeof e!="object"||e===null||Array.isArray(e))return{};let t={};for(let[r,i]of Object.entries(e)){if(typeof i!="object"||i===null)continue;let s=i;t[r]={name:typeof s.name=="string"?s.Line truncated
|
||||
`),timeoutSecs:8,icon:"security-high",sinks:o,urgency:v(t)==="warn"?"critical":"normal"});for(let c of u.failed)n.logger.warn(`Native target ${c.sink} failed: ${c.error}`);return}}if(n.notifications.desktopAvailable){n.notifications.desktop({title:s,subtitle:a.join(" \xB7 "),accent:v(t),...t.joiner.userId===""?{}:{friendId:t.joiner.userId}});return}n.logger.info("No desktop or VR channel is reachable: the native companion is not running and this platform has no tray toast.")}async function ee(n,e,t){if(!e.notifyDiscord)return;let r=e.discordWebhookUrl.trim();if(!X.test(r)){n.logger.warn("Discord webhook is enabled but the URL is not a discord.com webhook URL.");return}let i=k(t),s={ok:3908957,warn:15548997,info:5793266}[v(t)],a={username:"Club Security",embeds:[{title:i[0],description:i.slice(1).join(`
|
||||
`),color:s,footer:{text:`${t.instance.worldName} \xB7 ${t.instance.instanceType}`},timestamp:new Date(t.at).toISOString()}],allowed_mentions:{parse:[]}},o=await fetch(r,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(a),signal:n.signal,credentials:"omit",referrerPolicy:"no-referrer"});o.ok||n.logger.warn(`Discord webhook answered ${String(o.status)}.`)}async function P(n,e){let t=n.settings.values;t.notifyToast&&n.notifications.toast({message:B(e),ok:v(e)!=="warn"});let r=await Promise.allSettled([Z(n,t,e),ee(n,t,e)]);for(let i of r)i.status==="rejected"&&n.logger.warn(`Notification channel failed: ${String(i.reason)}`)}var j=25,x=class{#e;#n;#t=[];#r;#i;constructor(e,t){this.#e=e,this.#n=t}install(){this.#e.ui.addNavTab({label:"Club Security",icon:"security",render:e=>{this.#s(e)}}),this.#e.ui.addSettingsCard({title:"Club Security",icon:"security",render:e=>{e.appendChild(this.#e.ui.kit.description("Reports go out for joins in instances that pass every filter above. Test them from the Club Security tab."))}}),this.#e.settings.onChange(()=>{this.refresh()})}push(e){this.#t.unshift(e),this.#t.length>j&&(this.#t.length=j),this.refresh()}refresh(){let e=this.#e.ui.kit;this.#r!==void 0&&e.setChildren(this.#r,this.#o()),this.#i!==void 0&&e.setChildren(this.#i,this.#a())}#s(e){let t=this.#e.ui.kit;this.#r=t.card({title:"Status",icon:"shield"}),this.#i=t.card({title:"Recent reports",icon:"history"});let r=t.card({title:"Actions",icon:"build",children:[t.description("A test report uses the current instance and your own name, and goes to every enabled channel."),t.buttonRow(t.button({label:"Send test notification",icon:"send",onClick:()=>{this.#n.sendTest()}}),t.button({label:"Forget who joined before",icon:"delete_sweep",onClick:()=>{this.#d()}}))]});e.append(t.layout(t.pair(this.#r,r),this.#i)),this.refresh()}#o(){let e=this.#e.ui.kit,t=this.#e.settings.values,r=m(t),i=this.#n.currentInstance(),s=i!==void 0&&I(r,i),a=[t.notifyToast&&"toast",t.notifyDesktop&&"desktop",t.notifyVr&&"VR",t.notifyDiscord&&"Discord"].filter(o=>typeof o=="string");return[e.row({label:"Reporting",value:t.enabled?e.badge("ok","On"):e.badge("neutral","Off")}),e.row({label:"Watching",detail:V(r)}),e.row({label:"Current instance",detail:i===void 0?"Not in an instance":`${i.worldName} \xB7 ${i.instanceType}`,value:i===void 0?void 0:e.badge(s?"ok":"neutral",s?"Matches":"Filtered out")}),e.row({label:"Channels",detail:a.length===0?"none enabled":a.join(", ")}),e.row({label:"Players remembered",value:e.valueText(String(this.#n.memory.size))})]}#a(){let e=this.#e.ui.kit;return this.#t.length===0?[e.emptyState("No joins reported yet.")]:this.#t.map(t=>{let r=k(t),i=new Date(t.at).toLocaleTimeString();return e.row({label:`${i} \xB7 ${t.joiner.name}`,detail:r.slice(1).join(" \xB7 "),value:t.previous===void 0?e.badge("accent","New"):e.badge("warn","Rejoin")})})}async#d(){await this.#e.notifications.confirm({title:"Forget join history",message:"Every player will count as a first-time joiner again. Continue?",confirmLabel:"Forget",icon:"delete_sweep"})&&(await this.#n.memory.clear(),this.#e.notifications.toast({message:"Join history cleared."}),this.refresh())}};var M={enabled:{kind:"boolean",label:"Report joins",description:"Master switch. Filters below decide which instances count.",default:!0},instanceTypes:{kind:"string",label:"Only in these instance types",description:'Comma-separated. Leave empty for every instance. Types: public, friends+, friends, hidden, private, invite_plus, group-public, group-plus, group-members, or just "group" for all group instances.',default:"",placeholder:"group-public, group-plus"},groupId:{kind:"string",label:"Only in instances of this group",description:"A grp_\u2026 id. Leave empty for any group. When set, the report also says whether the joiner is a member.",default:"",placeholder:"grp_00000000-0000-0000-0000-000000000000"},worldIds:{kind:"string",label:"Only in these worlds",description:"Comma-separated wrld_\u2026 ids. Leave empty for any world.",default:"",placeholder:"wrld_\u2026, wrld_\u2026"},collectTimeoutSecs:{kind:"number",label:"Seconds to wait for details",description:"How long to wait for VRCNext to load the profile and avatar before reporting what is known.",default:25,min:5,max:120,step:5},notifyToast:{kind:"boolean",label:"In-app toast",default:!0},notifyDesktop:{kind:"boolean",label:"Desktop notification",description:"Through the native companion on any platform, or VRCNext\u2019s tray toast on Windows.",default:!0},notifyVr:{kind:"boolean",label:"VR overlay notification",description:"Through the native companion\u2019s VR target on any platform, or the SteamVR wrist overlay on Windows.",default:!0},notifyDiscord:{kind:"boolean",label:"Discord webhook",default:!1},discordWebhookUrl:{kind:"string",label:"Discord webhook URL",description:"Server Settings \u2192 Integrations \u2192 Webhooks. Sent straight from this page; the URL is stored locally only.",default:"",placeh
Line truncated
|
||||
function f(t){return typeof t=="object"&&t!==null?t:void 0}function d(t){return typeof t=="string"?t:""}function G(t){return Array.isArray(t)?t.filter(e=>typeof e=="string"):[]}function J(t){return/~group\((grp_[0-9a-f-]+)\)/i.exec(t)?.[1]??""}function q(t){let e=f(t);if(e===void 0)return;let n=d(e.id),r=d(e.displayName);if(!(n===""&&r===""))return{id:n,displayName:r,ageVerified:e.ageVerified===!0,ageVerificationStatus:d(e.ageVerificationStatus),platform:d(e.platform),tags:G(e.tags),lastLogin:d(e.lastLogin),avatarId:d(e.avatarId),avatarName:d(e.avatarName)}}function N(t){let e=f(t);if(e===void 0)return;let n=d(e.location);if(n==="")return;let r=Array.isArray(e.users)?e.users:[];return{location:n,worldId:d(e.worldId),worldName:d(e.worldName),instanceType:d(e.instanceType),groupId:J(n),users:r.flatMap(i=>{let s=q(i);return s===void 0?[]:[s]})}}function C(t){return t.ageVerificationStatus!==""||t.tags.length>0||t.lastLogin!==""}function L(t){let e=f(t);if(e===void 0)return;let n=d(e.userId);if(n==="")return;let r=Array.isArray(e.groups)?e.groups:[];return{userId:n,groupIds:r.flatMap(i=>{let s=d(f(i)?.id);return s===""?[]:[s]})}}function R(t){let e=f(t);if(e===void 0)return;let n=d(e.userId);if(n!=="")return{userId:n,avatarId:d(e.avatarId),avatarName:d(e.avatarName)}}function _(t){let e=f(t);if(e===void 0)return;let n=d(e.id);if(n!=="")return{avatarId:n,name:d(e.name),pc:d(e.pcPerf),quest:d(e.questPerf)}}function $(t){return d(f(t)?.id)}function y(t,e,n,r){return new Promise(i=>{let s=!1,a=l=>{s||(s=!0,clearTimeout(u),c(),r.signal.removeEventListener("abort",o),i(l))},o=()=>{a(void 0)},u=setTimeout(()=>{a(void 0)},r.ms),c=t.on(e,l=>{let p=n(l);p!==void 0&&a(p)});r.signal.addEventListener("abort",o,{once:!0})})}function A(t,e){return t.users.find(n=>e.userId!==""?n.id===e.userId:n.displayName===e.name)}function W(){let t=document.getElementById("modalAvatarDetail");return t!==null&&t.offsetParent!==null}var h=class{#e;#n;#t=new Map;constructor(e){this.#e=e,e.events.on("vrcCurrentInstance",n=>{let r=N(n);r!==void 0&&(this.#n=r)}),e.events.on("vrcAvatarDetail",n=>{let r=_(n);r!==void 0&&this.#t.set(r.avatarId,{name:r.name,pc:r.pc,quest:r.quest})})}get instance(){return this.#n}async collect(e,n,r){let i=this.#e.signal,[s,a,o]=await Promise.all([this.#r(e,r,i),n===""?Promise.resolve(void 0):this.#i(e,n,r,i),this.#s(e,r,i)]);return{ageVerified:s===void 0?void 0:s.ageVerified,ageStatus:s?.ageVerificationStatus??"",platform:s?.platform??"",avatar:o,inGroup:a}}async#r(e,n,r){let i=this.#n===void 0?void 0:A(this.#n,e);return i!==void 0&&C(i)?i:await y(this.#e.events,"vrcCurrentInstance",a=>{let o=N(a),u=o===void 0?void 0:A(o,e);return u!==void 0&&C(u)?u:void 0},{ms:n,signal:r})??i}async#i(e,n,r,i){if(e.userId==="")return;let s=n.toLowerCase(),a=y(this.#e.events,"vrcGroupsForNetwork",u=>{let c=L(u);return c?.userId===e.userId?c.groupIds:void 0},{ms:r,signal:i});this.#e.bridge.send("vrcGetGroupsForNetwork",{userId:e.userId});let o=await a;return o===void 0?void 0:o.some(u=>u.toLowerCase()===s)}async#s(e,n,r){if(e.userId==="")return;let i=Date.now(),s=()=>Math.max(1e3,n-(Date.now()-i)),a=this.#n===void 0?"":A(this.#n,e)?.avatarId??"",o="";if(a===""){let p=y(this.#e.events,"vrcInstanceAvatarFound",O=>{let E=R(O);return E?.userId===e.userId?E:void 0},{ms:s(),signal:r});this.#e.bridge.send("vrcGetInstanceAvatars",{userIds:[e.userId]});let g=await p;if(g===void 0)return;a=g.avatarId,o=g.avatarName}if(a==="")return o===""?void 0:{name:o,pc:"",quest:""};let u=this.#t.get(a);if(u!==void 0)return u;if(W())return this.#e.logger.debug("Avatar modal is open; not fetching performance ranks behind it."),{name:o,pc:"",quest:""};let c=y(this.#e.events,"vrcAvatarDetail",p=>{let g=_(p);return g?.avatarId===a?g:void 0},{ms:s(),signal:r});this.#e.bridge.send("vrcGetAvatarDetail",{avatarId:a});let l=await c;return l===void 0?{name:o,pc:"",quest:""}:{name:l.name===""?o:l.name,pc:l.pc,quest:l.quest}}};function F(t){return t.split(/[,\s]+/).map(e=>e.trim().toLowerCase()).filter(e=>e.length>0)}function m(t){return{instanceTypes:F(t.instanceTypes),groupId:t.groupId.trim().toLowerCase(),worldIds:F(t.worldIds)}}function K(t,e){if(t.length===0)return!0;let n=e.toLowerCase();return t.some(r=>r===n||r==="group"&&n.startsWith("group"))}function I(t,e){if(!K(t.instanceTypes,e.instanceType))return!1;let n=t.groupId.toLowerCase();if(n!==""&&e.groupId.toLowerCase()!==n)return!1;let r=t.worldIds.map(i=>i.toLowerCase());return!(r.length>0&&!r.includes(e.worldId.toLowerCase()))}function V(t){let e=[];return t.instanceTypes.length>0&&e.push(`types: ${t.instanceTypes.join(", ")}`),t.groupId!==""&&e.push(`group: ${t.groupId}`),t.worldIds.length>0&&e.push(`worlds: ${String(t.worldIds.length)}`),e.length===0?"every instance":e.join(" \xB7 ")}function Y(t){try{let e=JSON.parse(t);if(typeof e!="object"||e===null||Array.isArray(e))return{};let n={};for(let[r,i]of Object.entries(e)){if(typeof i!="object"||i===null)continue;let s=i;n[r]={name:typeof s.name=="string"?s.Line truncated
|
||||
`),timeoutSecs:8,icon:"security-high",sinks:o,urgency:v(n)==="warn"?"critical":"normal"});for(let c of u.failed)t.logger.warn(`Native target ${c.sink} failed: ${c.error}`);return}}if(t.notifications.desktopAvailable){t.notifications.desktop({title:s,subtitle:a.join(" \xB7 "),accent:v(n),...n.joiner.userId===""?{}:{friendId:n.joiner.userId}});return}t.logger.info("No desktop or VR channel is reachable: the native companion is not running and this platform has no tray toast.")}async function ee(t,e,n){if(!e.notifyDiscord)return;let r=e.discordWebhookUrl.trim();if(!X.test(r)){t.logger.warn("Discord webhook is enabled but the URL is not a discord.com webhook URL.");return}let i=x(n),s={ok:3908957,warn:15548997,info:5793266}[v(n)],a={username:"Club Security",embeds:[{title:i[0],description:i.slice(1).join(`
|
||||
`),color:s,footer:{text:`${n.instance.worldName} \xB7 ${n.instance.instanceType}`},timestamp:new Date(n.at).toISOString()}],allowed_mentions:{parse:[]}},o=await fetch(r,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(a),signal:t.signal,credentials:"omit",referrerPolicy:"no-referrer"});o.ok||t.logger.warn(`Discord webhook answered ${String(o.status)}.`)}async function T(t,e){let n=t.settings.values;n.notifyToast&&t.notifications.toast({message:B(e),ok:v(e)!=="warn"});let r=await Promise.allSettled([Z(t,n,e),ee(t,n,e)]);for(let i of r)i.status==="rejected"&&t.logger.warn(`Notification channel failed: ${String(i.reason)}`)}var j=25,k=class{#e;#n;#t=[];#r;#i;constructor(e,n){this.#e=e,this.#n=n}install(){this.#e.ui.addNavTab({label:"Club Security",icon:"security",render:e=>{this.#s(e)}}),this.#e.ui.addSettingsCard({title:"Club Security",icon:"security",render:e=>{e.appendChild(this.#e.ui.kit.description("Reports go out for joins in instances that pass every filter above. Test them from the Club Security tab."))}}),this.#e.settings.onChange(()=>{this.refresh()})}push(e){this.#t.unshift(e),this.#t.length>j&&(this.#t.length=j),this.refresh()}refresh(){let e=this.#e.ui.kit;this.#r!==void 0&&e.setChildren(this.#r,this.#o()),this.#i!==void 0&&e.setChildren(this.#i,this.#a())}#s(e){let n=this.#e.ui.kit;this.#r=n.card({title:"Status",icon:"shield"}),this.#i=n.card({title:"Recent reports",icon:"history"});let r=n.card({title:"Actions",icon:"build",children:[n.description("A test report uses the current instance and your own name, and goes to every enabled channel."),n.buttonRow(n.button({label:"Send test notification",icon:"send",onClick:()=>{this.#n.sendTest()}}),n.button({label:"Forget who joined before",icon:"delete_sweep",onClick:()=>{this.#d()}}))]});e.append(n.layout(n.pair(this.#r,r),this.#i)),this.refresh()}#o(){let e=this.#e.ui.kit,n=this.#e.settings.values,r=m(n),i=this.#n.currentInstance(),s=i!==void 0&&I(r,i),a=[n.notifyToast&&"toast",n.notifyDesktop&&"desktop",n.notifyVr&&"VR",n.notifyDiscord&&"Discord"].filter(o=>typeof o=="string");return[e.row({label:"Reporting",value:n.enabled?e.badge("ok","On"):e.badge("neutral","Off")}),e.row({label:"Watching",detail:V(r)}),e.row({label:"Current instance",detail:i===void 0?"Not in an instance":`${i.worldName} \xB7 ${i.instanceType}`,value:i===void 0?void 0:e.badge(s?"ok":"neutral",s?"Matches":"Filtered out")}),e.row({label:"Channels",detail:a.length===0?"none enabled":a.join(", ")}),e.row({label:"Players remembered",value:e.valueText(String(this.#n.memory.size))})]}#a(){let e=this.#e.ui.kit;return this.#t.length===0?[e.emptyState("No joins reported yet.")]:this.#t.map(n=>{let r=x(n),i=new Date(n.at).toLocaleTimeString();return e.row({label:`${i} \xB7 ${n.joiner.name}`,detail:r.slice(1).join(" \xB7 "),value:n.previous===void 0?e.badge("accent","New"):e.badge("warn","Rejoin")})})}async#d(){await this.#e.notifications.confirm({title:"Forget join history",message:"Every player will count as a first-time joiner again. Continue?",confirmLabel:"Forget",icon:"delete_sweep"})&&(await this.#n.memory.clear(),this.#e.notifications.toast({message:"Join history cleared."}),this.refresh())}};var D={enabled:{kind:"boolean",label:"Report joins",description:"Master switch. Filters below decide which instances count.",default:!0},instanceTypes:{kind:"string",label:"Only in these instance types",description:'Comma-separated. Leave empty for every instance. Types: public, friends+, friends, hidden, private, invite_plus, group-public, group-plus, group-members, or just "group" for all group instances.',default:"",placeholder:"group-public, group-plus"},groupId:{kind:"string",label:"Only in instances of this group",description:"A grp_\u2026 id. Leave empty for any group. When set, the report also says whether the joiner is a member.",default:"",placeholder:"grp_00000000-0000-0000-0000-000000000000"},worldIds:{kind:"string",label:"Only in these worlds",description:"Comma-separated wrld_\u2026 ids. Leave empty for any world.",default:"",placeholder:"wrld_\u2026, wrld_\u2026"},settleSecs:{kind:"number",label:"Seconds to ignore after you join",description:"When you enter an instance, VRChat logs a join for everyone already there. Joins inside this window are remembered but not reported.",default:15,min:3,max:120,step:1},collectTimeoutSecs:{kind:"number",label:"Seconds to wait for details",description:"How long to wait for VRCNext to load the profile and avatar before reporting what is known.",default:25,min:5,max:120,step:5},notifyToast:{kind:"boolean",label:"In-app toast",default:!0},notifyDesktop:{kind:"boolean",label:"Desktop notification",description:"Through the native companion on any platform, or VRCNext\u2019s tray toast on Windows.",default:!0},notifyVr:{kind:"boolean",label:"VR overlay notification",description:"Through the native companion\u2019s VR target on any platform, or the SteamVR wrist overlay on Windows.",default:!0},notifyDiscord:{kind:"boole
Line truncated
|
||||
//# sourceMappingURL=club-security.js.map
|
||||
Vendored
+3
-3
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../src/vrcnext-data.ts", "../src/collector.ts", "../src/filters.ts", "../src/memory.ts", "../src/notify.ts", "../src/panel.ts", "../src/settings.ts", "../src/index.ts"],
|
||||
"sourcesContent": ["/**\n * Narrowers for the VRCNext events this plugin consumes.\n *\n * None of these events are in the API's verified map, so every payload arrives as `unknown`.\n * Shapes were read out of VRCNext 2026.61.2: `InstanceController.PushCurrentInstanceFromCache`,\n * `GroupsController` (`vrcGetGroupsForNetwork`), `FriendsController` (`vrcGetInstanceAvatars`)\n * and `MessageRouter` (`vrcGetAvatarDetail`).\n */\n\nexport interface InstanceUser {\n readonly id: string;\n readonly displayName: string;\n readonly ageVerified: boolean;\n /** VRChat's own status string, e.g. `18+`, `verified`, `hidden`. Empty until the profile loaded. */\n readonly ageVerificationStatus: string;\n readonly platform: string;\n /** Present once VRCNext fetched the profile; an empty list means it has not yet. */\n readonly tags: readonly string[];\n readonly lastLogin: string;\n readonly avatarId: string;\n readonly avatarName: string;\n}\n\nexport interface CurrentInstance {\n readonly location: string;\n readonly worldId: string;\n readonly worldName: string;\n readonly instanceType: string;\n /** Parsed from `~group(grp_\u2026)` in the location; empty for non-group instances. */\n readonly groupId: string;\n readonly users: readonly InstanceUser[];\n}\n\nfunction rec(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null ? (value as Record<string, unknown>) : undefined;\n}\n\nfunction str(value: unknown): string {\n return typeof value === 'string' ? value : '';\n}\n\nfunction strings(value: unknown): readonly string[] {\n return Array.isArray(value) ? value.filter((v): v is string => typeof v === 'string') : [];\n}\n\nexport function groupIdOf(location: string): string {\n const match = /~group\\((grp_[0-9a-f-]+)\\)/i.exec(location);\n return match?.[1] ?? '';\n}\n\nfunction toInstanceUser(value: unknown): InstanceUser | undefined {\n const r = rec(value);\n if (r === undefined) return undefined;\n const id = str(r['id']);\n const displayName = str(r['displayName']);\n if (id === '' && displayName === '') return undefined;\n return {\n id,\n displayName,\n ageVerified: r['ageVerified'] === true,\n ageVerificationStatus: str(r['ageVerificationStatus']),\n platform: str(r['platform']),\n tags: strings(r['tags']),\n lastLogin: str(r['lastLogin']),\n avatarId: str(r['avatarId']),\n avatarName: str(r['avatarName']),\n };\n}\n\n/** `undefined` for the `{ empty: true }` and `{ error }` variants. */\nexport function toCurrentInstance(payload: unknown): CurrentInstance | undefined {\n const r = rec(payload);\n if (r === undefined) return undefined;\n const location = str(r['location']);\n if (location === '') return undefined;\n const rawUsers = Array.isArray(r['users']) ? r['users'] : [];\n return {\n location,\n worldId: str(r['worldId']),\n worldName: str(r['worldName']),\n instanceType: str(r['instanceType']),\n groupId: groupIdOf(location),\n users: rawUsers.flatMap((u) => {\n const user = toInstanceUser(u);\n return user === undefined ? [] : [user];\n }),\n };\n}\n\n/** VRCNext only fills these once it has fetched the profile from the API. */\nexport function profileLoaded(user: InstanceUser): boolean {\n return user.ageVerificationStatus !== '' || user.tags.length > 0 || user.lastLogin !== '';\n}\n\nexport interface UserGroups {\n readonly userId: string;\n readonly groupIds: readonly string[];\n}\n\nexport function toUserGroups(payload: unknown): UserGroups | undefined {\n const r = rec(payload);\n if (r === undefined) return undefined;\n const userId = str(r['userId']);\n if (userId === '') return undefined;\n const groups = Array.isArray(r['groups']) ? r['groups'] : [];\n return {\n userId,\n groupIds: groups.flatMap((g) => {\n const id = str(rec(g)?.['id']);\n return id === '' ? [] : [id];\n }),\n };\n}\n\nexport interface InstanceAvatar {\n readonly userId: string;\n readonly avatarId: string;\n readonly avatarName: string;\n}\n\nexport function toInstanceAvatar(payload: unknown): InstanceAvatar | undefined {\n const r = rec(payload);\n if (r === undefined) return undefined;\n const userId = str(r['userId']);\n if (userId === '') return undefined;\n return { userId, avatarId: str(r['avatarId']), avatarName: str(r['avatarName']) };\n}\n\nexport interface AvatarPerformance {\n readonly avatarId: string;\n readonly name: string;\n readonly pc: string;\n readonly quest: string;\n}\n\nexport function toAvatarPerformance(payload: unknown): AvatarPerformance | undefined {\n const r = rec(payload);\n if (r === undefined) return undefined;\n const avatarId = str(r['id']);\n if (avatarId === '') return undefined;\n return {\n avatarId,\n name: str(r['name']),\n pc: str(r['pcPerf']),\n quest: str(r['questPerf']),\n };\n}\n\n/** The signed-in account, from the `vrcUser` event VRCNext sends after login. */\nexport fuLine truncated
|
||||
"mappings": "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 truncated
|
||||
"names": ["rec", "value", "str", "strings", "v", "groupIdOf", "location", "toInstanceUser", "r", "id", "displayName", "toCurrentInstance", "payload", "rawUsers", "u", "user", "profileLoaded", "toUserGroups", "userId", "groups", "g", "toInstanceAvatar", "toAvatarPerformance", "avatarId", "toSelfId", "waitFor", "events", "type", "pick", "options", "resolve", "done", "finish", "value", "timer", "unsubscribe", "onAbort", "payload", "findUser", "instance", "joiner", "u", "avatarModalOpen", "modal", "FactCollector", "#ctx", "#latest", "#perfCache", "ctx", "toCurrentInstance", "perf", "toAvatarPerformance", "groupId", "deadlineMs", "signal", "profile", "inGroup", "avatar", "#profile", "#membership", "#avatar", "ms", "current", "profileLoaded", "user", "wanted", "pending", "groups", "toUserGroups", "groupIds", "id", "started", "remaining", "avatarId", "avatarName", "found", "toInstanceAvatar", "cached", "splitList", "value", "s", "filterFrom", "values", "typeMatches", "wanted", "actual", "type", "w", "instanceMatches", "filter", "instance", "groupId", "worldIds", "describeFilter", "parts", "parse", "raw", "value", "out", "key", "entry", "e", "trimmed", "map", "entries", "a", "b", "JoinMemory", "#store", "#map", "store", "name", "location", "before", "now", "DISCORD_WEBHOOK", "yesNo", "value", "unknown", "rank", "rejoinText", "previous", "when", "reportLines", "report", "facts", "age", "lines", "reportSummary", "bits", "accentFor", "nativeSinks", "ctx", "wantDesktop", "wantVr", "t", "sendDesktopAndVr", "values", "title", "sinks", "result", "failure", "sendDiscord", "url", "colour", "body", "response", "notifyAll", "results", "MAX_SHOWN", "ReportPanel", "#ctx", "#deps", "#reports", "#status", "#list", "ctx", "deps", "tab", "#render", "card", "report", "k", "#statusRows", "#reportRows", "actions", "#clearMemory", "values", "filter", "filterFrom", "instance", "matches", "instanceMatches", "channels", "c", "describeFilter", "lines", "reportLines", "time", "settings", "JOIN_EVENT", "selfIdFromPage", "user", "id", "ClubSecurity", "#ctx", "#collector", "#memory", "#panel", "#selfId", "#selfName", "#inFlight", "ctx", "FactCollector", "JoinMemory", "ReportPanel", "#sendTest", "payload", "toSelfId", "name", "entry", "#onJoin", "joiner", "values", "#isSelf", "instance", "filter", "filterFrom", "instanceMatches", "key", "previous", "facts", "report", "notifyAll", "error", "me", "index_default", "settings"]
|
||||
"sourcesContent": ["/**\n * Narrowers for the VRCNext events this plugin consumes.\n *\n * None of these events are in the API's verified map, so every payload arrives as `unknown`.\n * Shapes were read out of VRCNext 2026.61.2: `InstanceController.PushCurrentInstanceFromCache`,\n * `GroupsController` (`vrcGetGroupsForNetwork`), `FriendsController` (`vrcGetInstanceAvatars`)\n * and `MessageRouter` (`vrcGetAvatarDetail`).\n */\n\nexport interface InstanceUser {\n readonly id: string;\n readonly displayName: string;\n readonly ageVerified: boolean;\n /** VRChat's own status string, e.g. `18+`, `verified`, `hidden`. Empty until the profile loaded. */\n readonly ageVerificationStatus: string;\n readonly platform: string;\n /** Present once VRCNext fetched the profile; an empty list means it has not yet. */\n readonly tags: readonly string[];\n readonly lastLogin: string;\n readonly avatarId: string;\n readonly avatarName: string;\n}\n\nexport interface CurrentInstance {\n readonly location: string;\n readonly worldId: string;\n readonly worldName: string;\n readonly instanceType: string;\n /** Parsed from `~group(grp_\u2026)` in the location; empty for non-group instances. */\n readonly groupId: string;\n readonly users: readonly InstanceUser[];\n}\n\nfunction rec(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null ? (value as Record<string, unknown>) : undefined;\n}\n\nfunction str(value: unknown): string {\n return typeof value === 'string' ? value : '';\n}\n\nfunction strings(value: unknown): readonly string[] {\n return Array.isArray(value) ? value.filter((v): v is string => typeof v === 'string') : [];\n}\n\nexport function groupIdOf(location: string): string {\n const match = /~group\\((grp_[0-9a-f-]+)\\)/i.exec(location);\n return match?.[1] ?? '';\n}\n\nfunction toInstanceUser(value: unknown): InstanceUser | undefined {\n const r = rec(value);\n if (r === undefined) return undefined;\n const id = str(r['id']);\n const displayName = str(r['displayName']);\n if (id === '' && displayName === '') return undefined;\n return {\n id,\n displayName,\n ageVerified: r['ageVerified'] === true,\n ageVerificationStatus: str(r['ageVerificationStatus']),\n platform: str(r['platform']),\n tags: strings(r['tags']),\n lastLogin: str(r['lastLogin']),\n avatarId: str(r['avatarId']),\n avatarName: str(r['avatarName']),\n };\n}\n\n/** `undefined` for the `{ empty: true }` and `{ error }` variants. */\nexport function toCurrentInstance(payload: unknown): CurrentInstance | undefined {\n const r = rec(payload);\n if (r === undefined) return undefined;\n const location = str(r['location']);\n if (location === '') return undefined;\n const rawUsers = Array.isArray(r['users']) ? r['users'] : [];\n return {\n location,\n worldId: str(r['worldId']),\n worldName: str(r['worldName']),\n instanceType: str(r['instanceType']),\n groupId: groupIdOf(location),\n users: rawUsers.flatMap((u) => {\n const user = toInstanceUser(u);\n return user === undefined ? [] : [user];\n }),\n };\n}\n\n/** VRCNext only fills these once it has fetched the profile from the API. */\nexport function profileLoaded(user: InstanceUser): boolean {\n return user.ageVerificationStatus !== '' || user.tags.length > 0 || user.lastLogin !== '';\n}\n\nexport interface UserGroups {\n readonly userId: string;\n readonly groupIds: readonly string[];\n}\n\nexport function toUserGroups(payload: unknown): UserGroups | undefined {\n const r = rec(payload);\n if (r === undefined) return undefined;\n const userId = str(r['userId']);\n if (userId === '') return undefined;\n const groups = Array.isArray(r['groups']) ? r['groups'] : [];\n return {\n userId,\n groupIds: groups.flatMap((g) => {\n const id = str(rec(g)?.['id']);\n return id === '' ? [] : [id];\n }),\n };\n}\n\nexport interface InstanceAvatar {\n readonly userId: string;\n readonly avatarId: string;\n readonly avatarName: string;\n}\n\nexport function toInstanceAvatar(payload: unknown): InstanceAvatar | undefined {\n const r = rec(payload);\n if (r === undefined) return undefined;\n const userId = str(r['userId']);\n if (userId === '') return undefined;\n return { userId, avatarId: str(r['avatarId']), avatarName: str(r['avatarName']) };\n}\n\nexport interface AvatarPerformance {\n readonly avatarId: string;\n readonly name: string;\n readonly pc: string;\n readonly quest: string;\n}\n\nexport function toAvatarPerformance(payload: unknown): AvatarPerformance | undefined {\n const r = rec(payload);\n if (r === undefined) return undefined;\n const avatarId = str(r['id']);\n if (avatarId === '') return undefined;\n return {\n avatarId,\n name: str(r['name']),\n pc: str(r['pcPerf']),\n quest: str(r['questPerf']),\n };\n}\n\n/** The signed-in account, from the `vrcUser` event VRCNext sends after login. */\nexport fuLine truncated
|
||||
"mappings": "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 truncated
|
||||
"names": ["rec", "value", "str", "strings", "v", "groupIdOf", "location", "toInstanceUser", "r", "id", "displayName", "toCurrentInstance", "payload", "rawUsers", "u", "user", "profileLoaded", "toUserGroups", "userId", "groups", "g", "toInstanceAvatar", "toAvatarPerformance", "avatarId", "toSelfId", "waitFor", "events", "type", "pick", "options", "resolve", "done", "finish", "value", "timer", "unsubscribe", "onAbort", "payload", "findUser", "instance", "joiner", "u", "avatarModalOpen", "modal", "FactCollector", "#ctx", "#latest", "#perfCache", "ctx", "toCurrentInstance", "perf", "toAvatarPerformance", "groupId", "deadlineMs", "signal", "profile", "inGroup", "avatar", "#profile", "#membership", "#avatar", "ms", "current", "profileLoaded", "user", "wanted", "pending", "groups", "toUserGroups", "groupIds", "id", "started", "remaining", "avatarId", "avatarName", "found", "toInstanceAvatar", "cached", "splitList", "value", "s", "filterFrom", "values", "typeMatches", "wanted", "actual", "type", "w", "instanceMatches", "filter", "instance", "groupId", "worldIds", "describeFilter", "parts", "parse", "raw", "value", "out", "key", "entry", "e", "trimmed", "map", "entries", "a", "b", "JoinMemory", "#store", "#map", "store", "name", "location", "before", "now", "DISCORD_WEBHOOK", "yesNo", "value", "unknown", "rank", "rejoinText", "previous", "when", "reportLines", "report", "facts", "age", "lines", "reportSummary", "bits", "accentFor", "nativeSinks", "ctx", "wantDesktop", "wantVr", "t", "sendDesktopAndVr", "values", "title", "sinks", "result", "failure", "sendDiscord", "url", "colour", "body", "response", "notifyAll", "results", "MAX_SHOWN", "ReportPanel", "#ctx", "#deps", "#reports", "#status", "#list", "ctx", "deps", "tab", "#render", "card", "report", "k", "#statusRows", "#reportRows", "actions", "#clearMemory", "values", "filter", "filterFrom", "instance", "matches", "instanceMatches", "channels", "c", "describeFilter", "lines", "reportLines", "time", "settings", "JOIN_EVENT", "WORLD_JOIN_EVENT", "selfFromPage", "ClubSecurity", "#ctx", "#collector", "#memory", "#panel", "#selfId", "#selfName", "#inFlight", "#settledAt", "ctx", "FactCollector", "JoinMemory", "ReportPanel", "#sendTest", "payload", "id", "toSelfId", "name", "#startSettling", "entry", "#onJoin", "joiner", "values", "#isSelf", "instance", "filter", "filterFrom", "instanceMatches", "key", "previous", "facts", "report", "notifyAll", "error", "#self", "page", "self", "me", "u", "index_default", "settings"]
|
||||
}
|
||||
Reference in new issue
Block a user