@indiegems/gem-web-sdk 7.4.2 → 7.6.0

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.
@@ -1,3 +1,3 @@
1
- var ve=Object.defineProperty;var Re=(n,e)=>{for(var t in e)ve(n,t,{get:e[t],enumerable:true});};globalThis.__gemWebSdkVersion="[gem-web-sdk:sdkVersion:7.4.2]";function xe(n,e){return e!==void 0?!e:n==="chain_exhausted"}var $=class{constructor(e){this.options=e;}options;grant=null;state="pending";failure=null;generation=0;inFlight=null;rejected=false;get currentState(){return this.state}get lastFailure(){return this.failure}async get(){if(this.state==="lost")throw new _(this.failure??"unavailable","the session cannot be renewed");let e=this.seconds();if(this.grant&&e<this.grant.expiresAt-this.renewBefore())return this.grant.token;if(this.grant&&e>=this.grant.chainEndsAt)throw this.enter("lost","chain_exhausted"),new _("chain_exhausted","the token chain reached its ceiling");return this.refresh(this.nextReason())}nextReason(){return this.rejected?"rejected":this.grant?"expiring":"initial"}invalidate(e){e!==void 0&&this.grant!==null&&this.grant.token!==e||this.rejected&&this.grant===null||(this.grant=null,this.generation+=1,this.inFlight=null,this.rejected=true,this.state!=="lost"&&this.enter("pending"));}accept(e){this.state!=="lost"&&(this.grant=e,this.rejected=false,this.enter("ready"));}close(e="unavailable"){this.grant=null,this.generation+=1,this.inFlight=null,this.enter("lost",e);}refresh(e){if(this.inFlight)return this.inFlight;let t=this.generation;this.enter("pending");let r=this.options.request(e).then(o=>{if(t!==this.generation)throw new _("internal","token arrived for a superseded generation");return this.grant=o,this.rejected=false,this.enter("ready"),o.token}).catch(o=>{let s=Se(o),a=o?.retryable;throw t===this.generation&&this.enter(xe(s,typeof a=="boolean"?a:void 0)?"lost":"degraded",s),o instanceof _?o:new _(s,String(o))}).finally(()=>{this.inFlight===r&&(this.inFlight=null);});return this.inFlight=r,r}enter(e,t){this.failure=t??(e==="ready"?null:this.failure),this.state!==e&&(this.state=e,this.options.onStateChange?.(e,t));}renewBefore(){return this.options.renewBeforeSeconds??60}seconds(){return Math.floor(this.options.clock.now()/1e3)}},_=class n extends Error{constructor(t,r){super(`auth ${t}: ${r}`);this.reason=t;this.name="AuthError";}reason;static isAuthError(t){if(t instanceof n)return true;let r=t;return r?.name==="AuthError"&&typeof r.reason=="string"}};function Se(n){if(n instanceof _)return n.reason;let e=n?.reason;return typeof e=="string"&&["chain_exhausted","unavailable","timeout","internal"].includes(e)?e:"internal"}var p=class n extends Error{retryable=false;constructor(e){super(e),this.name="TransportRefusal";}static isRefusal(e){if(e instanceof n)return true;let t=e;return t?.name==="TransportRefusal"&&t.retryable===false}},j=["if-match","if-none-match"],W=4096;function ke(n){if(!n)return;let e={};for(let[t,r]of Object.entries(n)){let o=t.toLowerCase();if(!j.includes(o)||r===void 0)continue;let s=typeof r=="string"?we(r):r;if(typeof s!="string"||s.length>W||!Ae(s))throw new p(`the ${o} header value cannot be sent \u2014 it is not a string, is longer than ${W} characters, or contains a character outside the range an HTTP header value may carry. This is a malformed request, not a server failure; the value is withheld here rather than written to logs.`);s!==""&&(e[o]=s);}return Object.freeze(e)}function we(n){let e=o=>o===32||o===9||o===10||o===13,t=0,r=n.length;for(;t<r&&e(n.charCodeAt(t));)t++;for(;r>t&&e(n.charCodeAt(r-1));)r--;return n.slice(t,r)}function Ae(n){for(let e=0;e<n.length;e++){let t=n.charCodeAt(e);if(t!==9&&(t<32||t===127||t>255))return false}return true}function Te(n){let{bytes:e}=n;if(e!==void 0){if(Object.prototype.toString.call(e)!=="[object Uint8Array]")throw new p("the raw body is not a Uint8Array, so it cannot be sent as bytes. This is a malformed request, not a server failure.");if(n.body!==void 0)throw new p("the request carries both a JSON body and a raw body, and only one can be sent. This is a malformed request, not a server failure.");return new Uint8Array(e)}}function z(n,e){let t=e.replayUnauthorizedOnce??true;return {async request(r){let o={...r},s=ke(o.headers),a=Te(o),l=Object.freeze({...o,headers:s,...a===void 0?{}:{bytes:a}}),d=await e.tokenSource.get(),c=await n(l,d);if(c.status!==401||!t)return c;e.tokenSource.invalidate(d);let g=await e.tokenSource.get(),b=await n(l,g);if(b.status===401)throw e.tokenSource.close("unavailable"),new _("unavailable","the server refused a freshly minted token");return b}}}function K(n){let e=typeof n=="string"?new TextEncoder().encode(n):n;return btoa(Pe(e))}function Pe(n){let t="";for(let r=0;r<n.length;r+=32768)t+=String.fromCharCode(...n.subarray(r,r+32768));return t}var m=class extends Error{constructor(t,r,o,s,a){super(`${t} (${r}): ${o}`);this.reason=t;this.status=r;this.detail=o;this.retryAfterSeconds=s;this.code=a;this.name="GemApiError";}reason;status;detail;retryAfterSeconds;code;get retryable(){return this.reason==="unavailable"||this.reason==="rate_limited"}},J=new WeakMap;function X(n){return J.get(n)??{}}var Oe=new Set([408,429,500,502,503,504]),Ge=6e4;function Ce(n){if(n===void 0)return 2;if(!Number.isInteger(n)||n<0||n>10)throw new p(`maxRetries must be a whole number between 0 and 10; received ${JSON.stringify(n)}. This is a configuration fault, not a server failure.`);return n}var P=class{constructor(e){this.options=e;}options;async get(e,t){return this.send({method:"GET",path:e,signal:t},true)}async getWithEtag(e,t={}){let r=await this.sendRaw({method:"GET",path:e,...t.signal===void 0?{}:{signal:t.signal},...t.ifNoneMatch===void 0?{}:{headers:{"if-none-match":t.ifNoneMatch}}},true),o=r.etag===void 0?{}:{etag:r.etag};return r.status===304?{modified:false,...o}:{modified:true,body:r.body,...o}}async put(e,t,r,o={}){return this.send({method:"PUT",path:e,body:t,signal:r,...E(o)},o.replaySafe===true)}async post(e,t,r,o={}){return this.send({method:"POST",path:e,body:t,signal:r,...E(o)},o.replaySafe===true)}async postBytes(e,t,r,o={}){let s=await this.sendRaw({method:"POST",path:e,bytes:t,responseType:"bytes",signal:r,...E(o)},o.replaySafe===true);return {bytes:Ee(s.body),...s.invocationId===void 0?{}:{invocationId:s.invocationId}}}async patch(e,t,r,o={}){return this.send({method:"PATCH",path:e,body:t,signal:r,...E(o)},o.replaySafe===true)}async delete(e,t,r={}){return this.send({method:"DELETE",path:e,signal:t,...E(r)},r.replaySafe===true)}async send(e,t){return (await this.sendRaw(e,t)).body}async sendRaw(e,t){let r=t?Ce(this.options.maxRetries)+1:1,o=null;if(e.signal?.aborted)throw Y(e.signal);for(let s=0;s<r;s++){if(s>0&&await this.backoff(s,o,e.signal),e.signal?.aborted)throw Y(e.signal);let a;try{a=await this.options.transport.request(e);}catch(d){if(_.isAuthError(d)||p.isRefusal(d)||e.signal?.aborted||Ie(d))throw d;o=new m("unavailable",0,String(d));continue}if(a.status>=200&&a.status<300||a.status===304)return a;let l=qe(a);if(!Oe.has(a.status))throw l;o=l;}throw o??new m("unavailable",0,"no attempt was made")}backoff(e,t,r){if(r?.aborted)return Promise.resolve();let o=t?.retryAfterSeconds,s=o!==void 0?o*1e3:2**(e-1)*250,a=2**(e-1)*250,l=Math.min(Math.max(s,a),Ge);return new Promise(d=>{let c=this.options.clock,g=false,b=false,x,f=()=>{g||(g=true,b&&c.clearTimeout(x),r?.removeEventListener("abort",f),d());};r?.addEventListener("abort",f,{once:true}),x=c.setTimeout(f,l),b=true,g&&c.clearTimeout(x);})}};function Ee(n){if(n instanceof Uint8Array)return n;if(n==null)return new Uint8Array(0);let e=typeof n=="string"?n:JSON.stringify(n);return new TextEncoder().encode(e)}function E(n){return {...n.keepalive===void 0?{}:{keepalive:n.keepalive},...n.ifMatch===void 0?{}:{headers:{"if-match":n.ifMatch}}}}function Y(n){return n.reason!==void 0?n.reason:new DOMException("The operation was aborted.","AbortError")}function Ie(n){let e=n?.name;return e==="AbortError"||e==="TimeoutError"}function qe(n){let e=$e(n),t=Me(n.body),r={...t===void 0?{}:{details:t},...n.invocationId===void 0?{}:{invocationId:n.invocationId}};return Object.keys(r).length>0&&J.set(e,r),e}var Le=new Map([["insufficient_funds","insufficient_funds"]]);function $e(n){let{status:e,body:t}=n,r=je(t),o=n.retryAfterSeconds??Ue(t),s=Fe(t),a=s===void 0?void 0:Le.get(s);if(a!==void 0)return new m(a,e,r,void 0,s);switch(e){case 304:return new m("not_modified",e,r);case 400:case 422:return new m("invalid",e,r,void 0,s);case 403:return new m("forbidden",e,r,void 0,s);case 404:return new m("not_found",e,r,void 0,s);case 402:return new m("insufficient_funds",e,r,void 0,s);case 409:return new m("conflict",e,r,void 0,s);case 412:return new m("precondition_failed",e,r,void 0,s);case 413:return new m("too_large",e,r,void 0,s);case 429:return new m("rate_limited",e,r,o,s);default:return new m("unavailable",e,r,o,s)}}function je(n){if(typeof n=="string")return n;let e=n?.message;if(typeof e=="string")return e;let t=n?.error;if(typeof t=="string")return t;let r=t?.message;return typeof r=="string"?r:"no detail"}function Me(n){let t=n?.error?.details;return t===null?void 0:t}function Fe(n){let t=n?.error?.code;return typeof t=="string"&&t.length>0?t:void 0}function Ue(n){let e=n?.retryAfterSeconds;return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:void 0}function Be(n){let e=n.lastIndexOf("@");return (e===-1?n:`***@${n.slice(e+1)}`).slice(0,200)}var Ne=new Set(j);function De(n){if(!n)return {};let e={};for(let[t,r]of Object.entries(n))Ne.has(t.toLowerCase())&&(e[t.toLowerCase()]=r);return e}function Q(n){let e=n.fetch??globalThis.fetch.bind(globalThis);return z(async(t,r)=>{let o;try{o=new URL(n.baseUrl.replace(/\/+$/,""));}catch{throw new p("the configured baseUrl is not a valid URL. Its value is withheld here rather than written to logs. This is a configuration fault, not a server failure.")}let s;try{s=new URL(o.href.replace(/\/+$/,"")+t.path);}catch{throw new p(`${JSON.stringify(typeof t.path=="string"?Be(t.path):"(a non-string path)")} does not form a valid URL against ${o.protocol}//${o.host}. This is a malformed request, not a server failure.`)}if(s.protocol!==o.protocol||s.host!==o.host)throw new p(`${JSON.stringify(s.pathname)} resolves to ${s.protocol}//${s.host}, not ${o.protocol}//${o.host}. A request path may not change the request's origin \u2014 it carries the play token.`);if(s.username!==""||s.password!==""){let f=o.username!==""||o.password!=="",v=s.username!==o.username||s.password!==o.password,y=f?v?"baseUrl (and possibly the request path)":"baseUrl":"request path";throw new p(`the ${y} puts credentials in the URL, which cannot be fetched (${t.method} ${s.pathname}). The value is withheld here rather than written to logs. This is a malformed request, not a server failure.`)}for(let[f,v]of Object.entries(n.defaultQuery??{}))s.searchParams.has(f)||s.searchParams.set(f,v);let a=t.bytes,l=t.bytes===void 0?void 0:"application/octet-stream";try{t.body!==void 0&&(a=JSON.stringify(t.body),l="application/json");}catch(f){throw new p(`the body of ${t.method} ${JSON.stringify(s.pathname)} could not be serialised to JSON: ${String(f)}. This is a bug in the request, not a server failure \u2014 retrying sends the same unserialisable value.`)}let d=await e(s.toString(),{method:t.method,headers:{authorization:`Bearer ${r}`,...l===void 0?{}:{"content-type":l},...De(t.headers)},body:a,signal:t.signal,...t.keepalive===void 0?{}:{keepalive:t.keepalive},credentials:"omit",mode:"cors",redirect:"error",cache:"no-store",referrerPolicy:"no-referrer"}),c=null;if(t.responseType==="bytes"&&d.status>=200&&d.status<300)c=new Uint8Array(await d.arrayBuffer());else {let f=await d.text();if(f.length>0)try{c=JSON.parse(f);}catch{c=f;}}let g=d.headers.get("etag"),b=He(d.headers.get("retry-after")),x=d.headers.get("x-gem-invocation-id");return {status:d.status,body:c,...g===null?{}:{etag:g},...b===void 0?{}:{retryAfterSeconds:b},...x===null||x===""?{}:{invocationId:x}}},n)}function He(n){if(n===null)return;let e=n.trim();if(!/^\d+$/.test(e))return;let t=Number(e);return Number.isFinite(t)?t:void 0}var Ve="gem-web-bridge";var O=65536,Z=8,M=5e3,ee=1024;function B(n){return Object.freeze(Object.assign(Object.create(null),n))}B({"gem.handshake":30,"gem.handshake.accept":5,"gem.token":30,"gem.token.denied":30,"gem.player":12,"gem.pause":120,"gem.prefs":60,"gem.cohorts":12,"gem.earnAllowanceChanged":30,"gem.viewport":60,"gem.deviceSettings":12,"gem.willTerminate":10,"gem.roomEvent":120,"gem.socketState":12,"gem.seatedEvent":60,"gem.autoStartFailedEvent":30,"gem.signalEvent":1800,"gem.dedicatedEvent":120,"gem.partyResult":30,"gem.clusterTarget":12,"gem.devtools":30,"gem.screenshot":6,"gem.screenshot.denied":12,"gem.requestContext":12,"gem.gameContext":12,"gem.signal":1200,"gem.dedicatedOffer":60,"gem.partyRequest":12,"gem.ready":5,"gem.progress":600,"gem.requestToken":12,"gem.requestLocalServer":6,"gem.localServer":30,"gem.localServer.denied":30,"gem.exit":5,"gem.openExternal":6,"gem.requestFullscreen":30,"gem.audioState":120,"gem.rewardCue":60,"gem.walletDisplay":60,"gem.requestShare":6,"gem.frameStats":120,"gem.error":60,"gem.requestPurchase":12,"gem.purchaseResult":30,"gem.deviceSettings.put":30,"gem.deviceSettings.result":30,"gem.requestAd":6,"gem.adResult":12,"gem.requestSignIn":6,"gem.signInResult":12,"gem.requestFriendChallenge":12,"gem.friendChallengeResult":30,__malformed:60});B({"gem.requestAd":"ads","gem.adResult":"ads","gem.requestSignIn":"signIn","gem.signInResult":"signIn","gem.requestPurchase":"purchases","gem.purchaseResult":"purchases","gem.requestFriendChallenge":"friendChallenges","gem.friendChallengeResult":"friendChallenges","gem.devtools":"devtools","gem.screenshot":"screenshot","gem.screenshot.denied":"screenshot","gem.requestContext":"feedbackContext","gem.gameContext":"feedbackContext","gem.roomEvent":"rooms","gem.signal":"p2p","gem.signalEvent":"p2p","gem.dedicatedOffer":"dedicated","gem.dedicatedEvent":"dedicated","gem.clusterTarget":"clusterTarget","gem.partyRequest":"parties","gem.partyResult":"parties","gem.autoStartFailedEvent":"autoStartFailure","gem.seatedEvent":"partySeating","gem.socketState":"socketState","gem.audioState":"audioState","gem.rewardCue":"rewardCue","gem.frameStats":"frameStats","gem.viewport":"viewport","gem.walletDisplay":"walletDisplay","gem.requestLocalServer":"localHost","gem.localServer":"localHost","gem.localServer.denied":"localHost","gem.cohorts":"cohorts","gem.earnAllowanceChanged":"earnAllowance","gem.deviceSettings":"deviceSettings","gem.deviceSettings.put":"deviceSettings","gem.deviceSettings.result":"deviceSettings","gem.requestShare":"share"});function ze(n){let e=/^([a-z][a-z0-9+.-]*):\/\/([a-z0-9.-]+|\[[0-9a-f:.]+\])(:([0-9]{1,5}))?$/i.exec(n);return e===null?false:e[4]===void 0||Number(e[4])<=65535}function Ke(n){let e;try{e=new URL(n);}catch{return false}return e.username!==""||e.password!==""?false:e.protocol==="https:"?true:e.protocol==="http:"&&(e.hostname==="localhost"||e.hostname==="127.0.0.1")}function Ye(n){return /^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i.test(n)}function Je(n){return /^[a-z_]+$/.test(n)}function U(n,e,t){if(e>Z)return `nesting deeper than ${Z}`;if(++t.nodes>M)return `more than ${M} values`;if(t.bytes>O)return `over the ${O} byte limit`;if(n==null)return t.bytes+=4,null;let r=typeof n;if(r==="boolean")return t.bytes+=5,null;if(r==="number")return t.bytes+=8,null;if(r==="string")return t.bytes+=n.length*3+2,null;if(r!=="object")return `${r} is not plain data`;let o=n;if(t.seen.has(o))return "a repeated or cyclic object reference";if(t.seen.add(o),Array.isArray(n)){if(n.length>ee)return `an array of ${n.length} entries, over the ${ee} limit`;t.bytes+=2;for(let l of n){let d=U(l,e+1,t);if(d)return d}return null}let s=Object.getPrototypeOf(n);if(s!==Object.prototype&&s!==null)return "a value that is not a plain object";t.bytes+=2;let a=n;for(let l in a){if(!Object.prototype.hasOwnProperty.call(a,l))continue;if(++t.nodes>M)return `more than ${M} values`;if(t.bytes+=l.length*3+4,t.bytes>O)return `over the ${O} byte limit`;let d=U(a[l],e+1,t);if(d)return d}return null}function Xe(n){let e={nodes:0,bytes:0,seen:new Set},t=U(n,0,e);return t?`message contains ${t}`:e.bytes>O?`message is over the ${O} byte limit`:null}var Qe={origin:[ze,"not a well-formed origin"],url:[Ke,"not a safe absolute http(s) URL"],bcp47:[Ye,"not a well-formed BCP 47 tag"],code:[Je,"not a code of lower-case letters and underscores"]};function ne(n,e,t){for(let r of e){let o=t===""?r.n:`${t}.${r.n}`,s=n[r.n];if(s==null){if(r.o)continue;return `${o}: required`}let a=te(s,r,o);if(a)return a}return null}function te(n,e,t){switch(e.k){case "string":{if(typeof n!="string")return `${t}: expected string`;if(n.length>e.max)return `${t}: exceeds ${e.max} characters`;if(e.f){let[r,o]=Qe[e.f];if(!r(n))return `${t}: ${o}`}return null}case "int":return typeof n!="number"||!Number.isInteger(n)?`${t}: expected integer`:n<e.lo||n>e.hi?`${t}: out of range ${e.lo}..${e.hi}`:null;case "boolean":return typeof n=="boolean"?null:`${t}: expected boolean`;case "enum":{let r=e.v;return r.includes(n)?null:`${t}: not one of ${r.join("|")}`}case "object":return typeof n!="object"||n===null||Array.isArray(n)?`${t}: expected object`:ne(n,e.fs,t);case "json":return typeof n!="object"||n===null||Array.isArray(n)?`${t}: expected a plain object`:null;case "array":{if(!Array.isArray(n))return `${t}: expected array`;if(n.length>e.max)return `${t}: exceeds ${e.max} items`;let r=e.it,o=`${t}[]`;for(let s of n){if(s==null){if(r.o)continue;return `${o}: required`}let a=te(s,r,o);if(a)return a}return null}default:{let r=e.k;return `${t}: unknown kind ${String(r)}`}}}function u(n,e){return t=>{let r=Xe(t);if(r)return r;if(typeof t!="object"||t===null||Array.isArray(t))return "message: expected object";let o=t;return o.gem!==Ve?"gem: wrong protocol marker":o.type!==n?`type: expected ${n}`:ne(o,e,"")}}var Ze=u("gem.handshake",[{n:"versions",k:"object",fs:[{n:"min",k:"int",lo:1,hi:1e3},{n:"max",k:"int",lo:1,hi:1e3}]},{n:"capabilities",k:"array",o:1,max:64,it:{n:"",k:"string",max:64}},{n:"embedder",k:"string",max:2048,f:"origin"}]),en=u("gem.handshake.accept",[{n:"v",k:"int",lo:1,hi:1e3},{n:"capabilities",k:"array",o:1,max:64,it:{n:"",k:"string",max:64}}]),nn=u("gem.token",[{n:"token",k:"string",max:4096},{n:"requestId",k:"string",o:1,max:64},{n:"generation",k:"int",lo:0,hi:2147483647},{n:"apiBaseUrl",k:"string",o:1,max:512,f:"url"},{n:"playerId",k:"string",max:64},{n:"gameId",k:"string",max:64},{n:"channel",k:"enum",v:["dev","test","release"]},{n:"gameVersion",k:"string",o:1,max:64},{n:"expiresAt",k:"int",lo:0,hi:4102444800},{n:"chainEndsAt",k:"int",lo:0,hi:4102444800},{n:"allowDevTools",k:"boolean",o:1}]),tn=u("gem.token.denied",[{n:"requestId",k:"string",max:64},{n:"retryable",k:"boolean"},{n:"retryAfterMs",k:"int",o:1,lo:0,hi:36e5},{n:"reason",k:"enum",v:["chain_exhausted","unavailable"]},{n:"correlationId",k:"string",max:64}]),rn=u("gem.player",[{n:"untrusted",k:"object",fs:[{n:"displayName",k:"string",max:64},{n:"displayTag",k:"string",o:1,max:80},{n:"displayHandle",k:"string",max:80}]},{n:"playerId",k:"string",o:1,max:64},{n:"discriminator",k:"string",o:1,max:8},{n:"avatarIconUrl",k:"string",o:1,max:2048,f:"url"},{n:"badges",k:"array",o:1,max:2,it:{n:"",k:"object",fs:[{n:"itemId",k:"string",max:64},{n:"iconUrl",k:"string",max:2048,f:"url"}]}},{n:"displayTag",k:"string",max:8},{n:"avatarUrl",k:"string",o:1,max:2048,f:"url"},{n:"boost",k:"object",o:1,fs:[{n:"multipliers",k:"array",max:8,it:{n:"",k:"object",fs:[{n:"currencyId",k:"string",max:64},{n:"currencySlug",k:"string",max:32},{n:"multiplierBp",k:"int",lo:1e4,hi:1e6}]}},{n:"expiresInDays",k:"int",o:1,lo:1,hi:7}]}]),on=u("gem.pause",[{n:"paused",k:"boolean"}]),sn=u("gem.prefs",[{n:"reducedMotion",k:"boolean"},{n:"muted",k:"boolean"},{n:"showFrameStats",k:"boolean",o:1},{n:"locale",k:"string",max:35,f:"bcp47"}]),an=u("gem.cohorts",[{n:"cohorts",k:"array",max:8,it:{n:"",k:"object",fs:[{n:"experimentId",k:"string",max:36},{n:"variantKey",k:"string",max:32}]}}]),ln=u("gem.earnAllowanceChanged",[]),dn=u("gem.viewport",[{n:"insets",k:"object",fs:[{n:"top",k:"int",lo:0,hi:4096},{n:"right",k:"int",lo:0,hi:4096},{n:"bottom",k:"int",lo:0,hi:4096},{n:"left",k:"int",lo:0,hi:4096}]},{n:"reserved",k:"array",o:1,max:4,it:{n:"",k:"object",fs:[{n:"x",k:"int",lo:0,hi:16384},{n:"y",k:"int",lo:0,hi:16384},{n:"width",k:"int",lo:0,hi:16384},{n:"height",k:"int",lo:0,hi:16384}]}}]),un=u("gem.deviceSettings",[{n:"settings",k:"json",o:1}]),cn=u("gem.willTerminate",[{n:"reason",k:"enum",v:["grant_expiring","session_ended","navigating","kill_switch"]},{n:"graceMs",k:"int",lo:0,hi:6e4}]),gn=u("gem.roomEvent",[{n:"event",k:"enum",v:["updated","match_started","match_ready","match_failed","version_stale"]},{n:"roomId",k:"string",max:64},{n:"matchId",k:"string",o:1,max:64},{n:"version",k:"int",o:1,lo:0,hi:2147483647},{n:"reason",k:"string",o:1,max:64},{n:"platform",k:"enum",o:1,v:["universal","mobile"]}]),mn=u("gem.socketState",[{n:"connected",k:"boolean"},{n:"reason",k:"enum",o:1,v:["connecting","dropped","watchdog","terminal"]}]),pn=u("gem.seatedEvent",[{n:"roomId",k:"string",max:64}]),yn=u("gem.autoStartFailedEvent",[{n:"roomId",k:"string",max:64},{n:"code",k:"string",max:64}]),fn=u("gem.signalEvent",[{n:"event",k:"enum",v:["hello","offer","answer","ice","peerJoined","peerLeft","migration","matchEnded","error"]},{n:"matchId",k:"string",max:64},{n:"data",k:"json"}]),hn=u("gem.dedicatedEvent",[{n:"event",k:"enum",v:["answer","error","matchEnded"]},{n:"matchId",k:"string",max:64},{n:"sdp",k:"string",o:1,max:10240},{n:"sessionId",k:"string",o:1,max:64},{n:"code",k:"string",o:1,max:64},{n:"message",k:"string",o:1,max:256},{n:"reason",k:"string",o:1,max:64}]),_n=u("gem.partyResult",[{n:"requestId",k:"string",max:64},{n:"partyId",k:"string",o:1,max:64}]),bn=u("gem.clusterTarget",[{n:"clusterTargetId",k:"string",max:64},{n:"clusterTargetIds",k:"array",o:1,max:3,it:{n:"",k:"string",max:64}}]),vn=u("gem.devtools",[{n:"action",k:"enum",v:["open","close","toggle"]}]),Rn=u("gem.screenshot",[{n:"maxWidth",k:"int",lo:1,hi:7680},{n:"maxHeight",k:"int",lo:1,hi:4320}]),xn=u("gem.screenshot.denied",[{n:"reason",k:"enum",v:["not_wired","no_source","unsupported","unreadable","tainted","too_large","busy","declined","failed"]},{n:"retryable",k:"boolean"}]),Sn=u("gem.requestContext",[]),kn=u("gem.gameContext",[{n:"context",k:"json"}]),wn=u("gem.signal",[{n:"signal",k:"enum",v:["join","offer","answer","ice","migrationAck","hostUnreachable"]},{n:"matchId",k:"string",max:64},{n:"data",k:"json"}]),An=u("gem.dedicatedOffer",[{n:"matchId",k:"string",max:64},{n:"sdp",k:"string",max:10240},{n:"intent",k:"enum",v:["initial","ice_restart","full_reconnect"]}]),Tn=u("gem.partyRequest",[{n:"requestId",k:"string",max:64}]),Pn=u("gem.ready",[]),On=u("gem.progress",[{n:"loaded",k:"int",lo:0,hi:1099511627776},{n:"total",k:"int",lo:0,hi:1099511627776}]),Gn=u("gem.requestToken",[{n:"requestId",k:"string",max:64},{n:"reason",k:"enum",v:["initial","expiring","rejected"]}]),Cn=u("gem.requestLocalServer",[{n:"requestId",k:"string",max:64},{n:"gameRoomId",k:"string",max:64}]),En=u("gem.localServer",[{n:"requestId",k:"string",max:64},{n:"serverId",k:"string",o:1,max:128}]),In=u("gem.localServer.denied",[{n:"requestId",k:"string",max:64},{n:"retryable",k:"boolean"},{n:"reason",k:"enum",v:["refused","unavailable"]}]),qn=u("gem.exit",[{n:"reason",k:"string",o:1,max:64}]),Ln=u("gem.openExternal",[{n:"url",k:"string",max:2048,f:"url"}]),$n=u("gem.requestFullscreen",[{n:"enabled",k:"boolean"}]),jn=u("gem.audioState",[{n:"muted",k:"boolean"}]),Mn=u("gem.rewardCue",[{n:"currencySlug",k:"string",max:32},{n:"expected",k:"int",o:1,lo:1,hi:1e9},{n:"origin",k:"object",o:1,fs:[{n:"x",k:"int",lo:0,hi:16384},{n:"y",k:"int",lo:0,hi:16384}]}]),Fn=u("gem.walletDisplay",[{n:"visible",k:"boolean"},{n:"currencies",k:"array",o:1,max:8,it:{n:"",k:"string",max:64}},{n:"score",k:"boolean",o:1}]),Un=u("gem.requestShare",[{n:"params",k:"array",max:16,it:{n:"",k:"object",fs:[{n:"key",k:"string",max:64},{n:"value",k:"string",max:512}]}}]),Bn=u("gem.frameStats",[{n:"fps",k:"int",lo:0,hi:1e3},{n:"frameTimeP95Ms",k:"int",lo:0,hi:1e5}]),Nn=u("gem.error",[{n:"code",k:"enum",v:["version_mismatch","handshake_timeout","handshake_duplicate","invalid_message","rate_limited","token_unavailable","unsupported","unsupported_capability","internal"]},{n:"message",k:"string",o:1,max:256}]),Dn=u("gem.requestPurchase",[{n:"requestId",k:"string",max:64},{n:"purchaseKind",k:"enum",v:["item","recipe"]},{n:"targetId",k:"string",max:64},{n:"currencySlug",k:"string",max:32},{n:"quantity",k:"int",o:1,lo:1,hi:10},{n:"catalogId",k:"string",o:1,max:64}]),Hn=u("gem.purchaseResult",[{n:"requestId",k:"string",max:64},{n:"outcome",k:"enum",v:["ok","declined","unavailable"]},{n:"reason",k:"string",o:1,max:64,f:"code"},{n:"purchaseId",k:"string",o:1,max:64}]),Vn=u("gem.deviceSettings.put",[{n:"requestId",k:"string",max:64},{n:"settings",k:"json"}]),Wn=u("gem.deviceSettings.result",[{n:"requestId",k:"string",max:64},{n:"outcome",k:"enum",v:["stored","too_large","unavailable"]}]),zn=u("gem.requestAd",[{n:"requestId",k:"string",max:64},{n:"placement",k:"string",max:32},{n:"format",k:"enum",v:["interstitial","rewarded"]}]),Kn=u("gem.adResult",[{n:"requestId",k:"string",max:64},{n:"outcome",k:"enum",v:["shown","no_ad","unavailable"]}]),Yn=u("gem.requestSignIn",[{n:"requestId",k:"string",max:64}]),Jn=u("gem.signInResult",[{n:"requestId",k:"string",max:64},{n:"outcome",k:"enum",v:["signed_in","declined","unavailable"]}]),Xn=u("gem.requestFriendChallenge",[{n:"requestId",k:"string",max:64},{n:"playerId",k:"string",max:64},{n:"template",k:"string",max:64},{n:"params",k:"json",o:1}]),Qn=u("gem.friendChallengeResult",[{n:"requestId",k:"string",max:64},{n:"outcome",k:"enum",v:["accepted","cancelled","refused","unavailable","rate_limited","invalid"]},{n:"code",k:"string",o:1,max:64},{n:"param",k:"string",o:1,max:64},{n:"channel",k:"string",o:1,max:16},{n:"configVersion",k:"int",o:1,lo:0,hi:9007199254740991},{n:"retryAfterMs",k:"int",o:1,lo:0,hi:864e5},{n:"detail",k:"string",o:1,max:300}]);B({"gem.handshake":Ze,"gem.handshake.accept":en,"gem.token":nn,"gem.token.denied":tn,"gem.player":rn,"gem.pause":on,"gem.prefs":sn,"gem.cohorts":an,"gem.earnAllowanceChanged":ln,"gem.viewport":dn,"gem.deviceSettings":un,"gem.willTerminate":cn,"gem.roomEvent":gn,"gem.socketState":mn,"gem.seatedEvent":pn,"gem.autoStartFailedEvent":yn,"gem.signalEvent":fn,"gem.dedicatedEvent":hn,"gem.partyResult":_n,"gem.clusterTarget":bn,"gem.devtools":vn,"gem.screenshot":Rn,"gem.screenshot.denied":xn,"gem.requestContext":Sn,"gem.gameContext":kn,"gem.signal":wn,"gem.dedicatedOffer":An,"gem.partyRequest":Tn,"gem.ready":Pn,"gem.progress":On,"gem.requestToken":Gn,"gem.requestLocalServer":Cn,"gem.localServer":En,"gem.localServer.denied":In,"gem.exit":qn,"gem.openExternal":Ln,"gem.requestFullscreen":$n,"gem.audioState":jn,"gem.rewardCue":Mn,"gem.walletDisplay":Fn,"gem.requestShare":Un,"gem.frameStats":Bn,"gem.error":Nn,"gem.requestPurchase":Dn,"gem.purchaseResult":Hn,"gem.deviceSettings.put":Vn,"gem.deviceSettings.result":Wn,"gem.requestAd":zn,"gem.adResult":Kn,"gem.requestSignIn":Yn,"gem.signInResult":Jn,"gem.requestFriendChallenge":Xn,"gem.friendChallengeResult":Qn});var G={now:()=>Date.now(),setTimeout:(n,e)=>setTimeout(n,e),clearTimeout:n=>clearTimeout(n)};var Zn=1e4;function re(n,e){return N(n,e)}function N(n,e){if(typeof n.serverToken!="function"||typeof n.onServerToken!="function")throw new Error("this runtime delivers no game-server token: host.serverToken/onServerToken are missing. The server image running this bundle predates token delivery \u2014 the bundle cannot call gem-api on it.");let t=a=>({token:a.token,expiresAt:a.expiresAt,chainEndsAt:Number.POSITIVE_INFINITY}),r=null,o=new $({clock:e.clock,...e.onStateChange===void 0?{}:{onStateChange:e.onStateChange},request:()=>new Promise((a,l)=>{let d=e.clock.setTimeout(()=>{r=null,l({reason:"unavailable",retryable:true});},e.timeoutMs??Zn);r={resolve:c=>{e.clock.clearTimeout(d),a(c);},reject:l,timer:d};})}),s=n.onServerToken(a=>{let l=t(a),d=r;if(d){r=null,d.resolve(l);return}o.accept(l);});return {source:o,dispose(){s(),r&&(e.clock.clearTimeout(r.timer),r.reject({reason:"unavailable",retryable:false}),r=null);}}}var H={};Re(H,{acceptTransfer:()=>et,addEntityProgression:()=>nt,adminAction:()=>tt,cancelInventoryTransfer:()=>rt,claimEntityProgressionRewards:()=>ot,closeGameRoom:()=>st,createEntityBatchOrder:()=>it,createEntityOrder:()=>at,createSession:()=>lt,deleteEntityGameSetting:()=>dt,deleteEntitySave:()=>ut,deleteSession:()=>ct,deleteShowcaseValue:()=>gt,executeEntityRecipe:()=>mt,finalizeSaveUpload:()=>pt,getChannelAssignment:()=>yt,getDropRates:()=>ft,getEntityCurrency:()=>ht,getEntityGameSetting:()=>_t,getEntityInventory:()=>bt,getEntityInventoryItem:()=>vt,getEntityLeaderboard:()=>Rt,getEntityOrder:()=>xt,getEntityProgression:()=>St,getEntityRecipeAvailability:()=>kt,getEntityRecipeUsage:()=>wt,getEntitySave:()=>At,getEvent:()=>Tt,getGameRoomV2:()=>Pt,getLeaderboard:()=>Ot,getPlayerGameProfile:()=>Gt,getPurchaseCatalog:()=>Ct,getResolvedTemplate:()=>Et,getRoomArgs:()=>It,getShowcaseValue:()=>qt,getTransferDetails:()=>Lt,ingestAnalyticsEvents:()=>D,initiateInventoryTransfer:()=>$t,invokeFunction:()=>jt,kickPlayer:()=>Mt,listChallenges:()=>Ft,listEntityGameSettings:()=>Ut,listEntityOrders:()=>Bt,listEntityProgressions:()=>Nt,listEntitySaves:()=>Dt,listEvents:()=>Ht,listGameRooms:()=>Vt,listResolvedTemplates:()=>Wt,listTransfers:()=>zt,maxEntityProgression:()=>Kt,putEntityGameSetting:()=>Yt,putRoomArgs:()=>Jt,putShowcaseValue:()=>Xt,rejectTransfer:()=>Qt,requestSaveUploadUrl:()=>Zt,resetEntityProgression:()=>er,simulateEntityOrder:()=>nr,transferHostV2:()=>tr,updateGameRoomV2:()=>rr});function i(n){let e=String(n);if(!/^[A-Za-z0-9_.-]{1,128}$/.test(e)||e==="."||e==="..")throw new TypeError(`${JSON.stringify(e)} is not a usable path segment \u2014 it is interpolated into a URL`);return encodeURIComponent(e)}async function et(n,e,t){let r=`/v1/inventory/transfers/${i(e)}/accept`;return n.client.post(r,void 0,t?.signal)}async function nt(n,e,t,r,o,s){let a=`/v1/inventory/${i(e)}/${i(t)}/progressions/${i(r)}/add`;return n.client.post(a,o,s?.signal)}async function tt(n,e,t,r){let o=`/v1/voice/sessions/${i(e)}/admin`;return n.client.post(o,t,r?.signal)}async function rt(n,e,t){let r=`/v1/inventory/transfers/${i(e)}/cancel`;return n.client.post(r,void 0,t?.signal)}async function ot(n,e,t,r,o,s){let a=`/v1/inventory/${i(e)}/${i(t)}/progressions/${i(r)}/claim`;return n.client.post(a,o,s?.signal)}async function st(n,e,t){let r=`/v1/games/${i(n.gameId())}/game-rooms/${i(e)}`;return n.client.delete(r,t?.signal)}async function it(n,e,t,r,o){let s=`/v1/inventory/${i(e)}/${i(t)}/orders/batch`;return n.client.post(s,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function at(n,e,t,r,o){let s=`/v1/inventory/${i(e)}/${i(t)}/orders`;return n.client.post(s,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function lt(n,e,t){return n.client.post("/v1/voice/sessions",e,t?.signal)}async function dt(n,e,t,r,o){let s=`/v1/settings/${i(e)}/${i(t)}/${i(r)}`;return n.client.delete(s,o?.signal)}async function ut(n,e,t,r,o){let s=`/v1/saves/${i(e)}/${i(t)}/${i(r)}`;return n.client.delete(s,o?.signal)}async function ct(n,e,t){let r=`/v1/voice/sessions/${i(e)}`;return n.client.delete(r,t?.signal)}async function gt(n,e,t,r){let o=`/v1/showcase/players/${i(e)}/${i(t)}`;return n.client.delete(o,r?.signal)}async function mt(n,e,t,r,o){let s=`/v1/inventory/${i(e)}/${i(t)}/recipes/execute`;return n.client.post(s,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function pt(n,e,t,r,o,s){let a=`/v1/saves/${i(e)}/${i(t)}/${i(r)}/finalize`;return n.client.post(a,o,s?.signal)}async function yt(n,e,t){let r=`/v1/games/${i(n.gameId())}/config/channels/${i(e)}`;return n.client.getWithEtag(r,{...t?.signal===void 0?{}:{signal:t.signal},...t?.ifNoneMatch===void 0?{}:{ifNoneMatch:t.ifNoneMatch}})}async function ft(n,e,t){let r=`/v1/inventory/loot-tables/${i(e)}/drop-rates`;return n.client.get(r,t?.signal)}async function ht(n,e,t,r,o){let s=`/v1/inventory/${i(e)}/${i(t)}/currencies/${i(r)}`;return n.client.get(s,o?.signal)}async function _t(n,e,t,r,o){let s=`/v1/settings/${i(e)}/${i(t)}/${i(r)}`;return n.client.getWithEtag(s,{...o?.signal===void 0?{}:{signal:o.signal},...o?.ifNoneMatch===void 0?{}:{ifNoneMatch:o.ifNoneMatch}})}async function bt(n,e,t,r){let o=new URLSearchParams;r?.include_buckets!==void 0&&o.set("include_buckets",String(r?.include_buckets)),r?.include_custom_data!==void 0&&o.set("include_custom_data",String(r?.include_custom_data)),r?.currency_limit!==void 0&&o.set("currency_limit",String(r?.currency_limit)),r?.currency_cursor!==void 0&&o.set("currency_cursor",String(r?.currency_cursor)),r?.item_limit!==void 0&&o.set("item_limit",String(r?.item_limit)),r?.item_cursor!==void 0&&o.set("item_cursor",String(r?.item_cursor)),r?.progression_limit!==void 0&&o.set("progression_limit",String(r?.progression_limit)),r?.progression_cursor!==void 0&&o.set("progression_cursor",String(r?.progression_cursor));let s=o.toString(),a=`/v1/inventory/${i(e)}/${i(t)}`+(s?`?${s}`:"");return n.client.get(a,r?.signal)}async function vt(n,e,t,r,o){let s=`/v1/inventory/${i(e)}/${i(t)}/items/${i(r)}`;return n.client.get(s,o?.signal)}async function Rt(n,e,t,r,o){let s=new URLSearchParams;o?.bucket_1!==void 0&&s.set("bucket_1",String(o?.bucket_1)),o?.bucket_2!==void 0&&s.set("bucket_2",String(o?.bucket_2)),o?.limit!==void 0&&s.set("limit",String(o?.limit));let a=s.toString(),l=`/v1/leaderboards/${i(e)}/${i(t)}/${i(r)}`+(a?`?${a}`:"");return n.client.get(l,o?.signal)}async function xt(n,e,t,r,o){let s=`/v1/inventory/${i(e)}/${i(t)}/orders/${i(r)}`;return n.client.get(s,o?.signal)}async function St(n,e,t,r,o){let s=`/v1/inventory/${i(e)}/${i(t)}/progressions/${i(r)}`;return n.client.get(s,o?.signal)}async function kt(n,e,t,r,o,s){let a=`/v1/inventory/${i(e)}/${i(t)}/catalogs/${i(r)}/recipes/${i(o)}/availability`;return n.client.get(a,s?.signal)}async function wt(n,e,t,r){let o=new URLSearchParams;r?.limit!==void 0&&o.set("limit",String(r?.limit));let s=o.toString(),a=`/v1/inventory/${i(e)}/${i(t)}/recipe-usage`+(s?`?${s}`:"");return n.client.get(a,r?.signal)}async function At(n,e,t,r,o){let s=`/v1/saves/${i(e)}/${i(t)}/${i(r)}`;return n.client.getWithEtag(s,{...o?.signal===void 0?{}:{signal:o.signal},...o?.ifNoneMatch===void 0?{}:{ifNoneMatch:o.ifNoneMatch}})}async function Tt(n,e,t){let r=`/v1/events/${i(e)}`;return n.client.get(r,t?.signal)}async function Pt(n,e,t){let r=`/v2/games/${i(n.gameId())}/game-rooms/${i(e)}`;return n.client.getWithEtag(r,{...t?.signal===void 0?{}:{signal:t.signal},...t?.ifNoneMatch===void 0?{}:{ifNoneMatch:t.ifNoneMatch}})}async function Ot(n,e,t){let r=new URLSearchParams;t?.bucket_1!==void 0&&r.set("bucket_1",String(t?.bucket_1)),t?.bucket_2!==void 0&&r.set("bucket_2",String(t?.bucket_2));let o=r.toString(),s=`/v1/leaderboards/${i(e)}`+(o?`?${o}`:"");return n.client.get(s,t?.signal)}async function Gt(n,e,t){let r=`/v1/profiles/players/${i(e)}`;return n.client.get(r,t?.signal)}async function Ct(n,e){let t=new URLSearchParams;e?.config_version!==void 0&&t.set("config_version",String(e?.config_version));let r=t.toString(),o="/v1/inventory/platform-funded-game-inventory-purchase-catalog"+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function Et(n,e,t){let r=`/v1/game-room-templates/${i(e)}`;return n.client.get(r,t?.signal)}async function It(n,e,t){let r=`/v1/games/${i(n.gameId())}/game-rooms/${i(e)}/room-args`;return n.client.get(r,t?.signal)}async function qt(n,e,t,r){let o=`/v1/showcase/players/${i(e)}/${i(t)}`;return n.client.get(o,r?.signal)}async function Lt(n,e,t){let r=`/v1/inventory/transfers/${i(e)}`;return n.client.get(r,t?.signal)}async function D(n,e,t){let r=`/v1/games/${i(n.gameId())}/analytics/events`;return n.client.post(r,e,t?.signal,{replaySafe:true})}async function $t(n,e,t){return n.client.post("/v1/inventory/transfers",e,t?.signal)}async function jt(n,e,t){return n.client.postBytes("/v1/functions/invoke",e,t?.signal)}async function Mt(n,e,t,r){let o=`/v1/games/${i(n.gameId())}/game-rooms/${i(e)}/kick/${i(t)}`;return n.client.post(o,void 0,r?.signal)}async function Ft(n,e){let t=new URLSearchParams;e?.periods_back!==void 0&&t.set("periods_back",String(e?.periods_back)),e?.player_id!==void 0&&t.set("player_id",String(e?.player_id));let r=t.toString(),o="/v1/challenges"+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function Ut(n,e,t,r){let o=`/v1/settings/${i(e)}/${i(t)}`;return n.client.get(o,r?.signal)}async function Bt(n,e,t,r){let o=new URLSearchParams;r?.limit!==void 0&&o.set("limit",String(r?.limit)),r?.cursor!==void 0&&o.set("cursor",String(r?.cursor));let s=o.toString(),a=`/v1/inventory/${i(e)}/${i(t)}/orders`+(s?`?${s}`:"");return n.client.get(a,r?.signal)}async function Nt(n,e,t,r){let o=`/v1/inventory/${i(e)}/${i(t)}/progressions`;return n.client.get(o,r?.signal)}async function Dt(n,e,t,r){let o=new URLSearchParams;r?.limit!==void 0&&o.set("limit",String(r?.limit)),r?.cursor!==void 0&&o.set("cursor",String(r?.cursor));let s=o.toString(),a=`/v1/saves/${i(e)}/${i(t)}`+(s?`?${s}`:"");return n.client.get(a,r?.signal)}async function Ht(n,e){let t=new URLSearchParams;e?.include_inactive!==void 0&&t.set("include_inactive",String(e?.include_inactive)),e?.limit!==void 0&&t.set("limit",String(e?.limit)),e?.offset!==void 0&&t.set("offset",String(e?.offset));let r=t.toString(),o="/v1/events"+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function Vt(n,e){let t=new URLSearchParams;e?.status!==void 0&&t.set("status",String(e?.status)),e?.game_channel!==void 0&&t.set("game_channel",String(e?.game_channel)),e?.game_room_type!==void 0&&t.set("game_room_type",String(e?.game_room_type)),e?.template_id!==void 0&&t.set("template_id",String(e?.template_id)),e?.template_slug!==void 0&&t.set("template_slug",String(e?.template_slug)),e?.limit!==void 0&&t.set("limit",String(e?.limit)),e?.cursor!==void 0&&t.set("cursor",String(e?.cursor));let r=t.toString(),o=`/v1/games/${i(n.gameId())}/game-rooms`+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function Wt(n,e){return n.client.get("/v1/game-room-templates",e?.signal)}async function zt(n,e){let t=new URLSearchParams;e.entity_type!==void 0&&t.set("entity_type",String(e.entity_type)),e.entity_id!==void 0&&t.set("entity_id",String(e.entity_id)),e?.direction!==void 0&&t.set("direction",String(e?.direction)),e?.status!==void 0&&t.set("status",String(e?.status)),e?.cursor!==void 0&&t.set("cursor",String(e?.cursor)),e?.limit!==void 0&&t.set("limit",String(e?.limit));let r=t.toString(),o="/v1/inventory/transfers"+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function Kt(n,e,t,r,o,s){let a=`/v1/inventory/${i(e)}/${i(t)}/progressions/${i(r)}/max`;return n.client.post(a,o,s?.signal)}async function Yt(n,e,t,r,o,s){let a=`/v1/settings/${i(e)}/${i(t)}/${i(r)}`;return n.client.put(a,o,s?.signal,{...s?.ifMatch===void 0?{}:{ifMatch:s.ifMatch}})}async function Jt(n,e,t,r){let o=`/v1/games/${i(n.gameId())}/game-rooms/${i(e)}/room-args`;return n.client.put(o,t,r?.signal)}async function Xt(n,e,t,r,o){let s=`/v1/showcase/players/${i(e)}/${i(t)}`;return n.client.put(s,r,o?.signal)}async function Qt(n,e,t){let r=`/v1/inventory/transfers/${i(e)}/reject`;return n.client.post(r,void 0,t?.signal)}async function Zt(n,e,t,r,o,s){let a=`/v1/saves/${i(e)}/${i(t)}/${i(r)}/upload-url`;return n.client.post(a,o,s?.signal,{replaySafe:true})}async function er(n,e,t,r,o,s){let a=`/v1/inventory/${i(e)}/${i(t)}/progressions/${i(r)}/reset`;return n.client.post(a,o,s?.signal)}async function nr(n,e,t,r,o){let s=`/v1/inventory/${i(e)}/${i(t)}/orders/simulate`;return n.client.post(s,r,o?.signal)}async function tr(n,e,t,r){let o=`/v2/games/${i(n.gameId())}/game-rooms/${i(e)}/transfer/${i(t)}`;return n.client.post(o,void 0,r?.signal)}async function rr(n,e,t,r){let o=`/v2/games/${i(n.gameId())}/game-rooms/${i(e)}`;return n.client.patch(o,t,r?.signal,{...r?.ifMatch===void 0?{}:{ifMatch:r.ifMatch}})}var oe="gem_";var ir=1e4,ar=50,lr=1e3,dr=65536-4*1024,se=n=>typeof n=="number"?n:0,ur=n=>typeof n=="string"?n:"";function ie(){let n=globalThis.crypto;return typeof n?.randomUUID=="function"?n.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{let t=Math.floor(Math.random()*16);return (e==="x"?t:t&3|8).toString(16)})}function cr(n){return n?.retryable===true}function gr(n,e){let t=n??{},r=Array.isArray(t.rejected)?t.rejected.map(o=>{let s=o??{};return {index:se(s.index),code:ur(s.code)}}):[];return {accepted:se(t.accepted),rejected:r,dropped:e,duplicate:t.duplicate===true}}function ae(n,e){return {event_uid:n.uid,name:n.name,offset_ms:Math.round(n.atMs)-e,player_id:n.playerId,dimensions:n.dimensions,measures:n.measures}}function le(n){let e=Math.max(1,Math.floor(n.maxQueue??lr)),t={client:n.client,gameId:()=>n.gameId},r=[],o=0,s=null,a=false,l=false,d=false,c=false,g=y=>{n.log?.(y);},b=()=>{s!==null&&(n.clock.clearTimeout(s),s=null);},x=()=>{s!==null||a||l||(s=n.clock.setTimeout(()=>{s=null,v().catch(()=>{});},ir));},f=()=>{let y=Math.min(r.length,100),h=128;for(let w=0;w<y;w+=1){let A=r[w];if(A===void 0)break;if(h+=JSON.stringify(ae(A,0)).length+1,h>dr)return Math.max(1,w)}return y};async function v(y){if(r.length===0)return {accepted:0,rejected:[],dropped:0,duplicate:false};b();let h=r.splice(0,f()),w=o;o=0;let A=Math.round(n.clock.now()),L={batch_id:ie(),sent_at_ms:A,events:h.map(S=>ae(S,A))};l=true;try{let S=await D(t,L,y===void 0?void 0:{signal:y}),T=gr(S,w);for(let be of T.rejected)g(`[gem] analytics: an event was refused (${be.code}). See the analytics_events section of your game config.`);return T}catch(S){if(cr(S))for(r=[...h,...r],o+=w;r.length>e;)r.shift(),o+=1;else g(`[gem] analytics: ${h.length} event(s) were discarded \u2014 the platform refused the batch and will refuse it again: ${String(S)}`);throw S}finally{l=false,r.length>0&&x();}}return {track(y,h,w={}){if(a)return;if(typeof y!="string"||y===""){c||(c=true,g(`[gem] analytics: '${h}' was not recorded \u2014 an event from a server has to name the player it is about. A game-server token names no player, so the platform cannot infer one; pass the id from join() or host.players().`));return}if(h.startsWith(oe)){d||(d=true,g(`[gem] analytics: '${h}' was not recorded \u2014 the gem_ prefix is reserved, and the platform's own events are client-sourced, so a server may not emit one at all. Name your event something else.`));return}let A={},L={};for(let[S,T]of Object.entries(w))typeof T=="string"?A[S]=T:typeof T=="number"&&Number.isFinite(T)&&(L[S]=T);for(;r.length>=e;)r.shift(),o+=1;r.push({uid:ie(),playerId:y,name:h,atMs:n.clock.now(),dimensions:A,measures:L}),r.length>=ar?v().catch(()=>{}):x();},flush:y=>v(y),get pending(){return r.length},dispose(){a=true,b(),r=[],o=0;}}}var mr=new Map([["function_error",false],["function_failed",false],["function_timeout",false],["function_not_published",false],["function_input_too_large",false],["functions_not_configured",false],["forbidden",false],["function_capacity_unavailable",true],["function_host_unreachable",true],["function_host_error",true],["rate_limited",true],["service_unavailable",true]]),I=class extends m{constructor(e,t){super(e.reason,e.status,e.detail,e.retryAfterSeconds,e.code),this.name="GemFunctionError",Object.assign(this,t);}get retryable(){return (this.code===void 0?void 0:mr.get(this.code))??super.retryable}},C=class{#e;constructor(e){this.#e=e;}async invoke(e,t={}){let r=pr(e),o;try{o=await this.#e(r,t.signal===void 0?{}:{signal:t.signal});}catch(s){throw s instanceof m?fr(s):s}return yr(o)}};function pr(n){if(n instanceof ArrayBuffer)return new Uint8Array(n);if(ArrayBuffer.isView(n))return new Uint8Array(n.buffer,n.byteOffset,n.byteLength);let e;try{e=JSON.stringify(n);}catch(t){throw new p(`the function input could not be serialised to JSON: ${String(t)}. Pass bytes, or a value JSON can carry. This is a bug in the call, not a server failure.`)}if(e===void 0)throw new p(`the function input is ${typeof n}, which JSON cannot carry. Pass bytes \u2014 an empty Uint8Array for no input \u2014 or a JSON value. This is a bug in the call, not a server failure.`);return new TextEncoder().encode(e)}function yr(n){let{bytes:e}=n,t=()=>new TextDecoder("utf-8",{fatal:true}).decode(e);return {bytes:e,...n.invocationId===void 0?{}:{invocationId:n.invocationId},text:t,json:()=>JSON.parse(t())}}function fr(n){let{details:e,invocationId:t}=X(n),o=e?.untrusted?.message,s=e?.reason;return new I(n,{...t===void 0?{}:{invocationId:t},...n.code==="function_error"&&typeof o=="string"?{functionMessage:o}:{},...n.code==="function_failed"&&typeof s=="string"?{failure:s}:{}})}var k=n=>typeof n=="string"?n:"",hr=/(?:Z|[+-]\d{2}:?\d{2})$/i;function de(n){let e=k(n);if(!hr.test(e))return 0;let t=Date.parse(e);return Number.isFinite(t)?Math.floor(t/1e3):0}var _r=/^[0-9a-f]{1,64}$/,br=/^[0-9a-f]{16}$/,vr=/^[A-Za-z][A-Za-z0-9_+\-/]{0,63}$/,Rr=/^(?:[01]\d|2[0-3]):[0-5]\d$/;function xr(n){let e=k(n),t=/^(\d{4})-(\d{2})-(\d{2})$/.exec(e);if(!t)return;let[r,o,s]=[Number(t[1]),Number(t[2]),Number(t[3])],a=new Date(Date.UTC(r,o-1,s));return a.getUTCFullYear()===r&&a.getUTCMonth()===o-1&&a.getUTCDate()===s?e:void 0}var Sr=4096,kr=new TextEncoder;function wr(n){let e=k(n.challenge_data),t=k(n.challenge_data_hash);return e===""||!br.test(t)?{}:kr.encode(e).length>Sr?{}:{data:e,dataHash:t}}function Ar(n){let e=n??{},t=de(e.period_start_at),r=de(e.period_ends_at);if(t===0||r===0)return;let o=k(e.slug),s=k(e.seed),a=xr(e.period_local_date),l=k(e.boundary),d=k(e.reset_time);return {id:k(e.progression_definition_id),...o===""?{}:{slug:o},window:k(e.window),periodStartAt:t,periodEndsAt:r,...a===void 0?{}:{periodLocalDate:a},boundary:vr.test(l)?l:"",resetTime:Rr.test(d)?d:"",seed:_r.test(s)?s:"",...wr(e)}}function ue(n){if(n!==void 0&&(!Number.isInteger(n)||n<0||n>400))throw new TypeError(`periodsBack must be an integer between 0 and 400, got ${String(n)}`)}function ce(n){let e=n??{};return Array.isArray(e.challenges)?e.challenges.map(Ar).filter(t=>t!==void 0):[]}function ge(n){return {async list(e){let{playerId:t,periodsBack:r,signal:o}=e??{};if(typeof t!="string"||t==="")throw new TypeError("gem.challenges.list needs { playerId }: a game-server token names no player, so the platform cannot tell whose period you mean. Pass the id from join() or gem.players().");ue(r);let s=await n({player_id:t,...r===void 0?{}:{periods_back:r},...o===void 0?{}:{signal:o}});return ce(s)}}}function Tr(n){let e={};for(let[t,r]of Object.entries(H))if(typeof r=="function"){let o=r;e[t]=(...s)=>o(n,...s);}return e}function F(n,e={}){let t=e.clock??G,r=e.baseUrl??n.apiBaseUrl;if(!r)throw new Error("this runtime names no gem-api host (host.apiBaseUrl is missing). The server image running this bundle predates token delivery \u2014 the bundle cannot call gem-api on it.");let o=N(n,{clock:t,...e.onAuthStateChange===void 0?{}:{onStateChange:e.onAuthStateChange}}),s=Q({baseUrl:r,tokenSource:o.source,defaultQuery:{game_id:n.gameId,channel:n.channel},...e.fetch===void 0?{}:{fetch:e.fetch}}),a=new P({transport:s,clock:t}),l={gameId:n.gameId,channel:n.channel,matchId:n.matchId,...n.gameRoomId===void 0?{}:{gameRoomId:n.gameRoomId}},d=Tr({client:a,gameId:()=>l.gameId}),c=l.gameRoomId,g=n.endMatch,b=n.log,x=le({client:a,clock:t,gameId:l.gameId,...typeof b=="function"?{log:v=>b.call(n,v)}:{}});return {identity:l,client:a,api:d,match:{end:async()=>{if(g===void 0)throw new Error("this runtime cannot end the match: the server image running this bundle predates host.endMatch, and only the platform half holds the allocation proof an end needs.");await g.call(n);}},analytics:x,functions:new C(d.invokeFunction),challenges:ge(d.listChallenges),...c===void 0?{}:{room:{get:v=>d.getGameRoomV2(c,v),args:async v=>{let y=await d.getGameRoomV2(c,v?.signal===void 0?{}:{signal:v.signal}),h=y.modified?y.body:void 0;if(h?.room_args==null||h.room_args_template==null)throw new m("not_found",404,"this room's template declares no room args",void 0,"room_args_not_defined");return {room_args:h.room_args,room_args_template:h.room_args_template}}}},dispose:()=>{x.dispose(),o.dispose();}}}var Pr=["explicit","stale_cleanup","game_room_closed","replaced","migration_failed","host_left","insufficient_players","all_left","expired","migration_rate_exceeded","game_room_gone","failed","idle","reclaimed"],Or=new Set(Pr);function me(n){return typeof n=="string"&&Or.has(n)?n:"unknown"}var R=class{#e;constructor(e){this.#e=e,Object.freeze(this);}toString(){return "[gem: use gem.text.toPlain()]"}toJSON(){return this.toString()}get[Symbol.toStringTag](){return "PlayerText"}static unwrap(e){return e.#e}};function q(n){return new R(n)}var pe={toPlain(n){return R.unwrap(n)},compare(n,e,t){let r=n instanceof R?R.unwrap(n):n,o=e instanceof R?R.unwrap(e):e,s;try{s=new Intl.Collator(t);}catch{s=new Intl.Collator;}return s.compare(r,o)},equals(n,e){let t=n instanceof R?R.unwrap(n):n,r=e instanceof R?R.unwrap(e):e;return t.normalize("NFC")===r.normalize("NFC")}};var ye="the match has not started yet: the runtime hands over the host at `init`, and this was read before that. Read it from `init` or later \u2014 a bundle that needs a value at module scope is reading it one call too early.";function V(n,e={}){let t=e.clock??G,r=()=>{let l=n();if(l===null)throw new Error(ye);return l},o=null,s=()=>{if(o===null)throw new Error(ye);return o};return {server:{get identity(){return s().identity},get client(){return s().client},get api(){return s().api},get match(){return s().match},get analytics(){return s().analytics},get functions(){return s().functions},get challenges(){return s().challenges},get room(){return s().room},dispose(){o?.dispose();},get sizeClass(){return r().sizeClass},get roomArgs(){return r().roomArgs},get roster(){return r().roster},players(){return r().players()},profile(l){let c=r().profile?.(l);if(!c)return null;let g=c.displayName;return typeof g!="string"||g===""?null:{displayName:q(g),...typeof c.displayTag=="string"&&c.displayTag!==""?{displayTag:q(c.displayTag)}:{},...typeof c.discriminator=="string"?{discriminator:c.discriminator}:{}}},playerNumber(l){return r().playerNumber?.(l)},send(l,d,c){c===void 0?r().send(l,d):r().send(l,d,c);},broadcast(l,d){d===void 0?r().broadcast(l):r().broadcast(l,d);},kick(l,d){d===void 0?r().kick(l):r().kick(l,d);},log(l){r().log(l);},warn(l){r().warn(l);}},attach:()=>{o=F(r(),{...e,clock:t});}}}function fe(n,e={}){let{server:t,attach:r}=V(()=>n,e);return r(),t}function Gr(n){if(n===void 0||typeof n.reason!="string"||n.reason==="")return;let e=n.platform_reason??n.endedReason;return {reason:n.reason,...e===void 0?{}:{endedReason:me(e)}}}function he(n,e={}){return ()=>{let t=null,{server:r,attach:o}=V(()=>t,e),s=n(r),a={async init(l){t=l,o(),await s.init?.();},async shutdown(l){let d=Gr(l);try{await s.shutdown?.(d);}finally{r.dispose();}}};return s.join&&(a.join=(l,d)=>s.join?.(l,d)),s.leave&&(a.leave=(l,d)=>s.leave?.(l,d)),s.message&&(a.message=(l,d,c,g)=>s.message?.(l,d,c,g)),a}}var Cr=new Set(["unlocked","already_unlocked","suppressed"]);function _e(n){let e=n?.changes;if(!Array.isArray(e))return [];let t=[];for(let r of e){let o=r??{};if(o.type!=="achievement_unlocked"||typeof o.outcome!="string"||!Cr.has(o.outcome)||typeof o.achievement_id!="string"||o.achievement_id==="")continue;let s=o.outcome;t.push({achievementId:o.achievement_id,progressionDefinitionId:typeof o.progression_definition_id=="string"?o.progression_definition_id:"",points:s==="unlocked"&&typeof o.points=="number"&&Number.isFinite(o.points)?o.points:0,outcome:s,...typeof o.reason=="string"?{reason:o.reason}:{}});}return t}
2
- export{_ as AuthError,j as CONDITIONAL_HEADERS,C as FunctionsApi,m as GemApiError,P as GemClient,I as GemFunctionError,R as PlayerText,p as TransportRefusal,_e as achievementReceipts,q as asPlayerText,F as createGemServer,re as createHostTokenSource,fe as createMatchServer,he as defineServer,G as systemClock,pe as text,K as toBase64};//# sourceMappingURL=gem-web-sdk.server.js.map
1
+ var ve=Object.defineProperty;var Re=(n,e)=>{for(var t in e)ve(n,t,{get:e[t],enumerable:true});};globalThis.__gemWebSdkVersion="[gem-web-sdk:sdkVersion:7.6.0]";function xe(n,e){return e!==void 0?!e:n==="chain_exhausted"}var $=class{constructor(e){this.options=e;}options;grant=null;state="pending";failure=null;generation=0;inFlight=null;rejected=false;get currentState(){return this.state}get lastFailure(){return this.failure}async get(){if(this.state==="lost")throw new _(this.failure??"unavailable","the session cannot be renewed");let e=this.seconds();if(this.grant&&e<this.grant.expiresAt-this.renewBefore())return this.grant.token;if(this.grant&&e>=this.grant.chainEndsAt)throw this.enter("lost","chain_exhausted"),new _("chain_exhausted","the token chain reached its ceiling");return this.refresh(this.nextReason())}nextReason(){return this.rejected?"rejected":this.grant?"expiring":"initial"}invalidate(e){e!==void 0&&this.grant!==null&&this.grant.token!==e||this.rejected&&this.grant===null||(this.grant=null,this.generation+=1,this.inFlight=null,this.rejected=true,this.state!=="lost"&&this.enter("pending"));}accept(e){this.state!=="lost"&&(this.grant=e,this.rejected=false,this.enter("ready"));}close(e="unavailable"){this.grant=null,this.generation+=1,this.inFlight=null,this.enter("lost",e);}refresh(e){if(this.inFlight)return this.inFlight;let t=this.generation;this.enter("pending");let r=this.options.request(e).then(o=>{if(t!==this.generation)throw new _("internal","token arrived for a superseded generation");return this.grant=o,this.rejected=false,this.enter("ready"),o.token}).catch(o=>{let s=Se(o),a=o?.retryable;throw t===this.generation&&this.enter(xe(s,typeof a=="boolean"?a:void 0)?"lost":"degraded",s),o instanceof _?o:new _(s,String(o))}).finally(()=>{this.inFlight===r&&(this.inFlight=null);});return this.inFlight=r,r}enter(e,t){this.failure=t??(e==="ready"?null:this.failure),this.state!==e&&(this.state=e,this.options.onStateChange?.(e,t));}renewBefore(){return this.options.renewBeforeSeconds??60}seconds(){return Math.floor(this.options.clock.now()/1e3)}},_=class n extends Error{constructor(t,r){super(`auth ${t}: ${r}`);this.reason=t;this.name="AuthError";}reason;static isAuthError(t){if(t instanceof n)return true;let r=t;return r?.name==="AuthError"&&typeof r.reason=="string"}};function Se(n){if(n instanceof _)return n.reason;let e=n?.reason;return typeof e=="string"&&["chain_exhausted","unavailable","timeout","internal"].includes(e)?e:"internal"}var p=class n extends Error{retryable=false;constructor(e){super(e),this.name="TransportRefusal";}static isRefusal(e){if(e instanceof n)return true;let t=e;return t?.name==="TransportRefusal"&&t.retryable===false}},j=["if-match","if-none-match"],W=4096;function ke(n){if(!n)return;let e={};for(let[t,r]of Object.entries(n)){let o=t.toLowerCase();if(!j.includes(o)||r===void 0)continue;let s=typeof r=="string"?we(r):r;if(typeof s!="string"||s.length>W||!Ae(s))throw new p(`the ${o} header value cannot be sent \u2014 it is not a string, is longer than ${W} characters, or contains a character outside the range an HTTP header value may carry. This is a malformed request, not a server failure; the value is withheld here rather than written to logs.`);s!==""&&(e[o]=s);}return Object.freeze(e)}function we(n){let e=o=>o===32||o===9||o===10||o===13,t=0,r=n.length;for(;t<r&&e(n.charCodeAt(t));)t++;for(;r>t&&e(n.charCodeAt(r-1));)r--;return n.slice(t,r)}function Ae(n){for(let e=0;e<n.length;e++){let t=n.charCodeAt(e);if(t!==9&&(t<32||t===127||t>255))return false}return true}function Te(n){let{bytes:e}=n;if(e!==void 0){if(Object.prototype.toString.call(e)!=="[object Uint8Array]")throw new p("the raw body is not a Uint8Array, so it cannot be sent as bytes. This is a malformed request, not a server failure.");if(n.body!==void 0)throw new p("the request carries both a JSON body and a raw body, and only one can be sent. This is a malformed request, not a server failure.");return new Uint8Array(e)}}function z(n,e){let t=e.replayUnauthorizedOnce??true;return {async request(r){let o={...r},s=ke(o.headers),a=Te(o),l=Object.freeze({...o,headers:s,...a===void 0?{}:{bytes:a}}),d=await e.tokenSource.get(),c=await n(l,d);if(c.status!==401||!t)return c;e.tokenSource.invalidate(d);let g=await e.tokenSource.get(),b=await n(l,g);if(b.status===401)throw e.tokenSource.close("unavailable"),new _("unavailable","the server refused a freshly minted token");return b}}}function K(n){let e=typeof n=="string"?new TextEncoder().encode(n):n;return btoa(Pe(e))}function Pe(n){let t="";for(let r=0;r<n.length;r+=32768)t+=String.fromCharCode(...n.subarray(r,r+32768));return t}var m=class extends Error{constructor(t,r,o,s,a){super(`${t} (${r}): ${o}`);this.reason=t;this.status=r;this.detail=o;this.retryAfterSeconds=s;this.code=a;this.name="GemApiError";}reason;status;detail;retryAfterSeconds;code;get retryable(){return this.reason==="unavailable"||this.reason==="rate_limited"}},J=new WeakMap;function X(n){return J.get(n)??{}}var Oe=new Set([408,429,500,502,503,504]),Ge=6e4;function Ee(n){if(n===void 0)return 2;if(!Number.isInteger(n)||n<0||n>10)throw new p(`maxRetries must be a whole number between 0 and 10; received ${JSON.stringify(n)}. This is a configuration fault, not a server failure.`);return n}var P=class{constructor(e){this.options=e;}options;async get(e,t){return this.send({method:"GET",path:e,signal:t},true)}async getWithEtag(e,t={}){let r=await this.sendRaw({method:"GET",path:e,...t.signal===void 0?{}:{signal:t.signal},...t.ifNoneMatch===void 0?{}:{headers:{"if-none-match":t.ifNoneMatch}}},true),o=r.etag===void 0?{}:{etag:r.etag};return r.status===304?{modified:false,...o}:{modified:true,body:r.body,...o}}async put(e,t,r,o={}){return this.send({method:"PUT",path:e,body:t,signal:r,...C(o)},o.replaySafe===true)}async post(e,t,r,o={}){return this.send({method:"POST",path:e,body:t,signal:r,...C(o)},o.replaySafe===true)}async postBytes(e,t,r,o={}){let s=await this.sendRaw({method:"POST",path:e,bytes:t,responseType:"bytes",signal:r,...C(o)},o.replaySafe===true);return {bytes:Ce(s.body),...s.invocationId===void 0?{}:{invocationId:s.invocationId}}}async patch(e,t,r,o={}){return this.send({method:"PATCH",path:e,body:t,signal:r,...C(o)},o.replaySafe===true)}async delete(e,t,r={}){return this.send({method:"DELETE",path:e,signal:t,...C(r)},r.replaySafe===true)}async send(e,t){return (await this.sendRaw(e,t)).body}async sendRaw(e,t){let r=t?Ee(this.options.maxRetries)+1:1,o=null;if(e.signal?.aborted)throw Y(e.signal);for(let s=0;s<r;s++){if(s>0&&await this.backoff(s,o,e.signal),e.signal?.aborted)throw Y(e.signal);let a;try{a=await this.options.transport.request(e);}catch(d){if(_.isAuthError(d)||p.isRefusal(d)||e.signal?.aborted||Ie(d))throw d;o=new m("unavailable",0,String(d));continue}if(a.status>=200&&a.status<300||a.status===304)return a;let l=qe(a);if(!Oe.has(a.status))throw l;o=l;}throw o??new m("unavailable",0,"no attempt was made")}backoff(e,t,r){if(r?.aborted)return Promise.resolve();let o=t?.retryAfterSeconds,s=o!==void 0?o*1e3:2**(e-1)*250,a=2**(e-1)*250,l=Math.min(Math.max(s,a),Ge);return new Promise(d=>{let c=this.options.clock,g=false,b=false,x,f=()=>{g||(g=true,b&&c.clearTimeout(x),r?.removeEventListener("abort",f),d());};r?.addEventListener("abort",f,{once:true}),x=c.setTimeout(f,l),b=true,g&&c.clearTimeout(x);})}};function Ce(n){if(n instanceof Uint8Array)return n;if(n==null)return new Uint8Array(0);let e=typeof n=="string"?n:JSON.stringify(n);return new TextEncoder().encode(e)}function C(n){return {...n.keepalive===void 0?{}:{keepalive:n.keepalive},...n.ifMatch===void 0?{}:{headers:{"if-match":n.ifMatch}}}}function Y(n){return n.reason!==void 0?n.reason:new DOMException("The operation was aborted.","AbortError")}function Ie(n){let e=n?.name;return e==="AbortError"||e==="TimeoutError"}function qe(n){let e=$e(n),t=Me(n.body),r={...t===void 0?{}:{details:t},...n.invocationId===void 0?{}:{invocationId:n.invocationId}};return Object.keys(r).length>0&&J.set(e,r),e}var Le=new Map([["insufficient_funds","insufficient_funds"]]);function $e(n){let{status:e,body:t}=n,r=je(t),o=n.retryAfterSeconds??Ue(t),s=Fe(t),a=s===void 0?void 0:Le.get(s);if(a!==void 0)return new m(a,e,r,void 0,s);switch(e){case 304:return new m("not_modified",e,r);case 400:case 422:return new m("invalid",e,r,void 0,s);case 403:return new m("forbidden",e,r,void 0,s);case 404:return new m("not_found",e,r,void 0,s);case 402:return new m("insufficient_funds",e,r,void 0,s);case 409:return new m("conflict",e,r,void 0,s);case 412:return new m("precondition_failed",e,r,void 0,s);case 413:return new m("too_large",e,r,void 0,s);case 429:return new m("rate_limited",e,r,o,s);default:return new m("unavailable",e,r,o,s)}}function je(n){if(typeof n=="string")return n;let e=n?.message;if(typeof e=="string")return e;let t=n?.error;if(typeof t=="string")return t;let r=t?.message;return typeof r=="string"?r:"no detail"}function Me(n){let t=n?.error?.details;return t===null?void 0:t}function Fe(n){let t=n?.error?.code;return typeof t=="string"&&t.length>0?t:void 0}function Ue(n){let e=n?.retryAfterSeconds;return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:void 0}function Be(n){let e=n.lastIndexOf("@");return (e===-1?n:`***@${n.slice(e+1)}`).slice(0,200)}var Ne=new Set(j);function De(n){if(!n)return {};let e={};for(let[t,r]of Object.entries(n))Ne.has(t.toLowerCase())&&(e[t.toLowerCase()]=r);return e}function Q(n){let e=n.fetch??globalThis.fetch.bind(globalThis);return z(async(t,r)=>{let o;try{o=new URL(n.baseUrl.replace(/\/+$/,""));}catch{throw new p("the configured baseUrl is not a valid URL. Its value is withheld here rather than written to logs. This is a configuration fault, not a server failure.")}let s;try{s=new URL(o.href.replace(/\/+$/,"")+t.path);}catch{throw new p(`${JSON.stringify(typeof t.path=="string"?Be(t.path):"(a non-string path)")} does not form a valid URL against ${o.protocol}//${o.host}. This is a malformed request, not a server failure.`)}if(s.protocol!==o.protocol||s.host!==o.host)throw new p(`${JSON.stringify(s.pathname)} resolves to ${s.protocol}//${s.host}, not ${o.protocol}//${o.host}. A request path may not change the request's origin \u2014 it carries the play token.`);if(s.username!==""||s.password!==""){let f=o.username!==""||o.password!=="",v=s.username!==o.username||s.password!==o.password,y=f?v?"baseUrl (and possibly the request path)":"baseUrl":"request path";throw new p(`the ${y} puts credentials in the URL, which cannot be fetched (${t.method} ${s.pathname}). The value is withheld here rather than written to logs. This is a malformed request, not a server failure.`)}for(let[f,v]of Object.entries(n.defaultQuery??{}))s.searchParams.has(f)||s.searchParams.set(f,v);let a=t.bytes,l=t.bytes===void 0?void 0:"application/octet-stream";try{t.body!==void 0&&(a=JSON.stringify(t.body),l="application/json");}catch(f){throw new p(`the body of ${t.method} ${JSON.stringify(s.pathname)} could not be serialised to JSON: ${String(f)}. This is a bug in the request, not a server failure \u2014 retrying sends the same unserialisable value.`)}let d=await e(s.toString(),{method:t.method,headers:{authorization:`Bearer ${r}`,...l===void 0?{}:{"content-type":l},...De(t.headers)},body:a,signal:t.signal,...t.keepalive===void 0?{}:{keepalive:t.keepalive},credentials:"omit",mode:"cors",redirect:"error",cache:"no-store",referrerPolicy:"no-referrer"}),c=null;if(t.responseType==="bytes"&&d.status>=200&&d.status<300)c=new Uint8Array(await d.arrayBuffer());else {let f=await d.text();if(f.length>0)try{c=JSON.parse(f);}catch{c=f;}}let g=d.headers.get("etag"),b=He(d.headers.get("retry-after")),x=d.headers.get("x-gem-invocation-id");return {status:d.status,body:c,...g===null?{}:{etag:g},...b===void 0?{}:{retryAfterSeconds:b},...x===null||x===""?{}:{invocationId:x}}},n)}function He(n){if(n===null)return;let e=n.trim();if(!/^\d+$/.test(e))return;let t=Number(e);return Number.isFinite(t)?t:void 0}var Ve="gem-web-bridge";var O=65536,Z=8,M=5e3,ee=1024;function B(n){return Object.freeze(Object.assign(Object.create(null),n))}B({"gem.handshake":30,"gem.handshake.accept":5,"gem.token":30,"gem.token.denied":30,"gem.player":12,"gem.pause":120,"gem.prefs":60,"gem.cohorts":12,"gem.earnAllowanceChanged":30,"gem.viewport":60,"gem.deviceSettings":12,"gem.willTerminate":10,"gem.roomEvent":120,"gem.socketState":12,"gem.seatedEvent":60,"gem.autoStartFailedEvent":30,"gem.signalEvent":1800,"gem.dedicatedEvent":120,"gem.partyResult":30,"gem.clusterTarget":12,"gem.devtools":30,"gem.screenshot":6,"gem.screenshot.denied":12,"gem.requestContext":12,"gem.gameContext":12,"gem.signal":1200,"gem.dedicatedOffer":60,"gem.partyRequest":12,"gem.ready":5,"gem.engaged":5,"gem.progress":600,"gem.requestToken":12,"gem.requestLocalServer":6,"gem.localServer":30,"gem.localServer.denied":30,"gem.exit":5,"gem.openExternal":6,"gem.requestFullscreen":30,"gem.audioState":120,"gem.rewardCue":60,"gem.walletDisplay":60,"gem.requestShare":6,"gem.frameStats":120,"gem.error":60,"gem.requestPurchase":12,"gem.purchaseResult":30,"gem.deviceSettings.put":30,"gem.deviceSettings.result":30,"gem.requestAd":6,"gem.adResult":12,"gem.requestSignIn":6,"gem.signInResult":12,"gem.requestFriendChallenge":12,"gem.friendChallengeResult":30,__malformed:60});B({"gem.requestAd":"ads","gem.adResult":"ads","gem.requestSignIn":"signIn","gem.signInResult":"signIn","gem.requestPurchase":"purchases","gem.purchaseResult":"purchases","gem.requestFriendChallenge":"friendChallenges","gem.friendChallengeResult":"friendChallenges","gem.devtools":"devtools","gem.screenshot":"screenshot","gem.screenshot.denied":"screenshot","gem.requestContext":"feedbackContext","gem.gameContext":"feedbackContext","gem.roomEvent":"rooms","gem.signal":"p2p","gem.signalEvent":"p2p","gem.dedicatedOffer":"dedicated","gem.dedicatedEvent":"dedicated","gem.clusterTarget":"clusterTarget","gem.partyRequest":"parties","gem.partyResult":"parties","gem.autoStartFailedEvent":"autoStartFailure","gem.seatedEvent":"partySeating","gem.socketState":"socketState","gem.audioState":"audioState","gem.rewardCue":"rewardCue","gem.frameStats":"frameStats","gem.engaged":"engagement","gem.viewport":"viewport","gem.walletDisplay":"walletDisplay","gem.requestLocalServer":"localHost","gem.localServer":"localHost","gem.localServer.denied":"localHost","gem.cohorts":"cohorts","gem.earnAllowanceChanged":"earnAllowance","gem.deviceSettings":"deviceSettings","gem.deviceSettings.put":"deviceSettings","gem.deviceSettings.result":"deviceSettings","gem.requestShare":"share"});function ze(n){let e=/^([a-z][a-z0-9+.-]*):\/\/([a-z0-9.-]+|\[[0-9a-f:.]+\])(:([0-9]{1,5}))?$/i.exec(n);return e===null?false:e[4]===void 0||Number(e[4])<=65535}function Ke(n){let e;try{e=new URL(n);}catch{return false}return e.username!==""||e.password!==""?false:e.protocol==="https:"?true:e.protocol==="http:"&&(e.hostname==="localhost"||e.hostname==="127.0.0.1")}function Ye(n){return /^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i.test(n)}function Je(n){return /^[a-z_]+$/.test(n)}function U(n,e,t){if(e>Z)return `nesting deeper than ${Z}`;if(++t.nodes>M)return `more than ${M} values`;if(t.bytes>O)return `over the ${O} byte limit`;if(n==null)return t.bytes+=4,null;let r=typeof n;if(r==="boolean")return t.bytes+=5,null;if(r==="number")return t.bytes+=8,null;if(r==="string")return t.bytes+=n.length*3+2,null;if(r!=="object")return `${r} is not plain data`;let o=n;if(t.seen.has(o))return "a repeated or cyclic object reference";if(t.seen.add(o),Array.isArray(n)){if(n.length>ee)return `an array of ${n.length} entries, over the ${ee} limit`;t.bytes+=2;for(let l of n){let d=U(l,e+1,t);if(d)return d}return null}let s=Object.getPrototypeOf(n);if(s!==Object.prototype&&s!==null)return "a value that is not a plain object";t.bytes+=2;let a=n;for(let l in a){if(!Object.prototype.hasOwnProperty.call(a,l))continue;if(++t.nodes>M)return `more than ${M} values`;if(t.bytes+=l.length*3+4,t.bytes>O)return `over the ${O} byte limit`;let d=U(a[l],e+1,t);if(d)return d}return null}function Xe(n){let e={nodes:0,bytes:0,seen:new Set},t=U(n,0,e);return t?`message contains ${t}`:e.bytes>O?`message is over the ${O} byte limit`:null}var Qe={origin:[ze,"not a well-formed origin"],url:[Ke,"not a safe absolute http(s) URL"],bcp47:[Ye,"not a well-formed BCP 47 tag"],code:[Je,"not a code of lower-case letters and underscores"]};function ne(n,e,t){for(let r of e){let o=t===""?r.n:`${t}.${r.n}`,s=n[r.n];if(s==null){if(r.o)continue;return `${o}: required`}let a=te(s,r,o);if(a)return a}return null}function te(n,e,t){switch(e.k){case "string":{if(typeof n!="string")return `${t}: expected string`;if(n.length>e.max)return `${t}: exceeds ${e.max} characters`;if(e.f){let[r,o]=Qe[e.f];if(!r(n))return `${t}: ${o}`}return null}case "int":return typeof n!="number"||!Number.isInteger(n)?`${t}: expected integer`:n<e.lo||n>e.hi?`${t}: out of range ${e.lo}..${e.hi}`:null;case "boolean":return typeof n=="boolean"?null:`${t}: expected boolean`;case "enum":{let r=e.v;return r.includes(n)?null:`${t}: not one of ${r.join("|")}`}case "object":return typeof n!="object"||n===null||Array.isArray(n)?`${t}: expected object`:ne(n,e.fs,t);case "json":return typeof n!="object"||n===null||Array.isArray(n)?`${t}: expected a plain object`:null;case "array":{if(!Array.isArray(n))return `${t}: expected array`;if(n.length>e.max)return `${t}: exceeds ${e.max} items`;let r=e.it,o=`${t}[]`;for(let s of n){if(s==null){if(r.o)continue;return `${o}: required`}let a=te(s,r,o);if(a)return a}return null}default:{let r=e.k;return `${t}: unknown kind ${String(r)}`}}}function u(n,e){return t=>{let r=Xe(t);if(r)return r;if(typeof t!="object"||t===null||Array.isArray(t))return "message: expected object";let o=t;return o.gem!==Ve?"gem: wrong protocol marker":o.type!==n?`type: expected ${n}`:ne(o,e,"")}}var Ze=u("gem.handshake",[{n:"versions",k:"object",fs:[{n:"min",k:"int",lo:1,hi:1e3},{n:"max",k:"int",lo:1,hi:1e3}]},{n:"capabilities",k:"array",o:1,max:64,it:{n:"",k:"string",max:64}},{n:"embedder",k:"string",max:2048,f:"origin"},{n:"unbidden",k:"boolean",o:1}]),en=u("gem.handshake.accept",[{n:"v",k:"int",lo:1,hi:1e3},{n:"capabilities",k:"array",o:1,max:64,it:{n:"",k:"string",max:64}}]),nn=u("gem.token",[{n:"token",k:"string",max:4096},{n:"requestId",k:"string",o:1,max:64},{n:"generation",k:"int",lo:0,hi:2147483647},{n:"apiBaseUrl",k:"string",o:1,max:512,f:"url"},{n:"playerId",k:"string",max:64},{n:"gameId",k:"string",max:64},{n:"channel",k:"enum",v:["dev","test","release"]},{n:"gameVersion",k:"string",o:1,max:64},{n:"expiresAt",k:"int",lo:0,hi:4102444800},{n:"chainEndsAt",k:"int",lo:0,hi:4102444800},{n:"allowDevTools",k:"boolean",o:1}]),tn=u("gem.token.denied",[{n:"requestId",k:"string",max:64},{n:"retryable",k:"boolean"},{n:"retryAfterMs",k:"int",o:1,lo:0,hi:36e5},{n:"reason",k:"enum",v:["chain_exhausted","unavailable"]},{n:"correlationId",k:"string",max:64}]),rn=u("gem.player",[{n:"untrusted",k:"object",fs:[{n:"displayName",k:"string",max:64},{n:"displayTag",k:"string",o:1,max:80},{n:"displayHandle",k:"string",max:80}]},{n:"playerId",k:"string",o:1,max:64},{n:"discriminator",k:"string",o:1,max:8},{n:"avatarIconUrl",k:"string",o:1,max:2048,f:"url"},{n:"badges",k:"array",o:1,max:2,it:{n:"",k:"object",fs:[{n:"itemId",k:"string",max:64},{n:"iconUrl",k:"string",max:2048,f:"url"}]}},{n:"displayTag",k:"string",max:8},{n:"avatarUrl",k:"string",o:1,max:2048,f:"url"},{n:"boost",k:"object",o:1,fs:[{n:"multipliers",k:"array",max:8,it:{n:"",k:"object",fs:[{n:"currencyId",k:"string",max:64},{n:"currencySlug",k:"string",max:32},{n:"multiplierBp",k:"int",lo:1e4,hi:1e6}]}},{n:"expiresInDays",k:"int",o:1,lo:1,hi:7}]}]),on=u("gem.pause",[{n:"paused",k:"boolean"}]),sn=u("gem.prefs",[{n:"reducedMotion",k:"boolean"},{n:"muted",k:"boolean"},{n:"showFrameStats",k:"boolean",o:1},{n:"locale",k:"string",max:35,f:"bcp47"}]),an=u("gem.cohorts",[{n:"cohorts",k:"array",max:8,it:{n:"",k:"object",fs:[{n:"experimentId",k:"string",max:36},{n:"variantKey",k:"string",max:32}]}}]),ln=u("gem.earnAllowanceChanged",[]),dn=u("gem.viewport",[{n:"insets",k:"object",fs:[{n:"top",k:"int",lo:0,hi:4096},{n:"right",k:"int",lo:0,hi:4096},{n:"bottom",k:"int",lo:0,hi:4096},{n:"left",k:"int",lo:0,hi:4096}]},{n:"reserved",k:"array",o:1,max:4,it:{n:"",k:"object",fs:[{n:"x",k:"int",lo:0,hi:16384},{n:"y",k:"int",lo:0,hi:16384},{n:"width",k:"int",lo:0,hi:16384},{n:"height",k:"int",lo:0,hi:16384}]}}]),un=u("gem.deviceSettings",[{n:"settings",k:"json",o:1}]),cn=u("gem.willTerminate",[{n:"reason",k:"enum",v:["grant_expiring","session_ended","navigating","kill_switch"]},{n:"graceMs",k:"int",lo:0,hi:6e4}]),gn=u("gem.roomEvent",[{n:"event",k:"enum",v:["updated","match_started","match_ready","match_failed","version_stale"]},{n:"roomId",k:"string",max:64},{n:"matchId",k:"string",o:1,max:64},{n:"version",k:"int",o:1,lo:0,hi:2147483647},{n:"reason",k:"string",o:1,max:64},{n:"platform",k:"enum",o:1,v:["universal","mobile"]}]),mn=u("gem.socketState",[{n:"connected",k:"boolean"},{n:"reason",k:"enum",o:1,v:["connecting","dropped","watchdog","terminal"]}]),pn=u("gem.seatedEvent",[{n:"roomId",k:"string",max:64}]),yn=u("gem.autoStartFailedEvent",[{n:"roomId",k:"string",max:64},{n:"code",k:"string",max:64}]),fn=u("gem.signalEvent",[{n:"event",k:"enum",v:["hello","offer","answer","ice","peerJoined","peerLeft","migration","matchEnded","error"]},{n:"matchId",k:"string",max:64},{n:"data",k:"json"}]),hn=u("gem.dedicatedEvent",[{n:"event",k:"enum",v:["answer","error","matchEnded"]},{n:"matchId",k:"string",max:64},{n:"sdp",k:"string",o:1,max:10240},{n:"sessionId",k:"string",o:1,max:64},{n:"code",k:"string",o:1,max:64},{n:"message",k:"string",o:1,max:256},{n:"reason",k:"string",o:1,max:64}]),_n=u("gem.partyResult",[{n:"requestId",k:"string",max:64},{n:"partyId",k:"string",o:1,max:64}]),bn=u("gem.clusterTarget",[{n:"clusterTargetId",k:"string",max:64},{n:"clusterTargetIds",k:"array",o:1,max:3,it:{n:"",k:"string",max:64}}]),vn=u("gem.devtools",[{n:"action",k:"enum",v:["open","close","toggle"]}]),Rn=u("gem.screenshot",[{n:"maxWidth",k:"int",lo:1,hi:7680},{n:"maxHeight",k:"int",lo:1,hi:4320}]),xn=u("gem.screenshot.denied",[{n:"reason",k:"enum",v:["not_wired","no_source","unsupported","unreadable","tainted","too_large","busy","declined","failed"]},{n:"retryable",k:"boolean"}]),Sn=u("gem.requestContext",[]),kn=u("gem.gameContext",[{n:"context",k:"json"}]),wn=u("gem.signal",[{n:"signal",k:"enum",v:["join","offer","answer","ice","migrationAck","hostUnreachable"]},{n:"matchId",k:"string",max:64},{n:"data",k:"json"}]),An=u("gem.dedicatedOffer",[{n:"matchId",k:"string",max:64},{n:"sdp",k:"string",max:10240},{n:"intent",k:"enum",v:["initial","ice_restart","full_reconnect"]}]),Tn=u("gem.partyRequest",[{n:"requestId",k:"string",max:64}]),Pn=u("gem.ready",[]),On=u("gem.engaged",[]),Gn=u("gem.progress",[{n:"loaded",k:"int",lo:0,hi:1099511627776},{n:"total",k:"int",lo:0,hi:1099511627776}]),En=u("gem.requestToken",[{n:"requestId",k:"string",max:64},{n:"reason",k:"enum",v:["initial","expiring","rejected"]}]),Cn=u("gem.requestLocalServer",[{n:"requestId",k:"string",max:64},{n:"gameRoomId",k:"string",max:64}]),In=u("gem.localServer",[{n:"requestId",k:"string",max:64},{n:"serverId",k:"string",o:1,max:128}]),qn=u("gem.localServer.denied",[{n:"requestId",k:"string",max:64},{n:"retryable",k:"boolean"},{n:"reason",k:"enum",v:["refused","unavailable"]}]),Ln=u("gem.exit",[{n:"reason",k:"string",o:1,max:64}]),$n=u("gem.openExternal",[{n:"url",k:"string",max:2048,f:"url"}]),jn=u("gem.requestFullscreen",[{n:"enabled",k:"boolean"}]),Mn=u("gem.audioState",[{n:"muted",k:"boolean"}]),Fn=u("gem.rewardCue",[{n:"currencySlug",k:"string",max:32},{n:"expected",k:"int",o:1,lo:1,hi:1e9},{n:"origin",k:"object",o:1,fs:[{n:"x",k:"int",lo:0,hi:16384},{n:"y",k:"int",lo:0,hi:16384}]}]),Un=u("gem.walletDisplay",[{n:"visible",k:"boolean"},{n:"currencies",k:"array",o:1,max:8,it:{n:"",k:"string",max:64}},{n:"score",k:"boolean",o:1}]),Bn=u("gem.requestShare",[{n:"params",k:"array",max:16,it:{n:"",k:"object",fs:[{n:"key",k:"string",max:64},{n:"value",k:"string",max:512}]}}]),Nn=u("gem.frameStats",[{n:"fps",k:"int",lo:0,hi:1e3},{n:"frameTimeP95Ms",k:"int",lo:0,hi:1e5}]),Dn=u("gem.error",[{n:"code",k:"enum",v:["version_mismatch","handshake_timeout","handshake_duplicate","invalid_message","rate_limited","token_unavailable","unsupported","unsupported_capability","internal"]},{n:"message",k:"string",o:1,max:256}]),Hn=u("gem.requestPurchase",[{n:"requestId",k:"string",max:64},{n:"purchaseKind",k:"enum",v:["item","recipe"]},{n:"targetId",k:"string",max:64},{n:"currencySlug",k:"string",max:32},{n:"quantity",k:"int",o:1,lo:1,hi:10},{n:"catalogId",k:"string",o:1,max:64}]),Vn=u("gem.purchaseResult",[{n:"requestId",k:"string",max:64},{n:"outcome",k:"enum",v:["ok","declined","unavailable"]},{n:"reason",k:"string",o:1,max:64,f:"code"},{n:"purchaseId",k:"string",o:1,max:64}]),Wn=u("gem.deviceSettings.put",[{n:"requestId",k:"string",max:64},{n:"settings",k:"json"}]),zn=u("gem.deviceSettings.result",[{n:"requestId",k:"string",max:64},{n:"outcome",k:"enum",v:["stored","too_large","unavailable"]}]),Kn=u("gem.requestAd",[{n:"requestId",k:"string",max:64},{n:"placement",k:"string",max:32},{n:"format",k:"enum",v:["interstitial","rewarded"]}]),Yn=u("gem.adResult",[{n:"requestId",k:"string",max:64},{n:"outcome",k:"enum",v:["shown","no_ad","unavailable"]}]),Jn=u("gem.requestSignIn",[{n:"requestId",k:"string",max:64}]),Xn=u("gem.signInResult",[{n:"requestId",k:"string",max:64},{n:"outcome",k:"enum",v:["signed_in","declined","unavailable"]}]),Qn=u("gem.requestFriendChallenge",[{n:"requestId",k:"string",max:64},{n:"playerId",k:"string",max:64},{n:"template",k:"string",max:64},{n:"params",k:"json",o:1}]),Zn=u("gem.friendChallengeResult",[{n:"requestId",k:"string",max:64},{n:"outcome",k:"enum",v:["accepted","cancelled","refused","unavailable","rate_limited","invalid"]},{n:"code",k:"string",o:1,max:64},{n:"param",k:"string",o:1,max:64},{n:"channel",k:"string",o:1,max:16},{n:"configVersion",k:"int",o:1,lo:0,hi:9007199254740991},{n:"retryAfterMs",k:"int",o:1,lo:0,hi:864e5},{n:"detail",k:"string",o:1,max:300}]);B({"gem.handshake":Ze,"gem.handshake.accept":en,"gem.token":nn,"gem.token.denied":tn,"gem.player":rn,"gem.pause":on,"gem.prefs":sn,"gem.cohorts":an,"gem.earnAllowanceChanged":ln,"gem.viewport":dn,"gem.deviceSettings":un,"gem.willTerminate":cn,"gem.roomEvent":gn,"gem.socketState":mn,"gem.seatedEvent":pn,"gem.autoStartFailedEvent":yn,"gem.signalEvent":fn,"gem.dedicatedEvent":hn,"gem.partyResult":_n,"gem.clusterTarget":bn,"gem.devtools":vn,"gem.screenshot":Rn,"gem.screenshot.denied":xn,"gem.requestContext":Sn,"gem.gameContext":kn,"gem.signal":wn,"gem.dedicatedOffer":An,"gem.partyRequest":Tn,"gem.ready":Pn,"gem.engaged":On,"gem.progress":Gn,"gem.requestToken":En,"gem.requestLocalServer":Cn,"gem.localServer":In,"gem.localServer.denied":qn,"gem.exit":Ln,"gem.openExternal":$n,"gem.requestFullscreen":jn,"gem.audioState":Mn,"gem.rewardCue":Fn,"gem.walletDisplay":Un,"gem.requestShare":Bn,"gem.frameStats":Nn,"gem.error":Dn,"gem.requestPurchase":Hn,"gem.purchaseResult":Vn,"gem.deviceSettings.put":Wn,"gem.deviceSettings.result":zn,"gem.requestAd":Kn,"gem.adResult":Yn,"gem.requestSignIn":Jn,"gem.signInResult":Xn,"gem.requestFriendChallenge":Qn,"gem.friendChallengeResult":Zn});var G={now:()=>Date.now(),setTimeout:(n,e)=>setTimeout(n,e),clearTimeout:n=>clearTimeout(n)};var et=1e4;function re(n,e){return N(n,e)}function N(n,e){if(typeof n.serverToken!="function"||typeof n.onServerToken!="function")throw new Error("this runtime delivers no game-server token: host.serverToken/onServerToken are missing. The server image running this bundle predates token delivery \u2014 the bundle cannot call gem-api on it.");let t=a=>({token:a.token,expiresAt:a.expiresAt,chainEndsAt:Number.POSITIVE_INFINITY}),r=null,o=new $({clock:e.clock,...e.onStateChange===void 0?{}:{onStateChange:e.onStateChange},request:()=>new Promise((a,l)=>{let d=e.clock.setTimeout(()=>{r=null,l({reason:"unavailable",retryable:true});},e.timeoutMs??et);r={resolve:c=>{e.clock.clearTimeout(d),a(c);},reject:l,timer:d};})}),s=n.onServerToken(a=>{let l=t(a),d=r;if(d){r=null,d.resolve(l);return}o.accept(l);});return {source:o,dispose(){s(),r&&(e.clock.clearTimeout(r.timer),r.reject({reason:"unavailable",retryable:false}),r=null);}}}var H={};Re(H,{acceptTransfer:()=>nt,addEntityProgression:()=>tt,adminAction:()=>rt,cancelInventoryTransfer:()=>ot,claimEntityProgressionRewards:()=>st,closeGameRoom:()=>it,createEntityBatchOrder:()=>at,createEntityOrder:()=>lt,createSession:()=>dt,deleteEntityGameSetting:()=>ut,deleteEntitySave:()=>ct,deleteSession:()=>gt,deleteShowcaseValue:()=>mt,executeEntityRecipe:()=>pt,finalizeSaveUpload:()=>yt,getChannelAssignment:()=>ft,getDropRates:()=>ht,getEntityCurrency:()=>_t,getEntityGameSetting:()=>bt,getEntityInventory:()=>vt,getEntityInventoryItem:()=>Rt,getEntityLeaderboard:()=>xt,getEntityOrder:()=>St,getEntityProgression:()=>kt,getEntityRecipeAvailability:()=>wt,getEntityRecipeUsage:()=>At,getEntitySave:()=>Tt,getEvent:()=>Pt,getGameRoomV2:()=>Ot,getLeaderboard:()=>Gt,getPlayerGameProfile:()=>Et,getPurchaseCatalog:()=>Ct,getResolvedTemplate:()=>It,getRoomArgs:()=>qt,getShowcaseValue:()=>Lt,getTransferDetails:()=>$t,ingestAnalyticsEvents:()=>D,initiateInventoryTransfer:()=>jt,invokeFunction:()=>Mt,kickPlayer:()=>Ft,listChallenges:()=>Ut,listEntityGameSettings:()=>Bt,listEntityOrders:()=>Nt,listEntityProgressions:()=>Dt,listEntitySaves:()=>Ht,listEvents:()=>Vt,listGameRooms:()=>Wt,listResolvedTemplates:()=>zt,listTransfers:()=>Kt,maxEntityProgression:()=>Yt,putEntityGameSetting:()=>Jt,putRoomArgs:()=>Xt,putShowcaseValue:()=>Qt,rejectTransfer:()=>Zt,requestSaveUploadUrl:()=>er,resetEntityProgression:()=>nr,simulateEntityOrder:()=>tr,transferHostV2:()=>rr,updateGameRoomV2:()=>or});function i(n){let e=String(n);if(!/^[A-Za-z0-9_.-]{1,128}$/.test(e)||e==="."||e==="..")throw new TypeError(`${JSON.stringify(e)} is not a usable path segment \u2014 it is interpolated into a URL`);return encodeURIComponent(e)}async function nt(n,e,t){let r=`/v1/inventory/transfers/${i(e)}/accept`;return n.client.post(r,void 0,t?.signal)}async function tt(n,e,t,r,o,s){let a=`/v1/inventory/${i(e)}/${i(t)}/progressions/${i(r)}/add`;return n.client.post(a,o,s?.signal)}async function rt(n,e,t,r){let o=`/v1/voice/sessions/${i(e)}/admin`;return n.client.post(o,t,r?.signal)}async function ot(n,e,t){let r=`/v1/inventory/transfers/${i(e)}/cancel`;return n.client.post(r,void 0,t?.signal)}async function st(n,e,t,r,o,s){let a=`/v1/inventory/${i(e)}/${i(t)}/progressions/${i(r)}/claim`;return n.client.post(a,o,s?.signal)}async function it(n,e,t){let r=`/v1/games/${i(n.gameId())}/game-rooms/${i(e)}`;return n.client.delete(r,t?.signal)}async function at(n,e,t,r,o){let s=`/v1/inventory/${i(e)}/${i(t)}/orders/batch`;return n.client.post(s,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function lt(n,e,t,r,o){let s=`/v1/inventory/${i(e)}/${i(t)}/orders`;return n.client.post(s,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function dt(n,e,t){return n.client.post("/v1/voice/sessions",e,t?.signal)}async function ut(n,e,t,r,o){let s=`/v1/settings/${i(e)}/${i(t)}/${i(r)}`;return n.client.delete(s,o?.signal)}async function ct(n,e,t,r,o){let s=`/v1/saves/${i(e)}/${i(t)}/${i(r)}`;return n.client.delete(s,o?.signal)}async function gt(n,e,t){let r=`/v1/voice/sessions/${i(e)}`;return n.client.delete(r,t?.signal)}async function mt(n,e,t,r){let o=`/v1/showcase/players/${i(e)}/${i(t)}`;return n.client.delete(o,r?.signal)}async function pt(n,e,t,r,o){let s=`/v1/inventory/${i(e)}/${i(t)}/recipes/execute`;return n.client.post(s,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function yt(n,e,t,r,o,s){let a=`/v1/saves/${i(e)}/${i(t)}/${i(r)}/finalize`;return n.client.post(a,o,s?.signal)}async function ft(n,e,t){let r=`/v1/games/${i(n.gameId())}/config/channels/${i(e)}`;return n.client.getWithEtag(r,{...t?.signal===void 0?{}:{signal:t.signal},...t?.ifNoneMatch===void 0?{}:{ifNoneMatch:t.ifNoneMatch}})}async function ht(n,e,t){let r=`/v1/inventory/loot-tables/${i(e)}/drop-rates`;return n.client.get(r,t?.signal)}async function _t(n,e,t,r,o){let s=`/v1/inventory/${i(e)}/${i(t)}/currencies/${i(r)}`;return n.client.get(s,o?.signal)}async function bt(n,e,t,r,o){let s=`/v1/settings/${i(e)}/${i(t)}/${i(r)}`;return n.client.getWithEtag(s,{...o?.signal===void 0?{}:{signal:o.signal},...o?.ifNoneMatch===void 0?{}:{ifNoneMatch:o.ifNoneMatch}})}async function vt(n,e,t,r){let o=new URLSearchParams;r?.include_buckets!==void 0&&o.set("include_buckets",String(r?.include_buckets)),r?.include_custom_data!==void 0&&o.set("include_custom_data",String(r?.include_custom_data)),r?.currency_limit!==void 0&&o.set("currency_limit",String(r?.currency_limit)),r?.currency_cursor!==void 0&&o.set("currency_cursor",String(r?.currency_cursor)),r?.item_limit!==void 0&&o.set("item_limit",String(r?.item_limit)),r?.item_cursor!==void 0&&o.set("item_cursor",String(r?.item_cursor)),r?.progression_limit!==void 0&&o.set("progression_limit",String(r?.progression_limit)),r?.progression_cursor!==void 0&&o.set("progression_cursor",String(r?.progression_cursor));let s=o.toString(),a=`/v1/inventory/${i(e)}/${i(t)}`+(s?`?${s}`:"");return n.client.get(a,r?.signal)}async function Rt(n,e,t,r,o){let s=`/v1/inventory/${i(e)}/${i(t)}/items/${i(r)}`;return n.client.get(s,o?.signal)}async function xt(n,e,t,r,o){let s=new URLSearchParams;o?.bucket_1!==void 0&&s.set("bucket_1",String(o?.bucket_1)),o?.bucket_2!==void 0&&s.set("bucket_2",String(o?.bucket_2)),o?.limit!==void 0&&s.set("limit",String(o?.limit));let a=s.toString(),l=`/v1/leaderboards/${i(e)}/${i(t)}/${i(r)}`+(a?`?${a}`:"");return n.client.get(l,o?.signal)}async function St(n,e,t,r,o){let s=`/v1/inventory/${i(e)}/${i(t)}/orders/${i(r)}`;return n.client.get(s,o?.signal)}async function kt(n,e,t,r,o){let s=`/v1/inventory/${i(e)}/${i(t)}/progressions/${i(r)}`;return n.client.get(s,o?.signal)}async function wt(n,e,t,r,o,s){let a=`/v1/inventory/${i(e)}/${i(t)}/catalogs/${i(r)}/recipes/${i(o)}/availability`;return n.client.get(a,s?.signal)}async function At(n,e,t,r){let o=new URLSearchParams;r?.limit!==void 0&&o.set("limit",String(r?.limit));let s=o.toString(),a=`/v1/inventory/${i(e)}/${i(t)}/recipe-usage`+(s?`?${s}`:"");return n.client.get(a,r?.signal)}async function Tt(n,e,t,r,o){let s=`/v1/saves/${i(e)}/${i(t)}/${i(r)}`;return n.client.getWithEtag(s,{...o?.signal===void 0?{}:{signal:o.signal},...o?.ifNoneMatch===void 0?{}:{ifNoneMatch:o.ifNoneMatch}})}async function Pt(n,e,t){let r=`/v1/events/${i(e)}`;return n.client.get(r,t?.signal)}async function Ot(n,e,t){let r=`/v2/games/${i(n.gameId())}/game-rooms/${i(e)}`;return n.client.getWithEtag(r,{...t?.signal===void 0?{}:{signal:t.signal},...t?.ifNoneMatch===void 0?{}:{ifNoneMatch:t.ifNoneMatch}})}async function Gt(n,e,t){let r=new URLSearchParams;t?.bucket_1!==void 0&&r.set("bucket_1",String(t?.bucket_1)),t?.bucket_2!==void 0&&r.set("bucket_2",String(t?.bucket_2));let o=r.toString(),s=`/v1/leaderboards/${i(e)}`+(o?`?${o}`:"");return n.client.get(s,t?.signal)}async function Et(n,e,t){let r=`/v1/profiles/players/${i(e)}`;return n.client.get(r,t?.signal)}async function Ct(n,e){let t=new URLSearchParams;e?.config_version!==void 0&&t.set("config_version",String(e?.config_version));let r=t.toString(),o="/v1/inventory/platform-funded-game-inventory-purchase-catalog"+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function It(n,e,t){let r=`/v1/game-room-templates/${i(e)}`;return n.client.get(r,t?.signal)}async function qt(n,e,t){let r=`/v1/games/${i(n.gameId())}/game-rooms/${i(e)}/room-args`;return n.client.get(r,t?.signal)}async function Lt(n,e,t,r){let o=`/v1/showcase/players/${i(e)}/${i(t)}`;return n.client.get(o,r?.signal)}async function $t(n,e,t){let r=`/v1/inventory/transfers/${i(e)}`;return n.client.get(r,t?.signal)}async function D(n,e,t){let r=`/v1/games/${i(n.gameId())}/analytics/events`;return n.client.post(r,e,t?.signal,{replaySafe:true})}async function jt(n,e,t){return n.client.post("/v1/inventory/transfers",e,t?.signal)}async function Mt(n,e,t){return n.client.postBytes("/v1/functions/invoke",e,t?.signal)}async function Ft(n,e,t,r){let o=`/v1/games/${i(n.gameId())}/game-rooms/${i(e)}/kick/${i(t)}`;return n.client.post(o,void 0,r?.signal)}async function Ut(n,e){let t=new URLSearchParams;e?.periods_back!==void 0&&t.set("periods_back",String(e?.periods_back)),e?.player_id!==void 0&&t.set("player_id",String(e?.player_id));let r=t.toString(),o="/v1/challenges"+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function Bt(n,e,t,r){let o=`/v1/settings/${i(e)}/${i(t)}`;return n.client.get(o,r?.signal)}async function Nt(n,e,t,r){let o=new URLSearchParams;r?.limit!==void 0&&o.set("limit",String(r?.limit)),r?.cursor!==void 0&&o.set("cursor",String(r?.cursor));let s=o.toString(),a=`/v1/inventory/${i(e)}/${i(t)}/orders`+(s?`?${s}`:"");return n.client.get(a,r?.signal)}async function Dt(n,e,t,r){let o=`/v1/inventory/${i(e)}/${i(t)}/progressions`;return n.client.get(o,r?.signal)}async function Ht(n,e,t,r){let o=new URLSearchParams;r?.limit!==void 0&&o.set("limit",String(r?.limit)),r?.cursor!==void 0&&o.set("cursor",String(r?.cursor));let s=o.toString(),a=`/v1/saves/${i(e)}/${i(t)}`+(s?`?${s}`:"");return n.client.get(a,r?.signal)}async function Vt(n,e){let t=new URLSearchParams;e?.include_inactive!==void 0&&t.set("include_inactive",String(e?.include_inactive)),e?.limit!==void 0&&t.set("limit",String(e?.limit)),e?.offset!==void 0&&t.set("offset",String(e?.offset));let r=t.toString(),o="/v1/events"+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function Wt(n,e){let t=new URLSearchParams;e?.status!==void 0&&t.set("status",String(e?.status)),e?.game_channel!==void 0&&t.set("game_channel",String(e?.game_channel)),e?.game_room_type!==void 0&&t.set("game_room_type",String(e?.game_room_type)),e?.template_id!==void 0&&t.set("template_id",String(e?.template_id)),e?.template_slug!==void 0&&t.set("template_slug",String(e?.template_slug)),e?.limit!==void 0&&t.set("limit",String(e?.limit)),e?.cursor!==void 0&&t.set("cursor",String(e?.cursor));let r=t.toString(),o=`/v1/games/${i(n.gameId())}/game-rooms`+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function zt(n,e){return n.client.get("/v1/game-room-templates",e?.signal)}async function Kt(n,e){let t=new URLSearchParams;e.entity_type!==void 0&&t.set("entity_type",String(e.entity_type)),e.entity_id!==void 0&&t.set("entity_id",String(e.entity_id)),e?.direction!==void 0&&t.set("direction",String(e?.direction)),e?.status!==void 0&&t.set("status",String(e?.status)),e?.cursor!==void 0&&t.set("cursor",String(e?.cursor)),e?.limit!==void 0&&t.set("limit",String(e?.limit));let r=t.toString(),o="/v1/inventory/transfers"+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function Yt(n,e,t,r,o,s){let a=`/v1/inventory/${i(e)}/${i(t)}/progressions/${i(r)}/max`;return n.client.post(a,o,s?.signal)}async function Jt(n,e,t,r,o,s){let a=`/v1/settings/${i(e)}/${i(t)}/${i(r)}`;return n.client.put(a,o,s?.signal,{...s?.ifMatch===void 0?{}:{ifMatch:s.ifMatch}})}async function Xt(n,e,t,r){let o=`/v1/games/${i(n.gameId())}/game-rooms/${i(e)}/room-args`;return n.client.put(o,t,r?.signal)}async function Qt(n,e,t,r,o){let s=`/v1/showcase/players/${i(e)}/${i(t)}`;return n.client.put(s,r,o?.signal)}async function Zt(n,e,t){let r=`/v1/inventory/transfers/${i(e)}/reject`;return n.client.post(r,void 0,t?.signal)}async function er(n,e,t,r,o,s){let a=`/v1/saves/${i(e)}/${i(t)}/${i(r)}/upload-url`;return n.client.post(a,o,s?.signal,{replaySafe:true})}async function nr(n,e,t,r,o,s){let a=`/v1/inventory/${i(e)}/${i(t)}/progressions/${i(r)}/reset`;return n.client.post(a,o,s?.signal)}async function tr(n,e,t,r,o){let s=`/v1/inventory/${i(e)}/${i(t)}/orders/simulate`;return n.client.post(s,r,o?.signal)}async function rr(n,e,t,r){let o=`/v2/games/${i(n.gameId())}/game-rooms/${i(e)}/transfer/${i(t)}`;return n.client.post(o,void 0,r?.signal)}async function or(n,e,t,r){let o=`/v2/games/${i(n.gameId())}/game-rooms/${i(e)}`;return n.client.patch(o,t,r?.signal,{...r?.ifMatch===void 0?{}:{ifMatch:r.ifMatch}})}var oe="gem_";var ar=1e4,lr=50,dr=1e3,ur=65536-4*1024,se=n=>typeof n=="number"?n:0,cr=n=>typeof n=="string"?n:"";function ie(){let n=globalThis.crypto;return typeof n?.randomUUID=="function"?n.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{let t=Math.floor(Math.random()*16);return (e==="x"?t:t&3|8).toString(16)})}function gr(n){return n?.retryable===true}function mr(n,e){let t=n??{},r=Array.isArray(t.rejected)?t.rejected.map(o=>{let s=o??{};return {index:se(s.index),code:cr(s.code)}}):[];return {accepted:se(t.accepted),rejected:r,dropped:e,duplicate:t.duplicate===true}}function ae(n,e){return {event_uid:n.uid,name:n.name,offset_ms:Math.round(n.atMs)-e,player_id:n.playerId,dimensions:n.dimensions,measures:n.measures}}function le(n){let e=Math.max(1,Math.floor(n.maxQueue??dr)),t={client:n.client,gameId:()=>n.gameId},r=[],o=0,s=null,a=false,l=false,d=false,c=false,g=y=>{n.log?.(y);},b=()=>{s!==null&&(n.clock.clearTimeout(s),s=null);},x=()=>{s!==null||a||l||(s=n.clock.setTimeout(()=>{s=null,v().catch(()=>{});},ar));},f=()=>{let y=Math.min(r.length,100),h=128;for(let w=0;w<y;w+=1){let A=r[w];if(A===void 0)break;if(h+=JSON.stringify(ae(A,0)).length+1,h>ur)return Math.max(1,w)}return y};async function v(y){if(r.length===0)return {accepted:0,rejected:[],dropped:0,duplicate:false};b();let h=r.splice(0,f()),w=o;o=0;let A=Math.round(n.clock.now()),L={batch_id:ie(),sent_at_ms:A,events:h.map(S=>ae(S,A))};l=true;try{let S=await D(t,L,y===void 0?void 0:{signal:y}),T=mr(S,w);for(let be of T.rejected)g(`[gem] analytics: an event was refused (${be.code}). See the analytics_events section of your game config.`);return T}catch(S){if(gr(S))for(r=[...h,...r],o+=w;r.length>e;)r.shift(),o+=1;else g(`[gem] analytics: ${h.length} event(s) were discarded \u2014 the platform refused the batch and will refuse it again: ${String(S)}`);throw S}finally{l=false,r.length>0&&x();}}return {track(y,h,w={}){if(a)return;if(typeof y!="string"||y===""){c||(c=true,g(`[gem] analytics: '${h}' was not recorded \u2014 an event from a server has to name the player it is about. A game-server token names no player, so the platform cannot infer one; pass the id from join() or host.players().`));return}if(h.startsWith(oe)){d||(d=true,g(`[gem] analytics: '${h}' was not recorded \u2014 the gem_ prefix is reserved, and the platform's own events are client-sourced, so a server may not emit one at all. Name your event something else.`));return}let A={},L={};for(let[S,T]of Object.entries(w))typeof T=="string"?A[S]=T:typeof T=="number"&&Number.isFinite(T)&&(L[S]=T);for(;r.length>=e;)r.shift(),o+=1;r.push({uid:ie(),playerId:y,name:h,atMs:n.clock.now(),dimensions:A,measures:L}),r.length>=lr?v().catch(()=>{}):x();},flush:y=>v(y),get pending(){return r.length},dispose(){a=true,b(),r=[],o=0;}}}var pr=new Map([["function_error",false],["function_failed",false],["function_timeout",false],["function_not_published",false],["function_input_too_large",false],["functions_not_configured",false],["forbidden",false],["function_capacity_unavailable",true],["function_host_unreachable",true],["function_host_error",true],["rate_limited",true],["service_unavailable",true]]),I=class extends m{constructor(e,t){super(e.reason,e.status,e.detail,e.retryAfterSeconds,e.code),this.name="GemFunctionError",Object.assign(this,t);}get retryable(){return (this.code===void 0?void 0:pr.get(this.code))??super.retryable}},E=class{#e;constructor(e){this.#e=e;}async invoke(e,t={}){let r=yr(e),o;try{o=await this.#e(r,t.signal===void 0?{}:{signal:t.signal});}catch(s){throw s instanceof m?hr(s):s}return fr(o)}};function yr(n){if(n instanceof ArrayBuffer)return new Uint8Array(n);if(ArrayBuffer.isView(n))return new Uint8Array(n.buffer,n.byteOffset,n.byteLength);let e;try{e=JSON.stringify(n);}catch(t){throw new p(`the function input could not be serialised to JSON: ${String(t)}. Pass bytes, or a value JSON can carry. This is a bug in the call, not a server failure.`)}if(e===void 0)throw new p(`the function input is ${typeof n}, which JSON cannot carry. Pass bytes \u2014 an empty Uint8Array for no input \u2014 or a JSON value. This is a bug in the call, not a server failure.`);return new TextEncoder().encode(e)}function fr(n){let{bytes:e}=n,t=()=>new TextDecoder("utf-8",{fatal:true}).decode(e);return {bytes:e,...n.invocationId===void 0?{}:{invocationId:n.invocationId},text:t,json:()=>JSON.parse(t())}}function hr(n){let{details:e,invocationId:t}=X(n),o=e?.untrusted?.message,s=e?.reason;return new I(n,{...t===void 0?{}:{invocationId:t},...n.code==="function_error"&&typeof o=="string"?{functionMessage:o}:{},...n.code==="function_failed"&&typeof s=="string"?{failure:s}:{}})}var k=n=>typeof n=="string"?n:"",_r=/(?:Z|[+-]\d{2}:?\d{2})$/i;function de(n){let e=k(n);if(!_r.test(e))return 0;let t=Date.parse(e);return Number.isFinite(t)?Math.floor(t/1e3):0}var br=/^[0-9a-f]{1,64}$/,vr=/^[0-9a-f]{16}$/,Rr=/^[A-Za-z][A-Za-z0-9_+\-/]{0,63}$/,xr=/^(?:[01]\d|2[0-3]):[0-5]\d$/;function Sr(n){let e=k(n),t=/^(\d{4})-(\d{2})-(\d{2})$/.exec(e);if(!t)return;let[r,o,s]=[Number(t[1]),Number(t[2]),Number(t[3])],a=new Date(Date.UTC(r,o-1,s));return a.getUTCFullYear()===r&&a.getUTCMonth()===o-1&&a.getUTCDate()===s?e:void 0}var kr=4096,wr=new TextEncoder;function Ar(n){let e=k(n.challenge_data),t=k(n.challenge_data_hash);return e===""||!vr.test(t)?{}:wr.encode(e).length>kr?{}:{data:e,dataHash:t}}function Tr(n){let e=n??{},t=de(e.period_start_at),r=de(e.period_ends_at);if(t===0||r===0)return;let o=k(e.slug),s=k(e.seed),a=Sr(e.period_local_date),l=k(e.boundary),d=k(e.reset_time);return {id:k(e.progression_definition_id),...o===""?{}:{slug:o},window:k(e.window),periodStartAt:t,periodEndsAt:r,...a===void 0?{}:{periodLocalDate:a},boundary:Rr.test(l)?l:"",resetTime:xr.test(d)?d:"",seed:br.test(s)?s:"",...Ar(e)}}function ue(n){if(n!==void 0&&(!Number.isInteger(n)||n<0||n>400))throw new TypeError(`periodsBack must be an integer between 0 and 400, got ${String(n)}`)}function ce(n){let e=n??{};return Array.isArray(e.challenges)?e.challenges.map(Tr).filter(t=>t!==void 0):[]}function ge(n){return {async list(e){let{playerId:t,periodsBack:r,signal:o}=e??{};if(typeof t!="string"||t==="")throw new TypeError("gem.challenges.list needs { playerId }: a game-server token names no player, so the platform cannot tell whose period you mean. Pass the id from join() or gem.players().");ue(r);let s=await n({player_id:t,...r===void 0?{}:{periods_back:r},...o===void 0?{}:{signal:o}});return ce(s)}}}function Pr(n){let e={};for(let[t,r]of Object.entries(H))if(typeof r=="function"){let o=r;e[t]=(...s)=>o(n,...s);}return e}function F(n,e={}){let t=e.clock??G,r=e.baseUrl??n.apiBaseUrl;if(!r)throw new Error("this runtime names no gem-api host (host.apiBaseUrl is missing). The server image running this bundle predates token delivery \u2014 the bundle cannot call gem-api on it.");let o=N(n,{clock:t,...e.onAuthStateChange===void 0?{}:{onStateChange:e.onAuthStateChange}}),s=Q({baseUrl:r,tokenSource:o.source,defaultQuery:{game_id:n.gameId,channel:n.channel},...e.fetch===void 0?{}:{fetch:e.fetch}}),a=new P({transport:s,clock:t}),l={gameId:n.gameId,channel:n.channel,matchId:n.matchId,...n.gameRoomId===void 0?{}:{gameRoomId:n.gameRoomId}},d=Pr({client:a,gameId:()=>l.gameId}),c=l.gameRoomId,g=n.endMatch,b=n.log,x=le({client:a,clock:t,gameId:l.gameId,...typeof b=="function"?{log:v=>b.call(n,v)}:{}});return {identity:l,client:a,api:d,match:{end:async()=>{if(g===void 0)throw new Error("this runtime cannot end the match: the server image running this bundle predates host.endMatch, and only the platform half holds the allocation proof an end needs.");await g.call(n);}},analytics:x,functions:new E(d.invokeFunction),challenges:ge(d.listChallenges),...c===void 0?{}:{room:{get:v=>d.getGameRoomV2(c,v),args:async v=>{let y=await d.getGameRoomV2(c,v?.signal===void 0?{}:{signal:v.signal}),h=y.modified?y.body:void 0;if(h?.room_args==null||h.room_args_template==null)throw new m("not_found",404,"this room's template declares no room args",void 0,"room_args_not_defined");return {room_args:h.room_args,room_args_template:h.room_args_template}}}},dispose:()=>{x.dispose(),o.dispose();}}}var Or=["explicit","stale_cleanup","game_room_closed","replaced","migration_failed","host_left","insufficient_players","all_left","expired","migration_rate_exceeded","game_room_gone","failed","idle","reclaimed"],Gr=new Set(Or);function me(n){return typeof n=="string"&&Gr.has(n)?n:"unknown"}var R=class{#e;constructor(e){this.#e=e,Object.freeze(this);}toString(){return "[gem: use gem.text.toPlain()]"}toJSON(){return this.toString()}get[Symbol.toStringTag](){return "PlayerText"}static unwrap(e){return e.#e}};function q(n){return new R(n)}var pe={toPlain(n){return R.unwrap(n)},compare(n,e,t){let r=n instanceof R?R.unwrap(n):n,o=e instanceof R?R.unwrap(e):e,s;try{s=new Intl.Collator(t);}catch{s=new Intl.Collator;}return s.compare(r,o)},equals(n,e){let t=n instanceof R?R.unwrap(n):n,r=e instanceof R?R.unwrap(e):e;return t.normalize("NFC")===r.normalize("NFC")}};var ye="the match has not started yet: the runtime hands over the host at `init`, and this was read before that. Read it from `init` or later \u2014 a bundle that needs a value at module scope is reading it one call too early.";function V(n,e={}){let t=e.clock??G,r=()=>{let l=n();if(l===null)throw new Error(ye);return l},o=null,s=()=>{if(o===null)throw new Error(ye);return o};return {server:{get identity(){return s().identity},get client(){return s().client},get api(){return s().api},get match(){return s().match},get analytics(){return s().analytics},get functions(){return s().functions},get challenges(){return s().challenges},get room(){return s().room},dispose(){o?.dispose();},get sizeClass(){return r().sizeClass},get roomArgs(){return r().roomArgs},get roster(){return r().roster},players(){return r().players()},profile(l){let c=r().profile?.(l);if(!c)return null;let g=c.displayName;return typeof g!="string"||g===""?null:{displayName:q(g),...typeof c.displayTag=="string"&&c.displayTag!==""?{displayTag:q(c.displayTag)}:{},...typeof c.discriminator=="string"?{discriminator:c.discriminator}:{}}},playerNumber(l){return r().playerNumber?.(l)},send(l,d,c){c===void 0?r().send(l,d):r().send(l,d,c);},broadcast(l,d){d===void 0?r().broadcast(l):r().broadcast(l,d);},kick(l,d){d===void 0?r().kick(l):r().kick(l,d);},log(l){r().log(l);},warn(l){r().warn(l);}},attach:()=>{o=F(r(),{...e,clock:t});}}}function fe(n,e={}){let{server:t,attach:r}=V(()=>n,e);return r(),t}function Er(n){if(n===void 0||typeof n.reason!="string"||n.reason==="")return;let e=n.platform_reason??n.endedReason;return {reason:n.reason,...e===void 0?{}:{endedReason:me(e)}}}function he(n,e={}){return ()=>{let t=null,{server:r,attach:o}=V(()=>t,e),s=n(r),a={async init(l){t=l,o(),await s.init?.();},async shutdown(l){let d=Er(l);try{await s.shutdown?.(d);}finally{r.dispose();}}};return s.join&&(a.join=(l,d)=>s.join?.(l,d)),s.leave&&(a.leave=(l,d)=>s.leave?.(l,d)),s.message&&(a.message=(l,d,c,g)=>s.message?.(l,d,c,g)),a}}var Cr=new Set(["unlocked","already_unlocked","suppressed"]);function _e(n){let e=n?.changes;if(!Array.isArray(e))return [];let t=[];for(let r of e){let o=r??{};if(o.type!=="achievement_unlocked"||typeof o.outcome!="string"||!Cr.has(o.outcome)||typeof o.achievement_id!="string"||o.achievement_id==="")continue;let s=o.outcome;t.push({achievementId:o.achievement_id,progressionDefinitionId:typeof o.progression_definition_id=="string"?o.progression_definition_id:"",points:s==="unlocked"&&typeof o.points=="number"&&Number.isFinite(o.points)?o.points:0,outcome:s,...typeof o.reason=="string"?{reason:o.reason}:{}});}return t}
2
+ export{_ as AuthError,j as CONDITIONAL_HEADERS,E as FunctionsApi,m as GemApiError,P as GemClient,I as GemFunctionError,R as PlayerText,p as TransportRefusal,_e as achievementReceipts,q as asPlayerText,F as createGemServer,re as createHostTokenSource,fe as createMatchServer,he as defineServer,G as systemClock,pe as text,K as toBase64};//# sourceMappingURL=gem-web-sdk.server.js.map
3
3
  //# sourceMappingURL=gem-web-sdk.server.js.map
package/dist/index.d.ts CHANGED
@@ -50,6 +50,7 @@ declare const FRAME_TO_PARENT: readonly [
50
50
  "gem.dedicatedOffer",
51
51
  "gem.partyRequest",
52
52
  "gem.ready",
53
+ "gem.engaged",
53
54
  "gem.progress",
54
55
  "gem.requestToken",
55
56
  "gem.requestLocalServer",
@@ -68,7 +69,7 @@ declare const FRAME_TO_PARENT: readonly [
68
69
  "gem.requestSignIn",
69
70
  "gem.requestFriendChallenge"
70
71
  ];
71
- type GemCapability = "ads" | "signIn" | "purchases" | "friendChallenges" | "devtools" | "screenshot" | "feedbackContext" | "rooms" | "p2p" | "dedicated" | "clusterTarget" | "parties" | "autoStartFailure" | "partySeating" | "socketState" | "audioState" | "rewardCue" | "frameStats" | "viewport" | "reservedAreas" | "walletDisplay" | "localHost" | "cohorts" | "earnAllowance" | "deviceSettings" | "asyncOpponents" | "share";
72
+ type GemCapability = "ads" | "signIn" | "purchases" | "friendChallenges" | "devtools" | "screenshot" | "feedbackContext" | "rooms" | "p2p" | "dedicated" | "clusterTarget" | "parties" | "autoStartFailure" | "partySeating" | "socketState" | "audioState" | "rewardCue" | "frameStats" | "engagement" | "viewport" | "reservedAreas" | "walletDisplay" | "localHost" | "cohorts" | "earnAllowance" | "deviceSettings" | "asyncOpponents" | "share";
72
73
  declare const CAPABILITY_GATES: Readonly<Record<string, string>>;
73
74
  declare const CAPABILITY_NAMESPACE_GATES: ReadonlyArray<readonly [
74
75
  string,
@@ -85,6 +86,7 @@ interface GemHandshake {
85
86
  };
86
87
  readonly capabilities?: string[];
87
88
  readonly embedder: string;
89
+ readonly unbidden?: boolean;
88
90
  }
89
91
  interface GemHandshakeAccept {
90
92
  readonly gem: typeof PROTOCOL;
@@ -300,6 +302,10 @@ interface GemReady {
300
302
  readonly gem: typeof PROTOCOL;
301
303
  readonly type: "gem.ready";
302
304
  }
305
+ interface GemEngaged {
306
+ readonly gem: typeof PROTOCOL;
307
+ readonly type: "gem.engaged";
308
+ }
303
309
  interface GemProgress {
304
310
  readonly gem: typeof PROTOCOL;
305
311
  readonly type: "gem.progress";
@@ -463,7 +469,7 @@ interface GemFriendChallengeResult {
463
469
  readonly detail?: string;
464
470
  }
465
471
  type ParentMessage = GemHandshake | GemToken | GemTokenDenied | GemPlayer | GemPause | GemPrefs | GemCohorts | GemEarnAllowanceChanged | GemViewport | GemDeviceSettings | GemWillTerminate | GemRoomEvent | GemSocketState | GemSeatedEvent | GemAutoStartFailedEvent | GemSignalEvent | GemDedicatedEvent | GemPartyResult | GemClusterTarget | GemDevtools | GemScreenshot | GemRequestContext | GemLocalServer | GemLocalServerDenied | GemError | GemPurchaseResult | GemDeviceSettingsResult | GemAdResult | GemSignInResult | GemFriendChallengeResult;
466
- type FrameMessage = GemHandshakeAccept | GemScreenshotDenied | GemGameContext | GemSignal | GemDedicatedOffer | GemPartyRequest | GemReady | GemProgress | GemRequestToken | GemRequestLocalServer | GemExit | GemOpenExternal | GemRequestFullscreen | GemAudioState | GemRewardCue | GemWalletDisplay | GemRequestShare | GemFrameStats | GemError | GemRequestPurchase | GemDeviceSettingsPut | GemRequestAd | GemRequestSignIn | GemRequestFriendChallenge;
472
+ type FrameMessage = GemHandshakeAccept | GemScreenshotDenied | GemGameContext | GemSignal | GemDedicatedOffer | GemPartyRequest | GemReady | GemEngaged | GemProgress | GemRequestToken | GemRequestLocalServer | GemExit | GemOpenExternal | GemRequestFullscreen | GemAudioState | GemRewardCue | GemWalletDisplay | GemRequestShare | GemFrameStats | GemError | GemRequestPurchase | GemDeviceSettingsPut | GemRequestAd | GemRequestSignIn | GemRequestFriendChallenge;
467
473
  type GemMessage = ParentMessage | FrameMessage;
468
474
  type Rejection = string | null;
469
475
  declare function isOrigin(s: string): boolean;
@@ -497,6 +503,7 @@ declare const validateGemSignal: (raw: unknown) => Rejection;
497
503
  declare const validateGemDedicatedOffer: (raw: unknown) => Rejection;
498
504
  declare const validateGemPartyRequest: (raw: unknown) => Rejection;
499
505
  declare const validateGemReady: (raw: unknown) => Rejection;
506
+ declare const validateGemEngaged: (raw: unknown) => Rejection;
500
507
  declare const validateGemProgress: (raw: unknown) => Rejection;
501
508
  declare const validateGemRequestToken: (raw: unknown) => Rejection;
502
509
  declare const validateGemRequestLocalServer: (raw: unknown) => Rejection;
@@ -677,6 +684,7 @@ interface HostCallbacks {
677
684
  onOpenExternal?(msg: GemOpenExternal): void;
678
685
  onRequestFullscreen?(msg: GemRequestFullscreen): void;
679
686
  onAudioState?(msg: GemAudioState): void;
687
+ onEngaged?(): void;
680
688
  onRewardCue?(msg: GemRewardCue): void;
681
689
  onWalletDisplay?(msg: GemWalletDisplay): void;
682
690
  onFrameStats?(msg: GemFrameStats): void;
@@ -700,6 +708,7 @@ interface HostOptions extends HostCallbacks {
700
708
  frameOrigin: string;
701
709
  embedderOrigin: string;
702
710
  capabilities?: readonly string[];
711
+ unbidden?: boolean;
703
712
  clock?: Clock;
704
713
  }
705
714
  declare class GemHost {
@@ -954,6 +963,8 @@ declare class GemFrame {
954
963
  private port;
955
964
  private version;
956
965
  private peerCapabilities;
966
+ private unbidden;
967
+ private engagedSent;
957
968
  private readyPending;
958
969
  private readySent;
959
970
  private settleWaiters;
@@ -966,6 +977,7 @@ declare class GemFrame {
966
977
  get parentCapabilities(): readonly string[];
967
978
  parentSupports(capability: string): boolean;
968
979
  get protocolVersion(): number | null;
980
+ get unbiddenLaunch(): boolean;
969
981
  handleWindowMessage(event: HandshakeEvent): boolean;
970
982
  ready(): void;
971
983
  settled(timeoutMs?: number): Promise<FrameState>;
@@ -976,6 +988,7 @@ declare class GemFrame {
976
988
  openExternal(url: string): void;
977
989
  requestFullscreen(enabled: boolean): void;
978
990
  reportMuted(muted: boolean): boolean;
991
+ reportEngaged(): boolean;
979
992
  cueReward(cue: RewardCue): boolean;
980
993
  setWalletVisible(visible: boolean, options?: {
981
994
  only?: readonly string[];
@@ -2157,4 +2170,4 @@ interface P2pMatchApi {
2157
2170
  session(matchId: string): P2pSession | null;
2158
2171
  }
2159
2172
  declare function createP2pApi(options: P2pApiOptions): P2pMatchApi;
2160
- export { type AutoReconnectOptions, type AwaitMatchOptions, CAPABILITY_GATES, CAPABILITY_NAMESPACE_GATES, CHANNELS, CHANNEL_KINDS, type ChannelKind, type ClientPlatform, ClientTelemetry, type ClientTelemetryOptions, type ClientVersion, type Clock, type ClusterTarget, type ClusterTargetBridge, type ClusterTargetLike, type ClusterTargetListResolver, type ClusterTargetRefresher, type ClusterTargetResolver, type ClusterTargetSource, type ClusterTargetSourceOptions, type ConnectOptions, type CreateRoomOptions, INBOUND_EVENTS as DEDICATED_INBOUND_EVENTS, DEFAULT_WELCOME_CEILING_MS, DEVICE_SETTINGS_MAX_BYTES, type DataChannelLike$1 as DataChannelLike, type DedicatedServerApi, type DedicatedServerApiOptions, DedicatedServerError, type DedicatedServerFailure, type DedicatedServerSession, type DedicatedSignalTransport, DedicatedSignalingHub, type DedicatedSignalingOptions, type EstablishOptions, FRAME_TO_PARENT, type FailedMatch, type FrameCallbacks, type FrameMessage, type FrameOptions, type FrameState, type GemAdResult, type GemAudioState, type GemAutoStartFailedEvent, type GemCapability, type GemClusterTarget, type GemCohorts, type GemDedicatedEvent, type GemDedicatedOffer, type GemDeviceSettings, type GemDeviceSettingsPut, type GemDeviceSettingsResult, type GemDevtools, type GemEarnAllowanceChanged, type GemError, type GemErrorCode, type GemExit, GemFrame, type GemFrameStats, type GemFriendChallengeResult, type GemGameContext, type GemHandshake, type GemHandshakeAccept, GemHost, type GemLocalServer, type GemLocalServerDenied, type GemMessage, type GemOpenExternal, type GemPartyRequest, type GemPartyResult, type GemPause, type GemPlayer, type GemPrefs, type GemProgress, type GemPurchaseResult, type GemReady, type GemRequestAd, type GemRequestContext, type GemRequestFriendChallenge, type GemRequestFullscreen, type GemRequestLocalServer, type GemRequestPurchase, type GemRequestShare, type GemRequestSignIn, type GemRequestToken, type GemRewardCue, type GemRoomEvent, type GemScreenshot, type GemScreenshotDenied, type GemSeatedEvent, type GemSignInResult, type GemSignal, type GemSignalEvent, type GemSocketState, type GemToken, type GemTokenDenied, type GemViewport, type GemWalletDisplay, type GemWillTerminate, HANDSHAKE_TIMEOUT_MS, type HandshakeEvent, type HostCallbacks, HostMigration, type HostOptions, type HostState, type JoinCredential, type JoinExchange, type JoinRoomOptions, type JoinWelcome, type KeySource, type ListRoomsOptions, MALFORMED_INBOUND_KEY, MAX_ARRAY_LENGTH, MAX_CLUSTER_TARGETS, MAX_MESSAGE_BYTES, MAX_MESSAGE_DEPTH, MAX_MESSAGE_NODES, MAX_SIGNALS_PER_SECOND, MAX_SOCKET_FRAME_BYTES, MIGRATION_TIMEOUT_MS, type MatchAutoStartFailed, type MatchConnectionState, type MatchEnded, type MatchOutcome, type MatchOutcomeWaitOptions, type MatchReconnected, type MatchReconnecting, type MatchSession, type MatchSessionPhase, type MatchSuspended, type MigrationState, type OfferRefusal, type OfferRequest, P2pApi, type P2pConnectOptions, P2pError, type P2pEventMap, type P2pEventName, type P2pFailure, type P2pMatchApi, type P2pPeer, P2pSession, PARENT_TO_FRAME, PROTOCOL, type ParentMessage, type PartyBridge, type PartyEventRelay, type PartyResolver, type PartyResolverOptions, type PeerConnectionLike$1 as PeerConnectionLike, PlayerText, type PortLike, type PortMessageHandler, type PresentCredentialOptions, type PurchaseRefusalCode, type QuickJoinOptions, RATE_LIMITS, RateLimiter, type ReadyMatch, type Rejection, type RelayedDedicatedEvent, type RelayedRoomEvent, type RelayedSignal, type ResolvedClientVersion, type Room, type RoomArgEntry, type RoomArgScalar, type RoomArgType, type RoomArgValue, type RoomArgs, RoomEmitter, type RoomEventMap, type RoomEventName, type RoomManager, type RoomManagerOptions, type RoomMember, type RoomOperationError, type RoomPage, type RoomStatus, type RoomSummary, RoomsApi, type RoomsApiOptions, SUPPORTED_VERSIONS, type SdpType$1 as SdpType, type SendPlayerInput, type SessionDescriptionLike$1 as SessionDescriptionLike, type SignalTransport, type SignalingAnswer, type SignalingChannel, SignalingClient, type SignalingIntent, type StartMatchOptions, type StartedMatch$1 as StartedMatch, TELEMETRY_EVENTS, TRANSPORT_LABELS, type TelemetrySample, type TokenDenial, type TokenGrant, type TransportLabel, type TurnLease, type UpdateRoomOptions, VALIDATORS, type VerifiedCredential, WEBRTC_DEDICATED, WEBRTC_P2P, WEB_ENGINE_VERSION, WEB_PROTOCOL_VERSION, type WindowLike, asPlayerText, awaitMatchOutcome, browserPeerConnection, buildDedicatedOfferFrame, buildSocketFrame, capabilityFor, createClusterTargetSource, createDedicatedServerApi, createKeySource, createP2pApi, createPartyResolver, createRoomManager, deviceSettingsByteLength, establishDataChannel, fingerprintOf, fingerprintsMatch, generateCertificate, isOrigin, listClusterTargets, memberFromWire, negotiateVersion, normaliseClusterTarget, normaliseClusterTargets, normaliseFingerprint, originsEqual, presentJoinCredential, projectDedicatedEvent, projectPartyEvent, projectSignal, roomArgValuesFromWire, roomArgsTemplateFromWire, roomFromWire, startMatch, summaryFromWire, systemClock, text, unavailableSignaling, validateGemAdResult, validateGemAudioState, validateGemAutoStartFailedEvent, validateGemClusterTarget, validateGemCohorts, validateGemDedicatedEvent, validateGemDedicatedOffer, validateGemDeviceSettings, validateGemDeviceSettingsPut, validateGemDeviceSettingsResult, validateGemDevtools, validateGemEarnAllowanceChanged, validateGemError, validateGemExit, validateGemFrameStats, validateGemFriendChallengeResult, validateGemGameContext, validateGemHandshake, validateGemHandshakeAccept, validateGemLocalServer, validateGemLocalServerDenied, validateGemOpenExternal, validateGemPartyRequest, validateGemPartyResult, validateGemPause, validateGemPlayer, validateGemPrefs, validateGemProgress, validateGemPurchaseResult, validateGemReady, validateGemRequestAd, validateGemRequestContext, validateGemRequestFriendChallenge, validateGemRequestFullscreen, validateGemRequestLocalServer, validateGemRequestPurchase, validateGemRequestShare, validateGemRequestSignIn, validateGemRequestToken, validateGemRewardCue, validateGemRoomEvent, validateGemScreenshot, validateGemScreenshotDenied, validateGemSeatedEvent, validateGemSignInResult, validateGemSignal, validateGemSignalEvent, validateGemSocketState, validateGemToken, validateGemTokenDenied, validateGemViewport, validateGemWalletDisplay, validateGemWillTerminate, validateSize, verifyCredential };
2173
+ export { type AutoReconnectOptions, type AwaitMatchOptions, CAPABILITY_GATES, CAPABILITY_NAMESPACE_GATES, CHANNELS, CHANNEL_KINDS, type ChannelKind, type ClientPlatform, ClientTelemetry, type ClientTelemetryOptions, type ClientVersion, type Clock, type ClusterTarget, type ClusterTargetBridge, type ClusterTargetLike, type ClusterTargetListResolver, type ClusterTargetRefresher, type ClusterTargetResolver, type ClusterTargetSource, type ClusterTargetSourceOptions, type ConnectOptions, type CreateRoomOptions, INBOUND_EVENTS as DEDICATED_INBOUND_EVENTS, DEFAULT_WELCOME_CEILING_MS, DEVICE_SETTINGS_MAX_BYTES, type DataChannelLike$1 as DataChannelLike, type DedicatedServerApi, type DedicatedServerApiOptions, DedicatedServerError, type DedicatedServerFailure, type DedicatedServerSession, type DedicatedSignalTransport, DedicatedSignalingHub, type DedicatedSignalingOptions, type EstablishOptions, FRAME_TO_PARENT, type FailedMatch, type FrameCallbacks, type FrameMessage, type FrameOptions, type FrameState, type GemAdResult, type GemAudioState, type GemAutoStartFailedEvent, type GemCapability, type GemClusterTarget, type GemCohorts, type GemDedicatedEvent, type GemDedicatedOffer, type GemDeviceSettings, type GemDeviceSettingsPut, type GemDeviceSettingsResult, type GemDevtools, type GemEarnAllowanceChanged, type GemEngaged, type GemError, type GemErrorCode, type GemExit, GemFrame, type GemFrameStats, type GemFriendChallengeResult, type GemGameContext, type GemHandshake, type GemHandshakeAccept, GemHost, type GemLocalServer, type GemLocalServerDenied, type GemMessage, type GemOpenExternal, type GemPartyRequest, type GemPartyResult, type GemPause, type GemPlayer, type GemPrefs, type GemProgress, type GemPurchaseResult, type GemReady, type GemRequestAd, type GemRequestContext, type GemRequestFriendChallenge, type GemRequestFullscreen, type GemRequestLocalServer, type GemRequestPurchase, type GemRequestShare, type GemRequestSignIn, type GemRequestToken, type GemRewardCue, type GemRoomEvent, type GemScreenshot, type GemScreenshotDenied, type GemSeatedEvent, type GemSignInResult, type GemSignal, type GemSignalEvent, type GemSocketState, type GemToken, type GemTokenDenied, type GemViewport, type GemWalletDisplay, type GemWillTerminate, HANDSHAKE_TIMEOUT_MS, type HandshakeEvent, type HostCallbacks, HostMigration, type HostOptions, type HostState, type JoinCredential, type JoinExchange, type JoinRoomOptions, type JoinWelcome, type KeySource, type ListRoomsOptions, MALFORMED_INBOUND_KEY, MAX_ARRAY_LENGTH, MAX_CLUSTER_TARGETS, MAX_MESSAGE_BYTES, MAX_MESSAGE_DEPTH, MAX_MESSAGE_NODES, MAX_SIGNALS_PER_SECOND, MAX_SOCKET_FRAME_BYTES, MIGRATION_TIMEOUT_MS, type MatchAutoStartFailed, type MatchConnectionState, type MatchEnded, type MatchOutcome, type MatchOutcomeWaitOptions, type MatchReconnected, type MatchReconnecting, type MatchSession, type MatchSessionPhase, type MatchSuspended, type MigrationState, type OfferRefusal, type OfferRequest, P2pApi, type P2pConnectOptions, P2pError, type P2pEventMap, type P2pEventName, type P2pFailure, type P2pMatchApi, type P2pPeer, P2pSession, PARENT_TO_FRAME, PROTOCOL, type ParentMessage, type PartyBridge, type PartyEventRelay, type PartyResolver, type PartyResolverOptions, type PeerConnectionLike$1 as PeerConnectionLike, PlayerText, type PortLike, type PortMessageHandler, type PresentCredentialOptions, type PurchaseRefusalCode, type QuickJoinOptions, RATE_LIMITS, RateLimiter, type ReadyMatch, type Rejection, type RelayedDedicatedEvent, type RelayedRoomEvent, type RelayedSignal, type ResolvedClientVersion, type Room, type RoomArgEntry, type RoomArgScalar, type RoomArgType, type RoomArgValue, type RoomArgs, RoomEmitter, type RoomEventMap, type RoomEventName, type RoomManager, type RoomManagerOptions, type RoomMember, type RoomOperationError, type RoomPage, type RoomStatus, type RoomSummary, RoomsApi, type RoomsApiOptions, SUPPORTED_VERSIONS, type SdpType$1 as SdpType, type SendPlayerInput, type SessionDescriptionLike$1 as SessionDescriptionLike, type SignalTransport, type SignalingAnswer, type SignalingChannel, SignalingClient, type SignalingIntent, type StartMatchOptions, type StartedMatch$1 as StartedMatch, TELEMETRY_EVENTS, TRANSPORT_LABELS, type TelemetrySample, type TokenDenial, type TokenGrant, type TransportLabel, type TurnLease, type UpdateRoomOptions, VALIDATORS, type VerifiedCredential, WEBRTC_DEDICATED, WEBRTC_P2P, WEB_ENGINE_VERSION, WEB_PROTOCOL_VERSION, type WindowLike, asPlayerText, awaitMatchOutcome, browserPeerConnection, buildDedicatedOfferFrame, buildSocketFrame, capabilityFor, createClusterTargetSource, createDedicatedServerApi, createKeySource, createP2pApi, createPartyResolver, createRoomManager, deviceSettingsByteLength, establishDataChannel, fingerprintOf, fingerprintsMatch, generateCertificate, isOrigin, listClusterTargets, memberFromWire, negotiateVersion, normaliseClusterTarget, normaliseClusterTargets, normaliseFingerprint, originsEqual, presentJoinCredential, projectDedicatedEvent, projectPartyEvent, projectSignal, roomArgValuesFromWire, roomArgsTemplateFromWire, roomFromWire, startMatch, summaryFromWire, systemClock, text, unavailableSignaling, validateGemAdResult, validateGemAudioState, validateGemAutoStartFailedEvent, validateGemClusterTarget, validateGemCohorts, validateGemDedicatedEvent, validateGemDedicatedOffer, validateGemDeviceSettings, validateGemDeviceSettingsPut, validateGemDeviceSettingsResult, validateGemDevtools, validateGemEarnAllowanceChanged, validateGemEngaged, validateGemError, validateGemExit, validateGemFrameStats, validateGemFriendChallengeResult, validateGemGameContext, validateGemHandshake, validateGemHandshakeAccept, validateGemLocalServer, validateGemLocalServerDenied, validateGemOpenExternal, validateGemPartyRequest, validateGemPartyResult, validateGemPause, validateGemPlayer, validateGemPrefs, validateGemProgress, validateGemPurchaseResult, validateGemReady, validateGemRequestAd, validateGemRequestContext, validateGemRequestFriendChallenge, validateGemRequestFullscreen, validateGemRequestLocalServer, validateGemRequestPurchase, validateGemRequestShare, validateGemRequestSignIn, validateGemRequestToken, validateGemRewardCue, validateGemRoomEvent, validateGemScreenshot, validateGemScreenshotDenied, validateGemSeatedEvent, validateGemSignInResult, validateGemSignal, validateGemSignalEvent, validateGemSocketState, validateGemToken, validateGemTokenDenied, validateGemViewport, validateGemWalletDisplay, validateGemWillTerminate, validateSize, verifyCredential };
package/dist/sdk.d.ts CHANGED
@@ -1410,6 +1410,9 @@ declare class AnalyticsApi {
1410
1410
  get environment(): Readonly<Record<string, string>>;
1411
1411
  flush(options?: AnalyticsFlushOptions): Promise<AnalyticsFlushResult>;
1412
1412
  trackPlatform(name: PlatformEventName, props?: Readonly<Record<string, AnalyticsValue>>): void;
1413
+ hold(): void;
1414
+ release(): void;
1415
+ get held(): boolean;
1413
1416
  startSession(): void;
1414
1417
  endSession(reason: SessionEndReason): void;
1415
1418
  setPaused(paused: boolean): void;
@@ -4147,6 +4150,8 @@ declare class GemFrame {
4147
4150
  private port;
4148
4151
  private version;
4149
4152
  private peerCapabilities;
4153
+ private unbidden;
4154
+ private engagedSent;
4150
4155
  private readyPending;
4151
4156
  private readySent;
4152
4157
  private settleWaiters;
@@ -4159,6 +4164,7 @@ declare class GemFrame {
4159
4164
  get parentCapabilities(): readonly string[];
4160
4165
  parentSupports(capability: string): boolean;
4161
4166
  get protocolVersion(): number | null;
4167
+ get unbiddenLaunch(): boolean;
4162
4168
  handleWindowMessage(event: HandshakeEvent): boolean;
4163
4169
  ready(): void;
4164
4170
  settled(timeoutMs?: number): Promise<FrameState>;
@@ -4169,6 +4175,7 @@ declare class GemFrame {
4169
4175
  openExternal(url: string): void;
4170
4176
  requestFullscreen(enabled: boolean): void;
4171
4177
  reportMuted(muted: boolean): boolean;
4178
+ reportEngaged(): boolean;
4172
4179
  cueReward(cue: RewardCue): boolean;
4173
4180
  setWalletVisible(visible: boolean, options?: {
4174
4181
  only?: readonly string[];
@@ -4227,6 +4234,9 @@ interface DeviceSettingsApi {
4227
4234
  wait(timeoutMs?: number): Promise<DeviceSettings | null>;
4228
4235
  put(settings: DeviceSettings): Promise<DeviceSettingsPutOutcome>;
4229
4236
  }
4237
+ declare class GemUnframedError extends Error {
4238
+ constructor();
4239
+ }
4230
4240
  declare const DEVICE_SETTINGS_MAX_BYTES = 16384;
4231
4241
  declare const ARCADE_EMBEDDERS: readonly string[];
4232
4242
  interface GemOptions {
@@ -4363,4 +4373,4 @@ interface ExitAnalytics {
4363
4373
  }
4364
4374
  declare function leaveAndExit(rooms: ExitRooms, bridge: ExitBridge | null, reason?: string, analytics?: ExitAnalytics): Promise<void>;
4365
4375
  declare function createGem(options?: GemOptions): Gem;
4366
- export { ARCADE_EMBEDDERS, type AccountApi, type AdFormat, type AdOutcome, type AdOutcomeKind, type AdRequest, type AdsApi, AnalyticsApi, type AnalyticsFlushOptions, type AnalyticsFlushResult, type AnalyticsOptions, type AnalyticsRejection$1 as AnalyticsRejection, type AnalyticsValue, AuthError, type AuthFailure, type AuthState, type Base64String, type BootMark, type BootTimeline, type BroadcastOptions, type BytesResponse, CONDITIONAL_HEADERS, type Challenge, type ChallengeWindow, ChallengesApi, type ClientOptions, type Clock, type ConditionalRequestHeaders, type ConfiguredPurchasePayment, type ConfiguredPurchaseRequest, type ConfiguredPurchaseResult, DEVICE_SETTINGS_MAX_BYTES, DedicatedServerError, type DedicatedServerFailure, type DedicatedServerSession, type DevToolsOpener, type DeviceSettings, type DeviceSettingsApi, type DeviceSettingsPutOutcome, type DirectPurchaseRequest, type DirectPurchaseResult, type EarnAllowance, type EarnAllowanceEvent, type EarnAllowancePeriod, type EarnAllowanceReadOptions, type EntityLeaderboard, type EntityLeaderboardEntry, type EntityLeaderboardOptions, type EntityType$1 as EntityType, type ExitAnalytics, type ExitBridge, type ExitRooms, type FrameState, type Friend, FriendChallengeError, type FriendChallengeErrorCode, type FriendChallengeOutcome, type FriendChallengeOutcomeKind, type FriendChallengeRequest, FriendsApi, type FriendsPage, type FunctionFailure, type FunctionInvokeOptions, type FunctionResult, FunctionsApi, type GameApi, type GameConfig, type GameServerLink, type Gem, GemApiError, GemClient, type GemCohort, type GemCohorts, GemConfigError, type GemDevTools, type GemErrorReason, GemFrame, GemFunctionError, type GemIdentity, type GemInsets, type GemMatchApi, type GemMatchServer, type GemMatchServerModule, type GemOptions, type GemPlayer, type GemPrefs, type GemReservedArea, GemSaveError, type GemServer, type GemServerBundle, type GemServerFactory, type GemServerHost, type GemServerHostProfile, type GemServerIdentity, type GemServerLifecycle, type GemServerOptions, type GemServerProfile, type GemTerminationNotice, type GemViewport, type GetLeaderboardOptions, type HostTokenSource, type HostTokenSourceOptions, type JoinWelcome, type Leaderboard, type LeaderboardEntry, LeaderboardsApi, type ListChallengesOptions, type ListFriendsOptions, MAX_PERIODS_BACK, type MatchConnectOptions, type MatchConnection, type MatchHosting, type MatchHostingMode, type MatchServeOptions, type MatchTransport, type MessageMeta, type MultiTransportSession, PLATFORM_EVENTS, PlatformApi, PlatformCurrenciesApi, type PlatformCurrency, type PlatformCurrencyAccess, type PlatformCurrencyPurchasePayment, type PlatformCurrencyPurchaseRequest, type PlatformCurrencyPurchaseResult, type PlatformCurrencyReadOptions, PlatformEarnAllowanceApi, type PlatformEventName, type PlayerBadge$1 as PlayerBadge, type PlayerBoost, type PlayerBoostMultiplier, type PlayerIdentity, type PlayerProfile, PlayerText, type ProfileCallOptions, type ProfileShowcaseEntry$1 as ProfileShowcaseEntry, ProfilesApi, type PurchaseApi, type PurchaseOptions, type PurchaseOutcome, PurchaseRefusal, type PurchaseRefusalCode, type PurchaseRequest, type PutBytesOptions, type PutSaveOptions, type RankedRow, type RecipeAvailability, type RecipeLock, type RequestOptions, type RewardCue, type RoomArgValue, type SavePage, type SaveRecord, type SendOptions$1 as SendOptions, type ServerApi, type ServerBundleHost, type ServerTokenGrant, type SessionEndReason, type ShareApi, type ShareRequest, ShowcaseApi, type ShowcaseCallOptions, type ShowcaseFriendEntry, type ShowcaseFriends, type ShowcaseValue, type SignInOutcome, type SignInOutcomeKind, type SnapshotCurrency, type SnapshotItem, type TokenGrant, type Transport, type TransportAdvert, type TransportKind, TransportRefusal, type TransportRequest, type TransportResponse, UNRELIABLE_CHANNEL_LABEL, type VersionedGetOptions, type VersionedResponse, type WalletVisibleOptions, asPlayerText, createBootTimeline, createGem, createGemServer, createHostTokenSource, createMatchServer, defineServer, leaveAndExit, mapIdentity, markOnResolve, platformIconUrl, presentJoinCredential, readTemplateTransports, readTransportAdvert, reportOnResolve, systemClock, text, toBase64, webTransportAvailable };
4376
+ export { ARCADE_EMBEDDERS, type AccountApi, type AdFormat, type AdOutcome, type AdOutcomeKind, type AdRequest, type AdsApi, AnalyticsApi, type AnalyticsFlushOptions, type AnalyticsFlushResult, type AnalyticsOptions, type AnalyticsRejection$1 as AnalyticsRejection, type AnalyticsValue, AuthError, type AuthFailure, type AuthState, type Base64String, type BootMark, type BootTimeline, type BroadcastOptions, type BytesResponse, CONDITIONAL_HEADERS, type Challenge, type ChallengeWindow, ChallengesApi, type ClientOptions, type Clock, type ConditionalRequestHeaders, type ConfiguredPurchasePayment, type ConfiguredPurchaseRequest, type ConfiguredPurchaseResult, DEVICE_SETTINGS_MAX_BYTES, DedicatedServerError, type DedicatedServerFailure, type DedicatedServerSession, type DevToolsOpener, type DeviceSettings, type DeviceSettingsApi, type DeviceSettingsPutOutcome, type DirectPurchaseRequest, type DirectPurchaseResult, type EarnAllowance, type EarnAllowanceEvent, type EarnAllowancePeriod, type EarnAllowanceReadOptions, type EntityLeaderboard, type EntityLeaderboardEntry, type EntityLeaderboardOptions, type EntityType$1 as EntityType, type ExitAnalytics, type ExitBridge, type ExitRooms, type FrameState, type Friend, FriendChallengeError, type FriendChallengeErrorCode, type FriendChallengeOutcome, type FriendChallengeOutcomeKind, type FriendChallengeRequest, FriendsApi, type FriendsPage, type FunctionFailure, type FunctionInvokeOptions, type FunctionResult, FunctionsApi, type GameApi, type GameConfig, type GameServerLink, type Gem, GemApiError, GemClient, type GemCohort, type GemCohorts, GemConfigError, type GemDevTools, type GemErrorReason, GemFrame, GemFunctionError, type GemIdentity, type GemInsets, type GemMatchApi, type GemMatchServer, type GemMatchServerModule, type GemOptions, type GemPlayer, type GemPrefs, type GemReservedArea, GemSaveError, type GemServer, type GemServerBundle, type GemServerFactory, type GemServerHost, type GemServerHostProfile, type GemServerIdentity, type GemServerLifecycle, type GemServerOptions, type GemServerProfile, type GemTerminationNotice, GemUnframedError, type GemViewport, type GetLeaderboardOptions, type HostTokenSource, type HostTokenSourceOptions, type JoinWelcome, type Leaderboard, type LeaderboardEntry, LeaderboardsApi, type ListChallengesOptions, type ListFriendsOptions, MAX_PERIODS_BACK, type MatchConnectOptions, type MatchConnection, type MatchHosting, type MatchHostingMode, type MatchServeOptions, type MatchTransport, type MessageMeta, type MultiTransportSession, PLATFORM_EVENTS, PlatformApi, PlatformCurrenciesApi, type PlatformCurrency, type PlatformCurrencyAccess, type PlatformCurrencyPurchasePayment, type PlatformCurrencyPurchaseRequest, type PlatformCurrencyPurchaseResult, type PlatformCurrencyReadOptions, PlatformEarnAllowanceApi, type PlatformEventName, type PlayerBadge$1 as PlayerBadge, type PlayerBoost, type PlayerBoostMultiplier, type PlayerIdentity, type PlayerProfile, PlayerText, type ProfileCallOptions, type ProfileShowcaseEntry$1 as ProfileShowcaseEntry, ProfilesApi, type PurchaseApi, type PurchaseOptions, type PurchaseOutcome, PurchaseRefusal, type PurchaseRefusalCode, type PurchaseRequest, type PutBytesOptions, type PutSaveOptions, type RankedRow, type RecipeAvailability, type RecipeLock, type RequestOptions, type RewardCue, type RoomArgValue, type SavePage, type SaveRecord, type SendOptions$1 as SendOptions, type ServerApi, type ServerBundleHost, type ServerTokenGrant, type SessionEndReason, type ShareApi, type ShareRequest, ShowcaseApi, type ShowcaseCallOptions, type ShowcaseFriendEntry, type ShowcaseFriends, type ShowcaseValue, type SignInOutcome, type SignInOutcomeKind, type SnapshotCurrency, type SnapshotItem, type TokenGrant, type Transport, type TransportAdvert, type TransportKind, TransportRefusal, type TransportRequest, type TransportResponse, UNRELIABLE_CHANNEL_LABEL, type VersionedGetOptions, type VersionedResponse, type WalletVisibleOptions, asPlayerText, createBootTimeline, createGem, createGemServer, createHostTokenSource, createMatchServer, defineServer, leaveAndExit, mapIdentity, markOnResolve, platformIconUrl, presentJoinCredential, readTemplateTransports, readTransportAdvert, reportOnResolve, systemClock, text, toBase64, webTransportAvailable };
package/docs/analytics.md CHANGED
@@ -119,11 +119,21 @@ one — a key that is not in this table would refuse the whole event rather than
119
119
  context therefore reaches your own `track` calls and stops there: these arrive carrying exactly
120
120
  what the table says, however much context you have set.
121
121
 
122
- Two of these are worth knowing the shape of before you build a report on them:
123
-
124
- - **`gem_session_start` is the handshake, not the first frame.** A game opened outside the arcade
125
- never establishes a play session, so it starts no session and sends nothing. That is expected
126
- while you are developing locally.
122
+ Three of these are worth knowing the shape of before you build a report on them:
123
+
124
+ - **`gem_session_start` is the handshake, not the first frame.** A game whose frame never connects
125
+ establishes no play session, so it starts no session and sends nothing.
126
+ - **A game the Arcade starts on its own is not a session until the player touches it.** On a
127
+ desktop the Arcade may autoplay your game on its information page before anyone has asked for
128
+ it, and a view is not a play. The SDK then holds **everything** — `gem_session_start`,
129
+ `gem_boot_ready`, and your own `track` calls too — until the player's first real input inside
130
+ your game: a pointer press, a key press or a gamepad button the browser itself reported. At
131
+ that moment the session starts and what was held goes out, all stamped at that instant with
132
+ `gem_session_start` first, so a funnel that begins there still sees the rest; `boot_ms` still
133
+ says how long the load really took, and `duration_ms` measures play, not time on the page. A
134
+ pause or resume before that input is dropped, and a launch nobody touches sends nothing at
135
+ all. You write nothing for this — but do not read a missing event before the first input as a
136
+ fault.
127
137
  - **`gem_session_end` on a closing page is best effort.** The browser gives a page that is going
128
138
  away a small budget for requests in flight and the SDK spends part of it here; the room leave
129
139
  gets the larger part, because a stranded room membership is the failure a player notices.