@indiegems/gem-web-sdk 23.0.6 → 23.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,3 @@
1
- var je=Object.defineProperty;var $e=(n,e)=>{for(var t in e)je(n,t,{get:e[t],enumerable:true});};globalThis.__gemWebSdkVersion="[gem-web-sdk:sdkVersion:23.0.6]";var Be={initialDelayMs:2e3,maxDelayMs:6e4};function Fe(n,e){return e!==void 0?!e:n==="chain_exhausted"}var N=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}=Be,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=Ue(o),{retryable:i,retryAfterMs:d}=o??{};throw t===this.generation&&(Fe(a,typeof i=="boolean"?i:void 0)?this.enter("lost",a):(this.scheduleRetry(typeof d=="number"&&Number.isFinite(d)&&d>0?d: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 Ue(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}},H=["if-match","if-none-match"],ee=4096;function De(n){if(!n)return;let e={};for(let[t,r]of Object.entries(n)){let o=t.toLowerCase();if(!H.includes(o)||r===void 0)continue;let a=typeof r=="string"?Ne(r):r;if(typeof a!="string"||a.length>ee||!He(a))throw new f(`the ${o} header value cannot be sent \u2014 it is not a string, is longer than ${ee} 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 Ne(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 He(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 Ve(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 ne(n,e){let t=e.replayUnauthorizedOnce??true;return {async request(r){let o={...r},a=De(o.headers),i=Ve(o),d=Object.freeze({...o,headers:a,...i===void 0?{}:{bytes:i}}),u=await e.tokenSource.get(),c=await n(d,u);if(c.status!==401||!t)return c;e.tokenSource.invalidate(u);let g=await e.tokenSource.get(),S=await n(d,g);if(S.status===401)throw e.tokenSource.close("unavailable"),new h("unavailable","the server refused a freshly minted token");return S}}}function te(n){let e=typeof n=="string"?new TextEncoder().encode(n):n;return btoa(We(e))}function We(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"}},ae=new WeakMap;function se(n){return ae.get(n)??{}}var ze=new Set([408,429,500,502,503,504]),Ke=6e4,Ye=new WeakMap;function re(n){return n!==null&&(n.reason==="rate_limited"||n.retryAfterSeconds!==void 0)}function Je(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 q=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,...j(o)},o.replaySafe===true,o.retryRateLimited!==false)}async post(e,t,r,o={}){return this.send({method:"POST",path:e,body:t,signal:r,...j(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,...j(o)},o.replaySafe===true,o.retryRateLimited!==false);return {bytes:Xe(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,...j(o)},o.replaySafe===true,o.retryRateLimited!==false)}async delete(e,t,r={}){return this.send({method:"DELETE",path:e,signal:t,...j(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?Je(this.options.maxRetries)+1:1,a=null;if(e.signal?.aborted)throw oe(e.signal);let i=e.signal===void 0?void 0:Ye.get(e.signal);for(let d=0;d<o;d++){if(d>0){let g=this.backoffMs(d,a);if(re(a)&&i!==void 0&&g>=i())throw a;await this.backoff(g,e.signal);}if(e.signal?.aborted)throw re(a)&&i!==void 0&&i()<=0?a:oe(e.signal);let u;try{u=await this.options.transport.request(e);}catch(g){if(h.isAuthError(g)||f.isRefusal(g)||e.signal?.aborted||Qe(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=Ze(u);if(!ze.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),Ke)}backoff(e,t){return t?.aborted?Promise.resolve():new Promise(r=>{let o=this.options.clock,a=false,i=false,d,u=()=>{a||(a=true,i&&o.clearTimeout(d),t?.removeEventListener("abort",u),r());};t?.addEventListener("abort",u,{once:true}),d=o.setTimeout(u,e),i=true,a&&o.clearTimeout(d);})}};function Xe(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 j(n){return {...n.keepalive===void 0?{}:{keepalive:n.keepalive},...n.ifMatch===void 0?{}:{headers:{"if-match":n.ifMatch}}}}function oe(n){return n.reason!==void 0?n.reason:new DOMException("The operation was aborted.","AbortError")}function Qe(n){let e=n?.name;return e==="AbortError"||e==="TimeoutError"}function Ze(n){let e=nn(n),t=rn(n.body),r={...t===void 0?{}:{details:t},...n.invocationId===void 0?{}:{invocationId:n.invocationId}};return Object.keys(r).length>0&&ae.set(e,r),e}var en=new Map([["insufficient_funds","insufficient_funds"]]);function nn(n){let{status:e,body:t}=n,r=tn(t),o=n.retryAfterSeconds??an(t),a=on(t),i=a===void 0?void 0:en.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 tn(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 rn(n){let t=n?.error?.details;return t===null?void 0:t}function on(n){let t=n?.error?.code;return typeof t=="string"&&t.length>0?t:void 0}function an(n){let e=n?.retryAfterSeconds;return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:void 0}function sn(n){let e=n.lastIndexOf("@");return (e===-1?n:`***@${n.slice(e+1)}`).slice(0,200)}var ln=new Set(H);function dn(n){if(!n)return {};let e={};for(let[t,r]of Object.entries(n))ln.has(t.toLowerCase())&&(e[t.toLowerCase()]=r);return e}function ie(n){let e=n.fetch??globalThis.fetch.bind(globalThis);return ne(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"?sn(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 b=o.username!==""||o.password!=="",y=a.username!==o.username||a.password!==o.password,x=b?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[b,y]of Object.entries(n.defaultQuery??{}))a.searchParams.has(b)||a.searchParams.set(b,y);let i=t.bytes,d=t.bytes===void 0?void 0:"application/octet-stream";try{t.body!==void 0&&(i=JSON.stringify(t.body),d="application/json");}catch(b){throw new f(`the body of ${t.method} ${JSON.stringify(a.pathname)} could not be serialised to JSON: ${String(b)}. 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}`,...d===void 0?{}:{"content-type":d},...dn(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 b=await u.text();if(b.length>0)try{c=JSON.parse(b);}catch{c=b;}}let g=u.headers.get("etag"),S=un(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 un(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 cn="gem-web-bridge";var mn=65536,le=8,V=5e3,de=1024;var W=Object.create(null);var ue=Object.create(null);function gn(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 pn(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 yn(n){return /^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i.test(n)}function fn(n){return /^[a-z_]+$/.test(n)}function hn(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 K(n,e,t){if(e>le)return `nesting deeper than ${le}`;if(++t.nodes>V)return `more than ${V} 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>de)return `an array of ${n.length} entries, over the ${de} limit`;t.bytes+=2;for(let d of n){let u=K(d,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 d in i){if(!Object.prototype.hasOwnProperty.call(i,d))continue;if(++t.nodes>V)return `more than ${V} values`;if(t.bytes+=d.length*3+4,t.bytes>t.cap)return `over the ${t.cap} byte limit`;let u=K(i[d],e+1,t);if(u)return u}return null}function _n(n,e=mn){let t={nodes:0,bytes:0,seen:new Set,cap:e},r=K(n,0,t);return r?`message contains ${r}`:t.bytes>e?`message is over the ${e} byte limit`:null}var Rn={origin:[gn,"not a well-formed origin"],url:[pn,"not a safe absolute http(s) URL"],bcp47:[yn,"not a well-formed BCP 47 tag"],code:[fn,"not a code of lower-case letters and underscores"],gameRef:[hn,"not a game id or web address"]};function ce(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=Y(a,r,o);if(i)return i}return null}function Y(n,e,t){let r=e[1].toLowerCase();switch(r){case "u":return typeof n=="boolean"?null:Y(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]=Rn[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`:ce(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 d=Y(i,o,a);if(d)return d}return null}default:return `${t}: unknown kind ${String(r)}`}}var me=Object.create(null);function l(n,e,t,r,o){return W[n]=t,r&&(ue[n]=r),me[n]=a=>{let i=_n(a,o);if(i)return i;if(typeof a!="object"||a===null||Array.isArray(a))return "message: expected object";let d=a;return d.gem!==cn?"gem: wrong protocol marker":d.type!==n?`type: expected ${n}`:ce(d,e,"")}}var $=["","s",64],m=["requestId","s",64],B=["matchId","s",64],T=["reason","S",64,"code"],E=["outcome","e",["ok","declined","unavailable"]];l("gem.handshake",[["versions","o",[["min","i",1,1e3],["max","i",1,1e3]]],["capabilities","A",64,$],["embedder","s",2048,"origin"],["unbidden","B"]],30);l("gem.handshake.accept",[["v","i",1,1e3],["capabilities","A",64,$]],5);l("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);l("gem.token.denied",[m,["retryable","b"],["retryAfterMs","I",0,36e5],["reason","e",["chain_exhausted","unavailable"]],["correlationId","s",64]],30);l("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);l("gem.pause",[["paused","b"]],120);l("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);l("gem.cohorts",[["cohorts","a",8,["","o",[["experimentId","s",36],["variantKey","s",32]]]]],12,"cohorts");l("gem.earnAllowanceChanged",[],30,"earnAllowance");l("gem.inventoryChanged",[],30,"inventoryChanged");l("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");l("gem.deviceSettings",[["settings","J"]],12,"deviceSettings");l("gem.willTerminate",[["reason","e",["grant_expiring","session_ended","navigating","kill_switch"]],["graceMs","i",0,6e4]],10);l("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");l("gem.socketState",[["connected","b"],["reason","E",["connecting","dropped","watchdog","terminal"]]],12,"socketState");l("gem.seatedEvent",[["roomId","s",64]],60,"partySeating");l("gem.autoStartFailedEvent",[["roomId","s",64],["code","s",64]],30,"autoStartFailure");l("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");l("gem.signalEvent",[["event","e",["hello","offer","answer","ice","peerJoined","peerLeft","migration","matchEnded","error"]],B,["data","j"]],1800,"p2p");l("gem.relayDraining",[B,["clusterTargetId","s",64],["relayIps","a",16,$],["drainingSince","s",40],["deadline","s",40]],60,"p2pRelayDrain");l("gem.dedicatedEvent",[["event","e",["answer","error","matchEnded"]],B,["sdp","S",10240],["sessionId","S",64],["code","S",64],["message","S",256],["reason","S",64]],120,"dedicated");l("gem.partyResult",[m,["partyId","S",64]],30,"parties");l("gem.clusterTarget",[["clusterTargetId","s",64],["clusterTargetIds","A",3,$]],12,"clusterTarget");l("gem.graphicsRoutes",[["entries","a",32,["","o",[["gpu","s",32],["route","S",32],["host","S",32]]]]],12,"graphicsRoutes");l("gem.devtools",[["action","e",["open","close","toggle"]]],30,"devtools");l("gem.screenshot",[["maxWidth","i",1,7680],["maxHeight","i",1,4320]],6,"screenshot");l("gem.screenshot.denied",[["reason","e",["not_wired","no_source","unsupported","unreadable","tainted","too_large","busy","declined","failed"]],["retryable","b"]],12,"screenshot");l("gem.requestContext",[],12,"feedbackContext");l("gem.gameContext",[["context","j"]],12,"feedbackContext");l("gem.signal",[["signal","e",["join","offer","answer","ice","migrationAck","hostUnreachable"]],B,["data","j"]],1200,"p2p");l("gem.dedicatedOffer",[B,["sdp","s",10240],["intent","e",["initial","ice_restart","full_reconnect"]]],60,"dedicated");l("gem.partyRequest",[m],12,"parties");l("gem.ready",[],5);l("gem.engaged",[],5,"engagement");l("gem.progress",[["loaded","i",0,1099511627776],["total","i",0,1099511627776]],600);l("gem.requestToken",[m,["reason","e",["initial","expiring","rejected"]]],12);l("gem.requestLocalServer",[m,["gameRoomId","s",64]],6,"localHost");l("gem.localServer",[m,["serverId","S",128]],30,"localHost");l("gem.localServer.denied",[m,["retryable","b"],["reason","e",["refused","unavailable"]]],30,"localHost");l("gem.exit",[["reason","S",64]],5);l("gem.openExternal",[["url","s",2048,"url"]],6);l("gem.requestFullscreen",[["enabled","b"]],30);l("gem.audioState",[["muted","b"]],120,"audioState");l("gem.rewardCue",[["currencySlug","s",32],["cueId","S",64],["expected","I",1,1e9],["origin","O",[["x","i",0,16384],["y","i",0,16384]]]],60,"rewardCue");l("gem.rewardPresentation",[["mode","e",["arcade","game"]]],12,"rewardPresentation");l("gem.walletDisplay",[["visible","b"],["currencies","A",8,$],["score","B"]],60,"walletDisplay");l("gem.controlsDeclare",[["uses","o",[["lookSensitivity","S",16,"code"],["gamepadLookSensitivity","S",16,"code"],["invertLookY","S",16,"code"],["touchMovement","S",16,"code"]]]],60,"controls");l("gem.menu",[["settings","b"],["items","A",4,["","o",[["id","s",32],["label","s",40]]]]],60,"gameMenu");l("gem.menuSelect",[["entry","e",["settings","item"]],["id","S",32]],60,"gameMenu");l("gem.gemCorner",[["corner","e",["top-left","top-right","bottom-left","bottom-right"]]],12,"gemCorner");l("gem.menuStyle",[["ground","S",7],["accent","S",7]],12,"menuStyle");l("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");l("gem.settingChange",[["id","s",40],["value","u",40,-1e6,1e6]],120,"gameSettings");l("gem.requestShare",[["requestId","S",64],["params","a",16,["","o",[["key","s",64],["value","s",512]]]]],6,"share");l("gem.shareResult",[m,["outcome","e",["accepted","refused"]],T,["key","S",64]],30,"shareResult");l("gem.requestAvatarPicker",[["tab","E",["2d","3d"]]],6,"avatarPicker");l("gem.vibrate",[["pattern","a",99,["","i",0,1e4]]],600,"vibration");l("gem.frameStats",[["fps","i",0,1e3],["frameTimeP95Ms","i",0,1e5],["counts","E",["pageFrames","gameDraws"]]],120,"frameStats");l("gem.portraitBorders",[["name","S",40]],60,"portraitBorders");l("gem.error",[["code","e",["version_mismatch","handshake_timeout","handshake_duplicate","invalid_message","rate_limited","token_unavailable","unsupported","unsupported_capability","internal"]],["message","S",256]],60);l("gem.requestPurchase",[m,["purchaseKind","e",["item","recipe"]],["targetId","s",64],["currencySlug","s",32],["quantity","I",1,10],["catalogId","S",64],["origin","E",["sheet","direct_refused"]]],12,"purchases");l("gem.requestAvatar3dPurchase",[m,["itemId","s",64],["currencySlug","s",32]],12,"avatar3dPurchases");l("gem.purchaseResult",[m,E,T,["purchaseId","S",64]],30,"purchases");l("gem.purchaseSettled",[["purchaseKind","e",["item","recipe"]],["targetId","s",64],["catalogId","S",64],["quantity","i",1,10],["purchaseId","S",64]],30,"purchaseSettled");l("gem.deviceSettings.put",[m,["settings","j"]],30,"deviceSettings");l("gem.deviceSettings.result",[m,["outcome","e",["stored","too_large","unavailable"]]],30,"deviceSettings");l("gem.requestAd",[m,["placement","s",32],["format","e",["interstitial","rewarded"]]],6,"ads");l("gem.adResult",[m,["outcome","e",["shown","no_ad","unavailable"]]],12,"ads");l("gem.signalMoment",[m,["kind","e",["level_end","run_end","match_end","menu_return","other_break"]],["placement","S",32],["wall","B"]],6,"moments");l("gem.momentResult",[m,["shown","b"]],12,"moments");l("gem.requestSignIn",[m],6,"signIn");l("gem.signInResult",[m,["outcome","e",["signed_in","declined","unavailable"]]],12,"signIn");l("gem.requestFriendChallenge",[m,["playerId","s",64],["template","s",64],["params","J"]],12,"friendChallenges");l("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");l("gem.requestPlayInvite",[m,["params","A",16,["","o",[["key","s",64],["value","s",512]]]]],6,"playInvites");l("gem.playInviteResult",[m,["shown","b"]],12,"playInvites");l("gem.inviteParams",[["params","A",16,["","o",[["key","s",64],["value","s",512]]]]],30,"playInvites");l("gem.requestAppLinks",[m],12,"appLinks");l("gem.appLinksResult",[m,E,T,["arcade","O",[["store","e",["app_store","google_play"]]]],["game","O",[["store","e",["app_store","google_play"]]]]],30,"appLinks");l("gem.requestOpenApp",[m,["target","e",["arcade","game"]]],6,"appLinks");l("gem.openAppResult",[m,E,T],30,"appLinks");l("gem.requestOpenGame",[m,["ref","s",40,"gameRef"]],6,"openGame");l("gem.openGameResult",[m,E,T],30,"openGame");l("gem.requestSimilarGames",[m,["limit","I",1,24]],12,"openGame");l("gem.similarGamesResult",[m,E,T,["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);l("gem.requestStoreOffers",[m],12,"store");l("gem.storeOffersResult",[m,E,T,["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);l("gem.requestStorePurchase",[m,["skuId","s",64]],12,"store");l("gem.storePurchaseResult",[m,E,T],30,"store");l("gem.storePurchaseSettled",[["skuId","s",64]],30,"store");l("gem.requestStoreOfferSheet",[m,["skuId","s",64]],12,"storeOfferSheet");l("gem.storeOfferSheetResult",[m,E,T],30,"storeOfferSheet");Object.freeze(me);W.__malformed=60;Object.freeze(W);Object.freeze(ue);var L={now:()=>Date.now(),setTimeout:(n,e)=>setTimeout(n,e),clearTimeout:n=>clearTimeout(n)};function ge(n){let e=n.toLowerCase();return e==="localhost"||e.endsWith(".localhost")||e==="[::1]"||e==="::1"?true:/^127(\.\d{1,3}){3}$/.test(e)}var bn=1e4;function pe(n,e){return J(n,e)}function J(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 N({clock:e.clock,...e.onStateChange===void 0?{}:{onStateChange:e.onStateChange},request:()=>new Promise((i,d)=>{let u=e.clock.setTimeout(()=>{r=null,d({reason:"unavailable",retryable:true});},e.timeoutMs??bn);r={resolve:c=>{e.clock.clearTimeout(u),i(c);},reject:d,timer:u};})}),a=n.onServerToken(i=>{let d=t(i),u=r;if(u){r=null,u.resolve(d);return}o.accept(d);});return {source:o,dispose(){a(),o.dispose(),r&&(e.clock.clearTimeout(r.timer),r.reject({reason:"unavailable",retryable:false}),r=null);}}}var Q={};$e(Q,{acceptTransfer:()=>vn,addEntityProgression:()=>Sn,adminAction:()=>xn,cancelInventoryTransfer:()=>wn,claimEntityProgressionRewards:()=>kn,closeGameRoom:()=>An,createEntityBatchOrder:()=>On,createEntityOrder:()=>Pn,createSession:()=>Gn,deleteEntityGameSetting:()=>Tn,deleteEntitySave:()=>Cn,deleteSession:()=>In,deleteShowcaseValue:()=>En,executeEntityRecipe:()=>qn,finalizeSaveUpload:()=>Ln,getChannelAssignment:()=>Mn,getDropRates:()=>jn,getEntityCurrency:()=>$n,getEntityGameSetting:()=>Bn,getEntityInventory:()=>Fn,getEntityInventoryItem:()=>Un,getEntityLeaderboard:()=>Dn,getEntityOrder:()=>Nn,getEntityProgression:()=>Hn,getEntityRecipeAvailability:()=>Vn,getEntityRecipeUsage:()=>Wn,getEntitySave:()=>zn,getEvent:()=>Kn,getGameRoomV2:()=>Yn,getLeaderboard:()=>Jn,getPlayerGameProfile:()=>Xn,getPurchaseCatalog:()=>Qn,getResolvedTemplate:()=>Zn,getRoomArgs:()=>et,getShowcaseValue:()=>nt,getTransferDetails:()=>tt,ingestAnalyticsEvents:()=>X,initiateInventoryTransfer:()=>rt,invokeFunction:()=>ot,kickPlayer:()=>at,listChallenges:()=>st,listEntityGameSettings:()=>it,listEntityOrders:()=>lt,listEntityProgressions:()=>dt,listEntitySaves:()=>ut,listEvents:()=>ct,listGameRooms:()=>mt,listResolvedTemplates:()=>gt,listTransfers:()=>pt,maxEntityProgression:()=>yt,putEntityGameSetting:()=>ft,putRoomArgs:()=>ht,putShowcaseValue:()=>_t,rejectTransfer:()=>Rt,reportMatchPlayers:()=>bt,requestSaveUploadUrl:()=>vt,resetEntityProgression:()=>St,setMatchBackfill:()=>xt,simulateEntityOrder:()=>wt,transferHostV2:()=>kt,updateGameRoomV2:()=>At});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 vn(n,e,t){let r=`/v1/inventory/transfers/${s(e)}/accept`;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)}/add`;return n.client.post(i,o,a?.signal)}async function xn(n,e,t,r){let o=`/v1/voice/sessions/${s(e)}/admin`;return n.client.post(o,t,r?.signal)}async function wn(n,e,t){let r=`/v1/inventory/transfers/${s(e)}/cancel`;return n.client.post(r,void 0,t?.signal)}async function kn(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 An(n,e,t){let r=`/v1/games/${s(n.gameId())}/game-rooms/${s(e)}`;return n.client.delete(r,t?.signal)}async function On(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 Pn(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 Gn(n,e,t){return n.client.post("/v1/voice/sessions",e,t?.signal)}async function Tn(n,e,t,r,o){let a=`/v1/settings/${s(e)}/${s(t)}/${s(r)}`;return n.client.delete(a,o?.signal)}async function Cn(n,e,t,r,o){let a=`/v1/saves/${s(e)}/${s(t)}/${s(r)}`;return n.client.delete(a,o?.signal)}async function In(n,e,t){let r=`/v1/voice/sessions/${s(e)}`;return n.client.delete(r,t?.signal)}async function En(n,e,t,r){let o=`/v1/showcase/players/${s(e)}/${s(t)}`;return n.client.delete(o,r?.signal)}async function qn(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 Ln(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 Mn(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 jn(n,e,t){let r=`/v1/inventory/loot-tables/${s(e)}/drop-rates`;return n.client.get(r,t?.signal)}async function $n(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 Bn(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 Fn(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 Un(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 Dn(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(),d=`/v1/leaderboards/${s(e)}/${s(t)}/${s(r)}`+(i?`?${i}`:"");return n.client.get(d,o?.signal)}async function Nn(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 Hn(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 Vn(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 Wn(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 zn(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 Kn(n,e,t){let r=`/v1/events/${s(e)}`;return n.client.get(r,t?.signal)}async function Yn(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 Jn(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 Xn(n,e,t){let r=`/v1/profiles/players/${s(e)}`;return n.client.get(r,t?.signal)}async function Qn(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 Zn(n,e,t){let r=`/v1/game-room-templates/${s(e)}`;return n.client.get(r,t?.signal)}async function et(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 nt(n,e,t,r){let o=`/v1/showcase/players/${s(e)}/${s(t)}`;return n.client.get(o,r?.signal)}async function tt(n,e,t){let r=`/v1/inventory/transfers/${s(e)}`;return n.client.get(r,t?.signal)}async function X(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 rt(n,e,t){return n.client.post("/v1/inventory/transfers",e,t?.signal)}async function ot(n,e,t){let r=new URLSearchParams;t?.cue_id!==void 0&&r.set("cue_id",String(t?.cue_id));let o=r.toString(),a="/v1/functions/invoke"+(o?`?${o}`:"");return n.client.postBytes(a,e,t?.signal)}async function at(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 st(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 it(n,e,t,r){let o=`/v1/settings/${s(e)}/${s(t)}`;return n.client.get(o,r?.signal)}async function lt(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 dt(n,e,t,r){let o=`/v1/inventory/${s(e)}/${s(t)}/progressions`;return n.client.get(o,r?.signal)}async function ut(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 ct(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 mt(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 gt(n,e){return n.client.get("/v1/game-room-templates",e?.signal)}async function pt(n,e){let t=new URLSearchParams;e.entity_type!==void 0&&t.set("entity_type",String(e.entity_type)),e.entity_id!==void 0&&t.set("entity_id",String(e.entity_id)),e?.direction!==void 0&&t.set("direction",String(e?.direction)),e?.status!==void 0&&t.set("status",String(e?.status)),e?.cursor!==void 0&&t.set("cursor",String(e?.cursor)),e?.limit!==void 0&&t.set("limit",String(e?.limit));let r=t.toString(),o="/v1/inventory/transfers"+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function yt(n,e,t,r,o,a){let i=`/v1/inventory/${s(e)}/${s(t)}/progressions/${s(r)}/max`;return n.client.post(i,o,a?.signal)}async function ft(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 ht(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 _t(n,e,t,r,o){let a=`/v1/showcase/players/${s(e)}/${s(t)}`;return n.client.put(a,r,o?.signal)}async function Rt(n,e,t){let r=`/v1/inventory/transfers/${s(e)}/reject`;return n.client.post(r,void 0,t?.signal)}async function bt(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 vt(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 St(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 xt(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 wt(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 kt(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 At(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 ye="gem_";function fe(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 Gt=1e4,Tt=50,Ct=1e3,It=65536-4*1024,he=n=>typeof n=="number"?n:0,Et=n=>typeof n=="string"?n:"";function _e(){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 qt(n){return n?.retryable===true}function Lt(n,e){let t=n??{},r=Array.isArray(t.rejected)?t.rejected.map(o=>{let a=o??{};return {index:he(a.index),code:Et(a.code)}}):[];return {accepted:he(t.accepted),rejected:r,dropped:e,duplicate:t.duplicate===true}}function Re(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 be(n){let e=Math.max(1,Math.floor(n.maxQueue??Ct)),t={client:n.client,gameId:()=>n.gameId},r=[],o=0,a=null,i=false,d=null,u=0,c=0,g=false,S=false,w=_=>{n.log?.(_);},b=()=>{a!==null&&(n.clock.clearTimeout(a),a=null);},y=()=>Math.max(0,c-n.clock.now()),x=()=>{a!==null||i||d!==null||(a=n.clock.setTimeout(()=>{a=null,P().catch(()=>{});},Math.max(Gt,y())));},A=()=>{let _=Math.min(r.length,100),R=128;for(let G=0;G<_;G+=1){let C=r[G];if(C===void 0)break;if(R+=JSON.stringify(Re(C,0)).length+1,R>It)return Math.max(1,G)}return _};async function P(_){for(;d!==null;)await d.catch(()=>{});if(r.length===0)return {accepted:0,rejected:[],dropped:0,duplicate:false};let R=Le(_);d=R;try{return await R}finally{d===R&&(d=null),r.length>0&&x();}}async function Le(_){b();let R=r.splice(0,A()),G=o;o=0;let C=Math.round(n.clock.now()),D={batch_id:_e(),sent_at_ms:C,events:R.map(k=>Re(k,C))};try{let k=await X(t,D,_===void 0?void 0:{signal:_}),I=Lt(k,G);u=0,c=0;for(let Me of I.rejected)w(`[gem] analytics: an event was refused (${Me.code}). See the analytics_events section of your game config.`);return I}catch(k){if(qt(k)){for(r=[...R,...r],o+=G;r.length>e;)r.shift(),o+=1;u+=1,c=n.clock.now()+fe(u,k);}else w(`[gem] analytics: ${R.length} event(s) were discarded \u2014 the platform refused the batch and will refuse it again: ${String(k)}`);throw k}}return {track(_,R,G={}){if(i)return;if(typeof _!="string"||_===""){S||(S=true,w(`[gem] analytics: '${R}' 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(R.startsWith(ye)){g||(g=true,w(`[gem] analytics: '${R}' 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 C={},D={};for(let[k,I]of Object.entries(G))typeof I=="string"?C[k]=I:typeof I=="number"&&Number.isFinite(I)&&(D[k]=I);for(;r.length>=e;)r.shift(),o+=1;r.push({uid:_e(),playerId:_,name:R,atMs:n.clock.now(),dimensions:C,measures:D}),r.length>=Tt&&d===null&&y()===0?P().catch(()=>{}):x();},flush:_=>P(_),get pending(){return r.length},dispose(){i=true,b(),r=[],o=0;}}}function Mt(n){return typeof n=="string"&&/^[\w-]{1,64}$/.test(n)}function ve(n,e){if(n===void 0||Mt(n))return n;let t=typeof n=="string"?JSON.stringify(n.slice(0,72)):`a value of type ${typeof n}`;console.warn(`[gem] ${e}: cueId ${t} is not 1 to 64 letters, digits, _ or -, so it was left out. Use one crypto.randomUUID() per award.`);}var jt=new Map([["function_error",false],["function_failed",false],["function_timeout",false],["function_not_published",false],["function_input_too_large",false],["invalid_cue_id",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]]),F=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:jt.get(this.code))??super.retryable}},M=class{#e;constructor(e){this.#e=e;}async invoke(e,t={}){let r=$t(e),o=ve(t.cueId,"functions.invoke"),a;try{a=await this.#e(r,{...t.signal===void 0?{}:{signal:t.signal},...o===void 0?{}:{cue_id:o}});}catch(i){throw i instanceof p?Ft(i):i}return Bt(a)}};function $t(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 Bt(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 Ft(n){let{details:e,invocationId:t}=se(n),o=e?.untrusted?.message,a=e?.reason;return new F(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:"",Ut=/(?:Z|[+-]\d{2}:?\d{2})$/i;function Se(n){let e=O(n);if(!Ut.test(e))return 0;let t=Date.parse(e);return Number.isFinite(t)?Math.floor(t/1e3):0}var Dt=/^[0-9a-f]{1,64}$/,Nt=/^[0-9a-f]{16}$/,Ht=/^[A-Za-z][A-Za-z0-9_+\-/]{0,63}$/,Vt=/^(?:[01]\d|2[0-3]):[0-5]\d$/;function Wt(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 zt=4096,Kt=new TextEncoder;function Yt(n){let e=O(n.challenge_data),t=O(n.challenge_data_hash);return e===""||!Nt.test(t)?{}:Kt.encode(e).length>zt?{}:{data:e,dataHash:t}}function Jt(n){let e=n??{},t=Se(e.period_start_at),r=Se(e.period_ends_at);if(t===0||r===0)return;let o=O(e.slug),a=O(e.seed),i=Wt(e.period_local_date),d=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:Ht.test(d)?d:"",resetTime:Vt.test(u)?u:"",seed:Dt.test(a)?a:"",...Yt(e)}}function xe(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 we(n){let e=n??{};return Array.isArray(e.challenges)?e.challenges.map(Jt).filter(t=>t!==void 0):[]}function ke(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().");xe(r);let a=await n({player_id:t,...r===void 0?{}:{periods_back:r},...o===void 0?{}:{signal:o}});return we(a)}}}function Xt(n){let e={};for(let[t,r]of Object.entries(Q))if(typeof r=="function"){let o=r;e[t]=(...a)=>o(n,...a);}return e}function z(n,e={}){let t=e.clock??L,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=J(n,{clock:t,...e.onAuthStateChange===void 0?{}:{onStateChange:e.onAuthStateChange}}),a=ie({baseUrl:r,tokenSource:o.source,defaultQuery:{game_id:n.gameId,channel:n.channel},...e.fetch===void 0?{}:{fetch:e.fetch}}),i=new q({transport:a,clock:t}),d={gameId:n.gameId,channel:n.channel,matchId:n.matchId,...n.gameRoomId===void 0?{}:{gameRoomId:n.gameRoomId}},u=Xt({client:i,gameId:()=>d.gameId}),c=d.gameRoomId,g=n.endMatch,S=n.log,w=be({client:i,clock:t,gameId:d.gameId,...typeof S=="function"?{log:y=>S.call(n,y)}:{}});return {identity:d,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(d.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(d.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:ke(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 Qt=["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"],Zt=new Set(Qt);function Ae(n){return typeof n=="string"&&Zt.has(n)?n:"unknown"}var Ge="[gem: use gem.text.toPlain()]",Oe=new Set,Pe;function er(n){try{if(Oe.has(n))return;let e=globalThis.location;if(Pe??=!!e?.port&&ge(e.hostname??""),!Pe)return;Oe.add(n),console.warn(`[gem] ${n} is PlayerText, turned into a string: players see ${Ge}. Render text.toPlain(value) (text is in @indiegems/gem-web-sdk/sdk).
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 er(this.#n),Ge}toJSON(){return this.toString()}get[Symbol.toStringTag](){return "PlayerText"}static unwrap(e){return e.#e}};function U(n,e){return new v(n,e)}var Te={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 Ce="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 Z(n,e={}){let t=e.clock??L,r=()=>{let d=n();if(d===null)throw new Error(Ce);return d},o=null,a=()=>{if(o===null)throw new Error(Ce);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(d){let c=r().profile?.(d);if(!c)return null;let g=c.displayName;return typeof g!="string"||g===""?null:{displayName:U(g,"profile.displayName"),...typeof c.displayTag=="string"&&c.displayTag!==""?{displayTag:U(c.displayTag,"profile.displayTag")}:{},...typeof c.discriminator=="string"?{discriminator:c.discriminator}:{}}},playerNumber(d){return r().playerNumber?.(d)},send(d,u,c){c===void 0?r().send(d,u):r().send(d,u,c);},broadcast(d,u){u===void 0?r().broadcast(d):r().broadcast(d,u);},kick(d,u){u===void 0?r().kick(d):r().kick(d,u);},log(d){r().log(d);},warn(d){r().warn(d);}},attach:()=>{o=z(r(),{...e,clock:t});}}}function Ie(n,e={}){let{server:t,attach:r}=Z(()=>n,e);return r(),t}function nr(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:Ae(e)}}}var tr=1e4;function rr(n){let e=false;return t=>{if(e)return;let r;try{r=n.match.reportPlayers([{playerId:t,state:"connected"}],AbortSignal.timeout(tr));}catch{return}r.catch(o=>{o instanceof p&&o.status>=400&&o.status<500&&(e=o.status!==429);});}}function Ee(n,e={}){return ()=>{let t=null,{server:r,attach:o}=Z(()=>t,e),a=n(r),i={async init(u){t=u,o(),await a.init?.();},async shutdown(u){let c=nr(u);try{await a.shutdown?.(c);}finally{r.dispose();}}},d=rr(r);return i.join=(u,c)=>(d(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 or=new Set(["unlocked","already_unlocked","suppressed"]);function qe(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"||!or.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,H as CONDITIONAL_HEADERS,M as FunctionsApi,p as GemApiError,q as GemClient,F as GemFunctionError,v as PlayerText,f as TransportRefusal,qe as achievementReceipts,U as asPlayerText,z as createGemServer,pe as createHostTokenSource,Ie as createMatchServer,Ee as defineServer,L as systemClock,Te as text,te as toBase64};//# sourceMappingURL=gem-web-sdk.server.js.map
1
+ var je=Object.defineProperty;var $e=(t,e)=>{for(var n in e)je(t,n,{get:e[n],enumerable:true});};globalThis.__gemWebSdkVersion="[gem-web-sdk:sdkVersion:23.1.0]";var Be={initialDelayMs:2e3,maxDelayMs:6e4};function Fe(t,e){return e!==void 0?!e:t==="chain_exhausted"}var N=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:n,maxDelayMs:r}=Be,o=Math.min(r,n*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 n=this.generation;this.enter("pending");let r=this.options.request(e).then(o=>{if(n!==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=Ue(o),{retryable:i,retryAfterMs:d}=o??{};throw n===this.generation&&(Fe(a,typeof i=="boolean"?i:void 0)?this.enter("lost",a):(this.scheduleRetry(typeof d=="number"&&Number.isFinite(d)&&d>0?d: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,n){(e==="ready"||e==="lost")&&this.cancelRetry(),e==="ready"&&(this.failures=0,this.notBefore=0),this.failure=n??(e==="ready"?null:this.failure),this.state!==e&&(this.state=e,this.options.onStateChange?.(e,n));}renewBefore(){return this.options.renewBeforeSeconds??60}seconds(){return Math.floor(this.options.clock.now()/1e3)}},h=class t extends Error{constructor(n,r){super(`auth ${n}: ${r}`);this.reason=n;this.name="AuthError";}reason;static isAuthError(n){if(n instanceof t)return true;let r=n;return r?.name==="AuthError"&&typeof r.reason=="string"}};function Ue(t){if(t instanceof h)return t.reason;let e=t?.reason;return typeof e=="string"&&["chain_exhausted","unavailable","timeout","internal"].includes(e)?e:"internal"}var f=class t extends Error{retryable=false;constructor(e){super(e),this.name="TransportRefusal";}static isRefusal(e){if(e instanceof t)return true;let n=e;return n?.name==="TransportRefusal"&&n.retryable===false}},H=["if-match","if-none-match"],ee=4096;function De(t){if(!t)return;let e={};for(let[n,r]of Object.entries(t)){let o=n.toLowerCase();if(!H.includes(o)||r===void 0)continue;let a=typeof r=="string"?Ne(r):r;if(typeof a!="string"||a.length>ee||!He(a))throw new f(`the ${o} header value cannot be sent \u2014 it is not a string, is longer than ${ee} 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 Ne(t){let e=o=>o===32||o===9||o===10||o===13,n=0,r=t.length;for(;n<r&&e(t.charCodeAt(n));)n++;for(;r>n&&e(t.charCodeAt(r-1));)r--;return t.slice(n,r)}function He(t){for(let e=0;e<t.length;e++){let n=t.charCodeAt(e);if(n!==9&&(n<32||n===127||n>255))return false}return true}function Ve(t){let{bytes:e}=t;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(t.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 te(t,e){let n=e.replayUnauthorizedOnce??true;return {async request(r){let o={...r},a=De(o.headers),i=Ve(o),d=Object.freeze({...o,headers:a,...i===void 0?{}:{bytes:i}}),u=await e.tokenSource.get(),c=await t(d,u);if(c.status!==401||!n)return c;e.tokenSource.invalidate(u);let g=await e.tokenSource.get(),S=await t(d,g);if(S.status===401)throw e.tokenSource.close("unavailable"),new h("unavailable","the server refused a freshly minted token");return S}}}function ne(t){let e=typeof t=="string"?new TextEncoder().encode(t):t;return btoa(We(e))}function We(t){let n="";for(let r=0;r<t.length;r+=32768)n+=String.fromCharCode(...t.subarray(r,r+32768));return n}var p=class extends Error{constructor(n,r,o,a,i){super(`${n} (${r}): ${o}`);this.reason=n;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"}},ae=new WeakMap;function se(t){return ae.get(t)??{}}var ze=new Set([408,429,500,502,503,504]),Ke=6e4,Ye=new WeakMap;function re(t){return t!==null&&(t.reason==="rate_limited"||t.retryAfterSeconds!==void 0)}function Je(t){if(t===void 0)return 2;if(!Number.isInteger(t)||t<0||t>10)throw new f(`maxRetries must be a whole number between 0 and 10; received ${JSON.stringify(t)}. This is a configuration fault, not a server failure.`);return t}var q=class{constructor(e){this.options=e;}options;async get(e,n){return this.send({method:"GET",path:e,signal:n},true)}async getWithEtag(e,n={}){let r=await this.sendRaw({method:"GET",path:e,...n.signal===void 0?{}:{signal:n.signal},...n.ifNoneMatch===void 0?{}:{headers:{"if-none-match":n.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,n,r,o={}){return this.send({method:"PUT",path:e,body:n,signal:r,...j(o)},o.replaySafe===true,o.retryRateLimited!==false)}async post(e,n,r,o={}){return this.send({method:"POST",path:e,body:n,signal:r,...j(o)},o.replaySafe===true,o.retryRateLimited!==false)}async postBytes(e,n,r,o={}){let a=await this.sendRaw({method:"POST",path:e,bytes:n,responseType:"bytes",signal:r,...j(o)},o.replaySafe===true,o.retryRateLimited!==false);return {bytes:Xe(a.body),...a.invocationId===void 0?{}:{invocationId:a.invocationId}}}async patch(e,n,r,o={}){return this.send({method:"PATCH",path:e,body:n,signal:r,...j(o)},o.replaySafe===true,o.retryRateLimited!==false)}async delete(e,n,r={}){return this.send({method:"DELETE",path:e,signal:n,...j(r)},r.replaySafe===true,r.retryRateLimited!==false)}async send(e,n,r=true){return (await this.sendRaw(e,n,r)).body}async sendRaw(e,n,r=true){let o=n?Je(this.options.maxRetries)+1:1,a=null;if(e.signal?.aborted)throw oe(e.signal);let i=e.signal===void 0?void 0:Ye.get(e.signal);for(let d=0;d<o;d++){if(d>0){let g=this.backoffMs(d,a);if(re(a)&&i!==void 0&&g>=i())throw a;await this.backoff(g,e.signal);}if(e.signal?.aborted)throw re(a)&&i!==void 0&&i()<=0?a:oe(e.signal);let u;try{u=await this.options.transport.request(e);}catch(g){if(h.isAuthError(g)||f.isRefusal(g)||e.signal?.aborted||Qe(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=Ze(u);if(!ze.has(u.status)||u.status===429&&!r)throw c;a=c;}throw a??new p("unavailable",0,"no attempt was made")}backoffMs(e,n){let r=n?.retryAfterSeconds,o=r!==void 0?r*1e3:2**(e-1)*250,a=2**(e-1)*250;return Math.min(Math.max(o,a),Ke)}backoff(e,n){return n?.aborted?Promise.resolve():new Promise(r=>{let o=this.options.clock,a=false,i=false,d,u=()=>{a||(a=true,i&&o.clearTimeout(d),n?.removeEventListener("abort",u),r());};n?.addEventListener("abort",u,{once:true}),d=o.setTimeout(u,e),i=true,a&&o.clearTimeout(d);})}};function Xe(t){if(t instanceof Uint8Array)return t;if(t==null)return new Uint8Array(0);let e=typeof t=="string"?t:JSON.stringify(t);return new TextEncoder().encode(e)}function j(t){return {...t.keepalive===void 0?{}:{keepalive:t.keepalive},...t.ifMatch===void 0?{}:{headers:{"if-match":t.ifMatch}}}}function oe(t){return t.reason!==void 0?t.reason:new DOMException("The operation was aborted.","AbortError")}function Qe(t){let e=t?.name;return e==="AbortError"||e==="TimeoutError"}function Ze(t){let e=tt(t),n=rt(t.body),r={...n===void 0?{}:{details:n},...t.invocationId===void 0?{}:{invocationId:t.invocationId}};return Object.keys(r).length>0&&ae.set(e,r),e}var et=new Map([["insufficient_funds","insufficient_funds"]]);function tt(t){let{status:e,body:n}=t,r=nt(n),o=t.retryAfterSeconds??at(n),a=ot(n),i=a===void 0?void 0:et.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 nt(t){if(typeof t=="string")return t;let e=t?.message;if(typeof e=="string")return e;let n=t?.error;if(typeof n=="string")return n;let r=n?.message;return typeof r=="string"?r:"no detail"}function rt(t){let n=t?.error?.details;return n===null?void 0:n}function ot(t){let n=t?.error?.code;return typeof n=="string"&&n.length>0?n:void 0}function at(t){let e=t?.retryAfterSeconds;return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:void 0}function st(t){let e=t.lastIndexOf("@");return (e===-1?t:`***@${t.slice(e+1)}`).slice(0,200)}var it=new Set(H);function lt(t){if(!t)return {};let e={};for(let[n,r]of Object.entries(t))it.has(n.toLowerCase())&&(e[n.toLowerCase()]=r);return e}function ie(t){let e=t.fetch??globalThis.fetch.bind(globalThis);return te(async(n,r)=>{let o;try{o=new URL(t.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(/\/+$/,"")+n.path);}catch{throw new f(`${JSON.stringify(typeof n.path=="string"?st(n.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 b=o.username!==""||o.password!=="",y=a.username!==o.username||a.password!==o.password,x=b?y?"baseUrl (and possibly the request path)":"baseUrl":"request path";throw new f(`the ${x} puts credentials in the URL, which cannot be fetched (${n.method} ${a.pathname}). The value is withheld here rather than written to logs. This is a malformed request, not a server failure.`)}for(let[b,y]of Object.entries(t.defaultQuery??{}))a.searchParams.has(b)||a.searchParams.set(b,y);let i=n.bytes,d=n.bytes===void 0?void 0:"application/octet-stream";try{n.body!==void 0&&(i=JSON.stringify(n.body),d="application/json");}catch(b){throw new f(`the body of ${n.method} ${JSON.stringify(a.pathname)} could not be serialised to JSON: ${String(b)}. 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:n.method,headers:{authorization:`Bearer ${r}`,...d===void 0?{}:{"content-type":d},...lt(n.headers)},body:i,signal:n.signal,...n.keepalive===void 0?{}:{keepalive:n.keepalive},credentials:"omit",mode:"cors",redirect:"error",cache:"no-store",referrerPolicy:"no-referrer"}),c=null;if(n.responseType==="bytes"&&u.status>=200&&u.status<300)c=new Uint8Array(await u.arrayBuffer());else {let b=await u.text();if(b.length>0)try{c=JSON.parse(b);}catch{c=b;}}let g=u.headers.get("etag"),S=dt(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}}},t)}function dt(t){if(t===null)return;let e=t.trim();if(!/^\d+$/.test(e))return;let n=Number(e);return Number.isFinite(n)?n:void 0}var ut="gem-web-bridge";var ct=65536,le=8,V=5e3,de=1024;var W=Object.create(null);var ue=Object.create(null);function mt(t){let e=/^([a-z][a-z0-9+.-]*):\/\/([a-z0-9.-]+|\[[0-9a-f:.]+\])(:([0-9]{1,5}))?$/i.exec(t);return e===null?false:e[4]===void 0||Number(e[4])<=65535}function gt(t){let e;try{e=new URL(t);}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 pt(t){return /^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i.test(t)}function yt(t){return /^[a-z_]+$/.test(t)}function ft(t){return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(t)||/^[a-z0-9][a-z0-9-]{1,38}[a-z0-9]$/.test(t)&&!t.includes("--")}function K(t,e,n){if(e>le)return `nesting deeper than ${le}`;if(++n.nodes>V)return `more than ${V} values`;if(n.bytes>n.cap)return `over the ${n.cap} byte limit`;if(t==null)return n.bytes+=4,null;let r=typeof t;if(r==="boolean")return n.bytes+=5,null;if(r==="number")return n.bytes+=8,null;if(r==="string")return n.bytes+=t.length*3+2,null;if(r!=="object")return `${r} is not plain data`;let o=t;if(n.seen.has(o))return "a repeated or cyclic object reference";if(n.seen.add(o),Array.isArray(t)){if(t.length>de)return `an array of ${t.length} entries, over the ${de} limit`;n.bytes+=2;for(let d of t){let u=K(d,e+1,n);if(u)return u}return null}let a=Object.getPrototypeOf(t);if(a!==Object.prototype&&a!==null)return "a value that is not a plain object";n.bytes+=2;let i=t;for(let d in i){if(!Object.prototype.hasOwnProperty.call(i,d))continue;if(++n.nodes>V)return `more than ${V} values`;if(n.bytes+=d.length*3+4,n.bytes>n.cap)return `over the ${n.cap} byte limit`;let u=K(i[d],e+1,n);if(u)return u}return null}function ht(t,e=ct){let n={nodes:0,bytes:0,seen:new Set,cap:e},r=K(t,0,n);return r?`message contains ${r}`:n.bytes>e?`message is over the ${e} byte limit`:null}var _t={origin:[mt,"not a well-formed origin"],url:[gt,"not a safe absolute http(s) URL"],bcp47:[pt,"not a well-formed BCP 47 tag"],code:[yt,"not a code of lower-case letters and underscores"],gameRef:[ft,"not a game id or web address"]};function ce(t,e,n){for(let r of e){let o=n===""?r[0]:`${n}.${r[0]}`,a=t[r[0]];if(a==null){if(r[1]<"a")continue;return `${o}: required`}let i=Y(a,r,o);if(i)return i}return null}function Y(t,e,n){let r=e[1].toLowerCase();switch(r){case "u":return typeof t=="boolean"?null:Y(t,typeof t=="string"?[e[0],"s",e[2]]:[e[0],"n",e[3],e[4]],n);case "s":{if(typeof t!="string")return `${n}: expected string`;if(t.length>e[2])return `${n}: exceeds ${e[2]} characters`;if(e[3]){let[o,a]=_t[e[3]];if(!o(t))return `${n}: ${a}`}return null}case "n":case "i":return typeof t!="number"||!(r=="i"?Number.isInteger:Number.isFinite)(t)?`${n}: expected ${r=="i"?"integer":"number"}`:t<e[2]||t>e[3]?`${n}: out of range ${e[2]}..${e[3]}`:null;case "b":return typeof t=="boolean"?null:`${n}: expected boolean`;case "e":{let o=e[2];return o.includes(t)?null:`${n}: not one of ${o.join("|")}`}case "o":return typeof t!="object"||t===null||Array.isArray(t)?`${n}: expected object`:ce(t,e[2],n);case "j":return typeof t!="object"||t===null||Array.isArray(t)?`${n}: expected a plain object`:null;case "a":{if(!Array.isArray(t))return `${n}: expected array`;if(t.length>e[2])return `${n}: exceeds ${e[2]} items`;let o=e[3],a=`${n}[]`;for(let i of t){if(i==null){if(o[1]<"a")continue;return `${a}: required`}let d=Y(i,o,a);if(d)return d}return null}default:return `${n}: unknown kind ${String(r)}`}}var me=Object.create(null);function l(t,e,n,r,o){return W[t]=n,r&&(ue[t]=r),me[t]=a=>{let i=ht(a,o);if(i)return i;if(typeof a!="object"||a===null||Array.isArray(a))return "message: expected object";let d=a;return d.gem!==ut?"gem: wrong protocol marker":d.type!==t?`type: expected ${t}`:ce(d,e,"")}}var $=["","s",64],m=["requestId","s",64],B=["matchId","s",64],T=["reason","S",64,"code"],E=["outcome","e",["ok","declined","unavailable"]];l("gem.handshake",[["versions","o",[["min","i",1,1e3],["max","i",1,1e3]]],["capabilities","A",64,$],["embedder","s",2048,"origin"],["unbidden","B"]],30);l("gem.handshake.accept",[["v","i",1,1e3],["capabilities","A",64,$]],5);l("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);l("gem.token.denied",[m,["retryable","b"],["retryAfterMs","I",0,36e5],["reason","e",["chain_exhausted","unavailable"]],["correlationId","s",64]],30);l("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);l("gem.pause",[["paused","b"]],120);l("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"],["textScale","I",100,200]]]],60);l("gem.cohorts",[["cohorts","a",8,["","o",[["experimentId","s",36],["variantKey","s",32]]]]],12,"cohorts");l("gem.earnAllowanceChanged",[],30,"earnAllowance");l("gem.inventoryChanged",[],30,"inventoryChanged");l("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");l("gem.deviceSettings",[["settings","J"]],12,"deviceSettings");l("gem.willTerminate",[["reason","e",["grant_expiring","session_ended","navigating","kill_switch"]],["graceMs","i",0,6e4]],10);l("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");l("gem.socketState",[["connected","b"],["reason","E",["connecting","dropped","watchdog","terminal"]]],12,"socketState");l("gem.seatedEvent",[["roomId","s",64]],60,"partySeating");l("gem.autoStartFailedEvent",[["roomId","s",64],["code","s",64]],30,"autoStartFailure");l("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");l("gem.signalEvent",[["event","e",["hello","offer","answer","ice","peerJoined","peerLeft","migration","matchEnded","error"]],B,["data","j"]],1800,"p2p");l("gem.relayDraining",[B,["clusterTargetId","s",64],["relayIps","a",16,$],["drainingSince","s",40],["deadline","s",40]],60,"p2pRelayDrain");l("gem.dedicatedEvent",[["event","e",["answer","error","matchEnded"]],B,["sdp","S",10240],["sessionId","S",64],["code","S",64],["message","S",256],["reason","S",64]],120,"dedicated");l("gem.partyResult",[m,["partyId","S",64]],30,"parties");l("gem.clusterTarget",[["clusterTargetId","s",64],["clusterTargetIds","A",3,$]],12,"clusterTarget");l("gem.graphicsRoutes",[["entries","a",32,["","o",[["gpu","s",32],["route","S",32],["host","S",32]]]]],12,"graphicsRoutes");l("gem.devtools",[["action","e",["open","close","toggle"]]],30,"devtools");l("gem.screenshot",[["maxWidth","i",1,7680],["maxHeight","i",1,4320]],6,"screenshot");l("gem.screenshot.denied",[["reason","e",["not_wired","no_source","unsupported","unreadable","tainted","too_large","busy","declined","failed"]],["retryable","b"]],12,"screenshot");l("gem.requestContext",[],12,"feedbackContext");l("gem.gameContext",[["context","j"]],12,"feedbackContext");l("gem.signal",[["signal","e",["join","offer","answer","ice","migrationAck","hostUnreachable"]],B,["data","j"]],1200,"p2p");l("gem.dedicatedOffer",[B,["sdp","s",10240],["intent","e",["initial","ice_restart","full_reconnect"]]],60,"dedicated");l("gem.partyRequest",[m],12,"parties");l("gem.ready",[],5);l("gem.engaged",[],5,"engagement");l("gem.progress",[["loaded","i",0,1099511627776],["total","i",0,1099511627776]],600);l("gem.requestToken",[m,["reason","e",["initial","expiring","rejected"]]],12);l("gem.requestLocalServer",[m,["gameRoomId","s",64]],6,"localHost");l("gem.localServer",[m,["serverId","S",128]],30,"localHost");l("gem.localServer.denied",[m,["retryable","b"],["reason","e",["refused","unavailable"]]],30,"localHost");l("gem.exit",[["reason","S",64]],5);l("gem.openExternal",[["url","s",2048,"url"]],6);l("gem.requestFullscreen",[["enabled","b"]],30);l("gem.audioState",[["muted","b"]],120,"audioState");l("gem.rewardCue",[["currencySlug","s",32],["cueId","S",64],["expected","I",1,1e9],["origin","O",[["x","i",0,16384],["y","i",0,16384]]]],60,"rewardCue");l("gem.rewardPresentation",[["mode","e",["arcade","game"]]],12,"rewardPresentation");l("gem.walletDisplay",[["visible","b"],["currencies","A",8,$],["score","B"]],60,"walletDisplay");l("gem.controlsDeclare",[["uses","o",[["lookSensitivity","S",16,"code"],["gamepadLookSensitivity","S",16,"code"],["invertLookY","S",16,"code"],["touchMovement","S",16,"code"]]]],60,"controls");l("gem.menu",[["settings","b"],["items","A",4,["","o",[["id","s",32],["label","s",40]]]]],60,"gameMenu");l("gem.menuSelect",[["entry","e",["settings","item"]],["id","S",32]],60,"gameMenu");l("gem.gemCorner",[["corner","e",["top-left","top-right","bottom-left","bottom-right"]]],12,"gemCorner");l("gem.menuStyle",[["ground","S",7],["accent","S",7]],12,"menuStyle");l("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");l("gem.settingChange",[["id","s",40],["value","u",40,-1e6,1e6]],120,"gameSettings");l("gem.requestShare",[["requestId","S",64],["params","a",16,["","o",[["key","s",64],["value","s",512]]]]],6,"share");l("gem.shareResult",[m,["outcome","e",["accepted","refused"]],T,["key","S",64]],30,"shareResult");l("gem.requestAvatarPicker",[["tab","E",["2d","3d"]]],6,"avatarPicker");l("gem.vibrate",[["pattern","a",99,["","i",0,1e4]]],600,"vibration");l("gem.frameStats",[["fps","i",0,1e3],["frameTimeP95Ms","i",0,1e5],["counts","E",["pageFrames","gameDraws"]]],120,"frameStats");l("gem.portraitBorders",[["name","S",40]],60,"portraitBorders");l("gem.error",[["code","e",["version_mismatch","handshake_timeout","handshake_duplicate","invalid_message","rate_limited","token_unavailable","unsupported","unsupported_capability","internal"]],["message","S",256]],60);l("gem.requestPurchase",[m,["purchaseKind","e",["item","recipe"]],["targetId","s",64],["currencySlug","s",32],["quantity","I",1,10],["catalogId","S",64],["origin","E",["sheet","direct_refused"]]],12,"purchases");l("gem.requestAvatar3dPurchase",[m,["itemId","s",64],["currencySlug","s",32]],12,"avatar3dPurchases");l("gem.purchaseResult",[m,E,T,["purchaseId","S",64]],30,"purchases");l("gem.purchaseSettled",[["purchaseKind","e",["item","recipe"]],["targetId","s",64],["catalogId","S",64],["quantity","i",1,10],["purchaseId","S",64]],30,"purchaseSettled");l("gem.deviceSettings.put",[m,["settings","j"]],30,"deviceSettings");l("gem.deviceSettings.result",[m,["outcome","e",["stored","too_large","unavailable"]]],30,"deviceSettings");l("gem.requestAd",[m,["placement","s",32],["format","e",["interstitial","rewarded"]]],6,"ads");l("gem.adResult",[m,["outcome","e",["shown","no_ad","unavailable"]]],12,"ads");l("gem.signalMoment",[m,["kind","e",["level_end","run_end","match_end","menu_return","other_break"]],["placement","S",32],["wall","B"]],6,"moments");l("gem.momentResult",[m,["shown","b"]],12,"moments");l("gem.requestSignIn",[m],6,"signIn");l("gem.signInResult",[m,["outcome","e",["signed_in","declined","unavailable"]]],12,"signIn");l("gem.requestFriendChallenge",[m,["playerId","s",64],["template","s",64],["params","J"]],12,"friendChallenges");l("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");l("gem.requestPlayInvite",[m,["params","A",16,["","o",[["key","s",64],["value","s",512]]]]],6,"playInvites");l("gem.playInviteResult",[m,["shown","b"]],12,"playInvites");l("gem.inviteParams",[["params","A",16,["","o",[["key","s",64],["value","s",512]]]]],30,"playInvites");l("gem.requestAppLinks",[m],12,"appLinks");l("gem.appLinksResult",[m,E,T,["arcade","O",[["store","e",["app_store","google_play"]]]],["game","O",[["store","e",["app_store","google_play"]]]]],30,"appLinks");l("gem.requestOpenApp",[m,["target","e",["arcade","game"]]],6,"appLinks");l("gem.openAppResult",[m,E,T],30,"appLinks");l("gem.requestOpenGame",[m,["ref","s",40,"gameRef"]],6,"openGame");l("gem.openGameResult",[m,E,T],30,"openGame");l("gem.requestSimilarGames",[m,["limit","I",1,24]],12,"openGame");l("gem.similarGamesResult",[m,E,T,["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);l("gem.requestStoreOffers",[m],12,"store");l("gem.storeOffersResult",[m,E,T,["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);l("gem.requestStorePurchase",[m,["skuId","s",64]],12,"store");l("gem.storePurchaseResult",[m,E,T],30,"store");l("gem.storePurchaseSettled",[["skuId","s",64]],30,"store");l("gem.requestStoreOfferSheet",[m,["skuId","s",64]],12,"storeOfferSheet");l("gem.storeOfferSheetResult",[m,E,T],30,"storeOfferSheet");Object.freeze(me);W.__malformed=60;Object.freeze(W);Object.freeze(ue);var L={now:()=>Date.now(),setTimeout:(t,e)=>setTimeout(t,e),clearTimeout:t=>clearTimeout(t)};function ge(t){let e=t.toLowerCase();return e==="localhost"||e.endsWith(".localhost")||e==="[::1]"||e==="::1"?true:/^127(\.\d{1,3}){3}$/.test(e)}var Rt=1e4;function pe(t,e){return J(t,e)}function J(t,e){if(typeof t.serverToken!="function"||typeof t.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 n=i=>({token:i.token,expiresAt:i.expiresAt,chainEndsAt:Number.POSITIVE_INFINITY}),r=null,o=new N({clock:e.clock,...e.onStateChange===void 0?{}:{onStateChange:e.onStateChange},request:()=>new Promise((i,d)=>{let u=e.clock.setTimeout(()=>{r=null,d({reason:"unavailable",retryable:true});},e.timeoutMs??Rt);r={resolve:c=>{e.clock.clearTimeout(u),i(c);},reject:d,timer:u};})}),a=t.onServerToken(i=>{let d=n(i),u=r;if(u){r=null,u.resolve(d);return}o.accept(d);});return {source:o,dispose(){a(),o.dispose(),r&&(e.clock.clearTimeout(r.timer),r.reject({reason:"unavailable",retryable:false}),r=null);}}}var Q={};$e(Q,{acceptTransfer:()=>bt,addEntityProgression:()=>vt,adminAction:()=>St,cancelInventoryTransfer:()=>xt,claimEntityProgressionRewards:()=>wt,closeGameRoom:()=>kt,createEntityBatchOrder:()=>At,createEntityOrder:()=>Ot,createSession:()=>Pt,deleteEntityGameSetting:()=>Gt,deleteEntitySave:()=>Tt,deleteSession:()=>Ct,deleteShowcaseValue:()=>It,executeEntityRecipe:()=>Et,finalizeSaveUpload:()=>qt,getChannelAssignment:()=>Lt,getDropRates:()=>Mt,getEntityCurrency:()=>jt,getEntityGameSetting:()=>$t,getEntityInventory:()=>Bt,getEntityInventoryItem:()=>Ft,getEntityLeaderboard:()=>Ut,getEntityOrder:()=>Dt,getEntityProgression:()=>Nt,getEntityRecipeAvailability:()=>Ht,getEntityRecipeUsage:()=>Vt,getEntitySave:()=>Wt,getEvent:()=>zt,getGameRoomV2:()=>Kt,getLeaderboard:()=>Yt,getPlayerGameProfile:()=>Jt,getPurchaseCatalog:()=>Xt,getResolvedTemplate:()=>Qt,getRoomArgs:()=>Zt,getShowcaseValue:()=>en,getTransferDetails:()=>tn,ingestAnalyticsEvents:()=>X,initiateInventoryTransfer:()=>nn,invokeFunction:()=>rn,kickPlayer:()=>on,listChallenges:()=>an,listEntityGameSettings:()=>sn,listEntityOrders:()=>ln,listEntityProgressions:()=>dn,listEntitySaves:()=>un,listEvents:()=>cn,listGameRooms:()=>mn,listResolvedTemplates:()=>gn,listTransfers:()=>pn,maxEntityProgression:()=>yn,putEntityGameSetting:()=>fn,putRoomArgs:()=>hn,putShowcaseValue:()=>_n,rejectTransfer:()=>Rn,reportMatchPlayers:()=>bn,requestSaveUploadUrl:()=>vn,resetEntityProgression:()=>Sn,setMatchBackfill:()=>xn,simulateEntityOrder:()=>wn,transferHostV2:()=>kn,updateGameRoomV2:()=>An});function s(t){let e=String(t);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 bt(t,e,n){let r=`/v1/inventory/transfers/${s(e)}/accept`;return t.client.post(r,void 0,n?.signal)}async function vt(t,e,n,r,o,a){let i=`/v1/inventory/${s(e)}/${s(n)}/progressions/${s(r)}/add`;return t.client.post(i,o,a?.signal)}async function St(t,e,n,r){let o=`/v1/voice/sessions/${s(e)}/admin`;return t.client.post(o,n,r?.signal)}async function xt(t,e,n){let r=`/v1/inventory/transfers/${s(e)}/cancel`;return t.client.post(r,void 0,n?.signal)}async function wt(t,e,n,r,o,a){let i=`/v1/inventory/${s(e)}/${s(n)}/progressions/${s(r)}/claim`;return t.client.post(i,o,a?.signal)}async function kt(t,e,n){let r=`/v1/games/${s(t.gameId())}/game-rooms/${s(e)}`;return t.client.delete(r,n?.signal)}async function At(t,e,n,r,o){let a=`/v1/inventory/${s(e)}/${s(n)}/orders/batch`;return t.client.post(a,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function Ot(t,e,n,r,o){let a=`/v1/inventory/${s(e)}/${s(n)}/orders`;return t.client.post(a,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function Pt(t,e,n){return t.client.post("/v1/voice/sessions",e,n?.signal)}async function Gt(t,e,n,r,o){let a=`/v1/settings/${s(e)}/${s(n)}/${s(r)}`;return t.client.delete(a,o?.signal)}async function Tt(t,e,n,r,o){let a=`/v1/saves/${s(e)}/${s(n)}/${s(r)}`;return t.client.delete(a,o?.signal)}async function Ct(t,e,n){let r=`/v1/voice/sessions/${s(e)}`;return t.client.delete(r,n?.signal)}async function It(t,e,n,r){let o=`/v1/showcase/players/${s(e)}/${s(n)}`;return t.client.delete(o,r?.signal)}async function Et(t,e,n,r,o){let a=`/v1/inventory/${s(e)}/${s(n)}/recipes/execute`;return t.client.post(a,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function qt(t,e,n,r,o,a){let i=`/v1/saves/${s(e)}/${s(n)}/${s(r)}/finalize`;return t.client.post(i,o,a?.signal)}async function Lt(t,e,n){let r=`/v1/games/${s(t.gameId())}/config/channels/${s(e)}`;return t.client.getWithEtag(r,{...n?.signal===void 0?{}:{signal:n.signal},...n?.ifNoneMatch===void 0?{}:{ifNoneMatch:n.ifNoneMatch}})}async function Mt(t,e,n){let r=`/v1/inventory/loot-tables/${s(e)}/drop-rates`;return t.client.get(r,n?.signal)}async function jt(t,e,n,r,o){let a=`/v1/inventory/${s(e)}/${s(n)}/currencies/${s(r)}`;return t.client.get(a,o?.signal)}async function $t(t,e,n,r,o){let a=`/v1/settings/${s(e)}/${s(n)}/${s(r)}`;return t.client.getWithEtag(a,{...o?.signal===void 0?{}:{signal:o.signal},...o?.ifNoneMatch===void 0?{}:{ifNoneMatch:o.ifNoneMatch}})}async function Bt(t,e,n,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(n)}`+(a?`?${a}`:"");return t.client.get(i,r?.signal)}async function Ft(t,e,n,r,o){let a=`/v1/inventory/${s(e)}/${s(n)}/items/${s(r)}`;return t.client.get(a,o?.signal)}async function Ut(t,e,n,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(),d=`/v1/leaderboards/${s(e)}/${s(n)}/${s(r)}`+(i?`?${i}`:"");return t.client.get(d,o?.signal)}async function Dt(t,e,n,r,o){let a=`/v1/inventory/${s(e)}/${s(n)}/orders/${s(r)}`;return t.client.get(a,o?.signal)}async function Nt(t,e,n,r,o){let a=`/v1/inventory/${s(e)}/${s(n)}/progressions/${s(r)}`;return t.client.get(a,o?.signal)}async function Ht(t,e,n,r,o,a){let i=`/v1/inventory/${s(e)}/${s(n)}/catalogs/${s(r)}/recipes/${s(o)}/availability`;return t.client.get(i,a?.signal)}async function Vt(t,e,n,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(n)}/recipe-usage`+(a?`?${a}`:"");return t.client.get(i,r?.signal)}async function Wt(t,e,n,r,o){let a=`/v1/saves/${s(e)}/${s(n)}/${s(r)}`;return t.client.getWithEtag(a,{...o?.signal===void 0?{}:{signal:o.signal},...o?.ifNoneMatch===void 0?{}:{ifNoneMatch:o.ifNoneMatch}})}async function zt(t,e,n){let r=`/v1/events/${s(e)}`;return t.client.get(r,n?.signal)}async function Kt(t,e,n){let r=`/v2/games/${s(t.gameId())}/game-rooms/${s(e)}`;return t.client.getWithEtag(r,{...n?.signal===void 0?{}:{signal:n.signal},...n?.ifNoneMatch===void 0?{}:{ifNoneMatch:n.ifNoneMatch}})}async function Yt(t,e,n){let r=new URLSearchParams;n?.bucket_1!==void 0&&r.set("bucket_1",String(n?.bucket_1)),n?.bucket_2!==void 0&&r.set("bucket_2",String(n?.bucket_2)),n?.periods_back!==void 0&&r.set("periods_back",String(n?.periods_back)),n?.period!==void 0&&r.set("period",String(n?.period)),n?.player_id!==void 0&&r.set("player_id",String(n?.player_id));let o=r.toString(),a=`/v1/leaderboards/${s(e)}`+(o?`?${o}`:"");return t.client.get(a,n?.signal)}async function Jt(t,e,n){let r=`/v1/profiles/players/${s(e)}`;return t.client.get(r,n?.signal)}async function Xt(t,e){let n=new URLSearchParams;e?.config_version!==void 0&&n.set("config_version",String(e?.config_version));let r=n.toString(),o="/v1/inventory/platform-funded-game-inventory-purchase-catalog"+(r?`?${r}`:"");return t.client.get(o,e?.signal)}async function Qt(t,e,n){let r=`/v1/game-room-templates/${s(e)}`;return t.client.get(r,n?.signal)}async function Zt(t,e,n){let r=`/v1/games/${s(t.gameId())}/game-rooms/${s(e)}/room-args`;return t.client.get(r,n?.signal)}async function en(t,e,n,r){let o=`/v1/showcase/players/${s(e)}/${s(n)}`;return t.client.get(o,r?.signal)}async function tn(t,e,n){let r=`/v1/inventory/transfers/${s(e)}`;return t.client.get(r,n?.signal)}async function X(t,e,n){let r=`/v1/games/${s(t.gameId())}/analytics/events`;return t.client.post(r,e,n?.signal,{replaySafe:true,retryRateLimited:false})}async function nn(t,e,n){return t.client.post("/v1/inventory/transfers",e,n?.signal)}async function rn(t,e,n){let r=new URLSearchParams;n?.cue_id!==void 0&&r.set("cue_id",String(n?.cue_id));let o=r.toString(),a="/v1/functions/invoke"+(o?`?${o}`:"");return t.client.postBytes(a,e,n?.signal)}async function on(t,e,n,r){let o=`/v1/games/${s(t.gameId())}/game-rooms/${s(e)}/kick/${s(n)}`;return t.client.post(o,void 0,r?.signal)}async function an(t,e){let n=new URLSearchParams;e?.periods_back!==void 0&&n.set("periods_back",String(e?.periods_back)),e?.player_id!==void 0&&n.set("player_id",String(e?.player_id));let r=n.toString(),o="/v1/challenges"+(r?`?${r}`:"");return t.client.get(o,e?.signal)}async function sn(t,e,n,r){let o=`/v1/settings/${s(e)}/${s(n)}`;return t.client.get(o,r?.signal)}async function ln(t,e,n,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(n)}/orders`+(a?`?${a}`:"");return t.client.get(i,r?.signal)}async function dn(t,e,n,r){let o=`/v1/inventory/${s(e)}/${s(n)}/progressions`;return t.client.get(o,r?.signal)}async function un(t,e,n,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(n)}`+(a?`?${a}`:"");return t.client.get(i,r?.signal)}async function cn(t,e){let n=new URLSearchParams;e?.include_inactive!==void 0&&n.set("include_inactive",String(e?.include_inactive)),e?.limit!==void 0&&n.set("limit",String(e?.limit)),e?.offset!==void 0&&n.set("offset",String(e?.offset));let r=n.toString(),o="/v1/events"+(r?`?${r}`:"");return t.client.get(o,e?.signal)}async function mn(t,e){let n=new URLSearchParams;e?.status!==void 0&&n.set("status",String(e?.status)),e?.game_channel!==void 0&&n.set("game_channel",String(e?.game_channel)),e?.game_room_type!==void 0&&n.set("game_room_type",String(e?.game_room_type)),e?.template_id!==void 0&&n.set("template_id",String(e?.template_id)),e?.template_slug!==void 0&&n.set("template_slug",String(e?.template_slug)),e?.limit!==void 0&&n.set("limit",String(e?.limit)),e?.cursor!==void 0&&n.set("cursor",String(e?.cursor));let r=n.toString(),o=`/v1/games/${s(t.gameId())}/game-rooms`+(r?`?${r}`:"");return t.client.get(o,e?.signal)}async function gn(t,e){return t.client.get("/v1/game-room-templates",e?.signal)}async function pn(t,e){let n=new URLSearchParams;e.entity_type!==void 0&&n.set("entity_type",String(e.entity_type)),e.entity_id!==void 0&&n.set("entity_id",String(e.entity_id)),e?.direction!==void 0&&n.set("direction",String(e?.direction)),e?.status!==void 0&&n.set("status",String(e?.status)),e?.cursor!==void 0&&n.set("cursor",String(e?.cursor)),e?.limit!==void 0&&n.set("limit",String(e?.limit));let r=n.toString(),o="/v1/inventory/transfers"+(r?`?${r}`:"");return t.client.get(o,e?.signal)}async function yn(t,e,n,r,o,a){let i=`/v1/inventory/${s(e)}/${s(n)}/progressions/${s(r)}/max`;return t.client.post(i,o,a?.signal)}async function fn(t,e,n,r,o,a){let i=`/v1/settings/${s(e)}/${s(n)}/${s(r)}`;return t.client.put(i,o,a?.signal,{...a?.ifMatch===void 0?{}:{ifMatch:a.ifMatch}})}async function hn(t,e,n,r){let o=`/v1/games/${s(t.gameId())}/game-rooms/${s(e)}/room-args`;return t.client.put(o,n,r?.signal)}async function _n(t,e,n,r,o){let a=`/v1/showcase/players/${s(e)}/${s(n)}`;return t.client.put(a,r,o?.signal)}async function Rn(t,e,n){let r=`/v1/inventory/transfers/${s(e)}/reject`;return t.client.post(r,void 0,n?.signal)}async function bn(t,e,n,r){let o=`/v1/games/${s(t.gameId())}/matches/${s(e)}/players/report`;return t.client.post(o,n,r?.signal)}async function vn(t,e,n,r,o,a){let i=`/v1/saves/${s(e)}/${s(n)}/${s(r)}/upload-url`;return t.client.post(i,o,a?.signal,{replaySafe:true})}async function Sn(t,e,n,r,o,a){let i=`/v1/inventory/${s(e)}/${s(n)}/progressions/${s(r)}/reset`;return t.client.post(i,o,a?.signal)}async function xn(t,e,n,r){let o=`/v1/games/${s(t.gameId())}/matches/${s(e)}/backfill`;return t.client.put(o,n,r?.signal)}async function wn(t,e,n,r,o){let a=`/v1/inventory/${s(e)}/${s(n)}/orders/simulate`;return t.client.post(a,r,o?.signal)}async function kn(t,e,n,r){let o=`/v2/games/${s(t.gameId())}/game-rooms/${s(e)}/transfer/${s(n)}`;return t.client.post(o,void 0,r?.signal)}async function An(t,e,n,r){let o=`/v2/games/${s(t.gameId())}/game-rooms/${s(e)}`;return t.client.patch(o,n,r?.signal,{...r?.ifMatch===void 0?{}:{ifMatch:r.ifMatch}})}var ye="gem_";function fe(t,e){let n=e?.retryAfterSeconds,r=typeof n=="number"&&Number.isFinite(n)&&n>0?n*1e3:0,o=1e4*2**Math.min(Math.max(0,t-1),16);return Math.min(Math.max(r,o),3e5)}var Gn=1e4,Tn=50,Cn=1e3,In=65536-4*1024,he=t=>typeof t=="number"?t:0,En=t=>typeof t=="string"?t:"";function _e(){let t=globalThis.crypto;return typeof t?.randomUUID=="function"?t.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{let n=Math.floor(Math.random()*16);return (e==="x"?n:n&3|8).toString(16)})}function qn(t){return t?.retryable===true}function Ln(t,e){let n=t??{},r=Array.isArray(n.rejected)?n.rejected.map(o=>{let a=o??{};return {index:he(a.index),code:En(a.code)}}):[];return {accepted:he(n.accepted),rejected:r,dropped:e,duplicate:n.duplicate===true}}function Re(t,e){return {event_uid:t.uid,name:t.name,offset_ms:Math.round(t.atMs)-e,player_id:t.playerId,dimensions:t.dimensions,measures:t.measures}}function be(t){let e=Math.max(1,Math.floor(t.maxQueue??Cn)),n={client:t.client,gameId:()=>t.gameId},r=[],o=0,a=null,i=false,d=null,u=0,c=0,g=false,S=false,w=_=>{t.log?.(_);},b=()=>{a!==null&&(t.clock.clearTimeout(a),a=null);},y=()=>Math.max(0,c-t.clock.now()),x=()=>{a!==null||i||d!==null||(a=t.clock.setTimeout(()=>{a=null,P().catch(()=>{});},Math.max(Gn,y())));},A=()=>{let _=Math.min(r.length,100),R=128;for(let G=0;G<_;G+=1){let C=r[G];if(C===void 0)break;if(R+=JSON.stringify(Re(C,0)).length+1,R>In)return Math.max(1,G)}return _};async function P(_){for(;d!==null;)await d.catch(()=>{});if(r.length===0)return {accepted:0,rejected:[],dropped:0,duplicate:false};let R=Le(_);d=R;try{return await R}finally{d===R&&(d=null),r.length>0&&x();}}async function Le(_){b();let R=r.splice(0,A()),G=o;o=0;let C=Math.round(t.clock.now()),D={batch_id:_e(),sent_at_ms:C,events:R.map(k=>Re(k,C))};try{let k=await X(n,D,_===void 0?void 0:{signal:_}),I=Ln(k,G);u=0,c=0;for(let Me of I.rejected)w(`[gem] analytics: an event was refused (${Me.code}). See the analytics_events section of your game config.`);return I}catch(k){if(qn(k)){for(r=[...R,...r],o+=G;r.length>e;)r.shift(),o+=1;u+=1,c=t.clock.now()+fe(u,k);}else w(`[gem] analytics: ${R.length} event(s) were discarded \u2014 the platform refused the batch and will refuse it again: ${String(k)}`);throw k}}return {track(_,R,G={}){if(i)return;if(typeof _!="string"||_===""){S||(S=true,w(`[gem] analytics: '${R}' 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(R.startsWith(ye)){g||(g=true,w(`[gem] analytics: '${R}' 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 C={},D={};for(let[k,I]of Object.entries(G))typeof I=="string"?C[k]=I:typeof I=="number"&&Number.isFinite(I)&&(D[k]=I);for(;r.length>=e;)r.shift(),o+=1;r.push({uid:_e(),playerId:_,name:R,atMs:t.clock.now(),dimensions:C,measures:D}),r.length>=Tn&&d===null&&y()===0?P().catch(()=>{}):x();},flush:_=>P(_),get pending(){return r.length},dispose(){i=true,b(),r=[],o=0;}}}function Mn(t){return typeof t=="string"&&/^[\w-]{1,64}$/.test(t)}function ve(t,e){if(t===void 0||Mn(t))return t;let n=typeof t=="string"?JSON.stringify(t.slice(0,72)):`a value of type ${typeof t}`;console.warn(`[gem] ${e}: cueId ${n} is not 1 to 64 letters, digits, _ or -, so it was left out. Use one crypto.randomUUID() per award.`);}var jn=new Map([["function_error",false],["function_failed",false],["function_timeout",false],["function_not_published",false],["function_input_too_large",false],["invalid_cue_id",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]]),F=class extends p{constructor(e,n){super(e.reason,e.status,e.detail,e.retryAfterSeconds,e.code),this.name="GemFunctionError",Object.assign(this,n);}get retryable(){return (this.code===void 0?void 0:jn.get(this.code))??super.retryable}},M=class{#e;constructor(e){this.#e=e;}async invoke(e,n={}){let r=$n(e),o=ve(n.cueId,"functions.invoke"),a;try{a=await this.#e(r,{...n.signal===void 0?{}:{signal:n.signal},...o===void 0?{}:{cue_id:o}});}catch(i){throw i instanceof p?Fn(i):i}return Bn(a)}};function $n(t){if(t instanceof ArrayBuffer)return new Uint8Array(t);if(ArrayBuffer.isView(t))return new Uint8Array(t.buffer,t.byteOffset,t.byteLength);let e;try{e=JSON.stringify(t);}catch(n){throw new f(`the function input could not be serialised to JSON: ${String(n)}. 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 t}, 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 Bn(t){let{bytes:e}=t,n=()=>new TextDecoder("utf-8",{fatal:true}).decode(e);return {bytes:e,...t.invocationId===void 0?{}:{invocationId:t.invocationId},text:n,json:()=>JSON.parse(n())}}function Fn(t){let{details:e,invocationId:n}=se(t),o=e?.untrusted?.message,a=e?.reason;return new F(t,{...n===void 0?{}:{invocationId:n},...t.code==="function_error"&&typeof o=="string"?{functionMessage:o}:{},...t.code==="function_failed"&&typeof a=="string"?{failure:a}:{}})}var O=t=>typeof t=="string"?t:"",Un=/(?:Z|[+-]\d{2}:?\d{2})$/i;function Se(t){let e=O(t);if(!Un.test(e))return 0;let n=Date.parse(e);return Number.isFinite(n)?Math.floor(n/1e3):0}var Dn=/^[0-9a-f]{1,64}$/,Nn=/^[0-9a-f]{16}$/,Hn=/^[A-Za-z][A-Za-z0-9_+\-/]{0,63}$/,Vn=/^(?:[01]\d|2[0-3]):[0-5]\d$/;function Wn(t){let e=O(t),n=/^(\d{4})-(\d{2})-(\d{2})$/.exec(e);if(!n)return;let[r,o,a]=[Number(n[1]),Number(n[2]),Number(n[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 zn=4096,Kn=new TextEncoder;function Yn(t){let e=O(t.challenge_data),n=O(t.challenge_data_hash);return e===""||!Nn.test(n)?{}:Kn.encode(e).length>zn?{}:{data:e,dataHash:n}}function Jn(t){let e=t??{},n=Se(e.period_start_at),r=Se(e.period_ends_at);if(n===0||r===0)return;let o=O(e.slug),a=O(e.seed),i=Wn(e.period_local_date),d=O(e.boundary),u=O(e.reset_time);return {id:O(e.progression_definition_id),...o===""?{}:{slug:o},window:O(e.window),periodStartAt:n,periodEndsAt:r,...i===void 0?{}:{periodLocalDate:i},boundary:Hn.test(d)?d:"",resetTime:Vn.test(u)?u:"",seed:Dn.test(a)?a:"",...Yn(e)}}function xe(t){if(t!==void 0&&(!Number.isInteger(t)||t<0||t>400))throw new TypeError(`periodsBack must be an integer between 0 and 400, got ${String(t)}`)}function we(t){let e=t??{};return Array.isArray(e.challenges)?e.challenges.map(Jn).filter(n=>n!==void 0):[]}function ke(t){return {async list(e){let{playerId:n,periodsBack:r,signal:o}=e??{};if(typeof n!="string"||n==="")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().");xe(r);let a=await t({player_id:n,...r===void 0?{}:{periods_back:r},...o===void 0?{}:{signal:o}});return we(a)}}}function Xn(t){let e={};for(let[n,r]of Object.entries(Q))if(typeof r=="function"){let o=r;e[n]=(...a)=>o(t,...a);}return e}function z(t,e={}){let n=e.clock??L,r=e.baseUrl??t.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=J(t,{clock:n,...e.onAuthStateChange===void 0?{}:{onStateChange:e.onAuthStateChange}}),a=ie({baseUrl:r,tokenSource:o.source,defaultQuery:{game_id:t.gameId,channel:t.channel},...e.fetch===void 0?{}:{fetch:e.fetch}}),i=new q({transport:a,clock:n}),d={gameId:t.gameId,channel:t.channel,matchId:t.matchId,...t.gameRoomId===void 0?{}:{gameRoomId:t.gameRoomId}},u=Xn({client:i,gameId:()=>d.gameId}),c=d.gameRoomId,g=t.endMatch,S=t.log,w=be({client:i,clock:n,gameId:d.gameId,...typeof S=="function"?{log:y=>S.call(t,y)}:{}});return {identity:d,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(t);},setBackfill:async(y,x)=>{let A=await u.setMatchBackfill(d.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(d.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:ke(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 Qn=["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"],Zn=new Set(Qn);function Ae(t){return typeof t=="string"&&Zn.has(t)?t:"unknown"}var Ge="[gem: use gem.text.toPlain()]",Oe=new Set,Pe;function er(t){try{if(Oe.has(t))return;let e=globalThis.location;if(Pe??=!!e?.port&&ge(e.hostname??""),!Pe)return;Oe.add(t),console.warn(`[gem] ${t} is PlayerText, turned into a string: players see ${Ge}. Render text.toPlain(value) (text is in @indiegems/gem-web-sdk/sdk).
2
+ ${new Error().stack}`);}catch{}}var v=class{#e;#t;constructor(e,n="player text"){this.#e=e,this.#t=n,Object.freeze(this);}toString(){return er(this.#t),Ge}toJSON(){return this.toString()}get[Symbol.toStringTag](){return "PlayerText"}static unwrap(e){return e.#e}};function U(t,e){return new v(t,e)}var Te={toPlain(t){return v.unwrap(t)},compare(t,e,n){let r=t instanceof v?v.unwrap(t):t,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(n);}catch{a=new Intl.Collator;}return a.compare(r,o)},equals(t,e){let n=t instanceof v?v.unwrap(t):t,r=e instanceof v?v.unwrap(e):e;return n.normalize("NFC")===r.normalize("NFC")}};var Ce="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 Z(t,e={}){let n=e.clock??L,r=()=>{let d=t();if(d===null)throw new Error(Ce);return d},o=null,a=()=>{if(o===null)throw new Error(Ce);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(d){let c=r().profile?.(d);if(!c)return null;let g=c.displayName;return typeof g!="string"||g===""?null:{displayName:U(g,"profile.displayName"),...typeof c.displayTag=="string"&&c.displayTag!==""?{displayTag:U(c.displayTag,"profile.displayTag")}:{},...typeof c.discriminator=="string"?{discriminator:c.discriminator}:{}}},playerNumber(d){return r().playerNumber?.(d)},send(d,u,c){c===void 0?r().send(d,u):r().send(d,u,c);},broadcast(d,u){u===void 0?r().broadcast(d):r().broadcast(d,u);},kick(d,u){u===void 0?r().kick(d):r().kick(d,u);},log(d){r().log(d);},warn(d){r().warn(d);}},attach:()=>{o=z(r(),{...e,clock:n});}}}function Ie(t,e={}){let{server:n,attach:r}=Z(()=>t,e);return r(),n}function tr(t){if(t===void 0||typeof t.reason!="string"||t.reason==="")return;let e=t.platform_reason??t.endedReason;return {reason:t.reason,...e===void 0?{}:{endedReason:Ae(e)}}}var nr=1e4;function rr(t){let e=false;return n=>{if(e)return;let r;try{r=t.match.reportPlayers([{playerId:n,state:"connected"}],AbortSignal.timeout(nr));}catch{return}r.catch(o=>{o instanceof p&&o.status>=400&&o.status<500&&(e=o.status!==429);});}}function Ee(t,e={}){return ()=>{let n=null,{server:r,attach:o}=Z(()=>n,e),a=t(r),i={async init(u){n=u,o(),await a.init?.();},async shutdown(u){let c=tr(u);try{await a.shutdown?.(c);}finally{r.dispose();}}},d=rr(r);return i.join=(u,c)=>(d(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 or=new Set(["unlocked","already_unlocked","suppressed"]);function qe(t){let e=t?.changes;if(!Array.isArray(e))return [];let n=[];for(let r of e){let o=r??{};if(o.type!=="achievement_unlocked"||typeof o.outcome!="string"||!or.has(o.outcome)||typeof o.achievement_id!="string"||o.achievement_id==="")continue;let a=o.outcome;n.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 n}export{h as AuthError,H as CONDITIONAL_HEADERS,M as FunctionsApi,p as GemApiError,q as GemClient,F as GemFunctionError,v as PlayerText,f as TransportRefusal,qe as achievementReceipts,U as asPlayerText,z as createGemServer,pe as createHostTokenSource,Ie as createMatchServer,Ee as defineServer,L as systemClock,Te as text,ne as toBase64};//# sourceMappingURL=gem-web-sdk.server.js.map
3
3
  //# sourceMappingURL=gem-web-sdk.server.js.map
package/dist/index.d.ts CHANGED
@@ -107,7 +107,7 @@ declare const FRAME_TO_PARENT: readonly [
107
107
  "gem.requestStorePurchase",
108
108
  "gem.requestStoreOfferSheet"
109
109
  ];
110
- type GemCapability = "ads" | "signIn" | "purchases" | "purchaseSettled" | "avatar3dPurchases" | "friendChallenges" | "playInvites" | "devtools" | "screenshot" | "feedbackContext" | "rooms" | "p2p" | "dedicated" | "clusterTarget" | "graphicsRoutes" | "parties" | "autoStartFailure" | "ticketEvents" | "partySeating" | "socketState" | "audioState" | "rewardCue" | "rewardPresentation" | "frameStats" | "portraitBorders" | "engagement" | "viewport" | "reservedAreas" | "audioChannels" | "walletDisplay" | "localHost" | "cohorts" | "earnAllowance" | "inventoryChanged" | "deviceSettings" | "asyncOpponents" | "share" | "shareResult" | "shareRemap" | "avatarPicker" | "vibration" | "gameMenu" | "controls" | "gemCorner" | "gameSettings" | "moments" | "appLinks" | "openGame" | "store" | "storeOfferSheet" | "menuStyle" | "p2pRelayDrain";
110
+ type GemCapability = "ads" | "signIn" | "purchases" | "purchaseSettled" | "avatar3dPurchases" | "friendChallenges" | "playInvites" | "devtools" | "screenshot" | "feedbackContext" | "rooms" | "p2p" | "dedicated" | "clusterTarget" | "graphicsRoutes" | "parties" | "autoStartFailure" | "ticketEvents" | "partySeating" | "socketState" | "audioState" | "rewardCue" | "rewardPresentation" | "frameStats" | "portraitBorders" | "engagement" | "viewport" | "reservedAreas" | "audioChannels" | "textScale" | "walletDisplay" | "localHost" | "cohorts" | "earnAllowance" | "inventoryChanged" | "deviceSettings" | "asyncOpponents" | "share" | "shareResult" | "shareRemap" | "avatarPicker" | "vibration" | "gameMenu" | "controls" | "gemCorner" | "gameSettings" | "moments" | "appLinks" | "openGame" | "store" | "storeOfferSheet" | "menuStyle" | "p2pRelayDrain";
111
111
  declare const CAPABILITY_GATES: Readonly<Record<string, string>>;
112
112
  declare const CAPABILITY_NAMESPACE_GATES: ReadonlyArray<readonly [
113
113
  string,
@@ -219,6 +219,7 @@ interface GemPrefs {
219
219
  graphicsQuality?: string;
220
220
  graphicsQualityAuto?: boolean;
221
221
  colorHelp?: boolean;
222
+ textScale?: number;
222
223
  };
223
224
  }
224
225
  interface GemCohorts {
@@ -1325,6 +1326,7 @@ declare class GemHost {
1325
1326
  graphicsQuality?: "low" | "medium" | "high";
1326
1327
  graphicsQualityAuto?: boolean;
1327
1328
  colorHelp?: boolean;
1329
+ textScale?: number;
1328
1330
  };
1329
1331
  }): void;
1330
1332
  sendCohorts(cohorts: ReadonlyArray<{
package/dist/sdk.d.ts CHANGED
@@ -2206,6 +2206,7 @@ interface GemPrefs$1 {
2206
2206
  graphicsQuality?: string;
2207
2207
  graphicsQualityAuto?: boolean;
2208
2208
  colorHelp?: boolean;
2209
+ textScale?: number;
2209
2210
  };
2210
2211
  }
2211
2212
  interface GemCohorts$1 {
@@ -5262,6 +5263,7 @@ interface GemOptions {
5262
5263
  readonly onViewport?: (viewport: GemViewport) => void;
5263
5264
  readonly manageAudio?: boolean;
5264
5265
  readonly onAudioChannels?: (channels: GemAudioChannels) => void;
5266
+ readonly onTextScale?: (percent: number | null) => void;
5265
5267
  readonly selectableText?: boolean;
5266
5268
  readonly onPause?: (paused: boolean) => void;
5267
5269
  readonly onWillTerminate?: (notice: GemTerminationNotice) => void;
@@ -5305,6 +5307,7 @@ interface GemRecommendedSettings {
5305
5307
  readonly graphicsQuality: GemGraphicsQuality;
5306
5308
  readonly graphicsQualityAuto: boolean;
5307
5309
  readonly colorHelp: boolean | null;
5310
+ readonly textScale: number | null;
5308
5311
  }
5309
5312
  interface GemCohort {
5310
5313
  readonly experimentId: string;
@@ -5393,6 +5396,7 @@ interface Gem {
5393
5396
  awaitPlayer(timeoutMs?: number): Promise<GemPlayer | null>;
5394
5397
  readonly prefs: GemPrefs | null;
5395
5398
  readonly paused: boolean;
5399
+ readonly textScale: number | null;
5396
5400
  readonly cohorts: GemCohorts | null;
5397
5401
  readonly viewport: GemViewport | null;
5398
5402
  awaitCohorts(timeoutMs?: number): Promise<GemCohorts | null>;
@@ -1,6 +1,6 @@
1
1
  # The function surface — API reference
2
2
 
3
- Generated from `@indiegems/gem-web-sdk/function` v23.0.6, 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` v23.1.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.
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` v23.0.6, 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` v23.1.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.
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
 
@@ -10162,6 +10162,45 @@ switch flips your own `icon: 'music'` toggle when you declared one with
10162
10162
  [Gem.settings](#gem-settings). The same two values are always readable as
10163
10163
  `gem.prefs.music` and `gem.prefs.sounds`.
10164
10164
 
10165
+ <a id="gemoptions-ontextscale"></a>
10166
+
10167
+ ## GemOptions.onTextScale
10168
+
10169
+ ```ts
10170
+ readonly onTextScale?: (percent: number | null) => void
10171
+ ```
10172
+
10173
+ Apply the player's **Arcade Text size**: called with a percent from `100`
10174
+ to `200`, or `null` when the Arcade gave no advice. Pass it and the Arcade
10175
+ sends your game the player's text size; leave it out and it never does.
10176
+
10177
+ Size your interface in `rem` and leave the root alone, then apply the value
10178
+ by setting the root font size, so your whole interface scales together —
10179
+ text, padding, boxes and icons — rather than text alone:
10180
+
10181
+ ```js
10182
+ const MAX = 150; // the largest size your layout supports, at least 130
10183
+ createGem({
10184
+ allowedEmbedders,
10185
+ onTextScale: (p) => {
10186
+ document.documentElement.style.fontSize = (chosen ?? Math.min(p ?? 100, MAX)) + '%';
10187
+ },
10188
+ });
10189
+ ```
10190
+
10191
+ `chosen` is the size the player picked in your game, or `null` while they
10192
+ have not: **their choice beats the Arcade's**, and your game owns that
10193
+ precedence — the SDK applies nothing for you. Keep `chosen` per device
10194
+ (`gem.deviceSettings`), like the Arcade setting it overrides.
10195
+
10196
+ Two rules hold whatever your game does with it. **Never put a text size in
10197
+ analytics** — no event, dimension or measure carries `p`, your resolved
10198
+ size, or the value of a text-size change. **Save only the player's own
10199
+ choice**: never store `p` as it, and a `null` choice stays `null`.
10200
+
10201
+ Called on the first `gem.prefs` push and then whenever the value changes.
10202
+ The same value is readable as [Gem.textScale](#gem-textscale).
10203
+
10165
10204
  <a id="gemoptions-selectabletext"></a>
10166
10205
 
10167
10206
  ## GemOptions.selectableText
@@ -10911,6 +10950,23 @@ choice the player made in your game. A game with no such aids ignores it.
10911
10950
  `null` when the Arcade did not say (an older Arcade): that is no
10912
10951
  recommendation, not `false`, so keep your own default.
10913
10952
 
10953
+ <a id="gemrecommendedsettings-textscale"></a>
10954
+
10955
+ ## GemRecommendedSettings.textScale
10956
+
10957
+ ```ts
10958
+ readonly textScale: number | null
10959
+ ```
10960
+
10961
+ The player's Arcade Text size, as a percent from `100` to `200`. A game
10962
+ sized in `rem` applies it as its root font size, so its whole interface
10963
+ scales. A DEFAULT: the player's own text size in your game beats it, and
10964
+ you clamp it to the largest size your layout supports. Never record it in
10965
+ analytics, and never save it as the player's choice.
10966
+
10967
+ `null` unless you passed [GemOptions.onTextScale](#gemoptions-ontextscale) — the Arcade sends
10968
+ it only to a game that applies it — and when the Arcade did not say.
10969
+
10914
10970
  <a id="gemcohort"></a>
10915
10971
 
10916
10972
  ## GemCohort
@@ -12262,6 +12318,22 @@ any. The same pause `onPause` tells you about, readable at any moment —
12262
12318
  for code that was not around when the edge arrived, such as a frame-time
12263
12319
  monitor deciding whether a slow frame counts.
12264
12320
 
12321
+ <a id="gem-textscale"></a>
12322
+
12323
+ ## Gem.textScale
12324
+
12325
+ ```ts
12326
+ readonly textScale: number | null
12327
+ ```
12328
+
12329
+ The player's Arcade Text size, as a percent from `100` to `200`, or `null`
12330
+ when the Arcade has given no advice — the value
12331
+ [GemOptions.onTextScale](#gemoptions-ontextscale) was last called with. Readable at any
12332
+ moment, for code that was not around when it arrived.
12333
+
12334
+ Always `null` unless you passed `onTextScale`: the Arcade sends a text
12335
+ size only to a game that applies it.
12336
+
12265
12337
  <a id="gem-cohorts"></a>
12266
12338
 
12267
12339
  ## Gem.cohorts
@@ -1,6 +1,6 @@
1
1
  # The server surface — API reference
2
2
 
3
- Generated from `@indiegems/gem-web-sdk/sdk` v23.0.6, 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` v23.1.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.
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": "23.0.6"
5
+ "version": "23.1.0"
6
6
  },
7
7
  "entries": [
8
8
  {
@@ -11675,6 +11675,22 @@
11675
11675
  "defaultValue": null,
11676
11676
  "guides": []
11677
11677
  },
11678
+ {
11679
+ "id": "GemOptions.onTextScale",
11680
+ "name": "onTextScale",
11681
+ "anchor": "gemoptions-ontextscale",
11682
+ "group": "start",
11683
+ "signature": "readonly onTextScale?: (percent: number | null) => void",
11684
+ "documented": true,
11685
+ "summary": "Apply the player's **Arcade Text size**: called with a percent from `100`\nto `200`, or `null` when the Arcade gave no advice. Pass it and the Arcade\nsends your game the player's text size; leave it out and it never does.\n\nSize your interface in `rem` and leave the root alone, then apply the value\nby setting the root font size, so your whole interface scales together —\ntext, padding, boxes and icons — rather than text alone:\n\n```js\nconst MAX = 150; // the largest size your layout supports, at least 130\ncreateGem({\n allowedEmbedders,\n onTextScale: (p) => {\n document.documentElement.style.fontSize = (chosen ?? Math.min(p ?? 100, MAX)) + '%';\n },\n});\n```\n\n`chosen` is the size the player picked in your game, or `null` while they\nhave not: **their choice beats the Arcade's**, and your game owns that\nprecedence — the SDK applies nothing for you. Keep `chosen` per device\n(`gem.deviceSettings`), like the Arcade setting it overrides.\n\nTwo rules hold whatever your game does with it. **Never put a text size in\nanalytics** — no event, dimension or measure carries `p`, your resolved\nsize, or the value of a text-size change. **Save only the player's own\nchoice**: never store `p` as it, and a `null` choice stays `null`.\n\nCalled on the first `gem.prefs` push and then whenever the value changes.\nThe same value is readable as [Gem.textScale](api-reference-game.md#gem-textscale).",
11686
+ "deprecated": null,
11687
+ "params": [],
11688
+ "returns": null,
11689
+ "throws": null,
11690
+ "example": null,
11691
+ "defaultValue": null,
11692
+ "guides": []
11693
+ },
11678
11694
  {
11679
11695
  "id": "GemOptions.selectableText",
11680
11696
  "name": "selectableText",
@@ -12431,6 +12447,22 @@
12431
12447
  "defaultValue": null,
12432
12448
  "guides": []
12433
12449
  },
12450
+ {
12451
+ "id": "GemRecommendedSettings.textScale",
12452
+ "name": "textScale",
12453
+ "anchor": "gemrecommendedsettings-textscale",
12454
+ "group": "player",
12455
+ "signature": "readonly textScale: number | null",
12456
+ "documented": true,
12457
+ "summary": "The player's Arcade Text size, as a percent from `100` to `200`. A game\nsized in `rem` applies it as its root font size, so its whole interface\nscales. A DEFAULT: the player's own text size in your game beats it, and\nyou clamp it to the largest size your layout supports. Never record it in\nanalytics, and never save it as the player's choice.\n\n`null` unless you passed [GemOptions.onTextScale](api-reference-game.md#gemoptions-ontextscale) — the Arcade sends\nit only to a game that applies it — and when the Arcade did not say.",
12458
+ "deprecated": null,
12459
+ "params": [],
12460
+ "returns": null,
12461
+ "throws": null,
12462
+ "example": null,
12463
+ "defaultValue": null,
12464
+ "guides": []
12465
+ },
12434
12466
  {
12435
12467
  "id": "GemCohort",
12436
12468
  "name": "GemCohort",
@@ -13744,6 +13776,22 @@
13744
13776
  "defaultValue": null,
13745
13777
  "guides": []
13746
13778
  },
13779
+ {
13780
+ "id": "Gem.textScale",
13781
+ "name": "textScale",
13782
+ "anchor": "gem-textscale",
13783
+ "group": "start",
13784
+ "signature": "readonly textScale: number | null",
13785
+ "documented": true,
13786
+ "summary": "The player's Arcade Text size, as a percent from `100` to `200`, or `null`\nwhen the Arcade has given no advice — the value\n[GemOptions.onTextScale](api-reference-game.md#gemoptions-ontextscale) was last called with. Readable at any\nmoment, for code that was not around when it arrived.\n\nAlways `null` unless you passed `onTextScale`: the Arcade sends a text\nsize only to a game that applies it.",
13787
+ "deprecated": null,
13788
+ "params": [],
13789
+ "returns": null,
13790
+ "throws": null,
13791
+ "example": null,
13792
+ "defaultValue": null,
13793
+ "guides": []
13794
+ },
13747
13795
  {
13748
13796
  "id": "Gem.cohorts",
13749
13797
  "name": "cohorts",