@indiegems/gem-web-sdk 23.1.1 → 23.1.3

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=(t,e)=>{for(var n in e)je(t,n,{get:e[n],enumerable:true});};globalThis.__gemWebSdkVersion="[gem-web-sdk:sdkVersion:23.1.1]";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).
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.3]";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
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
@@ -1,6 +1,6 @@
1
1
  # The function surface — API reference
2
2
 
3
- Generated from `@indiegems/gem-web-sdk/function` v23.1.1, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
3
+ Generated from `@indiegems/gem-web-sdk/function` v23.1.3, 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.1.1, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
3
+ Generated from `@indiegems/gem-web-sdk/sdk` v23.1.3, 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
 
@@ -5088,10 +5088,11 @@ purchase(request: Avatar3dPurchaseRequest): Promise<PurchaseOutcome>
5088
5088
  Buy one of your 3D avatars for the player and put it on. The Arcade
5089
5089
  prices it again, shows its own confirmation sheet, takes the currency and
5090
5090
  wears the avatar; your game then receives the player again, with the new
5091
- avatar worn, and [Avatars3dApi.onChange](#avatars3dapi-onchange) runs.
5091
+ avatar worn, and [Avatars3dApi.onChange](#avatars3dapi-onchange) runs. Asked in Coins
5092
+ (`ARCADE_TICKETS`) the player can afford, there is no sheet: the Arcade
5093
+ spends them at once and does not pause your game.
5092
5094
 
5093
- Call it from the player's own click or key press — the Arcade shows no
5094
- sheet without one and answers `declined` / `busy`.
5095
+ Call it only from the player's own Buy press.
5095
5096
 
5096
5097
  NOTHING REJECTS. Every outcome resolves, exactly as on
5097
5098
  `gem.purchases.request`:
@@ -15626,6 +15627,14 @@ request(req: PurchaseRequest): Promise<PurchaseOutcome>
15626
15627
 
15627
15628
  Ask the platform to complete one purchase.
15628
15629
 
15630
+ WHETHER THE PLAYER IS ASKED depends on the currency. For Gems the Arcade
15631
+ opens its purchase sheet and spends nothing until the player presses Buy.
15632
+ For Coins (`ARCADE_TICKETS`) the player can afford it opens no sheet: it
15633
+ spends at once, does not pause your game, and shows a "purchased" notice.
15634
+ Coins the player cannot afford open the sheet to say so, answered
15635
+ `declined` / `insufficient_funds`. Call this only from the player's own
15636
+ Buy press.
15637
+
15629
15638
  NOTHING REJECTS. A decline is an ordinary thing a shop does, not an
15630
15639
  exception, and neither is a store that cannot be reached — so every path
15631
15640
  out of here resolves, including the one where the SDK refuses your own
@@ -1,6 +1,6 @@
1
1
  # The server surface — API reference
2
2
 
3
- Generated from `@indiegems/gem-web-sdk/sdk` v23.1.1, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
3
+ Generated from `@indiegems/gem-web-sdk/sdk` v23.1.3, 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.1.1"
5
+ "version": "23.1.3"
6
6
  },
7
7
  "entries": [
8
8
  {
@@ -6071,7 +6071,7 @@
6071
6071
  "group": "avatars3d",
6072
6072
  "signature": "purchase(request: Avatar3dPurchaseRequest): Promise<PurchaseOutcome>",
6073
6073
  "documented": true,
6074
- "summary": "Buy one of your 3D avatars for the player and put it on. The Arcade\nprices it again, shows its own confirmation sheet, takes the currency and\nwears the avatar; your game then receives the player again, with the new\navatar worn, and [Avatars3dApi.onChange](api-reference-game.md#avatars3dapi-onchange) runs.\n\nCall it from the player's own click or key press — the Arcade shows no\nsheet without one and answers `declined` / `busy`.\n\nNOTHING REJECTS. Every outcome resolves, exactly as on\n`gem.purchases.request`:\n\n- `ok` — bought and worn, and the platform confirmed the player owns it.\n- `declined` — definitely not bought. `reason` says why:\n `already_owned` (the player has it — offer to wear it with\n `gem.openAvatarPicker({ tab: '3d' })`), `cancelled`, `insufficient_funds`,\n `no_price_in_currency`, `not_purchasable` (not on sale, or not an id from\n [Avatars3dApi.offers](api-reference-game.md#avatars3dapi-offers)), `busy`, and the rest of\n `PurchaseRefusalCode`. Return to your shop silently.\n- `unavailable` — no reliable answer. Show one neutral message, never\n retry on your own, and read [Avatars3dApi.worn](api-reference-game.md#avatars3dapi-worn) again.\n\n**Outside the Arcade** — opened at the top level of a page with no Arcade\naround it, or under an Arcade that does not sell 3D avatars yet — it\nresolves `unavailable` with reason `error` at once and asks nobody.",
6074
+ "summary": "Buy one of your 3D avatars for the player and put it on. The Arcade\nprices it again, shows its own confirmation sheet, takes the currency and\nwears the avatar; your game then receives the player again, with the new\navatar worn, and [Avatars3dApi.onChange](api-reference-game.md#avatars3dapi-onchange) runs. Asked in Coins\n(`ARCADE_TICKETS`) the player can afford, there is no sheet: the Arcade\nspends them at once and does not pause your game.\n\nCall it only from the player's own Buy press.\n\nNOTHING REJECTS. Every outcome resolves, exactly as on\n`gem.purchases.request`:\n\n- `ok` — bought and worn, and the platform confirmed the player owns it.\n- `declined` — definitely not bought. `reason` says why:\n `already_owned` (the player has it — offer to wear it with\n `gem.openAvatarPicker({ tab: '3d' })`), `cancelled`, `insufficient_funds`,\n `no_price_in_currency`, `not_purchasable` (not on sale, or not an id from\n [Avatars3dApi.offers](api-reference-game.md#avatars3dapi-offers)), `busy`, and the rest of\n `PurchaseRefusalCode`. Return to your shop silently.\n- `unavailable` — no reliable answer. Show one neutral message, never\n retry on your own, and read [Avatars3dApi.worn](api-reference-game.md#avatars3dapi-worn) again.\n\n**Outside the Arcade** — opened at the top level of a page with no Arcade\naround it, or under an Arcade that does not sell 3D avatars yet — it\nresolves `unavailable` with reason `error` at once and asks nobody.",
6075
6075
  "deprecated": null,
6076
6076
  "params": [
6077
6077
  {
@@ -17146,7 +17146,7 @@
17146
17146
  "group": "purchases",
17147
17147
  "signature": "request(req: PurchaseRequest): Promise<PurchaseOutcome>",
17148
17148
  "documented": true,
17149
- "summary": "Ask the platform to complete one purchase.\n\nNOTHING REJECTS. A decline is an ordinary thing a shop does, not an\nexception, and neither is a store that cannot be reached — so every path\nout of here resolves, including the one where the SDK refuses your own\narguments. A malformed `targetId` is answered `unavailable` immediately\nrather than thrown, because a game that has to handle \"the store is down\"\nalready has the branch and a game that has to handle a rejected promise on\na Buy button mostly does not write one.",
17149
+ "summary": "Ask the platform to complete one purchase.\n\nWHETHER THE PLAYER IS ASKED depends on the currency. For Gems the Arcade\nopens its purchase sheet and spends nothing until the player presses Buy.\nFor Coins (`ARCADE_TICKETS`) the player can afford it opens no sheet: it\nspends at once, does not pause your game, and shows a \"purchased\" notice.\nCoins the player cannot afford open the sheet to say so, answered\n`declined` / `insufficient_funds`. Call this only from the player's own\nBuy press.\n\nNOTHING REJECTS. A decline is an ordinary thing a shop does, not an\nexception, and neither is a store that cannot be reached — so every path\nout of here resolves, including the one where the SDK refuses your own\narguments. A malformed `targetId` is answered `unavailable` immediately\nrather than thrown, because a game that has to handle \"the store is down\"\nalready has the branch and a game that has to handle a rejected promise on\na Buy button mostly does not write one.",
17150
17150
  "deprecated": null,
17151
17151
  "params": [
17152
17152
  {
@@ -344,8 +344,9 @@ for (const offer of offers) {
344
344
 
345
345
  - **Render prices from `offers()`, never from numbers of your own.** The Arcade prices the sheet
346
346
  again from the platform's record, so a price you typed is a price that disagrees with it.
347
- - **Call `purchase` from a click or key press.** The Arcade shows its confirmation sheet only on
348
- one; anything else is answered `declined` with reason `busy`.
347
+ - **Call `purchase` only from the player's own Buy press.** Asked in Coins (`ARCADE_TICKETS`) the
348
+ player can afford, the Arcade spends them at once with no confirmation sheet and does not pause
349
+ your game. Asked in Gems, or in Coins the player cannot afford, it shows its sheet first.
349
350
  - **A bought avatar is worn at once.** The Arcade wears it in its family and sends the player
350
351
  again **before** it answers, so `onChange` runs and `worn()` already shows it when `purchase`
351
352
  resolves `ok`.
package/docs/changelog.md CHANGED
@@ -16,6 +16,18 @@ Its entries are grouped under up to five headings:
16
16
  - **Rebuild**: a type changed. Recompile against the new version; code that compiles today keeps compiling unless the entry says otherwise.
17
17
  - **New capability**: something a game can now do. Nothing changes unless you use it.
18
18
 
19
+ ## 23.1.3
20
+
21
+ Upgrading from 23.1.2. Impact: none.
22
+
23
+ Nothing in this release asks anything of a game.
24
+
25
+ ## 23.1.2
26
+
27
+ Upgrading from 23.1.1. Impact: none.
28
+
29
+ Nothing in this release asks anything of a game.
30
+
19
31
  ## 23.1.1
20
32
 
21
33
  Upgrading from 23.1.0. Impact: none.
@@ -272,8 +272,10 @@ full rule, and why platform currency is spent through the arcade's sheet.
272
272
 
273
273
  ### Buying it, and reading a refusal
274
274
 
275
- With the arcade's purchase sheet, the platform confirms and charges; your game asks and reads the
276
- outcome. A refusal carries a `reason` that says why:
275
+ With `gem.purchases.request`, the platform charges; your game asks and reads the outcome. A Coins
276
+ price the player can afford is spent at once, with no arcade sheet, so ask only from the player's
277
+ own Buy press. A Gems price, or Coins the player cannot afford, opens the arcade's sheet first. A
278
+ refusal carries a `reason` that says why:
277
279
 
278
280
  ```js
279
281
  const res = await gem.purchases.request({
@@ -50,7 +50,7 @@ either way.
50
50
  ```jsonc
51
51
  // package.json
52
52
  "dependencies": {
53
- "@indiegems/gem-web-sdk": "23.1.1"
53
+ "@indiegems/gem-web-sdk": "23.1.3"
54
54
  }
55
55
  ```
56
56
 
@@ -731,10 +731,10 @@ subject. [brand-art.md](brand-art.md) has both, how to draw them, and the rest o
731
731
  other platform currency through the arcade's buy sheet: the platform confirms the purchase with the
732
732
  player, offers a guest an account, and processes the order. Build your shop's Buy button on it.
733
733
 
734
- | Call | Who owns confirmation | Transport | Use it for |
735
- | -------------------------------- | --------------------- | ------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
736
- | `gem.purchases.request(...)` | the platform | postMessage bridge; platform sheet always opens | **every platform-currency purchase** — answers `ok`, `declined` or `unavailable` |
737
- | `gem.me.mutations.purchase(...)` | your game | direct authenticated SDK request; no bridge or platform sheet | recipes paid in your own game currency or items (`payment: { kind: 'configured' }`) |
734
+ | Call | Who owns confirmation | Transport | Use it for |
735
+ | -------------------------------- | --------------------- | -------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
736
+ | `gem.purchases.request(...)` | the platform | postMessage bridge; platform sheet (none for affordable Coins) | **every platform-currency purchase** — answers `ok`, `declined` or `unavailable` |
737
+ | `gem.me.mutations.purchase(...)` | your game | direct authenticated SDK request; no bridge or platform sheet | recipes paid in your own game currency or items (`payment: { kind: 'configured' }`) |
738
738
 
739
739
  `gem.me.mutations.purchase` with a `platform_currency` payment is **not for spending on
740
740
  gemarcade.com**. A web guest has no account the platform lets spend, so gem-api refuses them
@@ -764,9 +764,19 @@ if (res.outcome === 'ok' || res.outcome === 'unavailable') {
764
764
  }
765
765
  ```
766
766
 
767
- The platform always opens its purchase sheet for this call. It re-fetches the target and price,
768
- submits the order with the player's account session, and verifies an `ok` before returning it to the
769
- game.
767
+ The platform re-fetches the target and price, submits the order with the player's account session,
768
+ and verifies an `ok` before returning it to the game. Whether the player sees a sheet first depends
769
+ on the currency:
770
+
771
+ - **Gems and other platform currencies:** the arcade opens its purchase sheet, and nothing is spent
772
+ until the player presses Buy.
773
+ - **Coins (`ARCADE_TICKETS`) the player can afford:** no sheet. The arcade spends them at once, does
774
+ not pause your game, and says so over it ("Lantern purchased · 180 Coins left"). Coins are earned
775
+ by playing, never bought, so the arcade does not ask.
776
+ - **Coins the player cannot afford:** the arcade opens its sheet to say so, and answers `declined`
777
+ with reason `insufficient_funds`.
778
+
779
+ What the answer means:
770
780
 
771
781
  - `declined` means the player cancelled or the platform refused, before anything was charged.
772
782
  Return to the shop silently.
@@ -780,10 +790,10 @@ game.
780
790
  put the right state on the row or to find your own mistake. A reason your SDK version does not
781
791
  know arrives as `error`.
782
792
 
783
- The sheet opens only in answer to a player's click or key press, so call `request` from your Buy
784
- button's handler, never from a timer or on load: without one the answer is `declined` with reason
785
- `busy`, and nothing is shown. After a player cancels, the arcade answers further asks from your
786
- game `busy` for a short, growing interval — do not re-ask on `cancelled`.
793
+ Call `request` only when the player presses your Buy button, never from a timer or on load. No
794
+ gesture is required, and an `await` before the call is fine, but a Coins price the player can afford
795
+ is spent with no sheet in between, so the press must be the player's own choice. Do not re-ask on
796
+ `cancelled` by yourself: the player's next press opens the sheet again.
787
797
 
788
798
  Hide your Buy button when `gem.frame.parentSupports('purchases')` is false: that parent cannot sell
789
799
  for platform currency.
@@ -23,8 +23,8 @@
23
23
  },
24
24
  {
25
25
  "file": "arcade-avatars.md",
26
- "sha256": "e02e435d91e389f9cc2025945ebc0ac11882bac85a4e6d5d74278f11e38fee91",
27
- "updated": "2026-10-21T19:36:16Z"
26
+ "sha256": "d376a0fdc7b36355e08dd60871d8343f98b352df5938100129012248f5dbe7dc",
27
+ "updated": "2026-11-08T20:08:14Z"
28
28
  },
29
29
  {
30
30
  "file": "arcade-economy.md",
@@ -48,8 +48,8 @@
48
48
  },
49
49
  {
50
50
  "file": "changelog.md",
51
- "sha256": "ffe343dbeb0820cb452ac8395245fa39ae3d09e1b2252eaa3730b566f215a879",
52
- "updated": "2026-11-07T17:43:13Z"
51
+ "sha256": "e6195c6d12e52535a21a4a3291268a82a445b85e6a76f0049b981ff9ab374232",
52
+ "updated": "2026-11-09T03:45:00Z"
53
53
  },
54
54
  {
55
55
  "file": "daily-challenges.md",
@@ -73,13 +73,13 @@
73
73
  },
74
74
  {
75
75
  "file": "game-economy-tutorial.md",
76
- "sha256": "0ab25a9d69cf5e40351624355da5ef84e1431bf8a8a420e2c4d7350e20a5b1c5",
77
- "updated": "2026-11-04T16:44:33Z"
76
+ "sha256": "322f4414cf724c7f602fea9fc08a3dd71dd24176f6f7dd5aa47b3607dcaeab53",
77
+ "updated": "2026-11-08T20:08:14Z"
78
78
  },
79
79
  {
80
80
  "file": "getting-started.md",
81
- "sha256": "28ab09ea55162912ff25ae8ccb6f6cdc35e494d65ebf5e2b0ee8952ea0265a81",
82
- "updated": "2026-11-07T17:43:13Z"
81
+ "sha256": "aaed9165f80ea79b32eae8509dc2ef0af436b3e3df1d23cac30941c8268ee022",
82
+ "updated": "2026-11-09T03:45:00Z"
83
83
  },
84
84
  {
85
85
  "file": "graphics-route.md",
@@ -88,8 +88,8 @@
88
88
  },
89
89
  {
90
90
  "file": "inventory-and-catalogs.md",
91
- "sha256": "f5aa4e405989da098317ca704b4dd8b996a1369c78ef0515ed7442886aee85fc",
92
- "updated": "2026-11-04T23:38:54Z"
91
+ "sha256": "f0445a3b56f7a31590acd9ef2874a7f51cc8d89b6fbfc7de9ea5861f1ef555ca",
92
+ "updated": "2026-11-08T20:08:14Z"
93
93
  },
94
94
  {
95
95
  "file": "leaderboards.md",
@@ -118,8 +118,8 @@
118
118
  },
119
119
  {
120
120
  "file": "player-sign-in.md",
121
- "sha256": "df1e39628ccba04b6f7bcd0b90381dfa34a4480330a6af041d9b71bcaefddb5f",
122
- "updated": "2026-09-17T20:51:57Z"
121
+ "sha256": "22c798ff32ee15dda88f08f6701146f83fe92568c737d9321edd3e2550cb2df9",
122
+ "updated": "2026-11-09T02:37:14Z"
123
123
  },
124
124
  {
125
125
  "file": "rewarded-ads.md",
@@ -143,8 +143,8 @@
143
143
  },
144
144
  {
145
145
  "file": "server-bundles.md",
146
- "sha256": "c6b46f9b4628385858f0834dc4f44b6e737adba5805f3faefda8d4db44878b44",
147
- "updated": "2026-11-07T17:43:13Z"
146
+ "sha256": "3274318b99daed546ee192381e40962c9e1e62436cbf4edfb61340548d6dc493",
147
+ "updated": "2026-11-09T03:45:00Z"
148
148
  },
149
149
  {
150
150
  "file": "serverless-functions-js.md",