import{j as C}from"./jsx-runtime-agliiQSw.js";import{o as m,s as d,as as N,a1 as R,aJ as G,l as w,a as k,a2 as W}from"./types-BzMnrBW1.js";import{r as h}from"./index-BtyHvDgk.js";import{f as K}from"./chunk-UIGDSWPH-1hkfewjj.js";import{u as X}from"./online-BJUQDd5b.js";import{u as v,a as Z}from"./root-loader-CIAkTEfn.js";(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{};e.SENTRY_RELEASE={id:"8bd8bc3153d70a1c10ccde8d38796bd67282553d"}}catch{}})();const V="epic-web-presence",ee=`https://epic-web-presence.kentcdodds.partykit.dev/parties/main/${V}`,te=m({updatesAvailable:R().nullable().optional(),commitsAhead:N().nullable().optional(),commitsBehind:N().nullable().optional(),localCommit:d().nullable().optional(),remoteCommit:d().nullable().optional()}),H=m({workshopTitle:d().nullable().optional(),origin:d().nullable().optional(),productHost:d().nullable().optional(),exercise:m({type:G([w("problem"),w("solution")]).nullable().optional(),exerciseNumber:N().nullable().optional(),stepNumber:N().nullable().optional()}).nullable().optional(),epicshopVersion:d().nullable().optional(),repoStatus:te.nullable().optional(),lastUpdatedAt:d().nullable().optional()}),I=m({id:d(),hasAccess:R().nullable().optional(),avatarUrl:d().nullable().optional(),imageUrlSmall:d().nullable().optional(),imageUrlLarge:d().nullable().optional(),name:d().nullable().optional(),optOut:R().nullable().optional(),loggedInProductHosts:k(d()).nullable().optional(),location:H.nullable().optional(),locations:k(H).nullable().optional()}),se=m({type:w("remove-user"),payload:m({id:d()})}).or(m({type:w("add-user"),payload:I})).or(m({type:w("presence"),payload:m({users:k(I)})}));m({users:k(I)});const oe={"www.epicreact.dev":"🚀","www.epicai.pro":"⚡","www.epicweb.dev":"🌌"};function Le(e){return e?oe[e]??null:null}(!globalThis.EventTarget||!globalThis.Event)&&console.error(`
  PartySocket requires a global 'EventTarget' class to be available!
  You can polyfill this global by adding this to your code before any partysocket imports: 
  
  \`\`\`
  import 'partysocket/event-target-polyfill';
  \`\`\`
  Please file an issue at https://github.com/partykit/partykit if you're still having trouble.
`);var Q=class extends Event{message;error;constructor(e,t){super("error",t),this.message=e.message,this.error=e}},B=class extends Event{code;reason;wasClean=!0;constructor(e=1e3,t="",s){super("close",s),this.code=e,this.reason=t}},L={Event,ErrorEvent:Q,CloseEvent:B};function re(e,t){if(!e)throw new Error(t)}function ne(e){return new e.constructor(e.type,e)}function ie(e){return"data"in e?new MessageEvent(e.type,e):"code"in e||"reason"in e?new B(e.code||1999,e.reason||"unknown reason",e):"error"in e?new Q(e.error,e):new Event(e.type,e)}var M,ae=typeof process<"u"&&typeof((M=process.versions)==null?void 0:M.node)<"u"&&typeof document>"u",P=ae?ie:ne,g={maxReconnectionDelay:1e4,minReconnectionDelay:1e3+Math.random()*4e3,minUptime:5e3,reconnectionDelayGrowFactor:1.3,connectionTimeout:4e3,maxRetries:Number.POSITIVE_INFINITY,maxEnqueuedMessages:Number.POSITIVE_INFINITY},D=!1,ce=class b extends EventTarget{_ws;_retryCount=-1;_uptimeTimeout;_connectTimeout;_shouldReconnect=!0;_connectLock=!1;_binaryType="blob";_closeCalled=!1;_messageQueue=[];_debugLogger=console.log.bind(console);_url;_protocols;_options;constructor(t,s,o={}){super(),this._url=t,this._protocols=s,this._options=o,this._options.startClosed&&(this._shouldReconnect=!1),this._options.debugLogger&&(this._debugLogger=this._options.debugLogger),this._connect()}static get CONNECTING(){return 0}static get OPEN(){return 1}static get CLOSING(){return 2}static get CLOSED(){return 3}get CONNECTING(){return b.CONNECTING}get OPEN(){return b.OPEN}get CLOSING(){return b.CLOSING}get CLOSED(){return b.CLOSED}get binaryType(){return this._ws?this._ws.binaryType:this._binaryType}set binaryType(t){this._binaryType=t,this._ws&&(this._ws.binaryType=t)}get retryCount(){return Math.max(this._retryCount,0)}get bufferedAmount(){return this._messageQueue.reduce((s,o)=>(typeof o=="string"?s+=o.length:o instanceof Blob?s+=o.size:s+=o.byteLength,s),0)+(this._ws?this._ws.bufferedAmount:0)}get extensions(){return this._ws?this._ws.extensions:""}get protocol(){return this._ws?this._ws.protocol:""}get readyState(){return this._ws?this._ws.readyState:this._options.startClosed?b.CLOSED:b.CONNECTING}get url(){return this._ws?this._ws.url:""}get shouldReconnect(){return this._shouldReconnect}onclose=null;onerror=null;onmessage=null;onopen=null;close(t=1e3,s){if(this._closeCalled=!0,this._shouldReconnect=!1,this._clearTimeouts(),!this._ws){this._debug("close enqueued: no ws instance");return}if(this._ws.readyState===this.CLOSED){this._debug("close: already closed");return}this._ws.close(t,s)}reconnect(t,s){this._shouldReconnect=!0,this._closeCalled=!1,this._retryCount=-1,!this._ws||this._ws.readyState===this.CLOSED?this._connect():(this._disconnect(t,s),this._connect())}send(t){if(this._ws&&this._ws.readyState===this.OPEN)this._debug("send",t),this._ws.send(t);else{const{maxEnqueuedMessages:s=g.maxEnqueuedMessages}=this._options;this._messageQueue.length<s&&(this._debug("enqueue",t),this._messageQueue.push(t))}}_debug(...t){this._options.debug&&this._debugLogger("RWS>",...t)}_getNextDelay(){const{reconnectionDelayGrowFactor:t=g.reconnectionDelayGrowFactor,minReconnectionDelay:s=g.minReconnectionDelay,maxReconnectionDelay:o=g.maxReconnectionDelay}=this._options;let r=0;return this._retryCount>0&&(r=s*t**(this._retryCount-1),r>o&&(r=o)),this._debug("next delay",r),r}_wait(){return new Promise(t=>{setTimeout(t,this._getNextDelay())})}_getNextProtocols(t){if(!t)return Promise.resolve(null);if(typeof t=="string"||Array.isArray(t))return Promise.resolve(t);if(typeof t=="function"){const s=t();if(!s)return Promise.resolve(null);if(typeof s=="string"||Array.isArray(s))return Promise.resolve(s);if(s.then)return s}throw Error("Invalid protocols")}_getNextUrl(t){if(typeof t=="string")return Promise.resolve(t);if(typeof t=="function"){const s=t();if(typeof s=="string")return Promise.resolve(s);if(s.then)return s}throw Error("Invalid URL")}_connect(){if(this._connectLock||!this._shouldReconnect)return;this._connectLock=!0;const{maxRetries:t=g.maxRetries,connectionTimeout:s=g.connectionTimeout}=this._options;if(this._retryCount>=t){this._debug("max retries reached",this._retryCount,">=",t);return}this._retryCount++,this._debug("connect",this._retryCount),this._removeListeners(),this._wait().then(()=>Promise.all([this._getNextUrl(this._url),this._getNextProtocols(this._protocols||null)])).then(([o,r])=>{if(this._closeCalled){this._connectLock=!1;return}!this._options.WebSocket&&typeof WebSocket>"u"&&!D&&(console.error(`‼️ No WebSocket implementation available. You should define options.WebSocket. 

For example, if you're using node.js, run \`npm install ws\`, and then in your code:

import PartySocket from 'partysocket';
import WS from 'ws';

const partysocket = new PartySocket({
  host: "127.0.0.1:1999",
  room: "test-room",
  WebSocket: WS
});

`),D=!0);const n=this._options.WebSocket||WebSocket;this._debug("connect",{url:o,protocols:r}),this._ws=r?new n(o,r):new n(o),this._ws.binaryType=this._binaryType,this._connectLock=!1,this._addListeners(),this._connectTimeout=setTimeout(()=>this._handleTimeout(),s)}).catch(o=>{this._connectLock=!1,this._handleError(new L.ErrorEvent(Error(o.message),this))})}_handleTimeout(){this._debug("timeout event"),this._handleError(new L.ErrorEvent(Error("TIMEOUT"),this))}_disconnect(t=1e3,s){if(this._clearTimeouts(),!!this._ws){this._removeListeners();try{(this._ws.readyState===this.OPEN||this._ws.readyState===this.CONNECTING)&&this._ws.close(t,s),this._handleClose(new L.CloseEvent(t,s,this))}catch{}}}_acceptOpen(){this._debug("accept open"),this._retryCount=0}_handleOpen=t=>{this._debug("open event");const{minUptime:s=g.minUptime}=this._options;clearTimeout(this._connectTimeout),this._uptimeTimeout=setTimeout(()=>this._acceptOpen(),s),re(this._ws,"WebSocket is not defined"),this._ws.binaryType=this._binaryType,this._messageQueue.forEach(o=>{var r;(r=this._ws)==null||r.send(o)}),this._messageQueue=[],this.onopen&&this.onopen(t),this.dispatchEvent(P(t))};_handleMessage=t=>{this._debug("message event"),this.onmessage&&this.onmessage(t),this.dispatchEvent(P(t))};_handleError=t=>{this._debug("error event",t.message),this._disconnect(void 0,t.message==="TIMEOUT"?"timeout":void 0),this.onerror&&this.onerror(t),this._debug("exec error listeners"),this.dispatchEvent(P(t)),this._connect()};_handleClose=t=>{this._debug("close event"),this._clearTimeouts(),this._shouldReconnect&&this._connect(),this.onclose&&this.onclose(t),this.dispatchEvent(P(t))};_removeListeners(){this._ws&&(this._debug("removeListeners"),this._ws.removeEventListener("open",this._handleOpen),this._ws.removeEventListener("close",this._handleClose),this._ws.removeEventListener("message",this._handleMessage),this._ws.removeEventListener("error",this._handleError))}_addListeners(){this._ws&&(this._debug("addListeners"),this._ws.addEventListener("open",this._handleOpen),this._ws.addEventListener("close",this._handleClose),this._ws.addEventListener("message",this._handleMessage),this._ws.addEventListener("error",this._handleError))}_clearTimeouts(){clearTimeout(this._connectTimeout),clearTimeout(this._uptimeTimeout)}};var ue=e=>e[1]!==null&&e[1]!==void 0;function le(){if(crypto!=null&&crypto.randomUUID)return crypto.randomUUID();let e=Date.now(),t=performance?.now&&performance.now()*1e3||0;return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(s){let o=Math.random()*16;return e>0?(o=(e+o)%16|0,e=Math.floor(e/16)):(o=(t+o)%16|0,t=Math.floor(t/16)),(s==="x"?o:o&3|8).toString(16)})}function J(e,t,s={}){const{host:o,path:r,protocol:n,room:l,party:i,basePath:a,prefix:u,query:p}=e;let c=o.replace(/^(http|https|ws|wss):\/\//,"");if(c.endsWith("/")&&(c=c.slice(0,-1)),r?.startsWith("/"))throw new Error("path must not start with a slash");const x=i??"main",y=r?`/${r}`:"",f=n||(c.startsWith("localhost:")||c.startsWith("127.0.0.1:")||c.startsWith("192.168.")||c.startsWith("10.")||c.startsWith("172.")&&c.split(".")[1]>="16"&&c.split(".")[1]<="31"||c.startsWith("[::ffff:7f00:1]:")?t:`${t}s`),_=`${f}://${c}/${a||`${u||"parties"}/${x}/${l}`}${y}`,O=(S={})=>`${_}?${new URLSearchParams([...Object.entries(s),...Object.entries(S).filter(ue)])}`,E=typeof p=="function"?async()=>O(await p()):O(p);return{host:c,path:y,room:l,name:x,protocol:f,partyUrl:_,urlProvider:E}}var he=class extends ce{constructor(e){var t,s;const o=A(e);super(o.urlProvider,o.protocols,o.socketOptions),this.partySocketOptions=e,this.setWSProperties(o),e.disableNameValidation||((t=e.party)!=null&&t.includes("/")&&console.warn(`PartySocket: party name "${e.party}" contains forward slash which may cause routing issues. Consider using a name without forward slashes or set disableNameValidation: true to bypass this warning.`),(s=e.room)!=null&&s.includes("/")&&console.warn(`PartySocket: room name "${e.room}" contains forward slash which may cause routing issues. Consider using a name without forward slashes or set disableNameValidation: true to bypass this warning.`))}_pk;_pkurl;name;room;host;path;updateProperties(e){const t=A({...this.partySocketOptions,...e,host:e.host??this.host,room:e.room??this.room,path:e.path??this.path});this._url=t.urlProvider,this._protocols=t.protocols,this._options=t.socketOptions,this.setWSProperties(t)}setWSProperties(e){const{_pk:t,_pkurl:s,name:o,room:r,host:n,path:l}=e;this._pk=t,this._pkurl=s,this.name=o,this.room=r,this.host=n,this.path=l}reconnect(e,t){if(!this.room||!this.host)throw new Error("The room and host must be set before connecting, use `updateProperties` method to set them or pass them to the constructor.");super.reconnect(e,t)}get id(){return this._pk}get roomUrl(){return this._pkurl}static async fetch(e,t){const s=J(e,"http"),o=typeof s.urlProvider=="string"?s.urlProvider:await s.urlProvider();return(e.fetch??fetch)(o,t)}};function A(e){const{id:t,host:s,path:o,party:r,room:n,protocol:l,query:i,protocols:a,...u}=e,p=t||le(),c=J(e,"ws",{_pk:p});return{_pk:p,_pkurl:c.partyUrl,name:c.name,room:c.room,host:c.host,path:c.path,protocols:a,socketOptions:u,urlProvider:c.urlProvider}}var de=(e,t)=>{const s=h.useRef(t);s.current=t,h.useEffect(()=>{const o=i=>{var a,u;return(u=(a=s.current)==null?void 0:a.onOpen)==null?void 0:u.call(a,i)},r=i=>{var a,u;return(u=(a=s.current)==null?void 0:a.onMessage)==null?void 0:u.call(a,i)},n=i=>{var a,u;return(u=(a=s.current)==null?void 0:a.onClose)==null?void 0:u.call(a,i)},l=i=>{var a,u;return(u=(a=s.current)==null?void 0:a.onError)==null?void 0:u.call(a,i)};return e.addEventListener("open",o),e.addEventListener("close",n),e.addEventListener("error",l),e.addEventListener("message",r),()=>{e.removeEventListener("open",o),e.removeEventListener("close",n),e.removeEventListener("error",l),e.removeEventListener("message",r)}},[e])},pe=e=>[e.startClosed,e.minUptime,e.maxRetries,e.connectionTimeout,e.maxEnqueuedMessages,e.maxReconnectionDelay,e.minReconnectionDelay,e.reconnectionDelayGrowFactor,e.debug];function me({options:e,createSocket:t,createSocketMemoKey:s}){const o=s(e),r=h.useMemo(()=>e,[o]),[n,l]=h.useState(()=>t({...r,startClosed:!0})),i=h.useRef(null),a=h.useRef(t);return a.current=t,h.useEffect(()=>{if(i.current===n){const u=a.current({...r,startClosed:!1});l(u)}else return!i.current&&r.startClosed!==!0&&n.reconnect(),i.current=n,()=>{n.close()}},[n,r]),n}function fe(e){const{host:t,...s}=e,o=me({options:{host:t||(typeof window<"u"?window.location.host:"dummy-domain.com"),...s},createSocket:r=>new he(r),createSocketMemoKey:r=>JSON.stringify([r.query,r.id,r.host,r.room,r.party,r.path,r.protocol,r.protocols,r.basePath,r.prefix,...pe(r)])});return de(o,e),o}const U=h.createContext(null);function _e(){return v()?.preferences?.presence??null}function ye(){return v()?.workshopTitle??null}const ge=m({type:G([w("problem"),w("solution")]).optional(),exerciseNumber:W.number().finite(),stepNumber:W.number().finite().optional()});function be(e,t){const[s]=h.useState(()=>new Promise(i=>setTimeout(i,t))),o=h.useRef(!0),r=h.useRef(null),n=h.useRef(e);return h.useEffect(()=>{n.current=e},[e]),h.useCallback((...i)=>{const a=Symbol();r.current=a,s.then(()=>{o.current&&r.current===a&&n.current(...i)})},[s])}function we(){return v()?.workshopConfig?.product?.host??null}function ve(){return v()?.loggedInProductHosts??[]}function Y(){const e=ye(),t=Z(),s=we(),o=K(),r=ge.safeParse(o),n=r.success?r.data:null,{ENV:l,repoUpdates:i}=v()??{},a=l?.EPICSHOP_APP_VERSION??null,u=i&&"updatesAvailable"in i?{...i}:null;return{workshopTitle:e,origin:t.origin,productHost:s,epicshopVersion:a,repoStatus:u,...n?{exercise:{type:n.type,exerciseNumber:n.exerciseNumber,stepNumber:n.stepNumber}}:null}}function xe(e){const t=_e(),{userId:s,presence:o,userHasAccess:r}=v()??{},[n,l]=h.useState(o?.users??[]),i=Y(),a=ve(),u=be(E=>{const S=se.safeParse(JSON.parse(String(E.data)));S.success&&S.data.type==="presence"&&l(S.data.payload.users)},2e3),p=fe({host:new URL(ee).host,room:V,onMessage:u}),c=e?.id??s?.id,y=(c?o?.users?.find(E=>E.id===c):null)??e??{};let f=null;c&&(t?.optOut?f={type:"add-user",payload:{...y,id:c,hasAccess:r,optOut:!0,loggedInProductHosts:a,location:i}}:f={type:"add-user",payload:{...y,id:c,hasAccess:r,location:i,loggedInProductHosts:a}});const _=f?JSON.stringify(f):null;return h.useEffect(()=>{_&&p.send(_)},[_,p]),{users:z({id:s?.id,location:i},n)}}function T(e){return e.locations&&e.locations.length>0?e.locations.filter(Boolean):e.location?[e.location]:[]}function z(e,t){const{location:s}=e;return t.map(r=>{let n=0;if(r.optOut)return{user:r,score:0};const l=T(r);for(const i of l)s?.workshopTitle&&s.workshopTitle===i.workshopTitle?(n=Math.max(n,.4),s.exercise?.exerciseNumber!=null&&s.exercise.exerciseNumber===i.exercise?.exerciseNumber&&(n=Math.max(n,.6),s.exercise.stepNumber!=null&&s.exercise.stepNumber===i.exercise?.stepNumber&&(n=Math.max(n,.8),s.exercise.type&&s.exercise.type===i.exercise?.type&&(n=1)))):s?.productHost&&s.productHost===i.productHost&&(n=Math.max(n,.2));return{user:r,score:n}}).sort((r,n)=>{if(r.user.id===e.id)return-1;if(n.user.id===e.id||r.user.optOut&&!n.user.optOut)return 1;if(!r.user.optOut&&n.user.optOut)return-1;const l=F(s,r.user),i=F(s,n.user);if(l&&!i)return-1;if(!l&&i)return 1;const a=$(s,r.user),u=$(s,n.user);if(a&&!u)return-1;if(!a&&u)return 1;const p=q(s,r.user),c=q(s,n.user);if(p&&!c)return-1;if(!p&&c)return 1;const x=j(s,r.user),y=j(s,n.user);if(x&&!y)return-1;if(!x&&y)return 1;const f=r.user.loggedInProductHosts?.length??0,_=n.user.loggedInProductHosts?.length??0;return f!==_?_-f:0})}function F(e,t){return e?.exercise?T(t).some(o=>o.workshopTitle===e.workshopTitle&&o.exercise?.exerciseNumber===e.exercise?.exerciseNumber&&o.exercise?.stepNumber===e.exercise?.stepNumber&&o.exercise?.type===e.exercise?.type):!1}function $(e,t){return e?.exercise?.exerciseNumber?T(t).some(o=>o.workshopTitle===e.workshopTitle&&o.exercise?.exerciseNumber===e.exercise?.exerciseNumber):!1}function q(e,t){return e?.workshopTitle?T(t).some(o=>o.workshopTitle===e.workshopTitle):!1}function j(e,t){return e?.productHost?T(t).some(o=>o.productHost===e.productHost):!1}function Ee({user:e,children:t}){return C.jsx(U.Provider,{value:xe(e),children:t})}function Se({user:e,children:t}){const s=Y(),{presence:o}=v()??{};return C.jsx(U.Provider,{value:{users:z({id:e?.id,location:s},o?.users??[])},children:t})}function Re({user:e,children:t}){return X()?C.jsx(Ee,{user:e,children:t}):C.jsx(Se,{user:e,children:t})}function Ie(){const e=h.useContext(U);if(!e)throw new Error("usePresence must be used within a PresenceProvider");return e}export{Re as P,Le as g,oe as p,Ie as u};
//# sourceMappingURL=presence-BFO_Dmzq.js.map
