@indiegems/gem-web-sdk 16.3.0 → 16.3.1

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 Le=Object.defineProperty;var qe=(n,e)=>{for(var t in e)Le(n,t,{get:e[t],enumerable:true});};globalThis.__gemWebSdkVersion="[gem-web-sdk:sdkVersion:16.3.0]";var Me={initialDelayMs:2e3,maxDelayMs:6e4};function $e(n,e){return e!==void 0?!e:n==="chain_exhausted"}var U=class{constructor(e){this.options=e;}options;grant=null;state="pending";failure=null;generation=0;inFlight=null;rejected=false;retry=null;failures=0;notBefore=0;disposed=false;get currentState(){return this.state}get lastFailure(){return this.failure}async get(){if(this.state==="lost")throw new h(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.pastChainCeiling())throw new h("chain_exhausted","the token chain reached its ceiling");if(this.inFlight===null&&this.options.clock.now()<this.notBefore)throw new h(this.failure??"unavailable","the embedder asked for no new token yet; one is asked for when that wait is over");return this.refresh(this.nextReason())}pastChainCeiling(){return this.grant===null||this.seconds()<this.grant.chainEndsAt?false:(this.enter("lost","chain_exhausted"),true)}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);}dispose(){this.disposed=true,this.cancelRetry();}scheduleRetry(e){if(this.cancelRetry(),this.failures+=1,this.notBefore=e===void 0?0:this.options.clock.now()+e,this.disposed)return;let{initialDelayMs:t,maxDelayMs:r}=Me,o=Math.min(r,t*2**(this.failures-1)),a=Math.max(o/2,e??0)+Math.random()*(o/2);this.retry={handle:this.options.clock.setTimeout(()=>this.retryNow(),a)};}retryNow(){this.retry=null,this.notBefore=0,!(this.state==="lost"||this.pastChainCeiling())&&this.refresh(this.nextReason()).catch(()=>{});}cancelRetry(){this.retry!==null&&(this.options.clock.clearTimeout(this.retry.handle),this.retry=null);}refresh(e){if(this.inFlight)return this.inFlight;this.cancelRetry();let t=this.generation;this.enter("pending");let r=this.options.request(e).then(o=>{if(t!==this.generation)throw new h("internal","token arrived for a superseded generation");return this.grant=o,this.rejected=false,this.enter("ready"),o.token}).catch(o=>{let a=je(o),{retryable:i,retryAfterMs:l}=o??{};throw t===this.generation&&($e(a,typeof i=="boolean"?i:void 0)?this.enter("lost",a):(this.scheduleRetry(typeof l=="number"&&Number.isFinite(l)&&l>0?l:void 0),this.enter("degraded",a))),o instanceof h?o:new h(a,String(o))}).finally(()=>{this.inFlight===r&&(this.inFlight=null);});return this.inFlight=r,r}enter(e,t){(e==="ready"||e==="lost")&&this.cancelRetry(),e==="ready"&&(this.failures=0,this.notBefore=0),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)}},h=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 je(n){if(n instanceof h)return n.reason;let e=n?.reason;return typeof e=="string"&&["chain_exhausted","unavailable","timeout","internal"].includes(e)?e:"internal"}var f=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}},D=["if-match","if-none-match"],Q=4096;function Be(n){if(!n)return;let e={};for(let[t,r]of Object.entries(n)){let o=t.toLowerCase();if(!D.includes(o)||r===void 0)continue;let a=typeof r=="string"?Fe(r):r;if(typeof a!="string"||a.length>Q||!Ue(a))throw new f(`the ${o} header value cannot be sent \u2014 it is not a string, is longer than ${Q} 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.`);a!==""&&(e[o]=a);}return Object.freeze(e)}function Fe(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 Ue(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 De(n){let{bytes:e}=n;if(e!==void 0){if(Object.prototype.toString.call(e)!=="[object Uint8Array]")throw new f("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 f("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},a=Be(o.headers),i=De(o),l=Object.freeze({...o,headers:a,...i===void 0?{}:{bytes:i}}),u=await e.tokenSource.get(),c=await n(l,u);if(c.status!==401||!t)return c;e.tokenSource.invalidate(u);let g=await e.tokenSource.get(),S=await n(l,g);if(S.status===401)throw e.tokenSource.close("unavailable"),new h("unavailable","the server refused a freshly minted token");return S}}}function ee(n){let e=typeof n=="string"?new TextEncoder().encode(n):n;return btoa(Ne(e))}function Ne(n){let t="";for(let r=0;r<n.length;r+=32768)t+=String.fromCharCode(...n.subarray(r,r+32768));return t}var p=class extends Error{constructor(t,r,o,a,i){super(`${t} (${r}): ${o}`);this.reason=t;this.status=r;this.detail=o;this.retryAfterSeconds=a;this.code=i;this.name="GemApiError";}reason;status;detail;retryAfterSeconds;code;get retryable(){return this.reason==="unavailable"||this.reason==="rate_limited"}},re=new WeakMap;function oe(n){return re.get(n)??{}}var He=new Set([408,429,500,502,503,504]),Ve=6e4,We=new WeakMap;function ne(n){return n!==null&&(n.reason==="rate_limited"||n.retryAfterSeconds!==void 0)}function ze(n){if(n===void 0)return 2;if(!Number.isInteger(n)||n<0||n>10)throw new f(`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 L=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,...$(o)},o.replaySafe===true,o.retryRateLimited!==false)}async post(e,t,r,o={}){return this.send({method:"POST",path:e,body:t,signal:r,...$(o)},o.replaySafe===true,o.retryRateLimited!==false)}async postBytes(e,t,r,o={}){let a=await this.sendRaw({method:"POST",path:e,bytes:t,responseType:"bytes",signal:r,...$(o)},o.replaySafe===true,o.retryRateLimited!==false);return {bytes:Ke(a.body),...a.invocationId===void 0?{}:{invocationId:a.invocationId}}}async patch(e,t,r,o={}){return this.send({method:"PATCH",path:e,body:t,signal:r,...$(o)},o.replaySafe===true,o.retryRateLimited!==false)}async delete(e,t,r={}){return this.send({method:"DELETE",path:e,signal:t,...$(r)},r.replaySafe===true,r.retryRateLimited!==false)}async send(e,t,r=true){return (await this.sendRaw(e,t,r)).body}async sendRaw(e,t,r=true){let o=t?ze(this.options.maxRetries)+1:1,a=null;if(e.signal?.aborted)throw te(e.signal);let i=e.signal===void 0?void 0:We.get(e.signal);for(let l=0;l<o;l++){if(l>0){let g=this.backoffMs(l,a);if(ne(a)&&i!==void 0&&g>=i())throw a;await this.backoff(g,e.signal);}if(e.signal?.aborted)throw ne(a)&&i!==void 0&&i()<=0?a:te(e.signal);let u;try{u=await this.options.transport.request(e);}catch(g){if(h.isAuthError(g)||f.isRefusal(g)||e.signal?.aborted||Ye(g))throw g;a=new p("unavailable",0,String(g));continue}if(u.status>=200&&u.status<300||u.status===304)return u;let c=Je(u);if(!He.has(u.status)||u.status===429&&!r)throw c;a=c;}throw a??new p("unavailable",0,"no attempt was made")}backoffMs(e,t){let r=t?.retryAfterSeconds,o=r!==void 0?r*1e3:2**(e-1)*250,a=2**(e-1)*250;return Math.min(Math.max(o,a),Ve)}backoff(e,t){return t?.aborted?Promise.resolve():new Promise(r=>{let o=this.options.clock,a=false,i=false,l,u=()=>{a||(a=true,i&&o.clearTimeout(l),t?.removeEventListener("abort",u),r());};t?.addEventListener("abort",u,{once:true}),l=o.setTimeout(u,e),i=true,a&&o.clearTimeout(l);})}};function Ke(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 $(n){return {...n.keepalive===void 0?{}:{keepalive:n.keepalive},...n.ifMatch===void 0?{}:{headers:{"if-match":n.ifMatch}}}}function te(n){return n.reason!==void 0?n.reason:new DOMException("The operation was aborted.","AbortError")}function Ye(n){let e=n?.name;return e==="AbortError"||e==="TimeoutError"}function Je(n){let e=Qe(n),t=en(n.body),r={...t===void 0?{}:{details:t},...n.invocationId===void 0?{}:{invocationId:n.invocationId}};return Object.keys(r).length>0&&re.set(e,r),e}var Xe=new Map([["insufficient_funds","insufficient_funds"]]);function Qe(n){let{status:e,body:t}=n,r=Ze(t),o=n.retryAfterSeconds??tn(t),a=nn(t),i=a===void 0?void 0:Xe.get(a);if(i!==void 0)return new p(i,e,r,void 0,a);switch(e){case 304:return new p("not_modified",e,r);case 400:case 422:return new p("invalid",e,r,void 0,a);case 403:return new p("forbidden",e,r,void 0,a);case 404:return new p("not_found",e,r,void 0,a);case 402:return new p("insufficient_funds",e,r,void 0,a);case 409:return new p("conflict",e,r,void 0,a);case 412:return new p("precondition_failed",e,r,void 0,a);case 413:return new p("too_large",e,r,void 0,a);case 429:return new p("rate_limited",e,r,o,a);default:return new p("unavailable",e,r,o,a)}}function Ze(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 en(n){let t=n?.error?.details;return t===null?void 0:t}function nn(n){let t=n?.error?.code;return typeof t=="string"&&t.length>0?t:void 0}function tn(n){let e=n?.retryAfterSeconds;return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:void 0}function rn(n){let e=n.lastIndexOf("@");return (e===-1?n:`***@${n.slice(e+1)}`).slice(0,200)}var on=new Set(D);function an(n){if(!n)return {};let e={};for(let[t,r]of Object.entries(n))on.has(t.toLowerCase())&&(e[t.toLowerCase()]=r);return e}function ae(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 f("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 a;try{a=new URL(o.href.replace(/\/+$/,"")+t.path);}catch{throw new f(`${JSON.stringify(typeof t.path=="string"?rn(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(a.protocol!==o.protocol||a.host!==o.host)throw new f(`${JSON.stringify(a.pathname)} resolves to ${a.protocol}//${a.host}, not ${o.protocol}//${o.host}. A request path may not change the request's origin \u2014 it carries the play token.`);if(a.username!==""||a.password!==""){let R=o.username!==""||o.password!=="",y=a.username!==o.username||a.password!==o.password,x=R?y?"baseUrl (and possibly the request path)":"baseUrl":"request path";throw new f(`the ${x} puts credentials in the URL, which cannot be fetched (${t.method} ${a.pathname}). The value is withheld here rather than written to logs. This is a malformed request, not a server failure.`)}for(let[R,y]of Object.entries(n.defaultQuery??{}))a.searchParams.has(R)||a.searchParams.set(R,y);let i=t.bytes,l=t.bytes===void 0?void 0:"application/octet-stream";try{t.body!==void 0&&(i=JSON.stringify(t.body),l="application/json");}catch(R){throw new f(`the body of ${t.method} ${JSON.stringify(a.pathname)} could not be serialised to JSON: ${String(R)}. This is a bug in the request, not a server failure \u2014 retrying sends the same unserialisable value.`)}let u=await e(a.toString(),{method:t.method,headers:{authorization:`Bearer ${r}`,...l===void 0?{}:{"content-type":l},...an(t.headers)},body:i,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"&&u.status>=200&&u.status<300)c=new Uint8Array(await u.arrayBuffer());else {let R=await u.text();if(R.length>0)try{c=JSON.parse(R);}catch{c=R;}}let g=u.headers.get("etag"),S=sn(u.headers.get("retry-after")),w=u.headers.get("x-gem-invocation-id");return {status:u.status,body:c,...g===null?{}:{etag:g},...S===void 0?{}:{retryAfterSeconds:S},...w===null||w===""?{}:{invocationId:w}}},n)}function sn(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 ln="gem-web-bridge";var dn=65536,se=8,N=5e3,ie=1024;var H=Object.create(null);var le=Object.create(null);function un(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 cn(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 mn(n){return /^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i.test(n)}function gn(n){return /^[a-z_]+$/.test(n)}function pn(n){return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(n)||/^[a-z0-9][a-z0-9-]{1,38}[a-z0-9]$/.test(n)&&!n.includes("--")}function W(n,e,t){if(e>se)return `nesting deeper than ${se}`;if(++t.nodes>N)return `more than ${N} values`;if(t.bytes>t.cap)return `over the ${t.cap} 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>ie)return `an array of ${n.length} entries, over the ${ie} limit`;t.bytes+=2;for(let l of n){let u=W(l,e+1,t);if(u)return u}return null}let a=Object.getPrototypeOf(n);if(a!==Object.prototype&&a!==null)return "a value that is not a plain object";t.bytes+=2;let i=n;for(let l in i){if(!Object.prototype.hasOwnProperty.call(i,l))continue;if(++t.nodes>N)return `more than ${N} values`;if(t.bytes+=l.length*3+4,t.bytes>t.cap)return `over the ${t.cap} byte limit`;let u=W(i[l],e+1,t);if(u)return u}return null}function yn(n,e=dn){let t={nodes:0,bytes:0,seen:new Set,cap:e},r=W(n,0,t);return r?`message contains ${r}`:t.bytes>e?`message is over the ${e} byte limit`:null}var fn={origin:[un,"not a well-formed origin"],url:[cn,"not a safe absolute http(s) URL"],bcp47:[mn,"not a well-formed BCP 47 tag"],code:[gn,"not a code of lower-case letters and underscores"],gameRef:[pn,"not a game id or web address"]};function de(n,e,t){for(let r of e){let o=t===""?r[0]:`${t}.${r[0]}`,a=n[r[0]];if(a==null){if(r[1]<"a")continue;return `${o}: required`}let i=z(a,r,o);if(i)return i}return null}function z(n,e,t){let r=e[1].toLowerCase();switch(r){case "u":return typeof n=="boolean"?null:z(n,typeof n=="string"?[e[0],"s",e[2]]:[e[0],"n",e[3],e[4]],t);case "s":{if(typeof n!="string")return `${t}: expected string`;if(n.length>e[2])return `${t}: exceeds ${e[2]} characters`;if(e[3]){let[o,a]=fn[e[3]];if(!o(n))return `${t}: ${a}`}return null}case "n":case "i":return typeof n!="number"||!(r=="i"?Number.isInteger:Number.isFinite)(n)?`${t}: expected ${r=="i"?"integer":"number"}`:n<e[2]||n>e[3]?`${t}: out of range ${e[2]}..${e[3]}`:null;case "b":return typeof n=="boolean"?null:`${t}: expected boolean`;case "e":{let o=e[2];return o.includes(n)?null:`${t}: not one of ${o.join("|")}`}case "o":return typeof n!="object"||n===null||Array.isArray(n)?`${t}: expected object`:de(n,e[2],t);case "j":return typeof n!="object"||n===null||Array.isArray(n)?`${t}: expected a plain object`:null;case "a":{if(!Array.isArray(n))return `${t}: expected array`;if(n.length>e[2])return `${t}: exceeds ${e[2]} items`;let o=e[3],a=`${t}[]`;for(let i of n){if(i==null){if(o[1]<"a")continue;return `${a}: required`}let l=z(i,o,a);if(l)return l}return null}default:return `${t}: unknown kind ${String(r)}`}}var ue=Object.create(null);function d(n,e,t,r,o){return H[n]=t,r&&(le[n]=r),ue[n]=a=>{let i=yn(a,o);if(i)return i;if(typeof a!="object"||a===null||Array.isArray(a))return "message: expected object";let l=a;return l.gem!==ln?"gem: wrong protocol marker":l.type!==n?`type: expected ${n}`:de(l,e,"")}}var m=["requestId","s",64],I=["outcome","e",["ok","declined","unavailable"]],E=["reason","S",64,"code"];d("gem.handshake",[["versions","o",[["min","i",1,1e3],["max","i",1,1e3]]],["capabilities","A",64,["","s",64]],["embedder","s",2048,"origin"],["unbidden","B"]],30);d("gem.handshake.accept",[["v","i",1,1e3],["capabilities","A",64,["","s",64]]],5);d("gem.token",[["token","s",4096],["requestId","S",64],["generation","i",0,2147483647],["apiBaseUrl","S",512,"url"],["playerId","s",64],["gameId","s",64],["channel","e",["dev","test","release"]],["gameVersion","S",64],["expiresAt","i",0,4102444800],["chainEndsAt","i",0,4102444800],["allowDevTools","B"]],30);d("gem.token.denied",[m,["retryable","b"],["retryAfterMs","I",0,36e5],["reason","e",["chain_exhausted","unavailable"]],["correlationId","s",64]],30);d("gem.player",[["untrusted","o",[["displayName","s",64],["displayTag","S",80],["displayHandle","s",80]]],["playerId","S",64],["discriminator","S",8],["avatarIconUrl","S",2048,"url"],["avatarIconId","S",64],["avatar3dId","S",64],["avatar3dModelUrl","S",2048,"url"],["avatar3dIconUrl","S",2048,"url"],["avatars3d","A",8,["","o",[["family","s",32],["id","s",64],["modelUrl","s",256,"url"],["iconUrl","s",256,"url"]]]],["badges","A",2,["","o",[["itemId","s",64],["iconUrl","s",2048,"url"]]]],["displayTag","s",8],["avatarUrl","S",2048,"url"],["boost","O",[["multipliers","a",8,["","o",[["currencyId","s",64],["currencySlug","s",32],["multiplierBp","i",1e4,1e6]]]],["expiresInDays","I",1,7]]]],12);d("gem.pause",[["paused","b"]],120);d("gem.prefs",[["reducedMotion","b"],["muted","b"],["showFrameStats","B"],["music","B"],["sounds","B"],["locale","s",35,"bcp47"],["recommended","O",[["volume","i",0,100],["batterySaver","b"],["keyboardLayout","e",["wasd","arrows"]],["gamepadConfirm","e",["south","east"]],["vibration","b"],["lookSensitivity","I",20,400],["gamepadLookSensitivity","I",20,400],["invertLookY","B"],["touchMovement","S",16,"code"],["graphicsQuality","S",16,"code"],["graphicsQualityAuto","B"],["colorHelp","B"]]]],60);d("gem.cohorts",[["cohorts","a",8,["","o",[["experimentId","s",36],["variantKey","s",32]]]]],12,"cohorts");d("gem.earnAllowanceChanged",[],30,"earnAllowance");d("gem.viewport",[["insets","o",[["top","i",0,4096],["right","i",0,4096],["bottom","i",0,4096],["left","i",0,4096]]],["reserved","A",4,["","o",[["x","i",0,16384],["y","i",0,16384],["width","i",0,16384],["height","i",0,16384],["control","O",[["x","i",0,16384],["y","i",0,16384],["width","i",0,16384],["height","i",0,16384]]]]]]],60,"viewport");d("gem.deviceSettings",[["settings","J"]],12,"deviceSettings");d("gem.willTerminate",[["reason","e",["grant_expiring","session_ended","navigating","kill_switch"]],["graceMs","i",0,6e4]],10);d("gem.roomEvent",[["event","e",["updated","match_started","match_ready","match_failed","version_stale"]],["roomId","s",64],["matchId","S",64],["version","I",0,2147483647],["reason","S",64],["platform","E",["universal","mobile"]]],120,"rooms");d("gem.socketState",[["connected","b"],["reason","E",["connecting","dropped","watchdog","terminal"]]],12,"socketState");d("gem.seatedEvent",[["roomId","s",64]],60,"partySeating");d("gem.autoStartFailedEvent",[["roomId","s",64],["code","s",64]],30,"autoStartFailure");d("gem.ticketEvent",[["event","e",["queued","matched","expired","cancelled","failed"]],["ticketId","s",64],["partySize","I",1,64],["queuedAt","I",0,4102444800],["expiresAt","I",0,4102444800],["reason","S",64],["roomId","S",64]],60,"ticketEvents");d("gem.signalEvent",[["event","e",["hello","offer","answer","ice","peerJoined","peerLeft","migration","matchEnded","error"]],["matchId","s",64],["data","j"]],1800,"p2p");d("gem.dedicatedEvent",[["event","e",["answer","error","matchEnded"]],["matchId","s",64],["sdp","S",10240],["sessionId","S",64],["code","S",64],["message","S",256],["reason","S",64]],120,"dedicated");d("gem.partyResult",[m,["partyId","S",64]],30,"parties");d("gem.clusterTarget",[["clusterTargetId","s",64],["clusterTargetIds","A",3,["","s",64]]],12,"clusterTarget");d("gem.devtools",[["action","e",["open","close","toggle"]]],30,"devtools");d("gem.screenshot",[["maxWidth","i",1,7680],["maxHeight","i",1,4320]],6,"screenshot");d("gem.screenshot.denied",[["reason","e",["not_wired","no_source","unsupported","unreadable","tainted","too_large","busy","declined","failed"]],["retryable","b"]],12,"screenshot");d("gem.requestContext",[],12,"feedbackContext");d("gem.gameContext",[["context","j"]],12,"feedbackContext");d("gem.signal",[["signal","e",["join","offer","answer","ice","migrationAck","hostUnreachable"]],["matchId","s",64],["data","j"]],1200,"p2p");d("gem.dedicatedOffer",[["matchId","s",64],["sdp","s",10240],["intent","e",["initial","ice_restart","full_reconnect"]]],60,"dedicated");d("gem.partyRequest",[m],12,"parties");d("gem.ready",[],5);d("gem.engaged",[],5,"engagement");d("gem.progress",[["loaded","i",0,1099511627776],["total","i",0,1099511627776]],600);d("gem.requestToken",[m,["reason","e",["initial","expiring","rejected"]]],12);d("gem.requestLocalServer",[m,["gameRoomId","s",64]],6,"localHost");d("gem.localServer",[m,["serverId","S",128]],30,"localHost");d("gem.localServer.denied",[m,["retryable","b"],["reason","e",["refused","unavailable"]]],30,"localHost");d("gem.exit",[["reason","S",64]],5);d("gem.openExternal",[["url","s",2048,"url"]],6);d("gem.requestFullscreen",[["enabled","b"]],30);d("gem.audioState",[["muted","b"]],120,"audioState");d("gem.rewardCue",[["currencySlug","s",32],["expected","I",1,1e9],["origin","O",[["x","i",0,16384],["y","i",0,16384]]]],60,"rewardCue");d("gem.walletDisplay",[["visible","b"],["currencies","A",8,["","s",64]],["score","B"]],60,"walletDisplay");d("gem.controlsDeclare",[["uses","o",[["lookSensitivity","S",16,"code"],["gamepadLookSensitivity","S",16,"code"],["invertLookY","S",16,"code"],["touchMovement","S",16,"code"]]]],60,"controls");d("gem.menu",[["settings","b"],["items","A",4,["","o",[["id","s",32],["label","s",40]]]]],60,"gameMenu");d("gem.menuSelect",[["entry","e",["settings","item"]],["id","S",32]],60,"gameMenu");d("gem.gemCorner",[["corner","e",["top-left","top-right","bottom-left","bottom-right"]]],12,"gemCorner");d("gem.settingsDeclare",[["settings","a",8,["","o",[["id","s",40],["label","s",40],["kind","e",["toggle","slider","choice"]],["value","u",40,-1e6,1e6],["quick","B"],["icon","S",16,"code"],["min","N",-1e6,1e6],["max","N",-1e6,1e6],["step","N",0,1e6],["options","A",4,["","o",[["id","s",40],["label","s",40]]]]]]]],120,"gameSettings");d("gem.settingChange",[["id","s",40],["value","u",40,-1e6,1e6]],120,"gameSettings");d("gem.requestShare",[["params","a",16,["","o",[["key","s",64],["value","s",512]]]]],6,"share");d("gem.requestAvatarPicker",[["tab","E",["2d","3d"]]],6,"avatarPicker");d("gem.vibrate",[["pattern","a",99,["","i",0,1e4]]],600,"vibration");d("gem.frameStats",[["fps","i",0,1e3],["frameTimeP95Ms","i",0,1e5],["counts","E",["pageFrames","gameDraws"]]],120,"frameStats");d("gem.portraitBorders",[["name","S",40]],60,"portraitBorders");d("gem.error",[["code","e",["version_mismatch","handshake_timeout","handshake_duplicate","invalid_message","rate_limited","token_unavailable","unsupported","unsupported_capability","internal"]],["message","S",256]],60);d("gem.requestPurchase",[m,["purchaseKind","e",["item","recipe"]],["targetId","s",64],["currencySlug","s",32],["quantity","I",1,10],["catalogId","S",64]],12,"purchases");d("gem.requestAvatar3dPurchase",[m,["itemId","s",64],["currencySlug","s",32]],12,"avatar3dPurchases");d("gem.purchaseResult",[m,I,E,["purchaseId","S",64]],30,"purchases");d("gem.deviceSettings.put",[m,["settings","j"]],30,"deviceSettings");d("gem.deviceSettings.result",[m,["outcome","e",["stored","too_large","unavailable"]]],30,"deviceSettings");d("gem.requestAd",[m,["placement","s",32],["format","e",["interstitial","rewarded"]]],6,"ads");d("gem.adResult",[m,["outcome","e",["shown","no_ad","unavailable"]]],12,"ads");d("gem.signalMoment",[m,["kind","e",["level_end","run_end","match_end","menu_return","other_break"]],["placement","S",32],["wall","B"]],6,"moments");d("gem.momentResult",[m,["shown","b"]],12,"moments");d("gem.requestSignIn",[m],6,"signIn");d("gem.signInResult",[m,["outcome","e",["signed_in","declined","unavailable"]]],12,"signIn");d("gem.requestFriendChallenge",[m,["playerId","s",64],["template","s",64],["params","J"]],12,"friendChallenges");d("gem.friendChallengeResult",[m,["outcome","e",["accepted","cancelled","refused","unavailable","rate_limited","invalid"]],["code","S",64],["param","S",64],["channel","S",16],["configVersion","I",0,9007199254740991],["retryAfterMs","I",0,864e5],["detail","S",300]],30,"friendChallenges");d("gem.requestAppLinks",[m],12,"appLinks");d("gem.appLinksResult",[m,I,E,["arcade","O",[["store","e",["app_store","google_play"]]]],["game","O",[["store","e",["app_store","google_play"]]]]],30,"appLinks");d("gem.requestOpenApp",[m,["target","e",["arcade","game"]]],6,"appLinks");d("gem.openAppResult",[m,I,E],30,"appLinks");d("gem.requestOpenGame",[m,["ref","s",40,"gameRef"]],6,"openGame");d("gem.openGameResult",[m,I,E],30,"openGame");d("gem.requestSimilarGames",[m,["limit","I",1,24]],12,"openGame");d("gem.similarGamesResult",[m,I,E,["games","a",24,["","o",[["gameId","s",36,"gameRef"],["slug","S",40,"gameRef"],["iconUrl","s",1024,"url"],["capsuleLandscapeUrl","s",1024,"url"],["capsulePortraitUrl","s",1024,"url"],["previewVideoUrl","S",1024,"url"],["previewPosterUrl","S",1024,"url"],["untrusted","o",[["name","s",64],["tagline","s",64],["shortDescription","s",320],["tags","a",10,["","s",32]]]]]]]],30,"openGame",524288);d("gem.requestStoreOffers",[m],12,"store");d("gem.storeOffersResult",[m,I,E,["offers","a",32,["","o",[["skuId","s",64],["kind","e",["gem_pack","boost","pass","bundle"]],["name","s",80],["description","s",400],["imageUrl","S",1024,"url"],["priceDisplay","s",32],["grant","O",[["currency","s",32],["amount","i",1,1e9]]]]]]],30,"store",262144);d("gem.requestStorePurchase",[m,["skuId","s",64]],12,"store");d("gem.storePurchaseResult",[m,I,E],30,"store");d("gem.storePurchaseSettled",[["skuId","s",64]],30,"store");Object.freeze(ue);H.__malformed=60;Object.freeze(H);Object.freeze(le);var q={now:()=>Date.now(),setTimeout:(n,e)=>setTimeout(n,e),clearTimeout:n=>clearTimeout(n)};function ce(n){let e=n.toLowerCase();return e==="localhost"||e.endsWith(".localhost")||e==="[::1]"||e==="::1"?true:/^127(\.\d{1,3}){3}$/.test(e)}var hn=1e4;function me(n,e){return K(n,e)}function K(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=i=>({token:i.token,expiresAt:i.expiresAt,chainEndsAt:Number.POSITIVE_INFINITY}),r=null,o=new U({clock:e.clock,...e.onStateChange===void 0?{}:{onStateChange:e.onStateChange},request:()=>new Promise((i,l)=>{let u=e.clock.setTimeout(()=>{r=null,l({reason:"unavailable",retryable:true});},e.timeoutMs??hn);r={resolve:c=>{e.clock.clearTimeout(u),i(c);},reject:l,timer:u};})}),a=n.onServerToken(i=>{let l=t(i),u=r;if(u){r=null,u.resolve(l);return}o.accept(l);});return {source:o,dispose(){a(),o.dispose(),r&&(e.clock.clearTimeout(r.timer),r.reject({reason:"unavailable",retryable:false}),r=null);}}}var J={};qe(J,{acceptTransfer:()=>_n,addEntityProgression:()=>bn,adminAction:()=>Rn,cancelInventoryTransfer:()=>vn,claimEntityProgressionRewards:()=>Sn,closeGameRoom:()=>xn,createEntityBatchOrder:()=>wn,createEntityOrder:()=>kn,createSession:()=>An,deleteEntityGameSetting:()=>On,deleteEntitySave:()=>Pn,deleteSession:()=>Gn,deleteShowcaseValue:()=>Tn,executeEntityRecipe:()=>Cn,finalizeSaveUpload:()=>In,getChannelAssignment:()=>En,getDropRates:()=>Ln,getEntityCurrency:()=>qn,getEntityGameSetting:()=>Mn,getEntityInventory:()=>$n,getEntityInventoryItem:()=>jn,getEntityLeaderboard:()=>Bn,getEntityOrder:()=>Fn,getEntityProgression:()=>Un,getEntityRecipeAvailability:()=>Dn,getEntityRecipeUsage:()=>Nn,getEntitySave:()=>Hn,getEvent:()=>Vn,getGameRoomV2:()=>Wn,getLeaderboard:()=>zn,getPlayerGameProfile:()=>Kn,getPurchaseCatalog:()=>Yn,getResolvedTemplate:()=>Jn,getRoomArgs:()=>Xn,getShowcaseValue:()=>Qn,getTransferDetails:()=>Zn,ingestAnalyticsEvents:()=>Y,initiateInventoryTransfer:()=>et,invokeFunction:()=>nt,kickPlayer:()=>tt,listChallenges:()=>rt,listEntityGameSettings:()=>ot,listEntityOrders:()=>at,listEntityProgressions:()=>st,listEntitySaves:()=>it,listEvents:()=>lt,listGameRooms:()=>dt,listResolvedTemplates:()=>ut,listTransfers:()=>ct,maxEntityProgression:()=>mt,putEntityGameSetting:()=>gt,putRoomArgs:()=>pt,putShowcaseValue:()=>yt,rejectTransfer:()=>ft,reportMatchPlayers:()=>ht,requestSaveUploadUrl:()=>_t,resetEntityProgression:()=>bt,setMatchBackfill:()=>Rt,simulateEntityOrder:()=>vt,transferHostV2:()=>St,updateGameRoomV2:()=>xt});function s(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 _n(n,e,t){let r=`/v1/inventory/transfers/${s(e)}/accept`;return n.client.post(r,void 0,t?.signal)}async function bn(n,e,t,r,o,a){let i=`/v1/inventory/${s(e)}/${s(t)}/progressions/${s(r)}/add`;return n.client.post(i,o,a?.signal)}async function Rn(n,e,t,r){let o=`/v1/voice/sessions/${s(e)}/admin`;return n.client.post(o,t,r?.signal)}async function vn(n,e,t){let r=`/v1/inventory/transfers/${s(e)}/cancel`;return n.client.post(r,void 0,t?.signal)}async function Sn(n,e,t,r,o,a){let i=`/v1/inventory/${s(e)}/${s(t)}/progressions/${s(r)}/claim`;return n.client.post(i,o,a?.signal)}async function xn(n,e,t){let r=`/v1/games/${s(n.gameId())}/game-rooms/${s(e)}`;return n.client.delete(r,t?.signal)}async function wn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/orders/batch`;return n.client.post(a,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function kn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/orders`;return n.client.post(a,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function An(n,e,t){return n.client.post("/v1/voice/sessions",e,t?.signal)}async function On(n,e,t,r,o){let a=`/v1/settings/${s(e)}/${s(t)}/${s(r)}`;return n.client.delete(a,o?.signal)}async function Pn(n,e,t,r,o){let a=`/v1/saves/${s(e)}/${s(t)}/${s(r)}`;return n.client.delete(a,o?.signal)}async function Gn(n,e,t){let r=`/v1/voice/sessions/${s(e)}`;return n.client.delete(r,t?.signal)}async function Tn(n,e,t,r){let o=`/v1/showcase/players/${s(e)}/${s(t)}`;return n.client.delete(o,r?.signal)}async function Cn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/recipes/execute`;return n.client.post(a,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function In(n,e,t,r,o,a){let i=`/v1/saves/${s(e)}/${s(t)}/${s(r)}/finalize`;return n.client.post(i,o,a?.signal)}async function En(n,e,t){let r=`/v1/games/${s(n.gameId())}/config/channels/${s(e)}`;return n.client.getWithEtag(r,{...t?.signal===void 0?{}:{signal:t.signal},...t?.ifNoneMatch===void 0?{}:{ifNoneMatch:t.ifNoneMatch}})}async function Ln(n,e,t){let r=`/v1/inventory/loot-tables/${s(e)}/drop-rates`;return n.client.get(r,t?.signal)}async function qn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/currencies/${s(r)}`;return n.client.get(a,o?.signal)}async function Mn(n,e,t,r,o){let a=`/v1/settings/${s(e)}/${s(t)}/${s(r)}`;return n.client.getWithEtag(a,{...o?.signal===void 0?{}:{signal:o.signal},...o?.ifNoneMatch===void 0?{}:{ifNoneMatch:o.ifNoneMatch}})}async function $n(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 a=o.toString(),i=`/v1/inventory/${s(e)}/${s(t)}`+(a?`?${a}`:"");return n.client.get(i,r?.signal)}async function jn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/items/${s(r)}`;return n.client.get(a,o?.signal)}async function Bn(n,e,t,r,o){let a=new URLSearchParams;o?.bucket_1!==void 0&&a.set("bucket_1",String(o?.bucket_1)),o?.bucket_2!==void 0&&a.set("bucket_2",String(o?.bucket_2)),o?.limit!==void 0&&a.set("limit",String(o?.limit)),o?.periods_back!==void 0&&a.set("periods_back",String(o?.periods_back)),o?.period!==void 0&&a.set("period",String(o?.period)),o?.player_id!==void 0&&a.set("player_id",String(o?.player_id));let i=a.toString(),l=`/v1/leaderboards/${s(e)}/${s(t)}/${s(r)}`+(i?`?${i}`:"");return n.client.get(l,o?.signal)}async function Fn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/orders/${s(r)}`;return n.client.get(a,o?.signal)}async function Un(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/progressions/${s(r)}`;return n.client.get(a,o?.signal)}async function Dn(n,e,t,r,o,a){let i=`/v1/inventory/${s(e)}/${s(t)}/catalogs/${s(r)}/recipes/${s(o)}/availability`;return n.client.get(i,a?.signal)}async function Nn(n,e,t,r){let o=new URLSearchParams;r?.limit!==void 0&&o.set("limit",String(r?.limit));let a=o.toString(),i=`/v1/inventory/${s(e)}/${s(t)}/recipe-usage`+(a?`?${a}`:"");return n.client.get(i,r?.signal)}async function Hn(n,e,t,r,o){let a=`/v1/saves/${s(e)}/${s(t)}/${s(r)}`;return n.client.getWithEtag(a,{...o?.signal===void 0?{}:{signal:o.signal},...o?.ifNoneMatch===void 0?{}:{ifNoneMatch:o.ifNoneMatch}})}async function Vn(n,e,t){let r=`/v1/events/${s(e)}`;return n.client.get(r,t?.signal)}async function Wn(n,e,t){let r=`/v2/games/${s(n.gameId())}/game-rooms/${s(e)}`;return n.client.getWithEtag(r,{...t?.signal===void 0?{}:{signal:t.signal},...t?.ifNoneMatch===void 0?{}:{ifNoneMatch:t.ifNoneMatch}})}async function zn(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)),t?.periods_back!==void 0&&r.set("periods_back",String(t?.periods_back)),t?.period!==void 0&&r.set("period",String(t?.period)),t?.player_id!==void 0&&r.set("player_id",String(t?.player_id));let o=r.toString(),a=`/v1/leaderboards/${s(e)}`+(o?`?${o}`:"");return n.client.get(a,t?.signal)}async function Kn(n,e,t){let r=`/v1/profiles/players/${s(e)}`;return n.client.get(r,t?.signal)}async function Yn(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 Jn(n,e,t){let r=`/v1/game-room-templates/${s(e)}`;return n.client.get(r,t?.signal)}async function Xn(n,e,t){let r=`/v1/games/${s(n.gameId())}/game-rooms/${s(e)}/room-args`;return n.client.get(r,t?.signal)}async function Qn(n,e,t,r){let o=`/v1/showcase/players/${s(e)}/${s(t)}`;return n.client.get(o,r?.signal)}async function Zn(n,e,t){let r=`/v1/inventory/transfers/${s(e)}`;return n.client.get(r,t?.signal)}async function Y(n,e,t){let r=`/v1/games/${s(n.gameId())}/analytics/events`;return n.client.post(r,e,t?.signal,{replaySafe:true,retryRateLimited:false})}async function et(n,e,t){return n.client.post("/v1/inventory/transfers",e,t?.signal)}async function nt(n,e,t){return n.client.postBytes("/v1/functions/invoke",e,t?.signal)}async function tt(n,e,t,r){let o=`/v1/games/${s(n.gameId())}/game-rooms/${s(e)}/kick/${s(t)}`;return n.client.post(o,void 0,r?.signal)}async function rt(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 ot(n,e,t,r){let o=`/v1/settings/${s(e)}/${s(t)}`;return n.client.get(o,r?.signal)}async function at(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 a=o.toString(),i=`/v1/inventory/${s(e)}/${s(t)}/orders`+(a?`?${a}`:"");return n.client.get(i,r?.signal)}async function st(n,e,t,r){let o=`/v1/inventory/${s(e)}/${s(t)}/progressions`;return n.client.get(o,r?.signal)}async function it(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 a=o.toString(),i=`/v1/saves/${s(e)}/${s(t)}`+(a?`?${a}`:"");return n.client.get(i,r?.signal)}async function lt(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 dt(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/${s(n.gameId())}/game-rooms`+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function ut(n,e){return n.client.get("/v1/game-room-templates",e?.signal)}async function ct(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 mt(n,e,t,r,o,a){let i=`/v1/inventory/${s(e)}/${s(t)}/progressions/${s(r)}/max`;return n.client.post(i,o,a?.signal)}async function gt(n,e,t,r,o,a){let i=`/v1/settings/${s(e)}/${s(t)}/${s(r)}`;return n.client.put(i,o,a?.signal,{...a?.ifMatch===void 0?{}:{ifMatch:a.ifMatch}})}async function pt(n,e,t,r){let o=`/v1/games/${s(n.gameId())}/game-rooms/${s(e)}/room-args`;return n.client.put(o,t,r?.signal)}async function yt(n,e,t,r,o){let a=`/v1/showcase/players/${s(e)}/${s(t)}`;return n.client.put(a,r,o?.signal)}async function ft(n,e,t){let r=`/v1/inventory/transfers/${s(e)}/reject`;return n.client.post(r,void 0,t?.signal)}async function ht(n,e,t,r){let o=`/v1/games/${s(n.gameId())}/matches/${s(e)}/players/report`;return n.client.post(o,t,r?.signal)}async function _t(n,e,t,r,o,a){let i=`/v1/saves/${s(e)}/${s(t)}/${s(r)}/upload-url`;return n.client.post(i,o,a?.signal,{replaySafe:true})}async function bt(n,e,t,r,o,a){let i=`/v1/inventory/${s(e)}/${s(t)}/progressions/${s(r)}/reset`;return n.client.post(i,o,a?.signal)}async function Rt(n,e,t,r){let o=`/v1/games/${s(n.gameId())}/matches/${s(e)}/backfill`;return n.client.put(o,t,r?.signal)}async function vt(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/orders/simulate`;return n.client.post(a,r,o?.signal)}async function St(n,e,t,r){let o=`/v2/games/${s(n.gameId())}/game-rooms/${s(e)}/transfer/${s(t)}`;return n.client.post(o,void 0,r?.signal)}async function xt(n,e,t,r){let o=`/v2/games/${s(n.gameId())}/game-rooms/${s(e)}`;return n.client.patch(o,t,r?.signal,{...r?.ifMatch===void 0?{}:{ifMatch:r.ifMatch}})}var ge="gem_";function pe(n,e){let t=e?.retryAfterSeconds,r=typeof t=="number"&&Number.isFinite(t)&&t>0?t*1e3:0,o=1e4*2**Math.min(Math.max(0,n-1),16);return Math.min(Math.max(r,o),3e5)}var At=1e4,Ot=50,Pt=1e3,Gt=65536-4*1024,ye=n=>typeof n=="number"?n:0,Tt=n=>typeof n=="string"?n:"";function fe(){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 Ct(n){return n?.retryable===true}function It(n,e){let t=n??{},r=Array.isArray(t.rejected)?t.rejected.map(o=>{let a=o??{};return {index:ye(a.index),code:Tt(a.code)}}):[];return {accepted:ye(t.accepted),rejected:r,dropped:e,duplicate:t.duplicate===true}}function he(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 _e(n){let e=Math.max(1,Math.floor(n.maxQueue??Pt)),t={client:n.client,gameId:()=>n.gameId},r=[],o=0,a=null,i=false,l=null,u=0,c=0,g=false,S=false,w=_=>{n.log?.(_);},R=()=>{a!==null&&(n.clock.clearTimeout(a),a=null);},y=()=>Math.max(0,c-n.clock.now()),x=()=>{a!==null||i||l!==null||(a=n.clock.setTimeout(()=>{a=null,P().catch(()=>{});},Math.max(At,y())));},A=()=>{let _=Math.min(r.length,100),b=128;for(let G=0;G<_;G+=1){let T=r[G];if(T===void 0)break;if(b+=JSON.stringify(he(T,0)).length+1,b>Gt)return Math.max(1,G)}return _};async function P(_){for(;l!==null;)await l.catch(()=>{});if(r.length===0)return {accepted:0,rejected:[],dropped:0,duplicate:false};let b=Ie(_);l=b;try{return await b}finally{l===b&&(l=null),r.length>0&&x();}}async function Ie(_){R();let b=r.splice(0,A()),G=o;o=0;let T=Math.round(n.clock.now()),F={batch_id:fe(),sent_at_ms:T,events:b.map(k=>he(k,T))};try{let k=await Y(t,F,_===void 0?void 0:{signal:_}),C=It(k,G);u=0,c=0;for(let Ee of C.rejected)w(`[gem] analytics: an event was refused (${Ee.code}). See the analytics_events section of your game config.`);return C}catch(k){if(Ct(k)){for(r=[...b,...r],o+=G;r.length>e;)r.shift(),o+=1;u+=1,c=n.clock.now()+pe(u,k);}else w(`[gem] analytics: ${b.length} event(s) were discarded \u2014 the platform refused the batch and will refuse it again: ${String(k)}`);throw k}}return {track(_,b,G={}){if(i)return;if(typeof _!="string"||_===""){S||(S=true,w(`[gem] analytics: '${b}' 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(b.startsWith(ge)){g||(g=true,w(`[gem] analytics: '${b}' 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 T={},F={};for(let[k,C]of Object.entries(G))typeof C=="string"?T[k]=C:typeof C=="number"&&Number.isFinite(C)&&(F[k]=C);for(;r.length>=e;)r.shift(),o+=1;r.push({uid:fe(),playerId:_,name:b,atMs:n.clock.now(),dimensions:T,measures:F}),r.length>=Ot&&l===null&&y()===0?P().catch(()=>{}):x();},flush:_=>P(_),get pending(){return r.length},dispose(){i=true,R(),r=[],o=0;}}}var Et=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]]),j=class extends p{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:Et.get(this.code))??super.retryable}},M=class{#e;constructor(e){this.#e=e;}async invoke(e,t={}){let r=Lt(e),o;try{o=await this.#e(r,t.signal===void 0?{}:{signal:t.signal});}catch(a){throw a instanceof p?Mt(a):a}return qt(o)}};function Lt(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 f(`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 f(`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 qt(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 Mt(n){let{details:e,invocationId:t}=oe(n),o=e?.untrusted?.message,a=e?.reason;return new j(n,{...t===void 0?{}:{invocationId:t},...n.code==="function_error"&&typeof o=="string"?{functionMessage:o}:{},...n.code==="function_failed"&&typeof a=="string"?{failure:a}:{}})}var O=n=>typeof n=="string"?n:"",$t=/(?:Z|[+-]\d{2}:?\d{2})$/i;function be(n){let e=O(n);if(!$t.test(e))return 0;let t=Date.parse(e);return Number.isFinite(t)?Math.floor(t/1e3):0}var jt=/^[0-9a-f]{1,64}$/,Bt=/^[0-9a-f]{16}$/,Ft=/^[A-Za-z][A-Za-z0-9_+\-/]{0,63}$/,Ut=/^(?:[01]\d|2[0-3]):[0-5]\d$/;function Dt(n){let e=O(n),t=/^(\d{4})-(\d{2})-(\d{2})$/.exec(e);if(!t)return;let[r,o,a]=[Number(t[1]),Number(t[2]),Number(t[3])],i=new Date(Date.UTC(r,o-1,a));return i.getUTCFullYear()===r&&i.getUTCMonth()===o-1&&i.getUTCDate()===a?e:void 0}var Nt=4096,Ht=new TextEncoder;function Vt(n){let e=O(n.challenge_data),t=O(n.challenge_data_hash);return e===""||!Bt.test(t)?{}:Ht.encode(e).length>Nt?{}:{data:e,dataHash:t}}function Wt(n){let e=n??{},t=be(e.period_start_at),r=be(e.period_ends_at);if(t===0||r===0)return;let o=O(e.slug),a=O(e.seed),i=Dt(e.period_local_date),l=O(e.boundary),u=O(e.reset_time);return {id:O(e.progression_definition_id),...o===""?{}:{slug:o},window:O(e.window),periodStartAt:t,periodEndsAt:r,...i===void 0?{}:{periodLocalDate:i},boundary:Ft.test(l)?l:"",resetTime:Ut.test(u)?u:"",seed:jt.test(a)?a:"",...Vt(e)}}function Re(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 ve(n){let e=n??{};return Array.isArray(e.challenges)?e.challenges.map(Wt).filter(t=>t!==void 0):[]}function Se(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().");Re(r);let a=await n({player_id:t,...r===void 0?{}:{periods_back:r},...o===void 0?{}:{signal:o}});return ve(a)}}}function zt(n){let e={};for(let[t,r]of Object.entries(J))if(typeof r=="function"){let o=r;e[t]=(...a)=>o(n,...a);}return e}function V(n,e={}){let t=e.clock??q,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=K(n,{clock:t,...e.onAuthStateChange===void 0?{}:{onStateChange:e.onAuthStateChange}}),a=ae({baseUrl:r,tokenSource:o.source,defaultQuery:{game_id:n.gameId,channel:n.channel},...e.fetch===void 0?{}:{fetch:e.fetch}}),i=new L({transport:a,clock:t}),l={gameId:n.gameId,channel:n.channel,matchId:n.matchId,...n.gameRoomId===void 0?{}:{gameRoomId:n.gameRoomId}},u=zt({client:i,gameId:()=>l.gameId}),c=l.gameRoomId,g=n.endMatch,S=n.log,w=_e({client:i,clock:t,gameId:l.gameId,...typeof S=="function"?{log:y=>S.call(n,y)}:{}});return {identity:l,client:i,api:u,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);},setBackfill:async(y,x)=>{let A=await u.setMatchBackfill(l.matchId,{open:y.open,...y.seats===void 0?{}:{seats:y.seats}},x===void 0?{}:{signal:x});return {open:A.open,seats:A.seats??null}},reportPlayers:async(y,x)=>(await u.reportMatchPlayers(l.matchId,{players:y.map(P=>({player_id:P.playerId,state:P.state}))},x===void 0?{}:{signal:x})).players.map(P=>({playerId:P.player_id,outcome:P.outcome}))},analytics:w,functions:new M(u.invokeFunction),challenges:Se(u.listChallenges),...c===void 0?{}:{room:{get:y=>u.getGameRoomV2(c,y),args:async y=>{let x=await u.getGameRoomV2(c,y?.signal===void 0?{}:{signal:y.signal}),A=x.modified?x.body:void 0;if(A?.room_args==null||A.room_args_template==null)throw new p("not_found",404,"this room's template declares no room args",void 0,"room_args_not_defined");return {room_args:A.room_args,room_args_template:A.room_args_template}}}},dispose:()=>{w.dispose(),o.dispose();}}}var Kt=["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"],Yt=new Set(Kt);function xe(n){return typeof n=="string"&&Yt.has(n)?n:"unknown"}var Ae="[gem: use gem.text.toPlain()]",we=new Set,ke;function Jt(n){try{if(we.has(n))return;let e=globalThis.location;if(ke??=!!e?.port&&ce(e.hostname??""),!ke)return;we.add(n),console.warn(`[gem] ${n} is PlayerText, turned into a string: players see ${Ae}. Render text.toPlain(value) (text is in @indiegems/gem-web-sdk/sdk).
1
+ var Le=Object.defineProperty;var qe=(n,e)=>{for(var t in e)Le(n,t,{get:e[t],enumerable:true});};globalThis.__gemWebSdkVersion="[gem-web-sdk:sdkVersion:16.3.1]";var Me={initialDelayMs:2e3,maxDelayMs:6e4};function $e(n,e){return e!==void 0?!e:n==="chain_exhausted"}var U=class{constructor(e){this.options=e;}options;grant=null;state="pending";failure=null;generation=0;inFlight=null;rejected=false;retry=null;failures=0;notBefore=0;disposed=false;get currentState(){return this.state}get lastFailure(){return this.failure}async get(){if(this.state==="lost")throw new h(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.pastChainCeiling())throw new h("chain_exhausted","the token chain reached its ceiling");if(this.inFlight===null&&this.options.clock.now()<this.notBefore)throw new h(this.failure??"unavailable","the embedder asked for no new token yet; one is asked for when that wait is over");return this.refresh(this.nextReason())}pastChainCeiling(){return this.grant===null||this.seconds()<this.grant.chainEndsAt?false:(this.enter("lost","chain_exhausted"),true)}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);}dispose(){this.disposed=true,this.cancelRetry();}scheduleRetry(e){if(this.cancelRetry(),this.failures+=1,this.notBefore=e===void 0?0:this.options.clock.now()+e,this.disposed)return;let{initialDelayMs:t,maxDelayMs:r}=Me,o=Math.min(r,t*2**(this.failures-1)),a=Math.max(o/2,e??0)+Math.random()*(o/2);this.retry={handle:this.options.clock.setTimeout(()=>this.retryNow(),a)};}retryNow(){this.retry=null,this.notBefore=0,!(this.state==="lost"||this.pastChainCeiling())&&this.refresh(this.nextReason()).catch(()=>{});}cancelRetry(){this.retry!==null&&(this.options.clock.clearTimeout(this.retry.handle),this.retry=null);}refresh(e){if(this.inFlight)return this.inFlight;this.cancelRetry();let t=this.generation;this.enter("pending");let r=this.options.request(e).then(o=>{if(t!==this.generation)throw new h("internal","token arrived for a superseded generation");return this.grant=o,this.rejected=false,this.enter("ready"),o.token}).catch(o=>{let a=je(o),{retryable:i,retryAfterMs:l}=o??{};throw t===this.generation&&($e(a,typeof i=="boolean"?i:void 0)?this.enter("lost",a):(this.scheduleRetry(typeof l=="number"&&Number.isFinite(l)&&l>0?l:void 0),this.enter("degraded",a))),o instanceof h?o:new h(a,String(o))}).finally(()=>{this.inFlight===r&&(this.inFlight=null);});return this.inFlight=r,r}enter(e,t){(e==="ready"||e==="lost")&&this.cancelRetry(),e==="ready"&&(this.failures=0,this.notBefore=0),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)}},h=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 je(n){if(n instanceof h)return n.reason;let e=n?.reason;return typeof e=="string"&&["chain_exhausted","unavailable","timeout","internal"].includes(e)?e:"internal"}var f=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}},D=["if-match","if-none-match"],Q=4096;function Be(n){if(!n)return;let e={};for(let[t,r]of Object.entries(n)){let o=t.toLowerCase();if(!D.includes(o)||r===void 0)continue;let a=typeof r=="string"?Fe(r):r;if(typeof a!="string"||a.length>Q||!Ue(a))throw new f(`the ${o} header value cannot be sent \u2014 it is not a string, is longer than ${Q} 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.`);a!==""&&(e[o]=a);}return Object.freeze(e)}function Fe(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 Ue(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 De(n){let{bytes:e}=n;if(e!==void 0){if(Object.prototype.toString.call(e)!=="[object Uint8Array]")throw new f("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 f("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},a=Be(o.headers),i=De(o),l=Object.freeze({...o,headers:a,...i===void 0?{}:{bytes:i}}),u=await e.tokenSource.get(),c=await n(l,u);if(c.status!==401||!t)return c;e.tokenSource.invalidate(u);let g=await e.tokenSource.get(),S=await n(l,g);if(S.status===401)throw e.tokenSource.close("unavailable"),new h("unavailable","the server refused a freshly minted token");return S}}}function ee(n){let e=typeof n=="string"?new TextEncoder().encode(n):n;return btoa(Ne(e))}function Ne(n){let t="";for(let r=0;r<n.length;r+=32768)t+=String.fromCharCode(...n.subarray(r,r+32768));return t}var p=class extends Error{constructor(t,r,o,a,i){super(`${t} (${r}): ${o}`);this.reason=t;this.status=r;this.detail=o;this.retryAfterSeconds=a;this.code=i;this.name="GemApiError";}reason;status;detail;retryAfterSeconds;code;get retryable(){return this.reason==="unavailable"||this.reason==="rate_limited"}},re=new WeakMap;function oe(n){return re.get(n)??{}}var He=new Set([408,429,500,502,503,504]),Ve=6e4,We=new WeakMap;function ne(n){return n!==null&&(n.reason==="rate_limited"||n.retryAfterSeconds!==void 0)}function ze(n){if(n===void 0)return 2;if(!Number.isInteger(n)||n<0||n>10)throw new f(`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 L=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,...$(o)},o.replaySafe===true,o.retryRateLimited!==false)}async post(e,t,r,o={}){return this.send({method:"POST",path:e,body:t,signal:r,...$(o)},o.replaySafe===true,o.retryRateLimited!==false)}async postBytes(e,t,r,o={}){let a=await this.sendRaw({method:"POST",path:e,bytes:t,responseType:"bytes",signal:r,...$(o)},o.replaySafe===true,o.retryRateLimited!==false);return {bytes:Ke(a.body),...a.invocationId===void 0?{}:{invocationId:a.invocationId}}}async patch(e,t,r,o={}){return this.send({method:"PATCH",path:e,body:t,signal:r,...$(o)},o.replaySafe===true,o.retryRateLimited!==false)}async delete(e,t,r={}){return this.send({method:"DELETE",path:e,signal:t,...$(r)},r.replaySafe===true,r.retryRateLimited!==false)}async send(e,t,r=true){return (await this.sendRaw(e,t,r)).body}async sendRaw(e,t,r=true){let o=t?ze(this.options.maxRetries)+1:1,a=null;if(e.signal?.aborted)throw te(e.signal);let i=e.signal===void 0?void 0:We.get(e.signal);for(let l=0;l<o;l++){if(l>0){let g=this.backoffMs(l,a);if(ne(a)&&i!==void 0&&g>=i())throw a;await this.backoff(g,e.signal);}if(e.signal?.aborted)throw ne(a)&&i!==void 0&&i()<=0?a:te(e.signal);let u;try{u=await this.options.transport.request(e);}catch(g){if(h.isAuthError(g)||f.isRefusal(g)||e.signal?.aborted||Ye(g))throw g;a=new p("unavailable",0,String(g));continue}if(u.status>=200&&u.status<300||u.status===304)return u;let c=Je(u);if(!He.has(u.status)||u.status===429&&!r)throw c;a=c;}throw a??new p("unavailable",0,"no attempt was made")}backoffMs(e,t){let r=t?.retryAfterSeconds,o=r!==void 0?r*1e3:2**(e-1)*250,a=2**(e-1)*250;return Math.min(Math.max(o,a),Ve)}backoff(e,t){return t?.aborted?Promise.resolve():new Promise(r=>{let o=this.options.clock,a=false,i=false,l,u=()=>{a||(a=true,i&&o.clearTimeout(l),t?.removeEventListener("abort",u),r());};t?.addEventListener("abort",u,{once:true}),l=o.setTimeout(u,e),i=true,a&&o.clearTimeout(l);})}};function Ke(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 $(n){return {...n.keepalive===void 0?{}:{keepalive:n.keepalive},...n.ifMatch===void 0?{}:{headers:{"if-match":n.ifMatch}}}}function te(n){return n.reason!==void 0?n.reason:new DOMException("The operation was aborted.","AbortError")}function Ye(n){let e=n?.name;return e==="AbortError"||e==="TimeoutError"}function Je(n){let e=Qe(n),t=en(n.body),r={...t===void 0?{}:{details:t},...n.invocationId===void 0?{}:{invocationId:n.invocationId}};return Object.keys(r).length>0&&re.set(e,r),e}var Xe=new Map([["insufficient_funds","insufficient_funds"]]);function Qe(n){let{status:e,body:t}=n,r=Ze(t),o=n.retryAfterSeconds??tn(t),a=nn(t),i=a===void 0?void 0:Xe.get(a);if(i!==void 0)return new p(i,e,r,void 0,a);switch(e){case 304:return new p("not_modified",e,r);case 400:case 422:return new p("invalid",e,r,void 0,a);case 403:return new p("forbidden",e,r,void 0,a);case 404:return new p("not_found",e,r,void 0,a);case 402:return new p("insufficient_funds",e,r,void 0,a);case 409:return new p("conflict",e,r,void 0,a);case 412:return new p("precondition_failed",e,r,void 0,a);case 413:return new p("too_large",e,r,void 0,a);case 429:return new p("rate_limited",e,r,o,a);default:return new p("unavailable",e,r,o,a)}}function Ze(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 en(n){let t=n?.error?.details;return t===null?void 0:t}function nn(n){let t=n?.error?.code;return typeof t=="string"&&t.length>0?t:void 0}function tn(n){let e=n?.retryAfterSeconds;return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:void 0}function rn(n){let e=n.lastIndexOf("@");return (e===-1?n:`***@${n.slice(e+1)}`).slice(0,200)}var on=new Set(D);function an(n){if(!n)return {};let e={};for(let[t,r]of Object.entries(n))on.has(t.toLowerCase())&&(e[t.toLowerCase()]=r);return e}function ae(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 f("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 a;try{a=new URL(o.href.replace(/\/+$/,"")+t.path);}catch{throw new f(`${JSON.stringify(typeof t.path=="string"?rn(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(a.protocol!==o.protocol||a.host!==o.host)throw new f(`${JSON.stringify(a.pathname)} resolves to ${a.protocol}//${a.host}, not ${o.protocol}//${o.host}. A request path may not change the request's origin \u2014 it carries the play token.`);if(a.username!==""||a.password!==""){let R=o.username!==""||o.password!=="",y=a.username!==o.username||a.password!==o.password,x=R?y?"baseUrl (and possibly the request path)":"baseUrl":"request path";throw new f(`the ${x} puts credentials in the URL, which cannot be fetched (${t.method} ${a.pathname}). The value is withheld here rather than written to logs. This is a malformed request, not a server failure.`)}for(let[R,y]of Object.entries(n.defaultQuery??{}))a.searchParams.has(R)||a.searchParams.set(R,y);let i=t.bytes,l=t.bytes===void 0?void 0:"application/octet-stream";try{t.body!==void 0&&(i=JSON.stringify(t.body),l="application/json");}catch(R){throw new f(`the body of ${t.method} ${JSON.stringify(a.pathname)} could not be serialised to JSON: ${String(R)}. This is a bug in the request, not a server failure \u2014 retrying sends the same unserialisable value.`)}let u=await e(a.toString(),{method:t.method,headers:{authorization:`Bearer ${r}`,...l===void 0?{}:{"content-type":l},...an(t.headers)},body:i,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"&&u.status>=200&&u.status<300)c=new Uint8Array(await u.arrayBuffer());else {let R=await u.text();if(R.length>0)try{c=JSON.parse(R);}catch{c=R;}}let g=u.headers.get("etag"),S=sn(u.headers.get("retry-after")),w=u.headers.get("x-gem-invocation-id");return {status:u.status,body:c,...g===null?{}:{etag:g},...S===void 0?{}:{retryAfterSeconds:S},...w===null||w===""?{}:{invocationId:w}}},n)}function sn(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 ln="gem-web-bridge";var dn=65536,se=8,N=5e3,ie=1024;var H=Object.create(null);var le=Object.create(null);function un(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 cn(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 mn(n){return /^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i.test(n)}function gn(n){return /^[a-z_]+$/.test(n)}function pn(n){return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(n)||/^[a-z0-9][a-z0-9-]{1,38}[a-z0-9]$/.test(n)&&!n.includes("--")}function W(n,e,t){if(e>se)return `nesting deeper than ${se}`;if(++t.nodes>N)return `more than ${N} values`;if(t.bytes>t.cap)return `over the ${t.cap} 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>ie)return `an array of ${n.length} entries, over the ${ie} limit`;t.bytes+=2;for(let l of n){let u=W(l,e+1,t);if(u)return u}return null}let a=Object.getPrototypeOf(n);if(a!==Object.prototype&&a!==null)return "a value that is not a plain object";t.bytes+=2;let i=n;for(let l in i){if(!Object.prototype.hasOwnProperty.call(i,l))continue;if(++t.nodes>N)return `more than ${N} values`;if(t.bytes+=l.length*3+4,t.bytes>t.cap)return `over the ${t.cap} byte limit`;let u=W(i[l],e+1,t);if(u)return u}return null}function yn(n,e=dn){let t={nodes:0,bytes:0,seen:new Set,cap:e},r=W(n,0,t);return r?`message contains ${r}`:t.bytes>e?`message is over the ${e} byte limit`:null}var fn={origin:[un,"not a well-formed origin"],url:[cn,"not a safe absolute http(s) URL"],bcp47:[mn,"not a well-formed BCP 47 tag"],code:[gn,"not a code of lower-case letters and underscores"],gameRef:[pn,"not a game id or web address"]};function de(n,e,t){for(let r of e){let o=t===""?r[0]:`${t}.${r[0]}`,a=n[r[0]];if(a==null){if(r[1]<"a")continue;return `${o}: required`}let i=z(a,r,o);if(i)return i}return null}function z(n,e,t){let r=e[1].toLowerCase();switch(r){case "u":return typeof n=="boolean"?null:z(n,typeof n=="string"?[e[0],"s",e[2]]:[e[0],"n",e[3],e[4]],t);case "s":{if(typeof n!="string")return `${t}: expected string`;if(n.length>e[2])return `${t}: exceeds ${e[2]} characters`;if(e[3]){let[o,a]=fn[e[3]];if(!o(n))return `${t}: ${a}`}return null}case "n":case "i":return typeof n!="number"||!(r=="i"?Number.isInteger:Number.isFinite)(n)?`${t}: expected ${r=="i"?"integer":"number"}`:n<e[2]||n>e[3]?`${t}: out of range ${e[2]}..${e[3]}`:null;case "b":return typeof n=="boolean"?null:`${t}: expected boolean`;case "e":{let o=e[2];return o.includes(n)?null:`${t}: not one of ${o.join("|")}`}case "o":return typeof n!="object"||n===null||Array.isArray(n)?`${t}: expected object`:de(n,e[2],t);case "j":return typeof n!="object"||n===null||Array.isArray(n)?`${t}: expected a plain object`:null;case "a":{if(!Array.isArray(n))return `${t}: expected array`;if(n.length>e[2])return `${t}: exceeds ${e[2]} items`;let o=e[3],a=`${t}[]`;for(let i of n){if(i==null){if(o[1]<"a")continue;return `${a}: required`}let l=z(i,o,a);if(l)return l}return null}default:return `${t}: unknown kind ${String(r)}`}}var ue=Object.create(null);function d(n,e,t,r,o){return H[n]=t,r&&(le[n]=r),ue[n]=a=>{let i=yn(a,o);if(i)return i;if(typeof a!="object"||a===null||Array.isArray(a))return "message: expected object";let l=a;return l.gem!==ln?"gem: wrong protocol marker":l.type!==n?`type: expected ${n}`:de(l,e,"")}}var m=["requestId","s",64],I=["outcome","e",["ok","declined","unavailable"]],E=["reason","S",64,"code"];d("gem.handshake",[["versions","o",[["min","i",1,1e3],["max","i",1,1e3]]],["capabilities","A",64,["","s",64]],["embedder","s",2048,"origin"],["unbidden","B"]],30);d("gem.handshake.accept",[["v","i",1,1e3],["capabilities","A",64,["","s",64]]],5);d("gem.token",[["token","s",4096],["requestId","S",64],["generation","i",0,2147483647],["apiBaseUrl","S",512,"url"],["playerId","s",64],["gameId","s",64],["channel","e",["dev","test","release"]],["gameVersion","S",64],["expiresAt","i",0,4102444800],["chainEndsAt","i",0,4102444800],["allowDevTools","B"]],30);d("gem.token.denied",[m,["retryable","b"],["retryAfterMs","I",0,36e5],["reason","e",["chain_exhausted","unavailable"]],["correlationId","s",64]],30);d("gem.player",[["untrusted","o",[["displayName","s",64],["displayTag","S",80],["displayHandle","s",80]]],["playerId","S",64],["discriminator","S",8],["avatarIconUrl","S",2048,"url"],["avatarIconId","S",64],["avatar3dId","S",64],["avatar3dModelUrl","S",2048,"url"],["avatar3dIconUrl","S",2048,"url"],["avatars3d","A",8,["","o",[["family","s",32],["id","s",64],["modelUrl","s",256,"url"],["iconUrl","s",256,"url"]]]],["badges","A",2,["","o",[["itemId","s",64],["iconUrl","s",2048,"url"]]]],["displayTag","s",8],["avatarUrl","S",2048,"url"],["boost","O",[["multipliers","a",8,["","o",[["currencyId","s",64],["currencySlug","s",32],["multiplierBp","i",1e4,1e6]]]],["expiresInDays","I",1,7]]]],12);d("gem.pause",[["paused","b"]],120);d("gem.prefs",[["reducedMotion","b"],["muted","b"],["showFrameStats","B"],["music","B"],["sounds","B"],["locale","s",35,"bcp47"],["recommended","O",[["volume","i",0,100],["batterySaver","b"],["keyboardLayout","e",["wasd","arrows"]],["gamepadConfirm","e",["south","east"]],["vibration","b"],["lookSensitivity","I",20,400],["gamepadLookSensitivity","I",20,400],["invertLookY","B"],["touchMovement","S",16,"code"],["graphicsQuality","S",16,"code"],["graphicsQualityAuto","B"],["colorHelp","B"]]]],60);d("gem.cohorts",[["cohorts","a",8,["","o",[["experimentId","s",36],["variantKey","s",32]]]]],12,"cohorts");d("gem.earnAllowanceChanged",[],30,"earnAllowance");d("gem.viewport",[["insets","o",[["top","i",0,4096],["right","i",0,4096],["bottom","i",0,4096],["left","i",0,4096]]],["reserved","A",4,["","o",[["x","i",0,16384],["y","i",0,16384],["width","i",0,16384],["height","i",0,16384],["control","O",[["x","i",0,16384],["y","i",0,16384],["width","i",0,16384],["height","i",0,16384]]]]]]],60,"viewport");d("gem.deviceSettings",[["settings","J"]],12,"deviceSettings");d("gem.willTerminate",[["reason","e",["grant_expiring","session_ended","navigating","kill_switch"]],["graceMs","i",0,6e4]],10);d("gem.roomEvent",[["event","e",["updated","match_started","match_ready","match_failed","version_stale"]],["roomId","s",64],["matchId","S",64],["version","I",0,2147483647],["reason","S",64],["platform","E",["universal","mobile"]]],120,"rooms");d("gem.socketState",[["connected","b"],["reason","E",["connecting","dropped","watchdog","terminal"]]],12,"socketState");d("gem.seatedEvent",[["roomId","s",64]],60,"partySeating");d("gem.autoStartFailedEvent",[["roomId","s",64],["code","s",64]],30,"autoStartFailure");d("gem.ticketEvent",[["event","e",["queued","matched","expired","cancelled","failed"]],["ticketId","s",64],["partySize","I",1,64],["queuedAt","I",0,4102444800],["expiresAt","I",0,4102444800],["reason","S",64],["roomId","S",64]],60,"ticketEvents");d("gem.signalEvent",[["event","e",["hello","offer","answer","ice","peerJoined","peerLeft","migration","matchEnded","error"]],["matchId","s",64],["data","j"]],1800,"p2p");d("gem.dedicatedEvent",[["event","e",["answer","error","matchEnded"]],["matchId","s",64],["sdp","S",10240],["sessionId","S",64],["code","S",64],["message","S",256],["reason","S",64]],120,"dedicated");d("gem.partyResult",[m,["partyId","S",64]],30,"parties");d("gem.clusterTarget",[["clusterTargetId","s",64],["clusterTargetIds","A",3,["","s",64]]],12,"clusterTarget");d("gem.devtools",[["action","e",["open","close","toggle"]]],30,"devtools");d("gem.screenshot",[["maxWidth","i",1,7680],["maxHeight","i",1,4320]],6,"screenshot");d("gem.screenshot.denied",[["reason","e",["not_wired","no_source","unsupported","unreadable","tainted","too_large","busy","declined","failed"]],["retryable","b"]],12,"screenshot");d("gem.requestContext",[],12,"feedbackContext");d("gem.gameContext",[["context","j"]],12,"feedbackContext");d("gem.signal",[["signal","e",["join","offer","answer","ice","migrationAck","hostUnreachable"]],["matchId","s",64],["data","j"]],1200,"p2p");d("gem.dedicatedOffer",[["matchId","s",64],["sdp","s",10240],["intent","e",["initial","ice_restart","full_reconnect"]]],60,"dedicated");d("gem.partyRequest",[m],12,"parties");d("gem.ready",[],5);d("gem.engaged",[],5,"engagement");d("gem.progress",[["loaded","i",0,1099511627776],["total","i",0,1099511627776]],600);d("gem.requestToken",[m,["reason","e",["initial","expiring","rejected"]]],12);d("gem.requestLocalServer",[m,["gameRoomId","s",64]],6,"localHost");d("gem.localServer",[m,["serverId","S",128]],30,"localHost");d("gem.localServer.denied",[m,["retryable","b"],["reason","e",["refused","unavailable"]]],30,"localHost");d("gem.exit",[["reason","S",64]],5);d("gem.openExternal",[["url","s",2048,"url"]],6);d("gem.requestFullscreen",[["enabled","b"]],30);d("gem.audioState",[["muted","b"]],120,"audioState");d("gem.rewardCue",[["currencySlug","s",32],["expected","I",1,1e9],["origin","O",[["x","i",0,16384],["y","i",0,16384]]]],60,"rewardCue");d("gem.walletDisplay",[["visible","b"],["currencies","A",8,["","s",64]],["score","B"]],60,"walletDisplay");d("gem.controlsDeclare",[["uses","o",[["lookSensitivity","S",16,"code"],["gamepadLookSensitivity","S",16,"code"],["invertLookY","S",16,"code"],["touchMovement","S",16,"code"]]]],60,"controls");d("gem.menu",[["settings","b"],["items","A",4,["","o",[["id","s",32],["label","s",40]]]]],60,"gameMenu");d("gem.menuSelect",[["entry","e",["settings","item"]],["id","S",32]],60,"gameMenu");d("gem.gemCorner",[["corner","e",["top-left","top-right","bottom-left","bottom-right"]]],12,"gemCorner");d("gem.settingsDeclare",[["settings","a",8,["","o",[["id","s",40],["label","s",40],["kind","e",["toggle","slider","choice"]],["value","u",40,-1e6,1e6],["quick","B"],["icon","S",16,"code"],["min","N",-1e6,1e6],["max","N",-1e6,1e6],["step","N",0,1e6],["options","A",4,["","o",[["id","s",40],["label","s",40]]]]]]]],120,"gameSettings");d("gem.settingChange",[["id","s",40],["value","u",40,-1e6,1e6]],120,"gameSettings");d("gem.requestShare",[["params","a",16,["","o",[["key","s",64],["value","s",512]]]]],6,"share");d("gem.requestAvatarPicker",[["tab","E",["2d","3d"]]],6,"avatarPicker");d("gem.vibrate",[["pattern","a",99,["","i",0,1e4]]],600,"vibration");d("gem.frameStats",[["fps","i",0,1e3],["frameTimeP95Ms","i",0,1e5],["counts","E",["pageFrames","gameDraws"]]],120,"frameStats");d("gem.portraitBorders",[["name","S",40]],60,"portraitBorders");d("gem.error",[["code","e",["version_mismatch","handshake_timeout","handshake_duplicate","invalid_message","rate_limited","token_unavailable","unsupported","unsupported_capability","internal"]],["message","S",256]],60);d("gem.requestPurchase",[m,["purchaseKind","e",["item","recipe"]],["targetId","s",64],["currencySlug","s",32],["quantity","I",1,10],["catalogId","S",64]],12,"purchases");d("gem.requestAvatar3dPurchase",[m,["itemId","s",64],["currencySlug","s",32]],12,"avatar3dPurchases");d("gem.purchaseResult",[m,I,E,["purchaseId","S",64]],30,"purchases");d("gem.deviceSettings.put",[m,["settings","j"]],30,"deviceSettings");d("gem.deviceSettings.result",[m,["outcome","e",["stored","too_large","unavailable"]]],30,"deviceSettings");d("gem.requestAd",[m,["placement","s",32],["format","e",["interstitial","rewarded"]]],6,"ads");d("gem.adResult",[m,["outcome","e",["shown","no_ad","unavailable"]]],12,"ads");d("gem.signalMoment",[m,["kind","e",["level_end","run_end","match_end","menu_return","other_break"]],["placement","S",32],["wall","B"]],6,"moments");d("gem.momentResult",[m,["shown","b"]],12,"moments");d("gem.requestSignIn",[m],6,"signIn");d("gem.signInResult",[m,["outcome","e",["signed_in","declined","unavailable"]]],12,"signIn");d("gem.requestFriendChallenge",[m,["playerId","s",64],["template","s",64],["params","J"]],12,"friendChallenges");d("gem.friendChallengeResult",[m,["outcome","e",["accepted","cancelled","refused","unavailable","rate_limited","invalid"]],["code","S",64],["param","S",64],["channel","S",16],["configVersion","I",0,9007199254740991],["retryAfterMs","I",0,864e5],["detail","S",300]],30,"friendChallenges");d("gem.requestAppLinks",[m],12,"appLinks");d("gem.appLinksResult",[m,I,E,["arcade","O",[["store","e",["app_store","google_play"]]]],["game","O",[["store","e",["app_store","google_play"]]]]],30,"appLinks");d("gem.requestOpenApp",[m,["target","e",["arcade","game"]]],6,"appLinks");d("gem.openAppResult",[m,I,E],30,"appLinks");d("gem.requestOpenGame",[m,["ref","s",40,"gameRef"]],6,"openGame");d("gem.openGameResult",[m,I,E],30,"openGame");d("gem.requestSimilarGames",[m,["limit","I",1,24]],12,"openGame");d("gem.similarGamesResult",[m,I,E,["games","a",24,["","o",[["gameId","s",36,"gameRef"],["slug","S",40,"gameRef"],["iconUrl","s",1024,"url"],["capsuleLandscapeUrl","s",1024,"url"],["capsulePortraitUrl","s",1024,"url"],["previewVideoUrl","S",1024,"url"],["previewPosterUrl","S",1024,"url"],["untrusted","o",[["name","s",64],["tagline","s",64],["shortDescription","s",320],["tags","a",10,["","s",32]]]]]]]],30,"openGame",524288);d("gem.requestStoreOffers",[m],12,"store");d("gem.storeOffersResult",[m,I,E,["offers","a",32,["","o",[["skuId","s",64],["kind","e",["gem_pack","boost","pass","bundle"]],["name","s",80],["description","s",400],["imageUrl","S",1024,"url"],["priceDisplay","s",32],["grant","O",[["currency","s",32],["amount","i",1,1e9]]]]]]],30,"store",262144);d("gem.requestStorePurchase",[m,["skuId","s",64]],12,"store");d("gem.storePurchaseResult",[m,I,E],30,"store");d("gem.storePurchaseSettled",[["skuId","s",64]],30,"store");Object.freeze(ue);H.__malformed=60;Object.freeze(H);Object.freeze(le);var q={now:()=>Date.now(),setTimeout:(n,e)=>setTimeout(n,e),clearTimeout:n=>clearTimeout(n)};function ce(n){let e=n.toLowerCase();return e==="localhost"||e.endsWith(".localhost")||e==="[::1]"||e==="::1"?true:/^127(\.\d{1,3}){3}$/.test(e)}var hn=1e4;function me(n,e){return K(n,e)}function K(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=i=>({token:i.token,expiresAt:i.expiresAt,chainEndsAt:Number.POSITIVE_INFINITY}),r=null,o=new U({clock:e.clock,...e.onStateChange===void 0?{}:{onStateChange:e.onStateChange},request:()=>new Promise((i,l)=>{let u=e.clock.setTimeout(()=>{r=null,l({reason:"unavailable",retryable:true});},e.timeoutMs??hn);r={resolve:c=>{e.clock.clearTimeout(u),i(c);},reject:l,timer:u};})}),a=n.onServerToken(i=>{let l=t(i),u=r;if(u){r=null,u.resolve(l);return}o.accept(l);});return {source:o,dispose(){a(),o.dispose(),r&&(e.clock.clearTimeout(r.timer),r.reject({reason:"unavailable",retryable:false}),r=null);}}}var J={};qe(J,{acceptTransfer:()=>_n,addEntityProgression:()=>bn,adminAction:()=>Rn,cancelInventoryTransfer:()=>vn,claimEntityProgressionRewards:()=>Sn,closeGameRoom:()=>xn,createEntityBatchOrder:()=>wn,createEntityOrder:()=>kn,createSession:()=>An,deleteEntityGameSetting:()=>On,deleteEntitySave:()=>Pn,deleteSession:()=>Gn,deleteShowcaseValue:()=>Tn,executeEntityRecipe:()=>Cn,finalizeSaveUpload:()=>In,getChannelAssignment:()=>En,getDropRates:()=>Ln,getEntityCurrency:()=>qn,getEntityGameSetting:()=>Mn,getEntityInventory:()=>$n,getEntityInventoryItem:()=>jn,getEntityLeaderboard:()=>Bn,getEntityOrder:()=>Fn,getEntityProgression:()=>Un,getEntityRecipeAvailability:()=>Dn,getEntityRecipeUsage:()=>Nn,getEntitySave:()=>Hn,getEvent:()=>Vn,getGameRoomV2:()=>Wn,getLeaderboard:()=>zn,getPlayerGameProfile:()=>Kn,getPurchaseCatalog:()=>Yn,getResolvedTemplate:()=>Jn,getRoomArgs:()=>Xn,getShowcaseValue:()=>Qn,getTransferDetails:()=>Zn,ingestAnalyticsEvents:()=>Y,initiateInventoryTransfer:()=>et,invokeFunction:()=>nt,kickPlayer:()=>tt,listChallenges:()=>rt,listEntityGameSettings:()=>ot,listEntityOrders:()=>at,listEntityProgressions:()=>st,listEntitySaves:()=>it,listEvents:()=>lt,listGameRooms:()=>dt,listResolvedTemplates:()=>ut,listTransfers:()=>ct,maxEntityProgression:()=>mt,putEntityGameSetting:()=>gt,putRoomArgs:()=>pt,putShowcaseValue:()=>yt,rejectTransfer:()=>ft,reportMatchPlayers:()=>ht,requestSaveUploadUrl:()=>_t,resetEntityProgression:()=>bt,setMatchBackfill:()=>Rt,simulateEntityOrder:()=>vt,transferHostV2:()=>St,updateGameRoomV2:()=>xt});function s(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 _n(n,e,t){let r=`/v1/inventory/transfers/${s(e)}/accept`;return n.client.post(r,void 0,t?.signal)}async function bn(n,e,t,r,o,a){let i=`/v1/inventory/${s(e)}/${s(t)}/progressions/${s(r)}/add`;return n.client.post(i,o,a?.signal)}async function Rn(n,e,t,r){let o=`/v1/voice/sessions/${s(e)}/admin`;return n.client.post(o,t,r?.signal)}async function vn(n,e,t){let r=`/v1/inventory/transfers/${s(e)}/cancel`;return n.client.post(r,void 0,t?.signal)}async function Sn(n,e,t,r,o,a){let i=`/v1/inventory/${s(e)}/${s(t)}/progressions/${s(r)}/claim`;return n.client.post(i,o,a?.signal)}async function xn(n,e,t){let r=`/v1/games/${s(n.gameId())}/game-rooms/${s(e)}`;return n.client.delete(r,t?.signal)}async function wn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/orders/batch`;return n.client.post(a,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function kn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/orders`;return n.client.post(a,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function An(n,e,t){return n.client.post("/v1/voice/sessions",e,t?.signal)}async function On(n,e,t,r,o){let a=`/v1/settings/${s(e)}/${s(t)}/${s(r)}`;return n.client.delete(a,o?.signal)}async function Pn(n,e,t,r,o){let a=`/v1/saves/${s(e)}/${s(t)}/${s(r)}`;return n.client.delete(a,o?.signal)}async function Gn(n,e,t){let r=`/v1/voice/sessions/${s(e)}`;return n.client.delete(r,t?.signal)}async function Tn(n,e,t,r){let o=`/v1/showcase/players/${s(e)}/${s(t)}`;return n.client.delete(o,r?.signal)}async function Cn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/recipes/execute`;return n.client.post(a,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function In(n,e,t,r,o,a){let i=`/v1/saves/${s(e)}/${s(t)}/${s(r)}/finalize`;return n.client.post(i,o,a?.signal)}async function En(n,e,t){let r=`/v1/games/${s(n.gameId())}/config/channels/${s(e)}`;return n.client.getWithEtag(r,{...t?.signal===void 0?{}:{signal:t.signal},...t?.ifNoneMatch===void 0?{}:{ifNoneMatch:t.ifNoneMatch}})}async function Ln(n,e,t){let r=`/v1/inventory/loot-tables/${s(e)}/drop-rates`;return n.client.get(r,t?.signal)}async function qn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/currencies/${s(r)}`;return n.client.get(a,o?.signal)}async function Mn(n,e,t,r,o){let a=`/v1/settings/${s(e)}/${s(t)}/${s(r)}`;return n.client.getWithEtag(a,{...o?.signal===void 0?{}:{signal:o.signal},...o?.ifNoneMatch===void 0?{}:{ifNoneMatch:o.ifNoneMatch}})}async function $n(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 a=o.toString(),i=`/v1/inventory/${s(e)}/${s(t)}`+(a?`?${a}`:"");return n.client.get(i,r?.signal)}async function jn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/items/${s(r)}`;return n.client.get(a,o?.signal)}async function Bn(n,e,t,r,o){let a=new URLSearchParams;o?.bucket_1!==void 0&&a.set("bucket_1",String(o?.bucket_1)),o?.bucket_2!==void 0&&a.set("bucket_2",String(o?.bucket_2)),o?.limit!==void 0&&a.set("limit",String(o?.limit)),o?.periods_back!==void 0&&a.set("periods_back",String(o?.periods_back)),o?.period!==void 0&&a.set("period",String(o?.period)),o?.player_id!==void 0&&a.set("player_id",String(o?.player_id));let i=a.toString(),l=`/v1/leaderboards/${s(e)}/${s(t)}/${s(r)}`+(i?`?${i}`:"");return n.client.get(l,o?.signal)}async function Fn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/orders/${s(r)}`;return n.client.get(a,o?.signal)}async function Un(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/progressions/${s(r)}`;return n.client.get(a,o?.signal)}async function Dn(n,e,t,r,o,a){let i=`/v1/inventory/${s(e)}/${s(t)}/catalogs/${s(r)}/recipes/${s(o)}/availability`;return n.client.get(i,a?.signal)}async function Nn(n,e,t,r){let o=new URLSearchParams;r?.limit!==void 0&&o.set("limit",String(r?.limit));let a=o.toString(),i=`/v1/inventory/${s(e)}/${s(t)}/recipe-usage`+(a?`?${a}`:"");return n.client.get(i,r?.signal)}async function Hn(n,e,t,r,o){let a=`/v1/saves/${s(e)}/${s(t)}/${s(r)}`;return n.client.getWithEtag(a,{...o?.signal===void 0?{}:{signal:o.signal},...o?.ifNoneMatch===void 0?{}:{ifNoneMatch:o.ifNoneMatch}})}async function Vn(n,e,t){let r=`/v1/events/${s(e)}`;return n.client.get(r,t?.signal)}async function Wn(n,e,t){let r=`/v2/games/${s(n.gameId())}/game-rooms/${s(e)}`;return n.client.getWithEtag(r,{...t?.signal===void 0?{}:{signal:t.signal},...t?.ifNoneMatch===void 0?{}:{ifNoneMatch:t.ifNoneMatch}})}async function zn(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)),t?.periods_back!==void 0&&r.set("periods_back",String(t?.periods_back)),t?.period!==void 0&&r.set("period",String(t?.period)),t?.player_id!==void 0&&r.set("player_id",String(t?.player_id));let o=r.toString(),a=`/v1/leaderboards/${s(e)}`+(o?`?${o}`:"");return n.client.get(a,t?.signal)}async function Kn(n,e,t){let r=`/v1/profiles/players/${s(e)}`;return n.client.get(r,t?.signal)}async function Yn(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 Jn(n,e,t){let r=`/v1/game-room-templates/${s(e)}`;return n.client.get(r,t?.signal)}async function Xn(n,e,t){let r=`/v1/games/${s(n.gameId())}/game-rooms/${s(e)}/room-args`;return n.client.get(r,t?.signal)}async function Qn(n,e,t,r){let o=`/v1/showcase/players/${s(e)}/${s(t)}`;return n.client.get(o,r?.signal)}async function Zn(n,e,t){let r=`/v1/inventory/transfers/${s(e)}`;return n.client.get(r,t?.signal)}async function Y(n,e,t){let r=`/v1/games/${s(n.gameId())}/analytics/events`;return n.client.post(r,e,t?.signal,{replaySafe:true,retryRateLimited:false})}async function et(n,e,t){return n.client.post("/v1/inventory/transfers",e,t?.signal)}async function nt(n,e,t){return n.client.postBytes("/v1/functions/invoke",e,t?.signal)}async function tt(n,e,t,r){let o=`/v1/games/${s(n.gameId())}/game-rooms/${s(e)}/kick/${s(t)}`;return n.client.post(o,void 0,r?.signal)}async function rt(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 ot(n,e,t,r){let o=`/v1/settings/${s(e)}/${s(t)}`;return n.client.get(o,r?.signal)}async function at(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 a=o.toString(),i=`/v1/inventory/${s(e)}/${s(t)}/orders`+(a?`?${a}`:"");return n.client.get(i,r?.signal)}async function st(n,e,t,r){let o=`/v1/inventory/${s(e)}/${s(t)}/progressions`;return n.client.get(o,r?.signal)}async function it(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 a=o.toString(),i=`/v1/saves/${s(e)}/${s(t)}`+(a?`?${a}`:"");return n.client.get(i,r?.signal)}async function lt(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 dt(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/${s(n.gameId())}/game-rooms`+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function ut(n,e){return n.client.get("/v1/game-room-templates",e?.signal)}async function ct(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 mt(n,e,t,r,o,a){let i=`/v1/inventory/${s(e)}/${s(t)}/progressions/${s(r)}/max`;return n.client.post(i,o,a?.signal)}async function gt(n,e,t,r,o,a){let i=`/v1/settings/${s(e)}/${s(t)}/${s(r)}`;return n.client.put(i,o,a?.signal,{...a?.ifMatch===void 0?{}:{ifMatch:a.ifMatch}})}async function pt(n,e,t,r){let o=`/v1/games/${s(n.gameId())}/game-rooms/${s(e)}/room-args`;return n.client.put(o,t,r?.signal)}async function yt(n,e,t,r,o){let a=`/v1/showcase/players/${s(e)}/${s(t)}`;return n.client.put(a,r,o?.signal)}async function ft(n,e,t){let r=`/v1/inventory/transfers/${s(e)}/reject`;return n.client.post(r,void 0,t?.signal)}async function ht(n,e,t,r){let o=`/v1/games/${s(n.gameId())}/matches/${s(e)}/players/report`;return n.client.post(o,t,r?.signal)}async function _t(n,e,t,r,o,a){let i=`/v1/saves/${s(e)}/${s(t)}/${s(r)}/upload-url`;return n.client.post(i,o,a?.signal,{replaySafe:true})}async function bt(n,e,t,r,o,a){let i=`/v1/inventory/${s(e)}/${s(t)}/progressions/${s(r)}/reset`;return n.client.post(i,o,a?.signal)}async function Rt(n,e,t,r){let o=`/v1/games/${s(n.gameId())}/matches/${s(e)}/backfill`;return n.client.put(o,t,r?.signal)}async function vt(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/orders/simulate`;return n.client.post(a,r,o?.signal)}async function St(n,e,t,r){let o=`/v2/games/${s(n.gameId())}/game-rooms/${s(e)}/transfer/${s(t)}`;return n.client.post(o,void 0,r?.signal)}async function xt(n,e,t,r){let o=`/v2/games/${s(n.gameId())}/game-rooms/${s(e)}`;return n.client.patch(o,t,r?.signal,{...r?.ifMatch===void 0?{}:{ifMatch:r.ifMatch}})}var ge="gem_";function pe(n,e){let t=e?.retryAfterSeconds,r=typeof t=="number"&&Number.isFinite(t)&&t>0?t*1e3:0,o=1e4*2**Math.min(Math.max(0,n-1),16);return Math.min(Math.max(r,o),3e5)}var At=1e4,Ot=50,Pt=1e3,Gt=65536-4*1024,ye=n=>typeof n=="number"?n:0,Tt=n=>typeof n=="string"?n:"";function fe(){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 Ct(n){return n?.retryable===true}function It(n,e){let t=n??{},r=Array.isArray(t.rejected)?t.rejected.map(o=>{let a=o??{};return {index:ye(a.index),code:Tt(a.code)}}):[];return {accepted:ye(t.accepted),rejected:r,dropped:e,duplicate:t.duplicate===true}}function he(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 _e(n){let e=Math.max(1,Math.floor(n.maxQueue??Pt)),t={client:n.client,gameId:()=>n.gameId},r=[],o=0,a=null,i=false,l=null,u=0,c=0,g=false,S=false,w=_=>{n.log?.(_);},R=()=>{a!==null&&(n.clock.clearTimeout(a),a=null);},y=()=>Math.max(0,c-n.clock.now()),x=()=>{a!==null||i||l!==null||(a=n.clock.setTimeout(()=>{a=null,P().catch(()=>{});},Math.max(At,y())));},A=()=>{let _=Math.min(r.length,100),b=128;for(let G=0;G<_;G+=1){let T=r[G];if(T===void 0)break;if(b+=JSON.stringify(he(T,0)).length+1,b>Gt)return Math.max(1,G)}return _};async function P(_){for(;l!==null;)await l.catch(()=>{});if(r.length===0)return {accepted:0,rejected:[],dropped:0,duplicate:false};let b=Ie(_);l=b;try{return await b}finally{l===b&&(l=null),r.length>0&&x();}}async function Ie(_){R();let b=r.splice(0,A()),G=o;o=0;let T=Math.round(n.clock.now()),F={batch_id:fe(),sent_at_ms:T,events:b.map(k=>he(k,T))};try{let k=await Y(t,F,_===void 0?void 0:{signal:_}),C=It(k,G);u=0,c=0;for(let Ee of C.rejected)w(`[gem] analytics: an event was refused (${Ee.code}). See the analytics_events section of your game config.`);return C}catch(k){if(Ct(k)){for(r=[...b,...r],o+=G;r.length>e;)r.shift(),o+=1;u+=1,c=n.clock.now()+pe(u,k);}else w(`[gem] analytics: ${b.length} event(s) were discarded \u2014 the platform refused the batch and will refuse it again: ${String(k)}`);throw k}}return {track(_,b,G={}){if(i)return;if(typeof _!="string"||_===""){S||(S=true,w(`[gem] analytics: '${b}' 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(b.startsWith(ge)){g||(g=true,w(`[gem] analytics: '${b}' 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 T={},F={};for(let[k,C]of Object.entries(G))typeof C=="string"?T[k]=C:typeof C=="number"&&Number.isFinite(C)&&(F[k]=C);for(;r.length>=e;)r.shift(),o+=1;r.push({uid:fe(),playerId:_,name:b,atMs:n.clock.now(),dimensions:T,measures:F}),r.length>=Ot&&l===null&&y()===0?P().catch(()=>{}):x();},flush:_=>P(_),get pending(){return r.length},dispose(){i=true,R(),r=[],o=0;}}}var Et=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]]),j=class extends p{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:Et.get(this.code))??super.retryable}},M=class{#e;constructor(e){this.#e=e;}async invoke(e,t={}){let r=Lt(e),o;try{o=await this.#e(r,t.signal===void 0?{}:{signal:t.signal});}catch(a){throw a instanceof p?Mt(a):a}return qt(o)}};function Lt(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 f(`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 f(`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 qt(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 Mt(n){let{details:e,invocationId:t}=oe(n),o=e?.untrusted?.message,a=e?.reason;return new j(n,{...t===void 0?{}:{invocationId:t},...n.code==="function_error"&&typeof o=="string"?{functionMessage:o}:{},...n.code==="function_failed"&&typeof a=="string"?{failure:a}:{}})}var O=n=>typeof n=="string"?n:"",$t=/(?:Z|[+-]\d{2}:?\d{2})$/i;function be(n){let e=O(n);if(!$t.test(e))return 0;let t=Date.parse(e);return Number.isFinite(t)?Math.floor(t/1e3):0}var jt=/^[0-9a-f]{1,64}$/,Bt=/^[0-9a-f]{16}$/,Ft=/^[A-Za-z][A-Za-z0-9_+\-/]{0,63}$/,Ut=/^(?:[01]\d|2[0-3]):[0-5]\d$/;function Dt(n){let e=O(n),t=/^(\d{4})-(\d{2})-(\d{2})$/.exec(e);if(!t)return;let[r,o,a]=[Number(t[1]),Number(t[2]),Number(t[3])],i=new Date(Date.UTC(r,o-1,a));return i.getUTCFullYear()===r&&i.getUTCMonth()===o-1&&i.getUTCDate()===a?e:void 0}var Nt=4096,Ht=new TextEncoder;function Vt(n){let e=O(n.challenge_data),t=O(n.challenge_data_hash);return e===""||!Bt.test(t)?{}:Ht.encode(e).length>Nt?{}:{data:e,dataHash:t}}function Wt(n){let e=n??{},t=be(e.period_start_at),r=be(e.period_ends_at);if(t===0||r===0)return;let o=O(e.slug),a=O(e.seed),i=Dt(e.period_local_date),l=O(e.boundary),u=O(e.reset_time);return {id:O(e.progression_definition_id),...o===""?{}:{slug:o},window:O(e.window),periodStartAt:t,periodEndsAt:r,...i===void 0?{}:{periodLocalDate:i},boundary:Ft.test(l)?l:"",resetTime:Ut.test(u)?u:"",seed:jt.test(a)?a:"",...Vt(e)}}function Re(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 ve(n){let e=n??{};return Array.isArray(e.challenges)?e.challenges.map(Wt).filter(t=>t!==void 0):[]}function Se(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().");Re(r);let a=await n({player_id:t,...r===void 0?{}:{periods_back:r},...o===void 0?{}:{signal:o}});return ve(a)}}}function zt(n){let e={};for(let[t,r]of Object.entries(J))if(typeof r=="function"){let o=r;e[t]=(...a)=>o(n,...a);}return e}function V(n,e={}){let t=e.clock??q,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=K(n,{clock:t,...e.onAuthStateChange===void 0?{}:{onStateChange:e.onAuthStateChange}}),a=ae({baseUrl:r,tokenSource:o.source,defaultQuery:{game_id:n.gameId,channel:n.channel},...e.fetch===void 0?{}:{fetch:e.fetch}}),i=new L({transport:a,clock:t}),l={gameId:n.gameId,channel:n.channel,matchId:n.matchId,...n.gameRoomId===void 0?{}:{gameRoomId:n.gameRoomId}},u=zt({client:i,gameId:()=>l.gameId}),c=l.gameRoomId,g=n.endMatch,S=n.log,w=_e({client:i,clock:t,gameId:l.gameId,...typeof S=="function"?{log:y=>S.call(n,y)}:{}});return {identity:l,client:i,api:u,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);},setBackfill:async(y,x)=>{let A=await u.setMatchBackfill(l.matchId,{open:y.open,...y.seats===void 0?{}:{seats:y.seats}},x===void 0?{}:{signal:x});return {open:A.open,seats:A.seats??null}},reportPlayers:async(y,x)=>(await u.reportMatchPlayers(l.matchId,{players:y.map(P=>({player_id:P.playerId,state:P.state}))},x===void 0?{}:{signal:x})).players.map(P=>({playerId:P.player_id,outcome:P.outcome}))},analytics:w,functions:new M(u.invokeFunction),challenges:Se(u.listChallenges),...c===void 0?{}:{room:{get:y=>u.getGameRoomV2(c,y),args:async y=>{let x=await u.getGameRoomV2(c,y?.signal===void 0?{}:{signal:y.signal}),A=x.modified?x.body:void 0;if(A?.room_args==null||A.room_args_template==null)throw new p("not_found",404,"this room's template declares no room args",void 0,"room_args_not_defined");return {room_args:A.room_args,room_args_template:A.room_args_template}}}},dispose:()=>{w.dispose(),o.dispose();}}}var Kt=["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"],Yt=new Set(Kt);function xe(n){return typeof n=="string"&&Yt.has(n)?n:"unknown"}var Ae="[gem: use gem.text.toPlain()]",we=new Set,ke;function Jt(n){try{if(we.has(n))return;let e=globalThis.location;if(ke??=!!e?.port&&ce(e.hostname??""),!ke)return;we.add(n),console.warn(`[gem] ${n} is PlayerText, turned into a string: players see ${Ae}. Render text.toPlain(value) (text is in @indiegems/gem-web-sdk/sdk).
2
2
  ${new Error().stack}`);}catch{}}var v=class{#e;#n;constructor(e,t="player text"){this.#e=e,this.#n=t,Object.freeze(this);}toString(){return Jt(this.#n),Ae}toJSON(){return this.toString()}get[Symbol.toStringTag](){return "PlayerText"}static unwrap(e){return e.#e}};function B(n,e){return new v(n,e)}var Oe={toPlain(n){return v.unwrap(n)},compare(n,e,t){let r=n instanceof v?v.unwrap(n):n,o=e instanceof v?v.unwrap(e):e;if(typeof Intl>"u"||typeof Intl.Collator!="function")return r<o?-1:r>o?1:0;let a;try{a=new Intl.Collator(t);}catch{a=new Intl.Collator;}return a.compare(r,o)},equals(n,e){let t=n instanceof v?v.unwrap(n):n,r=e instanceof v?v.unwrap(e):e;return t.normalize("NFC")===r.normalize("NFC")}};var Pe="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 X(n,e={}){let t=e.clock??q,r=()=>{let l=n();if(l===null)throw new Error(Pe);return l},o=null,a=()=>{if(o===null)throw new Error(Pe);return o};return {server:{get identity(){return a().identity},get client(){return a().client},get api(){return a().api},get match(){return a().match},get analytics(){return a().analytics},get functions(){return a().functions},get challenges(){return a().challenges},get room(){return a().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:B(g,"profile.displayName"),...typeof c.displayTag=="string"&&c.displayTag!==""?{displayTag:B(c.displayTag,"profile.displayTag")}:{},...typeof c.discriminator=="string"?{discriminator:c.discriminator}:{}}},playerNumber(l){return r().playerNumber?.(l)},send(l,u,c){c===void 0?r().send(l,u):r().send(l,u,c);},broadcast(l,u){u===void 0?r().broadcast(l):r().broadcast(l,u);},kick(l,u){u===void 0?r().kick(l):r().kick(l,u);},log(l){r().log(l);},warn(l){r().warn(l);}},attach:()=>{o=V(r(),{...e,clock:t});}}}function Ge(n,e={}){let{server:t,attach:r}=X(()=>n,e);return r(),t}function Xt(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:xe(e)}}}var Qt=1e4;function Zt(n){let e=false;return t=>{if(e)return;let r;try{r=n.match.reportPlayers([{playerId:t,state:"connected"}],AbortSignal.timeout(Qt));}catch{return}r.catch(o=>{o instanceof p&&o.status>=400&&o.status<500&&(e=o.status!==429);});}}function Te(n,e={}){return ()=>{let t=null,{server:r,attach:o}=X(()=>t,e),a=n(r),i={async init(u){t=u,o(),await a.init?.();},async shutdown(u){let c=Xt(u);try{await a.shutdown?.(c);}finally{r.dispose();}}},l=Zt(r);return i.join=(u,c)=>(l(u),a.join?.(u,c)),a.leave&&(i.leave=(u,c)=>a.leave?.(u,c)),a.message&&(i.message=(u,c,g,S)=>a.message?.(u,c,g,S)),i}}var er=new Set(["unlocked","already_unlocked","suppressed"]);function Ce(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"||!er.has(o.outcome)||typeof o.achievement_id!="string"||o.achievement_id==="")continue;let a=o.outcome;t.push({achievementId:o.achievement_id,progressionDefinitionId:typeof o.progression_definition_id=="string"?o.progression_definition_id:"",points:a==="unlocked"&&typeof o.points=="number"&&Number.isFinite(o.points)?o.points:0,outcome:a,...typeof o.reason=="string"?{reason:o.reason}:{}});}return t}export{h as AuthError,D as CONDITIONAL_HEADERS,M as FunctionsApi,p as GemApiError,L as GemClient,j as GemFunctionError,v as PlayerText,f as TransportRefusal,Ce as achievementReceipts,B as asPlayerText,V as createGemServer,me as createHostTokenSource,Ge as createMatchServer,Te as defineServer,q as systemClock,Oe as text,ee as toBase64};//# sourceMappingURL=gem-web-sdk.server.js.map
3
3
  //# sourceMappingURL=gem-web-sdk.server.js.map
@@ -1,6 +1,6 @@
1
1
  # The function surface — API reference
2
2
 
3
- Generated from `@indiegems/gem-web-sdk/function` v16.3.0, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
3
+ Generated from `@indiegems/gem-web-sdk/function` v16.3.1, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
4
4
 
5
5
  `@indiegems/gem-web-sdk/function` exports exactly the symbols on this page and nothing else.
6
6
 
@@ -1,6 +1,6 @@
1
1
  # The browser surface — API reference
2
2
 
3
- Generated from `@indiegems/gem-web-sdk/sdk` v16.3.0, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
3
+ Generated from `@indiegems/gem-web-sdk/sdk` v16.3.1, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
4
4
 
5
5
  `@indiegems/gem-web-sdk/sdk` is the one import a game writes, wherever its code runs. `@indiegems/gem-web-sdk/game` exports exactly the symbols on this page and nothing else, for a build that wants only this half.
6
6
 
@@ -4590,7 +4590,7 @@ interface StoreApi
4590
4590
  ```
4591
4591
 
4592
4592
  **Real money.** The Arcade Store's own Gem packs, Boosts, passes and bundles,
4593
- bought with the player's money through the arcade's own purchase sheet.
4593
+ bought with the player's money through the Arcade Store's own checkout.
4594
4594
  `gem.store` is one of these. To spend Gems or Coins on your game's own items,
4595
4595
  use `gem.purchases`.
4596
4596
 
@@ -4628,20 +4628,24 @@ is withheld. Re-read on resume: what is on sale can change.
4628
4628
  purchase(skuId: string): Promise<ArcadeOutcome>
4629
4629
  ```
4630
4630
 
4631
- Ask the arcade to open its store's purchase sheet for one SKU from
4632
- [StoreApi.offers](#storeapi-offers). **Call it from the player's press handler** — the
4631
+ Ask the arcade to open checkout for one SKU from [StoreApi.offers](#storeapi-offers):
4632
+ the payment provider's page on the web, the app store's purchase sheet in
4633
+ the Arcade's apps, straight away, with no confirmation screen of the
4634
+ arcade's own first. **Call it from the player's press handler** — the
4633
4635
  arcade refuses an ask no person pressed for, `declined` / `busy`.
4634
4636
 
4635
4637
  - `ok` — the player paid. Re-read balances and inventory through `gem.me`;
4636
4638
  nothing here carries an amount. With `reason: 'pending'`, the provider
4637
4639
  has not settled yet: [StoreApi.onSettled](#storeapi-onsettled) hears when it does.
4638
- - `declined` — nothing was bought: `cancelled` (the player said no) or
4639
- `busy`. Return to your screen silently, and do not ask again unprompted.
4640
+ - `declined` — nothing was bought: `cancelled` (the player closed the
4641
+ checkout, or the offer cannot be bought again yet) or `busy` (after a
4642
+ closed checkout the arcade refuses the next ask for a while). Return to
4643
+ your screen silently, and do not ask again unprompted.
4640
4644
  - `unavailable` with `store_off`, `sign_in_required`, `not_found`,
4641
4645
  `unsupported`, `invalid_argument` or a payment provider's failure code —
4642
4646
  nothing was bought.
4643
4647
  - `unavailable` / `error` — **the outcome is unknown, and the player may
4644
- have paid.** It is what you get when the bridge closes while the sheet
4648
+ have paid.** It is what you get when the bridge closes while checkout
4645
4649
  is open, or the arcade has no reliable answer. Never tell the player
4646
4650
  nothing was bought: re-read balances and inventory through `gem.me`,
4647
4651
  and keep listening with [StoreApi.onSettled](#storeapi-onsettled).
@@ -10478,9 +10482,9 @@ readonly reserved: readonly GemReservedArea[]
10478
10482
  ```
10479
10483
 
10480
10484
  Rectangles of your frame the arcade's own controls cover — in the Gem
10481
- Arcade, its Gem button in whichever corner it sits, and the frame-rate readout
10482
- beside it while the player shows it; an embedder that draws wallets over
10483
- your game adds theirs (see `setWalletVisible`). Keep essential UI and touch
10485
+ Arcade, its Gem button in whichever corner it sits, the frame-rate readout
10486
+ beside it while the player shows it, and the wallets beside it while your
10487
+ game asks for them (see `setWalletVisible`). Keep essential UI and touch
10484
10488
  targets out of them. Empty when the arcade covers nothing.
10485
10489
 
10486
10490
  Each is a keep-out area, grown out to the frame edges it sits nearest — not
@@ -10629,10 +10633,10 @@ readonly only?: readonly string[]
10629
10633
 
10630
10634
  While shown, show ONLY these: platform currency slugs as
10631
10635
  `gem.platform.currencies.get()` lists them (`GEMS`, `ARCADE_TICKETS`),
10632
- matched exactly, and the literal `'score'` for the achievement score. Only
10633
- for a screen about one currency, such as a Coins store; leave it out and
10634
- every wallet shows, which is always safe. The Gem Arcade draws no wallet
10635
- over a game, so it has nothing to narrow and ignores it.
10636
+ matched exactly, and the literal `'score'` for the achievement score. Leave
10637
+ it out and every wallet shows, the achievement score's included. The Gem
10638
+ Arcade honours it: `{ only: ['GEMS', 'ARCADE_TICKETS'] }` shows those two
10639
+ and no achievement score; a slug the platform does not serve names nothing.
10636
10640
 
10637
10641
  <a id="gamemenuitem"></a>
10638
10642
 
@@ -10688,7 +10692,8 @@ interface GameMenu
10688
10692
  ```
10689
10693
 
10690
10694
  What your game adds to the arcade's menu — see `gem.setMenu`. Your settings
10691
- are not part of it: they open from your own settings button.
10695
+ screen is not part of it: it opens from your own settings button. An action
10696
+ on that screen (Replay the tutorial, How to play) may also be an entry here.
10692
10697
 
10693
10698
  <a id="gamemenu-items"></a>
10694
10699
 
@@ -11796,9 +11801,10 @@ Tell the arcade a platform-currency reward is on its way, so it **shows it
11796
11801
  landing**: in the Gem Arcade the currency flies from `origin` into the Gem
11797
11802
  button, wherever on your frame it sits, which pops as each mark lands, and
11798
11803
  the player's total moves once the platform confirms the grant. The Gem
11799
- Arcade draws no wallet over your game: the player sees their Gems and
11800
- Coins in the Gem menu. A payout you do not cue still flies, from the
11801
- middle of your frame, so cue the ones the player earns on screen.
11804
+ Arcade draws no wallet over your game unless you ask (`setWalletVisible`):
11805
+ the player sees their Gems and Coins in the Gem menu. A payout you do not
11806
+ cue still flies, from the middle of your frame, so cue the ones the player
11807
+ earns on screen.
11802
11808
 
11803
11809
  Call it the moment your game decides to award — when your server has moved
11804
11810
  (or is about to move) the progression mapped onto a platform currency —
@@ -11843,26 +11849,25 @@ landed — which it does on every channel, dev and test included.
11843
11849
  setWalletVisible(visible: boolean, options?: WalletVisibleOptions): boolean
11844
11850
  ```
11845
11851
 
11846
- Show or hide the player's wallets — Gems, Coins, the achievement score —
11847
- that an embedder draws over your game.
11852
+ Ask the arcade to show, or stop showing, the player's wallets — Gems,
11853
+ Coins, the achievement score — over your game.
11848
11854
 
11849
- **The Gem Arcade draws no wallet over a game** (since 2026-10-11): the
11850
- player sees their balances in the Gem menu, and payouts fly into the Gem
11851
- button. So under the Gem Arcade this changes nothing on screen — it is
11852
- accepted and harmless, and a game that already calls it keeps working.
11853
- Call it for an embedder that does draw wallets over your game: hide them
11854
- while you play, show them on your menus.
11855
+ **The Gem Arcade draws them on request** (the owner, 2026-10-29): a game
11856
+ that says nothing gets no wallet over it, as since 2026-10-11, and the
11857
+ player sees their balances in the Gem menu; a game that asks gets them
11858
+ drawn beside the Gem, from the platform's own figures. An Arcade from
11859
+ before that ignores the call, harmlessly.
11855
11860
 
11856
11861
  ```js
11857
- level.onStart = () => gem.setWalletVisible(false);
11858
- menu.onOpen = () => gem.setWalletVisible(true);
11862
+ gem.setWalletVisible(true, { only: ['GEMS', 'ARCADE_TICKETS'] }); // every screen
11863
+ level.onStart = () => gem.setWalletVisible(false); // or put them away during play
11859
11864
  ```
11860
11865
 
11861
11866
  **It is screen state, not a toggle.** Each call is the whole answer and
11862
- replaces the last. Where an embedder draws wallets, shown ones arrive as
11863
- rectangles in `gem.viewport.reserved` and hiding them gives that space
11864
- back; the Gem Arcade sends none for wallets. `only` narrows what shows,
11865
- where an embedder honours it; the Gem Arcade does not.
11867
+ replaces the last. Shown wallets arrive as rectangles in
11868
+ `gem.viewport.reserved` (and widen the Gem's corner in the
11869
+ `--gem-reserved-*` variables), and hiding them gives that space back.
11870
+ `only` narrows what shows.
11866
11871
 
11867
11872
  **Never draw a platform balance yourself**, and never show a pending state
11868
11873
  for one: the arcade takes every figure from the platform. If this returns
@@ -11895,10 +11900,14 @@ gem.setMenu({
11895
11900
  });
11896
11901
  ```
11897
11902
 
11898
- **Your settings are not in it: draw your own settings button, always** —
11903
+ **Your settings screen is not in it: draw your own settings button** —
11899
11904
  top-right, with your Back button just to its left, clear of
11900
11905
  `gem.viewport.reserved`. The Arcade's menu never opens your settings
11901
- screen.
11906
+ screen. Inside the Gem Arcade you may leave the button out while this
11907
+ returns `true`, when every setting on your screen is declared with
11908
+ `gem.settings` and every action on it is one of these entries; it returns
11909
+ `false` before the bridge is up and under an embedder with no menu, and the
11910
+ button stays there.
11902
11911
 
11903
11912
  **It is screen state, not a toggle.** Each call is the whole answer and
11904
11913
  replaces the last, so call it again when the entries change — a new
@@ -1,6 +1,6 @@
1
1
  # The server surface — API reference
2
2
 
3
- Generated from `@indiegems/gem-web-sdk/sdk` v16.3.0, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
3
+ Generated from `@indiegems/gem-web-sdk/sdk` v16.3.1, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
4
4
 
5
5
  `@indiegems/gem-web-sdk/sdk` is the one import a game writes, wherever its code runs. `@indiegems/gem-web-sdk/server` exports exactly the symbols on this page and nothing else, for a build that wants only this half.
6
6
 
@@ -2,7 +2,7 @@
2
2
  "schema_version": 2,
3
3
  "source": {
4
4
  "repo": "IndieGems/gem-web-sdk",
5
- "version": "16.3.0"
5
+ "version": "16.3.1"
6
6
  },
7
7
  "entries": [
8
8
  {
@@ -5512,7 +5512,7 @@
5512
5512
  "group": "store",
5513
5513
  "signature": "interface StoreApi",
5514
5514
  "documented": true,
5515
- "summary": "**Real money.** The Arcade Store's own Gem packs, Boosts, passes and bundles,\nbought with the player's money through the arcade's own purchase sheet.\n`gem.store` is one of these. To spend Gems or Coins on your game's own items,\nuse `gem.purchases`.",
5515
+ "summary": "**Real money.** The Arcade Store's own Gem packs, Boosts, passes and bundles,\nbought with the player's money through the Arcade Store's own checkout.\n`gem.store` is one of these. To spend Gems or Coins on your game's own items,\nuse `gem.purchases`.",
5516
5516
  "deprecated": null,
5517
5517
  "params": [],
5518
5518
  "returns": null,
@@ -5560,7 +5560,7 @@
5560
5560
  "group": "store",
5561
5561
  "signature": "purchase(skuId: string): Promise<ArcadeOutcome>",
5562
5562
  "documented": true,
5563
- "summary": "Ask the arcade to open its store's purchase sheet for one SKU from\n[StoreApi.offers](api-reference-game.md#storeapi-offers). **Call it from the player's press handler** — the\narcade refuses an ask no person pressed for, `declined` / `busy`.\n\n- `ok` — the player paid. Re-read balances and inventory through `gem.me`;\n nothing here carries an amount. With `reason: 'pending'`, the provider\n has not settled yet: [StoreApi.onSettled](api-reference-game.md#storeapi-onsettled) hears when it does.\n- `declined` — nothing was bought: `cancelled` (the player said no) or\n `busy`. Return to your screen silently, and do not ask again unprompted.\n- `unavailable` with `store_off`, `sign_in_required`, `not_found`,\n `unsupported`, `invalid_argument` or a payment provider's failure code —\n nothing was bought.\n- `unavailable` / `error` — **the outcome is unknown, and the player may\n have paid.** It is what you get when the bridge closes while the sheet\n is open, or the arcade has no reliable answer. Never tell the player\n nothing was bought: re-read balances and inventory through `gem.me`,\n and keep listening with [StoreApi.onSettled](api-reference-game.md#storeapi-onsettled).\n\nNO TIMEOUT: it waits for as long as the arcade is connected, because a\npayment takes as long as it takes.",
5563
+ "summary": "Ask the arcade to open checkout for one SKU from [StoreApi.offers](api-reference-game.md#storeapi-offers):\nthe payment provider's page on the web, the app store's purchase sheet in\nthe Arcade's apps, straight away, with no confirmation screen of the\narcade's own first. **Call it from the player's press handler** — the\narcade refuses an ask no person pressed for, `declined` / `busy`.\n\n- `ok` — the player paid. Re-read balances and inventory through `gem.me`;\n nothing here carries an amount. With `reason: 'pending'`, the provider\n has not settled yet: [StoreApi.onSettled](api-reference-game.md#storeapi-onsettled) hears when it does.\n- `declined` — nothing was bought: `cancelled` (the player closed the\n checkout, or the offer cannot be bought again yet) or `busy` (after a\n closed checkout the arcade refuses the next ask for a while). Return to\n your screen silently, and do not ask again unprompted.\n- `unavailable` with `store_off`, `sign_in_required`, `not_found`,\n `unsupported`, `invalid_argument` or a payment provider's failure code —\n nothing was bought.\n- `unavailable` / `error` — **the outcome is unknown, and the player may\n have paid.** It is what you get when the bridge closes while checkout\n is open, or the arcade has no reliable answer. Never tell the player\n nothing was bought: re-read balances and inventory through `gem.me`,\n and keep listening with [StoreApi.onSettled](api-reference-game.md#storeapi-onsettled).\n\nNO TIMEOUT: it waits for as long as the arcade is connected, because a\npayment takes as long as it takes.",
5564
5564
  "deprecated": null,
5565
5565
  "params": [
5566
5566
  {
@@ -12027,7 +12027,7 @@
12027
12027
  "group": "player",
12028
12028
  "signature": "readonly reserved: readonly GemReservedArea[]",
12029
12029
  "documented": true,
12030
- "summary": "Rectangles of your frame the arcade's own controls cover — in the Gem\nArcade, its Gem button in whichever corner it sits, and the frame-rate readout\nbeside it while the player shows it; an embedder that draws wallets over\nyour game adds theirs (see `setWalletVisible`). Keep essential UI and touch\ntargets out of them. Empty when the arcade covers nothing.\n\nEach is a keep-out area, grown out to the frame edges it sits nearest — not\nthe control's own box, and not something to line anything up with. Where\nthe arcade says, `control` on each is the control itself.\n\nA stylesheet reads the per-corner custom properties the SDK stamps from\nthese instead — `--gem-reserved-tl-height` and friends, and\n`--gem-reserved-tl-center-y` to line a top bar up with the Gem.",
12030
+ "summary": "Rectangles of your frame the arcade's own controls cover — in the Gem\nArcade, its Gem button in whichever corner it sits, the frame-rate readout\nbeside it while the player shows it, and the wallets beside it while your\ngame asks for them (see `setWalletVisible`). Keep essential UI and touch\ntargets out of them. Empty when the arcade covers nothing.\n\nEach is a keep-out area, grown out to the frame edges it sits nearest — not\nthe control's own box, and not something to line anything up with. Where\nthe arcade says, `control` on each is the control itself.\n\nA stylesheet reads the per-corner custom properties the SDK stamps from\nthese instead — `--gem-reserved-tl-height` and friends, and\n`--gem-reserved-tl-center-y` to line a top bar up with the Gem.",
12031
12031
  "deprecated": null,
12032
12032
  "params": [],
12033
12033
  "returns": null,
@@ -12235,7 +12235,7 @@
12235
12235
  "group": "platform",
12236
12236
  "signature": "readonly only?: readonly string[]",
12237
12237
  "documented": true,
12238
- "summary": "While shown, show ONLY these: platform currency slugs as\n`gem.platform.currencies.get()` lists them (`GEMS`, `ARCADE_TICKETS`),\nmatched exactly, and the literal `'score'` for the achievement score. Only\nfor a screen about one currency, such as a Coins store; leave it out and\nevery wallet shows, which is always safe. The Gem Arcade draws no wallet\nover a game, so it has nothing to narrow and ignores it.",
12238
+ "summary": "While shown, show ONLY these: platform currency slugs as\n`gem.platform.currencies.get()` lists them (`GEMS`, `ARCADE_TICKETS`),\nmatched exactly, and the literal `'score'` for the achievement score. Leave\nit out and every wallet shows, the achievement score's included. The Gem\nArcade honours it: `{ only: ['GEMS', 'ARCADE_TICKETS'] }` shows those two\nand no achievement score; a slug the platform does not serve names nothing.",
12239
12239
  "deprecated": null,
12240
12240
  "params": [],
12241
12241
  "returns": null,
@@ -12315,7 +12315,7 @@
12315
12315
  "group": "frame",
12316
12316
  "signature": "interface GameMenu",
12317
12317
  "documented": true,
12318
- "summary": "What your game adds to the arcade's menu — see `gem.setMenu`. Your settings\nare not part of it: they open from your own settings button.",
12318
+ "summary": "What your game adds to the arcade's menu — see `gem.setMenu`. Your settings\nscreen is not part of it: it opens from your own settings button. An action\non that screen (Replay the tutorial, How to play) may also be an entry here.",
12319
12319
  "deprecated": null,
12320
12320
  "params": [],
12321
12321
  "returns": null,
@@ -13234,7 +13234,7 @@
13234
13234
  "group": "start",
13235
13235
  "signature": "cueReward(cue: RewardCue): boolean",
13236
13236
  "documented": true,
13237
- "summary": "Tell the arcade a platform-currency reward is on its way, so it **shows it\nlanding**: in the Gem Arcade the currency flies from `origin` into the Gem\nbutton, wherever on your frame it sits, which pops as each mark lands, and\nthe player's total moves once the platform confirms the grant. The Gem\nArcade draws no wallet over your game: the player sees their Gems and\nCoins in the Gem menu. A payout you do not cue still flies, from the\nmiddle of your frame, so cue the ones the player earns on screen.\n\nCall it the moment your game decides to award — when your server has moved\n(or is about to move) the progression mapped onto a platform currency —\nand pass the centre of that currency's icon (or hero) on your screen, so\nthe flight starts from the mark the player is looking at:\n\n```js\nconst { x, y, width, height } = rewardGem.getBoundingClientRect(); // the gem's own box\ngem.cueReward({\n currencySlug: 'GEMS', // or 'ARCADE_TICKETS', from the coin\n expected: 15,\n origin: { x: x + width / 2, y: y + height / 2 },\n});\n```\n\n**This is the platform-currency animation, and the only one.** The display\nof every platform currency — Gems and Coins alike — belongs to the\narcade: a game draws no flight or celebration of its own for one and keeps\nno counter of one. **If this returns `false`, do nothing** — there is no\nfallback celebration.\n\n**The arcade never takes your word for the amount.** What lands, and the\nplayer's new total, come from the platform itself; `expected` is drawn as\nprovisional, and a cue the platform never confirms fades on its own — a\ngrant clamped to zero, say, or one the receipt reports `suppressed`. So\nthe cue can only ever make the wallet move for a reward that really\nlanded — which it does on every channel, dev and test included.",
13237
+ "summary": "Tell the arcade a platform-currency reward is on its way, so it **shows it\nlanding**: in the Gem Arcade the currency flies from `origin` into the Gem\nbutton, wherever on your frame it sits, which pops as each mark lands, and\nthe player's total moves once the platform confirms the grant. The Gem\nArcade draws no wallet over your game unless you ask (`setWalletVisible`):\nthe player sees their Gems and Coins in the Gem menu. A payout you do not\ncue still flies, from the middle of your frame, so cue the ones the player\nearns on screen.\n\nCall it the moment your game decides to award — when your server has moved\n(or is about to move) the progression mapped onto a platform currency —\nand pass the centre of that currency's icon (or hero) on your screen, so\nthe flight starts from the mark the player is looking at:\n\n```js\nconst { x, y, width, height } = rewardGem.getBoundingClientRect(); // the gem's own box\ngem.cueReward({\n currencySlug: 'GEMS', // or 'ARCADE_TICKETS', from the coin\n expected: 15,\n origin: { x: x + width / 2, y: y + height / 2 },\n});\n```\n\n**This is the platform-currency animation, and the only one.** The display\nof every platform currency — Gems and Coins alike — belongs to the\narcade: a game draws no flight or celebration of its own for one and keeps\nno counter of one. **If this returns `false`, do nothing** — there is no\nfallback celebration.\n\n**The arcade never takes your word for the amount.** What lands, and the\nplayer's new total, come from the platform itself; `expected` is drawn as\nprovisional, and a cue the platform never confirms fades on its own — a\ngrant clamped to zero, say, or one the receipt reports `suppressed`. So\nthe cue can only ever make the wallet move for a reward that really\nlanded — which it does on every channel, dev and test included.",
13238
13238
  "deprecated": null,
13239
13239
  "params": [
13240
13240
  {
@@ -13257,7 +13257,7 @@
13257
13257
  "group": "start",
13258
13258
  "signature": "setWalletVisible(visible: boolean, options?: WalletVisibleOptions): boolean",
13259
13259
  "documented": true,
13260
- "summary": "Show or hide the player's wallets — Gems, Coins, the achievement score —\nthat an embedder draws over your game.\n\n**The Gem Arcade draws no wallet over a game** (since 2026-10-11): the\nplayer sees their balances in the Gem menu, and payouts fly into the Gem\nbutton. So under the Gem Arcade this changes nothing on screen — it is\naccepted and harmless, and a game that already calls it keeps working.\nCall it for an embedder that does draw wallets over your game: hide them\nwhile you play, show them on your menus.\n\n```js\nlevel.onStart = () => gem.setWalletVisible(false);\nmenu.onOpen = () => gem.setWalletVisible(true);\n```\n\n**It is screen state, not a toggle.** Each call is the whole answer and\nreplaces the last. Where an embedder draws wallets, shown ones arrive as\nrectangles in `gem.viewport.reserved` and hiding them gives that space\nback; the Gem Arcade sends none for wallets. `only` narrows what shows,\nwhere an embedder honours it; the Gem Arcade does not.\n\n**Never draw a platform balance yourself**, and never show a pending state\nfor one: the arcade takes every figure from the platform. If this returns\n`false`, do nothing in its place.",
13260
+ "summary": "Ask the arcade to show, or stop showing, the player's wallets — Gems,\nCoins, the achievement score — over your game.\n\n**The Gem Arcade draws them on request** (the owner, 2026-10-29): a game\nthat says nothing gets no wallet over it, as since 2026-10-11, and the\nplayer sees their balances in the Gem menu; a game that asks gets them\ndrawn beside the Gem, from the platform's own figures. An Arcade from\nbefore that ignores the call, harmlessly.\n\n```js\ngem.setWalletVisible(true, { only: ['GEMS', 'ARCADE_TICKETS'] }); // every screen\nlevel.onStart = () => gem.setWalletVisible(false); // or put them away during play\n```\n\n**It is screen state, not a toggle.** Each call is the whole answer and\nreplaces the last. Shown wallets arrive as rectangles in\n`gem.viewport.reserved` (and widen the Gem's corner in the\n`--gem-reserved-*` variables), and hiding them gives that space back.\n`only` narrows what shows.\n\n**Never draw a platform balance yourself**, and never show a pending state\nfor one: the arcade takes every figure from the platform. If this returns\n`false`, do nothing in its place.",
13261
13261
  "deprecated": null,
13262
13262
  "params": [
13263
13263
  {
@@ -13286,7 +13286,7 @@
13286
13286
  "group": "start",
13287
13287
  "signature": "setMenu(menu: GameMenu): boolean",
13288
13288
  "documented": true,
13289
- "summary": "Put up to four entries of your own in the arcade's menu. The arcade keeps\none menu button over your game: it is how a player leaves, mutes, goes\nfullscreen, reports a problem and changes their Arcade-wide settings.\n\n```js\ngem.setMenu({\n items: [{ id: 'how-to-play', label: t('How to play'), onSelect: () => help.open() }],\n});\n```\n\n**Your settings are not in it: draw your own settings button, always** —\ntop-right, with your Back button just to its left, clear of\n`gem.viewport.reserved`. The Arcade's menu never opens your settings\nscreen.\n\n**It is screen state, not a toggle.** Each call is the whole answer and\nreplaces the last, so call it again when the entries change — a new\nlanguage, a screen with different options. `gem.setMenu({})` takes\neverything of yours back out. The arcade's own entries are not yours to\nchange, and Return to the Arcade is always among them.\n\n**The arcade pauses your game while its menu is open** (`onPause`), and\nresumes it before a handler of yours runs. A handler opens a screen; it\nshould not assume the game was paused by you.",
13289
+ "summary": "Put up to four entries of your own in the arcade's menu. The arcade keeps\none menu button over your game: it is how a player leaves, mutes, goes\nfullscreen, reports a problem and changes their Arcade-wide settings.\n\n```js\ngem.setMenu({\n items: [{ id: 'how-to-play', label: t('How to play'), onSelect: () => help.open() }],\n});\n```\n\n**Your settings screen is not in it: draw your own settings button** —\ntop-right, with your Back button just to its left, clear of\n`gem.viewport.reserved`. The Arcade's menu never opens your settings\nscreen. Inside the Gem Arcade you may leave the button out while this\nreturns `true`, when every setting on your screen is declared with\n`gem.settings` and every action on it is one of these entries; it returns\n`false` before the bridge is up and under an embedder with no menu, and the\nbutton stays there.\n\n**It is screen state, not a toggle.** Each call is the whole answer and\nreplaces the last, so call it again when the entries change — a new\nlanguage, a screen with different options. `gem.setMenu({})` takes\neverything of yours back out. The arcade's own entries are not yours to\nchange, and Return to the Arcade is always among them.\n\n**The arcade pauses your game while its menu is open** (`onPause`), and\nresumes it before a handler of yours runs. A handler opens a screen; it\nshould not assume the game was paused by you.",
13290
13290
  "deprecated": null,
13291
13291
  "params": [
13292
13292
  {