@indiegems/gem-web-sdk 19.0.0 → 19.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/gem-web-sdk.conformance.js +1 -1
- package/dist/gem-web-sdk.esm.js +1 -1
- package/dist/gem-web-sdk.function.js +1 -1
- package/dist/gem-web-sdk.game.js +3 -3
- package/dist/gem-web-sdk.min.js +3 -3
- package/dist/gem-web-sdk.sdk.js +3 -3
- package/dist/gem-web-sdk.server.js +1 -1
- package/docs/api/api-reference-function.md +1 -1
- package/docs/api/api-reference-game.md +6 -1
- package/docs/api/api-reference-server.md +1 -1
- package/docs/api/reference.json +2 -2
- package/docs/arcade-and-store.md +4 -8
- package/docs/changelog.md +6 -0
- package/docs/getting-started.md +1 -1
- package/docs/inventory-and-catalogs.md +13 -0
- package/docs/manifest.json +12 -12
- package/docs/server-bundles.md +2 -2
- package/docs/what-a-game-must-do.md +22 -1
- package/package.json +1 -1
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var Le=Object.defineProperty;var qe=(n,e)=>{for(var t in e)Le(n,t,{get:e[t],enumerable:true});};globalThis.__gemWebSdkVersion="[gem-web-sdk:sdkVersion:19.0.0]";var Me={initialDelayMs:2e3,maxDelayMs:6e4};function $e(n,e){return e!==void 0?!e:n==="chain_exhausted"}var U=class{constructor(e){this.options=e;}options;grant=null;state="pending";failure=null;generation=0;inFlight=null;rejected=false;retry=null;failures=0;notBefore=0;disposed=false;get currentState(){return this.state}get lastFailure(){return this.failure}async get(){if(this.state==="lost")throw new h(this.failure??"unavailable","the session cannot be renewed");let e=this.seconds();if(this.grant&&e<this.grant.expiresAt-this.renewBefore())return this.grant.token;if(this.pastChainCeiling())throw new h("chain_exhausted","the token chain reached its ceiling");if(this.inFlight===null&&this.options.clock.now()<this.notBefore)throw new h(this.failure??"unavailable","the embedder asked for no new token yet; one is asked for when that wait is over");return this.refresh(this.nextReason())}pastChainCeiling(){return this.grant===null||this.seconds()<this.grant.chainEndsAt?false:(this.enter("lost","chain_exhausted"),true)}nextReason(){return this.rejected?"rejected":this.grant?"expiring":"initial"}invalidate(e){e!==void 0&&this.grant!==null&&this.grant.token!==e||this.rejected&&this.grant===null||(this.grant=null,this.generation+=1,this.inFlight=null,this.rejected=true,this.state!=="lost"&&this.enter("pending"));}accept(e){this.state!=="lost"&&(this.grant=e,this.rejected=false,this.enter("ready"));}close(e="unavailable"){this.grant=null,this.generation+=1,this.inFlight=null,this.enter("lost",e);}dispose(){this.disposed=true,this.cancelRetry();}scheduleRetry(e){if(this.cancelRetry(),this.failures+=1,this.notBefore=e===void 0?0:this.options.clock.now()+e,this.disposed)return;let{initialDelayMs:t,maxDelayMs:r}=Me,o=Math.min(r,t*2**(this.failures-1)),a=Math.max(o/2,e??0)+Math.random()*(o/2);this.retry={handle:this.options.clock.setTimeout(()=>this.retryNow(),a)};}retryNow(){this.retry=null,this.notBefore=0,!(this.state==="lost"||this.pastChainCeiling())&&this.refresh(this.nextReason()).catch(()=>{});}cancelRetry(){this.retry!==null&&(this.options.clock.clearTimeout(this.retry.handle),this.retry=null);}refresh(e){if(this.inFlight)return this.inFlight;this.cancelRetry();let t=this.generation;this.enter("pending");let r=this.options.request(e).then(o=>{if(t!==this.generation)throw new h("internal","token arrived for a superseded generation");return this.grant=o,this.rejected=false,this.enter("ready"),o.token}).catch(o=>{let a=je(o),{retryable:i,retryAfterMs:d}=o??{};throw t===this.generation&&($e(a,typeof i=="boolean"?i:void 0)?this.enter("lost",a):(this.scheduleRetry(typeof d=="number"&&Number.isFinite(d)&&d>0?d:void 0),this.enter("degraded",a))),o instanceof h?o:new h(a,String(o))}).finally(()=>{this.inFlight===r&&(this.inFlight=null);});return this.inFlight=r,r}enter(e,t){(e==="ready"||e==="lost")&&this.cancelRetry(),e==="ready"&&(this.failures=0,this.notBefore=0),this.failure=t??(e==="ready"?null:this.failure),this.state!==e&&(this.state=e,this.options.onStateChange?.(e,t));}renewBefore(){return this.options.renewBeforeSeconds??60}seconds(){return Math.floor(this.options.clock.now()/1e3)}},h=class n extends Error{constructor(t,r){super(`auth ${t}: ${r}`);this.reason=t;this.name="AuthError";}reason;static isAuthError(t){if(t instanceof n)return true;let r=t;return r?.name==="AuthError"&&typeof r.reason=="string"}};function je(n){if(n instanceof h)return n.reason;let e=n?.reason;return typeof e=="string"&&["chain_exhausted","unavailable","timeout","internal"].includes(e)?e:"internal"}var f=class n extends Error{retryable=false;constructor(e){super(e),this.name="TransportRefusal";}static isRefusal(e){if(e instanceof n)return true;let t=e;return t?.name==="TransportRefusal"&&t.retryable===false}},D=["if-match","if-none-match"],Q=4096;function Be(n){if(!n)return;let e={};for(let[t,r]of Object.entries(n)){let o=t.toLowerCase();if(!D.includes(o)||r===void 0)continue;let a=typeof r=="string"?Fe(r):r;if(typeof a!="string"||a.length>Q||!Ue(a))throw new f(`the ${o} header value cannot be sent \u2014 it is not a string, is longer than ${Q} characters, or contains a character outside the range an HTTP header value may carry. This is a malformed request, not a server failure; the value is withheld here rather than written to logs.`);a!==""&&(e[o]=a);}return Object.freeze(e)}function Fe(n){let e=o=>o===32||o===9||o===10||o===13,t=0,r=n.length;for(;t<r&&e(n.charCodeAt(t));)t++;for(;r>t&&e(n.charCodeAt(r-1));)r--;return n.slice(t,r)}function Ue(n){for(let e=0;e<n.length;e++){let t=n.charCodeAt(e);if(t!==9&&(t<32||t===127||t>255))return false}return true}function De(n){let{bytes:e}=n;if(e!==void 0){if(Object.prototype.toString.call(e)!=="[object Uint8Array]")throw new f("the raw body is not a Uint8Array, so it cannot be sent as bytes. This is a malformed request, not a server failure.");if(n.body!==void 0)throw new f("the request carries both a JSON body and a raw body, and only one can be sent. This is a malformed request, not a server failure.");return new Uint8Array(e)}}function Z(n,e){let t=e.replayUnauthorizedOnce??true;return {async request(r){let o={...r},a=Be(o.headers),i=De(o),d=Object.freeze({...o,headers:a,...i===void 0?{}:{bytes:i}}),u=await e.tokenSource.get(),c=await n(d,u);if(c.status!==401||!t)return c;e.tokenSource.invalidate(u);let g=await e.tokenSource.get(),S=await n(d,g);if(S.status===401)throw e.tokenSource.close("unavailable"),new h("unavailable","the server refused a freshly minted token");return S}}}function ee(n){let e=typeof n=="string"?new TextEncoder().encode(n):n;return btoa(Ne(e))}function Ne(n){let t="";for(let r=0;r<n.length;r+=32768)t+=String.fromCharCode(...n.subarray(r,r+32768));return t}var p=class extends Error{constructor(t,r,o,a,i){super(`${t} (${r}): ${o}`);this.reason=t;this.status=r;this.detail=o;this.retryAfterSeconds=a;this.code=i;this.name="GemApiError";}reason;status;detail;retryAfterSeconds;code;get retryable(){return this.reason==="unavailable"||this.reason==="rate_limited"}},re=new WeakMap;function oe(n){return re.get(n)??{}}var He=new Set([408,429,500,502,503,504]),Ve=6e4,We=new WeakMap;function ne(n){return n!==null&&(n.reason==="rate_limited"||n.retryAfterSeconds!==void 0)}function ze(n){if(n===void 0)return 2;if(!Number.isInteger(n)||n<0||n>10)throw new f(`maxRetries must be a whole number between 0 and 10; received ${JSON.stringify(n)}. This is a configuration fault, not a server failure.`);return n}var L=class{constructor(e){this.options=e;}options;async get(e,t){return this.send({method:"GET",path:e,signal:t},true)}async getWithEtag(e,t={}){let r=await this.sendRaw({method:"GET",path:e,...t.signal===void 0?{}:{signal:t.signal},...t.ifNoneMatch===void 0?{}:{headers:{"if-none-match":t.ifNoneMatch}}},true),o=r.etag===void 0?{}:{etag:r.etag};return r.status===304?{modified:false,...o}:{modified:true,body:r.body,...o}}async put(e,t,r,o={}){return this.send({method:"PUT",path:e,body:t,signal:r,...$(o)},o.replaySafe===true,o.retryRateLimited!==false)}async post(e,t,r,o={}){return this.send({method:"POST",path:e,body:t,signal:r,...$(o)},o.replaySafe===true,o.retryRateLimited!==false)}async postBytes(e,t,r,o={}){let a=await this.sendRaw({method:"POST",path:e,bytes:t,responseType:"bytes",signal:r,...$(o)},o.replaySafe===true,o.retryRateLimited!==false);return {bytes:Ke(a.body),...a.invocationId===void 0?{}:{invocationId:a.invocationId}}}async patch(e,t,r,o={}){return this.send({method:"PATCH",path:e,body:t,signal:r,...$(o)},o.replaySafe===true,o.retryRateLimited!==false)}async delete(e,t,r={}){return this.send({method:"DELETE",path:e,signal:t,...$(r)},r.replaySafe===true,r.retryRateLimited!==false)}async send(e,t,r=true){return (await this.sendRaw(e,t,r)).body}async sendRaw(e,t,r=true){let o=t?ze(this.options.maxRetries)+1:1,a=null;if(e.signal?.aborted)throw te(e.signal);let i=e.signal===void 0?void 0:We.get(e.signal);for(let d=0;d<o;d++){if(d>0){let g=this.backoffMs(d,a);if(ne(a)&&i!==void 0&&g>=i())throw a;await this.backoff(g,e.signal);}if(e.signal?.aborted)throw ne(a)&&i!==void 0&&i()<=0?a:te(e.signal);let u;try{u=await this.options.transport.request(e);}catch(g){if(h.isAuthError(g)||f.isRefusal(g)||e.signal?.aborted||Ye(g))throw g;a=new p("unavailable",0,String(g));continue}if(u.status>=200&&u.status<300||u.status===304)return u;let c=Je(u);if(!He.has(u.status)||u.status===429&&!r)throw c;a=c;}throw a??new p("unavailable",0,"no attempt was made")}backoffMs(e,t){let r=t?.retryAfterSeconds,o=r!==void 0?r*1e3:2**(e-1)*250,a=2**(e-1)*250;return Math.min(Math.max(o,a),Ve)}backoff(e,t){return t?.aborted?Promise.resolve():new Promise(r=>{let o=this.options.clock,a=false,i=false,d,u=()=>{a||(a=true,i&&o.clearTimeout(d),t?.removeEventListener("abort",u),r());};t?.addEventListener("abort",u,{once:true}),d=o.setTimeout(u,e),i=true,a&&o.clearTimeout(d);})}};function Ke(n){if(n instanceof Uint8Array)return n;if(n==null)return new Uint8Array(0);let e=typeof n=="string"?n:JSON.stringify(n);return new TextEncoder().encode(e)}function $(n){return {...n.keepalive===void 0?{}:{keepalive:n.keepalive},...n.ifMatch===void 0?{}:{headers:{"if-match":n.ifMatch}}}}function te(n){return n.reason!==void 0?n.reason:new DOMException("The operation was aborted.","AbortError")}function Ye(n){let e=n?.name;return e==="AbortError"||e==="TimeoutError"}function Je(n){let e=Qe(n),t=en(n.body),r={...t===void 0?{}:{details:t},...n.invocationId===void 0?{}:{invocationId:n.invocationId}};return Object.keys(r).length>0&&re.set(e,r),e}var Xe=new Map([["insufficient_funds","insufficient_funds"]]);function Qe(n){let{status:e,body:t}=n,r=Ze(t),o=n.retryAfterSeconds??tn(t),a=nn(t),i=a===void 0?void 0:Xe.get(a);if(i!==void 0)return new p(i,e,r,void 0,a);switch(e){case 304:return new p("not_modified",e,r);case 400:case 422:return new p("invalid",e,r,void 0,a);case 403:return new p("forbidden",e,r,void 0,a);case 404:return new p("not_found",e,r,void 0,a);case 402:return new p("insufficient_funds",e,r,void 0,a);case 409:return new p("conflict",e,r,void 0,a);case 412:return new p("precondition_failed",e,r,void 0,a);case 413:return new p("too_large",e,r,void 0,a);case 429:return new p("rate_limited",e,r,o,a);default:return new p("unavailable",e,r,o,a)}}function Ze(n){if(typeof n=="string")return n;let e=n?.message;if(typeof e=="string")return e;let t=n?.error;if(typeof t=="string")return t;let r=t?.message;return typeof r=="string"?r:"no detail"}function en(n){let t=n?.error?.details;return t===null?void 0:t}function nn(n){let t=n?.error?.code;return typeof t=="string"&&t.length>0?t:void 0}function tn(n){let e=n?.retryAfterSeconds;return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:void 0}function rn(n){let e=n.lastIndexOf("@");return (e===-1?n:`***@${n.slice(e+1)}`).slice(0,200)}var on=new Set(D);function an(n){if(!n)return {};let e={};for(let[t,r]of Object.entries(n))on.has(t.toLowerCase())&&(e[t.toLowerCase()]=r);return e}function ae(n){let e=n.fetch??globalThis.fetch.bind(globalThis);return Z(async(t,r)=>{let o;try{o=new URL(n.baseUrl.replace(/\/+$/,""));}catch{throw new f("the configured baseUrl is not a valid URL. Its value is withheld here rather than written to logs. This is a configuration fault, not a server failure.")}let a;try{a=new URL(o.href.replace(/\/+$/,"")+t.path);}catch{throw new f(`${JSON.stringify(typeof t.path=="string"?rn(t.path):"(a non-string path)")} does not form a valid URL against ${o.protocol}//${o.host}. This is a malformed request, not a server failure.`)}if(a.protocol!==o.protocol||a.host!==o.host)throw new f(`${JSON.stringify(a.pathname)} resolves to ${a.protocol}//${a.host}, not ${o.protocol}//${o.host}. A request path may not change the request's origin \u2014 it carries the play token.`);if(a.username!==""||a.password!==""){let R=o.username!==""||o.password!=="",y=a.username!==o.username||a.password!==o.password,x=R?y?"baseUrl (and possibly the request path)":"baseUrl":"request path";throw new f(`the ${x} puts credentials in the URL, which cannot be fetched (${t.method} ${a.pathname}). The value is withheld here rather than written to logs. This is a malformed request, not a server failure.`)}for(let[R,y]of Object.entries(n.defaultQuery??{}))a.searchParams.has(R)||a.searchParams.set(R,y);let i=t.bytes,d=t.bytes===void 0?void 0:"application/octet-stream";try{t.body!==void 0&&(i=JSON.stringify(t.body),d="application/json");}catch(R){throw new f(`the body of ${t.method} ${JSON.stringify(a.pathname)} could not be serialised to JSON: ${String(R)}. This is a bug in the request, not a server failure \u2014 retrying sends the same unserialisable value.`)}let u=await e(a.toString(),{method:t.method,headers:{authorization:`Bearer ${r}`,...d===void 0?{}:{"content-type":d},...an(t.headers)},body:i,signal:t.signal,...t.keepalive===void 0?{}:{keepalive:t.keepalive},credentials:"omit",mode:"cors",redirect:"error",cache:"no-store",referrerPolicy:"no-referrer"}),c=null;if(t.responseType==="bytes"&&u.status>=200&&u.status<300)c=new Uint8Array(await u.arrayBuffer());else {let R=await u.text();if(R.length>0)try{c=JSON.parse(R);}catch{c=R;}}let g=u.headers.get("etag"),S=sn(u.headers.get("retry-after")),w=u.headers.get("x-gem-invocation-id");return {status:u.status,body:c,...g===null?{}:{etag:g},...S===void 0?{}:{retryAfterSeconds:S},...w===null||w===""?{}:{invocationId:w}}},n)}function sn(n){if(n===null)return;let e=n.trim();if(!/^\d+$/.test(e))return;let t=Number(e);return Number.isFinite(t)?t:void 0}var ln="gem-web-bridge";var dn=65536,se=8,N=5e3,ie=1024;var H=Object.create(null);var le=Object.create(null);function un(n){let e=/^([a-z][a-z0-9+.-]*):\/\/([a-z0-9.-]+|\[[0-9a-f:.]+\])(:([0-9]{1,5}))?$/i.exec(n);return e===null?false:e[4]===void 0||Number(e[4])<=65535}function cn(n){let e;try{e=new URL(n);}catch{return false}return e.username!==""||e.password!==""?false:e.protocol==="https:"?true:e.protocol==="http:"&&(e.hostname==="localhost"||e.hostname==="127.0.0.1")}function mn(n){return /^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i.test(n)}function gn(n){return /^[a-z_]+$/.test(n)}function pn(n){return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(n)||/^[a-z0-9][a-z0-9-]{1,38}[a-z0-9]$/.test(n)&&!n.includes("--")}function W(n,e,t){if(e>se)return `nesting deeper than ${se}`;if(++t.nodes>N)return `more than ${N} values`;if(t.bytes>t.cap)return `over the ${t.cap} byte limit`;if(n==null)return t.bytes+=4,null;let r=typeof n;if(r==="boolean")return t.bytes+=5,null;if(r==="number")return t.bytes+=8,null;if(r==="string")return t.bytes+=n.length*3+2,null;if(r!=="object")return `${r} is not plain data`;let o=n;if(t.seen.has(o))return "a repeated or cyclic object reference";if(t.seen.add(o),Array.isArray(n)){if(n.length>ie)return `an array of ${n.length} entries, over the ${ie} limit`;t.bytes+=2;for(let d of n){let u=W(d,e+1,t);if(u)return u}return null}let a=Object.getPrototypeOf(n);if(a!==Object.prototype&&a!==null)return "a value that is not a plain object";t.bytes+=2;let i=n;for(let d in i){if(!Object.prototype.hasOwnProperty.call(i,d))continue;if(++t.nodes>N)return `more than ${N} values`;if(t.bytes+=d.length*3+4,t.bytes>t.cap)return `over the ${t.cap} byte limit`;let u=W(i[d],e+1,t);if(u)return u}return null}function yn(n,e=dn){let t={nodes:0,bytes:0,seen:new Set,cap:e},r=W(n,0,t);return r?`message contains ${r}`:t.bytes>e?`message is over the ${e} byte limit`:null}var fn={origin:[un,"not a well-formed origin"],url:[cn,"not a safe absolute http(s) URL"],bcp47:[mn,"not a well-formed BCP 47 tag"],code:[gn,"not a code of lower-case letters and underscores"],gameRef:[pn,"not a game id or web address"]};function de(n,e,t){for(let r of e){let o=t===""?r[0]:`${t}.${r[0]}`,a=n[r[0]];if(a==null){if(r[1]<"a")continue;return `${o}: required`}let i=z(a,r,o);if(i)return i}return null}function z(n,e,t){let r=e[1].toLowerCase();switch(r){case "u":return typeof n=="boolean"?null:z(n,typeof n=="string"?[e[0],"s",e[2]]:[e[0],"n",e[3],e[4]],t);case "s":{if(typeof n!="string")return `${t}: expected string`;if(n.length>e[2])return `${t}: exceeds ${e[2]} characters`;if(e[3]){let[o,a]=fn[e[3]];if(!o(n))return `${t}: ${a}`}return null}case "n":case "i":return typeof n!="number"||!(r=="i"?Number.isInteger:Number.isFinite)(n)?`${t}: expected ${r=="i"?"integer":"number"}`:n<e[2]||n>e[3]?`${t}: out of range ${e[2]}..${e[3]}`:null;case "b":return typeof n=="boolean"?null:`${t}: expected boolean`;case "e":{let o=e[2];return o.includes(n)?null:`${t}: not one of ${o.join("|")}`}case "o":return typeof n!="object"||n===null||Array.isArray(n)?`${t}: expected object`:de(n,e[2],t);case "j":return typeof n!="object"||n===null||Array.isArray(n)?`${t}: expected a plain object`:null;case "a":{if(!Array.isArray(n))return `${t}: expected array`;if(n.length>e[2])return `${t}: exceeds ${e[2]} items`;let o=e[3],a=`${t}[]`;for(let i of n){if(i==null){if(o[1]<"a")continue;return `${a}: required`}let d=z(i,o,a);if(d)return d}return null}default:return `${t}: unknown kind ${String(r)}`}}var ue=Object.create(null);function l(n,e,t,r,o){return H[n]=t,r&&(le[n]=r),ue[n]=a=>{let i=yn(a,o);if(i)return i;if(typeof a!="object"||a===null||Array.isArray(a))return "message: expected object";let d=a;return d.gem!==ln?"gem: wrong protocol marker":d.type!==n?`type: expected ${n}`:de(d,e,"")}}var m=["requestId","s",64],I=["outcome","e",["ok","declined","unavailable"]],E=["reason","S",64,"code"];l("gem.handshake",[["versions","o",[["min","i",1,1e3],["max","i",1,1e3]]],["capabilities","A",64,["","s",64]],["embedder","s",2048,"origin"],["unbidden","B"]],30);l("gem.handshake.accept",[["v","i",1,1e3],["capabilities","A",64,["","s",64]]],5);l("gem.token",[["token","s",4096],["requestId","S",64],["generation","i",0,2147483647],["apiBaseUrl","S",512,"url"],["playerId","s",64],["gameId","s",64],["channel","e",["dev","test","release"]],["gameVersion","S",64],["expiresAt","i",0,4102444800],["chainEndsAt","i",0,4102444800],["allowDevTools","B"]],30);l("gem.token.denied",[m,["retryable","b"],["retryAfterMs","I",0,36e5],["reason","e",["chain_exhausted","unavailable"]],["correlationId","s",64]],30);l("gem.player",[["untrusted","o",[["displayName","s",64],["displayTag","S",80],["displayHandle","s",80]]],["playerId","S",64],["discriminator","S",8],["avatarIconUrl","S",2048,"url"],["avatarIconId","S",64],["avatar3dId","S",64],["avatar3dModelUrl","S",2048,"url"],["avatar3dIconUrl","S",2048,"url"],["avatars3d","A",8,["","o",[["family","s",32],["id","s",64],["modelUrl","s",256,"url"],["iconUrl","s",256,"url"]]]],["badges","A",2,["","o",[["itemId","s",64],["iconUrl","s",2048,"url"]]]],["displayTag","s",8],["avatarUrl","S",2048,"url"],["boost","O",[["multipliers","a",8,["","o",[["currencyId","s",64],["currencySlug","s",32],["multiplierBp","i",1e4,1e6]]]],["expiresInDays","I",1,7]]]],12);l("gem.pause",[["paused","b"]],120);l("gem.prefs",[["reducedMotion","b"],["muted","b"],["showFrameStats","B"],["music","B"],["sounds","B"],["locale","s",35,"bcp47"],["recommended","O",[["volume","i",0,100],["batterySaver","b"],["keyboardLayout","e",["wasd","arrows"]],["gamepadConfirm","e",["south","east"]],["vibration","b"],["lookSensitivity","I",20,400],["gamepadLookSensitivity","I",20,400],["invertLookY","B"],["touchMovement","S",16,"code"],["graphicsQuality","S",16,"code"],["graphicsQualityAuto","B"],["colorHelp","B"]]]],60);l("gem.cohorts",[["cohorts","a",8,["","o",[["experimentId","s",36],["variantKey","s",32]]]]],12,"cohorts");l("gem.earnAllowanceChanged",[],30,"earnAllowance");l("gem.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"]],["matchId","s",64],["data","j"]],1800,"p2p");l("gem.dedicatedEvent",[["event","e",["answer","error","matchEnded"]],["matchId","s",64],["sdp","S",10240],["sessionId","S",64],["code","S",64],["message","S",256],["reason","S",64]],120,"dedicated");l("gem.partyResult",[m,["partyId","S",64]],30,"parties");l("gem.clusterTarget",[["clusterTargetId","s",64],["clusterTargetIds","A",3,["","s",64]]],12,"clusterTarget");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"]],["matchId","s",64],["data","j"]],1200,"p2p");l("gem.dedicatedOffer",[["matchId","s",64],["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],["expected","I",1,1e9],["origin","O",[["x","i",0,16384],["y","i",0,16384]]]],60,"rewardCue");l("gem.walletDisplay",[["visible","b"],["currencies","A",8,["","s",64]],["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",[["params","a",16,["","o",[["key","s",64],["value","s",512]]]]],6,"share");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]],12,"purchases");l("gem.requestAvatar3dPurchase",[m,["itemId","s",64],["currencySlug","s",32]],12,"avatar3dPurchases");l("gem.purchaseResult",[m,I,E,["purchaseId","S",64]],30,"purchases");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.requestAppLinks",[m],12,"appLinks");l("gem.appLinksResult",[m,I,E,["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,I,E],30,"appLinks");l("gem.requestOpenGame",[m,["ref","s",40,"gameRef"]],6,"openGame");l("gem.openGameResult",[m,I,E],30,"openGame");l("gem.requestSimilarGames",[m,["limit","I",1,24]],12,"openGame");l("gem.similarGamesResult",[m,I,E,["games","a",24,["","o",[["gameId","s",36,"gameRef"],["slug","S",40,"gameRef"],["iconUrl","s",1024,"url"],["capsuleLandscapeUrl","s",1024,"url"],["capsulePortraitUrl","s",1024,"url"],["previewVideoUrl","S",1024,"url"],["previewPosterUrl","S",1024,"url"],["untrusted","o",[["name","s",64],["tagline","s",64],["shortDescription","s",320],["tags","a",10,["","s",32]]]]]]]],30,"openGame",524288);l("gem.requestStoreOffers",[m],12,"store");l("gem.storeOffersResult",[m,I,E,["offers","a",32,["","o",[["skuId","s",64],["kind","e",["gem_pack","boost","pass","bundle"]],["name","s",80],["description","s",400],["imageUrl","S",1024,"url"],["priceDisplay","s",32],["grant","O",[["currency","s",32],["amount","i",1,1e9]]]]]]],30,"store",262144);l("gem.requestStorePurchase",[m,["skuId","s",64]],12,"store");l("gem.storePurchaseResult",[m,I,E],30,"store");l("gem.storePurchaseSettled",[["skuId","s",64]],30,"store");l("gem.requestStoreOfferSheet",[m,["skuId","s",64]],12,"storeOfferSheet");l("gem.storeOfferSheetResult",[m,I,E],30,"storeOfferSheet");Object.freeze(ue);H.__malformed=60;Object.freeze(H);Object.freeze(le);var q={now:()=>Date.now(),setTimeout:(n,e)=>setTimeout(n,e),clearTimeout:n=>clearTimeout(n)};function ce(n){let e=n.toLowerCase();return e==="localhost"||e.endsWith(".localhost")||e==="[::1]"||e==="::1"?true:/^127(\.\d{1,3}){3}$/.test(e)}var hn=1e4;function me(n,e){return K(n,e)}function K(n,e){if(typeof n.serverToken!="function"||typeof n.onServerToken!="function")throw new Error("this runtime delivers no game-server token: host.serverToken/onServerToken are missing. The server image running this bundle predates token delivery \u2014 the bundle cannot call gem-api on it.");let t=i=>({token:i.token,expiresAt:i.expiresAt,chainEndsAt:Number.POSITIVE_INFINITY}),r=null,o=new U({clock:e.clock,...e.onStateChange===void 0?{}:{onStateChange:e.onStateChange},request:()=>new Promise((i,d)=>{let u=e.clock.setTimeout(()=>{r=null,d({reason:"unavailable",retryable:true});},e.timeoutMs??hn);r={resolve:c=>{e.clock.clearTimeout(u),i(c);},reject:d,timer:u};})}),a=n.onServerToken(i=>{let d=t(i),u=r;if(u){r=null,u.resolve(d);return}o.accept(d);});return {source:o,dispose(){a(),o.dispose(),r&&(e.clock.clearTimeout(r.timer),r.reject({reason:"unavailable",retryable:false}),r=null);}}}var J={};qe(J,{acceptTransfer:()=>_n,addEntityProgression:()=>bn,adminAction:()=>Rn,cancelInventoryTransfer:()=>vn,claimEntityProgressionRewards:()=>Sn,closeGameRoom:()=>xn,createEntityBatchOrder:()=>wn,createEntityOrder:()=>kn,createSession:()=>An,deleteEntityGameSetting:()=>On,deleteEntitySave:()=>Pn,deleteSession:()=>Gn,deleteShowcaseValue:()=>Tn,executeEntityRecipe:()=>Cn,finalizeSaveUpload:()=>In,getChannelAssignment:()=>En,getDropRates:()=>Ln,getEntityCurrency:()=>qn,getEntityGameSetting:()=>Mn,getEntityInventory:()=>$n,getEntityInventoryItem:()=>jn,getEntityLeaderboard:()=>Bn,getEntityOrder:()=>Fn,getEntityProgression:()=>Un,getEntityRecipeAvailability:()=>Dn,getEntityRecipeUsage:()=>Nn,getEntitySave:()=>Hn,getEvent:()=>Vn,getGameRoomV2:()=>Wn,getLeaderboard:()=>zn,getPlayerGameProfile:()=>Kn,getPurchaseCatalog:()=>Yn,getResolvedTemplate:()=>Jn,getRoomArgs:()=>Xn,getShowcaseValue:()=>Qn,getTransferDetails:()=>Zn,ingestAnalyticsEvents:()=>Y,initiateInventoryTransfer:()=>et,invokeFunction:()=>nt,kickPlayer:()=>tt,listChallenges:()=>rt,listEntityGameSettings:()=>ot,listEntityOrders:()=>at,listEntityProgressions:()=>st,listEntitySaves:()=>it,listEvents:()=>lt,listGameRooms:()=>dt,listResolvedTemplates:()=>ut,listTransfers:()=>ct,maxEntityProgression:()=>mt,putEntityGameSetting:()=>gt,putRoomArgs:()=>pt,putShowcaseValue:()=>yt,rejectTransfer:()=>ft,reportMatchPlayers:()=>ht,requestSaveUploadUrl:()=>_t,resetEntityProgression:()=>bt,setMatchBackfill:()=>Rt,simulateEntityOrder:()=>vt,transferHostV2:()=>St,updateGameRoomV2:()=>xt});function s(n){let e=String(n);if(!/^[A-Za-z0-9_.-]{1,128}$/.test(e)||e==="."||e==="..")throw new TypeError(`${JSON.stringify(e)} is not a usable path segment \u2014 it is interpolated into a URL`);return encodeURIComponent(e)}async function _n(n,e,t){let r=`/v1/inventory/transfers/${s(e)}/accept`;return n.client.post(r,void 0,t?.signal)}async function bn(n,e,t,r,o,a){let i=`/v1/inventory/${s(e)}/${s(t)}/progressions/${s(r)}/add`;return n.client.post(i,o,a?.signal)}async function Rn(n,e,t,r){let o=`/v1/voice/sessions/${s(e)}/admin`;return n.client.post(o,t,r?.signal)}async function vn(n,e,t){let r=`/v1/inventory/transfers/${s(e)}/cancel`;return n.client.post(r,void 0,t?.signal)}async function Sn(n,e,t,r,o,a){let i=`/v1/inventory/${s(e)}/${s(t)}/progressions/${s(r)}/claim`;return n.client.post(i,o,a?.signal)}async function xn(n,e,t){let r=`/v1/games/${s(n.gameId())}/game-rooms/${s(e)}`;return n.client.delete(r,t?.signal)}async function wn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/orders/batch`;return n.client.post(a,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function kn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/orders`;return n.client.post(a,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function An(n,e,t){return n.client.post("/v1/voice/sessions",e,t?.signal)}async function On(n,e,t,r,o){let a=`/v1/settings/${s(e)}/${s(t)}/${s(r)}`;return n.client.delete(a,o?.signal)}async function Pn(n,e,t,r,o){let a=`/v1/saves/${s(e)}/${s(t)}/${s(r)}`;return n.client.delete(a,o?.signal)}async function Gn(n,e,t){let r=`/v1/voice/sessions/${s(e)}`;return n.client.delete(r,t?.signal)}async function Tn(n,e,t,r){let o=`/v1/showcase/players/${s(e)}/${s(t)}`;return n.client.delete(o,r?.signal)}async function Cn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/recipes/execute`;return n.client.post(a,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function In(n,e,t,r,o,a){let i=`/v1/saves/${s(e)}/${s(t)}/${s(r)}/finalize`;return n.client.post(i,o,a?.signal)}async function En(n,e,t){let r=`/v1/games/${s(n.gameId())}/config/channels/${s(e)}`;return n.client.getWithEtag(r,{...t?.signal===void 0?{}:{signal:t.signal},...t?.ifNoneMatch===void 0?{}:{ifNoneMatch:t.ifNoneMatch}})}async function Ln(n,e,t){let r=`/v1/inventory/loot-tables/${s(e)}/drop-rates`;return n.client.get(r,t?.signal)}async function qn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/currencies/${s(r)}`;return n.client.get(a,o?.signal)}async function Mn(n,e,t,r,o){let a=`/v1/settings/${s(e)}/${s(t)}/${s(r)}`;return n.client.getWithEtag(a,{...o?.signal===void 0?{}:{signal:o.signal},...o?.ifNoneMatch===void 0?{}:{ifNoneMatch:o.ifNoneMatch}})}async function $n(n,e,t,r){let o=new URLSearchParams;r?.include_buckets!==void 0&&o.set("include_buckets",String(r?.include_buckets)),r?.include_custom_data!==void 0&&o.set("include_custom_data",String(r?.include_custom_data)),r?.currency_limit!==void 0&&o.set("currency_limit",String(r?.currency_limit)),r?.currency_cursor!==void 0&&o.set("currency_cursor",String(r?.currency_cursor)),r?.item_limit!==void 0&&o.set("item_limit",String(r?.item_limit)),r?.item_cursor!==void 0&&o.set("item_cursor",String(r?.item_cursor)),r?.progression_limit!==void 0&&o.set("progression_limit",String(r?.progression_limit)),r?.progression_cursor!==void 0&&o.set("progression_cursor",String(r?.progression_cursor));let a=o.toString(),i=`/v1/inventory/${s(e)}/${s(t)}`+(a?`?${a}`:"");return n.client.get(i,r?.signal)}async function jn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/items/${s(r)}`;return n.client.get(a,o?.signal)}async function Bn(n,e,t,r,o){let a=new URLSearchParams;o?.bucket_1!==void 0&&a.set("bucket_1",String(o?.bucket_1)),o?.bucket_2!==void 0&&a.set("bucket_2",String(o?.bucket_2)),o?.limit!==void 0&&a.set("limit",String(o?.limit)),o?.periods_back!==void 0&&a.set("periods_back",String(o?.periods_back)),o?.period!==void 0&&a.set("period",String(o?.period)),o?.player_id!==void 0&&a.set("player_id",String(o?.player_id));let i=a.toString(),d=`/v1/leaderboards/${s(e)}/${s(t)}/${s(r)}`+(i?`?${i}`:"");return n.client.get(d,o?.signal)}async function Fn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/orders/${s(r)}`;return n.client.get(a,o?.signal)}async function Un(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/progressions/${s(r)}`;return n.client.get(a,o?.signal)}async function Dn(n,e,t,r,o,a){let i=`/v1/inventory/${s(e)}/${s(t)}/catalogs/${s(r)}/recipes/${s(o)}/availability`;return n.client.get(i,a?.signal)}async function Nn(n,e,t,r){let o=new URLSearchParams;r?.limit!==void 0&&o.set("limit",String(r?.limit));let a=o.toString(),i=`/v1/inventory/${s(e)}/${s(t)}/recipe-usage`+(a?`?${a}`:"");return n.client.get(i,r?.signal)}async function Hn(n,e,t,r,o){let a=`/v1/saves/${s(e)}/${s(t)}/${s(r)}`;return n.client.getWithEtag(a,{...o?.signal===void 0?{}:{signal:o.signal},...o?.ifNoneMatch===void 0?{}:{ifNoneMatch:o.ifNoneMatch}})}async function Vn(n,e,t){let r=`/v1/events/${s(e)}`;return n.client.get(r,t?.signal)}async function Wn(n,e,t){let r=`/v2/games/${s(n.gameId())}/game-rooms/${s(e)}`;return n.client.getWithEtag(r,{...t?.signal===void 0?{}:{signal:t.signal},...t?.ifNoneMatch===void 0?{}:{ifNoneMatch:t.ifNoneMatch}})}async function zn(n,e,t){let r=new URLSearchParams;t?.bucket_1!==void 0&&r.set("bucket_1",String(t?.bucket_1)),t?.bucket_2!==void 0&&r.set("bucket_2",String(t?.bucket_2)),t?.periods_back!==void 0&&r.set("periods_back",String(t?.periods_back)),t?.period!==void 0&&r.set("period",String(t?.period)),t?.player_id!==void 0&&r.set("player_id",String(t?.player_id));let o=r.toString(),a=`/v1/leaderboards/${s(e)}`+(o?`?${o}`:"");return n.client.get(a,t?.signal)}async function Kn(n,e,t){let r=`/v1/profiles/players/${s(e)}`;return n.client.get(r,t?.signal)}async function Yn(n,e){let t=new URLSearchParams;e?.config_version!==void 0&&t.set("config_version",String(e?.config_version));let r=t.toString(),o="/v1/inventory/platform-funded-game-inventory-purchase-catalog"+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function Jn(n,e,t){let r=`/v1/game-room-templates/${s(e)}`;return n.client.get(r,t?.signal)}async function Xn(n,e,t){let r=`/v1/games/${s(n.gameId())}/game-rooms/${s(e)}/room-args`;return n.client.get(r,t?.signal)}async function Qn(n,e,t,r){let o=`/v1/showcase/players/${s(e)}/${s(t)}`;return n.client.get(o,r?.signal)}async function Zn(n,e,t){let r=`/v1/inventory/transfers/${s(e)}`;return n.client.get(r,t?.signal)}async function Y(n,e,t){let r=`/v1/games/${s(n.gameId())}/analytics/events`;return n.client.post(r,e,t?.signal,{replaySafe:true,retryRateLimited:false})}async function et(n,e,t){return n.client.post("/v1/inventory/transfers",e,t?.signal)}async function nt(n,e,t){return n.client.postBytes("/v1/functions/invoke",e,t?.signal)}async function tt(n,e,t,r){let o=`/v1/games/${s(n.gameId())}/game-rooms/${s(e)}/kick/${s(t)}`;return n.client.post(o,void 0,r?.signal)}async function rt(n,e){let t=new URLSearchParams;e?.periods_back!==void 0&&t.set("periods_back",String(e?.periods_back)),e?.player_id!==void 0&&t.set("player_id",String(e?.player_id));let r=t.toString(),o="/v1/challenges"+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function ot(n,e,t,r){let o=`/v1/settings/${s(e)}/${s(t)}`;return n.client.get(o,r?.signal)}async function at(n,e,t,r){let o=new URLSearchParams;r?.limit!==void 0&&o.set("limit",String(r?.limit)),r?.cursor!==void 0&&o.set("cursor",String(r?.cursor));let a=o.toString(),i=`/v1/inventory/${s(e)}/${s(t)}/orders`+(a?`?${a}`:"");return n.client.get(i,r?.signal)}async function st(n,e,t,r){let o=`/v1/inventory/${s(e)}/${s(t)}/progressions`;return n.client.get(o,r?.signal)}async function it(n,e,t,r){let o=new URLSearchParams;r?.limit!==void 0&&o.set("limit",String(r?.limit)),r?.cursor!==void 0&&o.set("cursor",String(r?.cursor));let a=o.toString(),i=`/v1/saves/${s(e)}/${s(t)}`+(a?`?${a}`:"");return n.client.get(i,r?.signal)}async function lt(n,e){let t=new URLSearchParams;e?.include_inactive!==void 0&&t.set("include_inactive",String(e?.include_inactive)),e?.limit!==void 0&&t.set("limit",String(e?.limit)),e?.offset!==void 0&&t.set("offset",String(e?.offset));let r=t.toString(),o="/v1/events"+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function dt(n,e){let t=new URLSearchParams;e?.status!==void 0&&t.set("status",String(e?.status)),e?.game_channel!==void 0&&t.set("game_channel",String(e?.game_channel)),e?.game_room_type!==void 0&&t.set("game_room_type",String(e?.game_room_type)),e?.template_id!==void 0&&t.set("template_id",String(e?.template_id)),e?.template_slug!==void 0&&t.set("template_slug",String(e?.template_slug)),e?.limit!==void 0&&t.set("limit",String(e?.limit)),e?.cursor!==void 0&&t.set("cursor",String(e?.cursor));let r=t.toString(),o=`/v1/games/${s(n.gameId())}/game-rooms`+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function ut(n,e){return n.client.get("/v1/game-room-templates",e?.signal)}async function ct(n,e){let t=new URLSearchParams;e.entity_type!==void 0&&t.set("entity_type",String(e.entity_type)),e.entity_id!==void 0&&t.set("entity_id",String(e.entity_id)),e?.direction!==void 0&&t.set("direction",String(e?.direction)),e?.status!==void 0&&t.set("status",String(e?.status)),e?.cursor!==void 0&&t.set("cursor",String(e?.cursor)),e?.limit!==void 0&&t.set("limit",String(e?.limit));let r=t.toString(),o="/v1/inventory/transfers"+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function mt(n,e,t,r,o,a){let i=`/v1/inventory/${s(e)}/${s(t)}/progressions/${s(r)}/max`;return n.client.post(i,o,a?.signal)}async function gt(n,e,t,r,o,a){let i=`/v1/settings/${s(e)}/${s(t)}/${s(r)}`;return n.client.put(i,o,a?.signal,{...a?.ifMatch===void 0?{}:{ifMatch:a.ifMatch}})}async function pt(n,e,t,r){let o=`/v1/games/${s(n.gameId())}/game-rooms/${s(e)}/room-args`;return n.client.put(o,t,r?.signal)}async function yt(n,e,t,r,o){let a=`/v1/showcase/players/${s(e)}/${s(t)}`;return n.client.put(a,r,o?.signal)}async function ft(n,e,t){let r=`/v1/inventory/transfers/${s(e)}/reject`;return n.client.post(r,void 0,t?.signal)}async function ht(n,e,t,r){let o=`/v1/games/${s(n.gameId())}/matches/${s(e)}/players/report`;return n.client.post(o,t,r?.signal)}async function _t(n,e,t,r,o,a){let i=`/v1/saves/${s(e)}/${s(t)}/${s(r)}/upload-url`;return n.client.post(i,o,a?.signal,{replaySafe:true})}async function bt(n,e,t,r,o,a){let i=`/v1/inventory/${s(e)}/${s(t)}/progressions/${s(r)}/reset`;return n.client.post(i,o,a?.signal)}async function Rt(n,e,t,r){let o=`/v1/games/${s(n.gameId())}/matches/${s(e)}/backfill`;return n.client.put(o,t,r?.signal)}async function vt(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/orders/simulate`;return n.client.post(a,r,o?.signal)}async function St(n,e,t,r){let o=`/v2/games/${s(n.gameId())}/game-rooms/${s(e)}/transfer/${s(t)}`;return n.client.post(o,void 0,r?.signal)}async function xt(n,e,t,r){let o=`/v2/games/${s(n.gameId())}/game-rooms/${s(e)}`;return n.client.patch(o,t,r?.signal,{...r?.ifMatch===void 0?{}:{ifMatch:r.ifMatch}})}var ge="gem_";function pe(n,e){let t=e?.retryAfterSeconds,r=typeof t=="number"&&Number.isFinite(t)&&t>0?t*1e3:0,o=1e4*2**Math.min(Math.max(0,n-1),16);return Math.min(Math.max(r,o),3e5)}var At=1e4,Ot=50,Pt=1e3,Gt=65536-4*1024,ye=n=>typeof n=="number"?n:0,Tt=n=>typeof n=="string"?n:"";function fe(){let n=globalThis.crypto;return typeof n?.randomUUID=="function"?n.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{let t=Math.floor(Math.random()*16);return (e==="x"?t:t&3|8).toString(16)})}function Ct(n){return n?.retryable===true}function It(n,e){let t=n??{},r=Array.isArray(t.rejected)?t.rejected.map(o=>{let a=o??{};return {index:ye(a.index),code:Tt(a.code)}}):[];return {accepted:ye(t.accepted),rejected:r,dropped:e,duplicate:t.duplicate===true}}function he(n,e){return {event_uid:n.uid,name:n.name,offset_ms:Math.round(n.atMs)-e,player_id:n.playerId,dimensions:n.dimensions,measures:n.measures}}function _e(n){let e=Math.max(1,Math.floor(n.maxQueue??Pt)),t={client:n.client,gameId:()=>n.gameId},r=[],o=0,a=null,i=false,d=null,u=0,c=0,g=false,S=false,w=_=>{n.log?.(_);},R=()=>{a!==null&&(n.clock.clearTimeout(a),a=null);},y=()=>Math.max(0,c-n.clock.now()),x=()=>{a!==null||i||d!==null||(a=n.clock.setTimeout(()=>{a=null,P().catch(()=>{});},Math.max(At,y())));},A=()=>{let _=Math.min(r.length,100),b=128;for(let G=0;G<_;G+=1){let T=r[G];if(T===void 0)break;if(b+=JSON.stringify(he(T,0)).length+1,b>Gt)return Math.max(1,G)}return _};async function P(_){for(;d!==null;)await d.catch(()=>{});if(r.length===0)return {accepted:0,rejected:[],dropped:0,duplicate:false};let b=Ie(_);d=b;try{return await b}finally{d===b&&(d=null),r.length>0&&x();}}async function Ie(_){R();let b=r.splice(0,A()),G=o;o=0;let T=Math.round(n.clock.now()),F={batch_id:fe(),sent_at_ms:T,events:b.map(k=>he(k,T))};try{let k=await Y(t,F,_===void 0?void 0:{signal:_}),C=It(k,G);u=0,c=0;for(let Ee of C.rejected)w(`[gem] analytics: an event was refused (${Ee.code}). See the analytics_events section of your game config.`);return C}catch(k){if(Ct(k)){for(r=[...b,...r],o+=G;r.length>e;)r.shift(),o+=1;u+=1,c=n.clock.now()+pe(u,k);}else w(`[gem] analytics: ${b.length} event(s) were discarded \u2014 the platform refused the batch and will refuse it again: ${String(k)}`);throw k}}return {track(_,b,G={}){if(i)return;if(typeof _!="string"||_===""){S||(S=true,w(`[gem] analytics: '${b}' was not recorded \u2014 an event from a server has to name the player it is about. A game-server token names no player, so the platform cannot infer one; pass the id from join() or host.players().`));return}if(b.startsWith(ge)){g||(g=true,w(`[gem] analytics: '${b}' was not recorded \u2014 the gem_ prefix is reserved, and the platform's own events are client-sourced, so a server may not emit one at all. Name your event something else.`));return}let T={},F={};for(let[k,C]of Object.entries(G))typeof C=="string"?T[k]=C:typeof C=="number"&&Number.isFinite(C)&&(F[k]=C);for(;r.length>=e;)r.shift(),o+=1;r.push({uid:fe(),playerId:_,name:b,atMs:n.clock.now(),dimensions:T,measures:F}),r.length>=Ot&&d===null&&y()===0?P().catch(()=>{}):x();},flush:_=>P(_),get pending(){return r.length},dispose(){i=true,R(),r=[],o=0;}}}var Et=new Map([["function_error",false],["function_failed",false],["function_timeout",false],["function_not_published",false],["function_input_too_large",false],["functions_not_configured",false],["forbidden",false],["function_capacity_unavailable",true],["function_host_unreachable",true],["function_host_error",true],["rate_limited",true],["service_unavailable",true]]),j=class extends p{constructor(e,t){super(e.reason,e.status,e.detail,e.retryAfterSeconds,e.code),this.name="GemFunctionError",Object.assign(this,t);}get retryable(){return (this.code===void 0?void 0:Et.get(this.code))??super.retryable}},M=class{#e;constructor(e){this.#e=e;}async invoke(e,t={}){let r=Lt(e),o;try{o=await this.#e(r,t.signal===void 0?{}:{signal:t.signal});}catch(a){throw a instanceof p?Mt(a):a}return qt(o)}};function Lt(n){if(n instanceof ArrayBuffer)return new Uint8Array(n);if(ArrayBuffer.isView(n))return new Uint8Array(n.buffer,n.byteOffset,n.byteLength);let e;try{e=JSON.stringify(n);}catch(t){throw new f(`the function input could not be serialised to JSON: ${String(t)}. Pass bytes, or a value JSON can carry. This is a bug in the call, not a server failure.`)}if(e===void 0)throw new f(`the function input is ${typeof n}, which JSON cannot carry. Pass bytes \u2014 an empty Uint8Array for no input \u2014 or a JSON value. This is a bug in the call, not a server failure.`);return new TextEncoder().encode(e)}function qt(n){let{bytes:e}=n,t=()=>new TextDecoder("utf-8",{fatal:true}).decode(e);return {bytes:e,...n.invocationId===void 0?{}:{invocationId:n.invocationId},text:t,json:()=>JSON.parse(t())}}function Mt(n){let{details:e,invocationId:t}=oe(n),o=e?.untrusted?.message,a=e?.reason;return new j(n,{...t===void 0?{}:{invocationId:t},...n.code==="function_error"&&typeof o=="string"?{functionMessage:o}:{},...n.code==="function_failed"&&typeof a=="string"?{failure:a}:{}})}var O=n=>typeof n=="string"?n:"",$t=/(?:Z|[+-]\d{2}:?\d{2})$/i;function be(n){let e=O(n);if(!$t.test(e))return 0;let t=Date.parse(e);return Number.isFinite(t)?Math.floor(t/1e3):0}var jt=/^[0-9a-f]{1,64}$/,Bt=/^[0-9a-f]{16}$/,Ft=/^[A-Za-z][A-Za-z0-9_+\-/]{0,63}$/,Ut=/^(?:[01]\d|2[0-3]):[0-5]\d$/;function Dt(n){let e=O(n),t=/^(\d{4})-(\d{2})-(\d{2})$/.exec(e);if(!t)return;let[r,o,a]=[Number(t[1]),Number(t[2]),Number(t[3])],i=new Date(Date.UTC(r,o-1,a));return i.getUTCFullYear()===r&&i.getUTCMonth()===o-1&&i.getUTCDate()===a?e:void 0}var Nt=4096,Ht=new TextEncoder;function Vt(n){let e=O(n.challenge_data),t=O(n.challenge_data_hash);return e===""||!Bt.test(t)?{}:Ht.encode(e).length>Nt?{}:{data:e,dataHash:t}}function Wt(n){let e=n??{},t=be(e.period_start_at),r=be(e.period_ends_at);if(t===0||r===0)return;let o=O(e.slug),a=O(e.seed),i=Dt(e.period_local_date),d=O(e.boundary),u=O(e.reset_time);return {id:O(e.progression_definition_id),...o===""?{}:{slug:o},window:O(e.window),periodStartAt:t,periodEndsAt:r,...i===void 0?{}:{periodLocalDate:i},boundary:Ft.test(d)?d:"",resetTime:Ut.test(u)?u:"",seed:jt.test(a)?a:"",...Vt(e)}}function Re(n){if(n!==void 0&&(!Number.isInteger(n)||n<0||n>400))throw new TypeError(`periodsBack must be an integer between 0 and 400, got ${String(n)}`)}function ve(n){let e=n??{};return Array.isArray(e.challenges)?e.challenges.map(Wt).filter(t=>t!==void 0):[]}function Se(n){return {async list(e){let{playerId:t,periodsBack:r,signal:o}=e??{};if(typeof t!="string"||t==="")throw new TypeError("gem.challenges.list needs { playerId }: a game-server token names no player, so the platform cannot tell whose period you mean. Pass the id from join() or gem.players().");Re(r);let a=await n({player_id:t,...r===void 0?{}:{periods_back:r},...o===void 0?{}:{signal:o}});return ve(a)}}}function zt(n){let e={};for(let[t,r]of Object.entries(J))if(typeof r=="function"){let o=r;e[t]=(...a)=>o(n,...a);}return e}function V(n,e={}){let t=e.clock??q,r=e.baseUrl??n.apiBaseUrl;if(!r)throw new Error("this runtime names no gem-api host (host.apiBaseUrl is missing). The server image running this bundle predates token delivery \u2014 the bundle cannot call gem-api on it.");let o=K(n,{clock:t,...e.onAuthStateChange===void 0?{}:{onStateChange:e.onAuthStateChange}}),a=ae({baseUrl:r,tokenSource:o.source,defaultQuery:{game_id:n.gameId,channel:n.channel},...e.fetch===void 0?{}:{fetch:e.fetch}}),i=new L({transport:a,clock:t}),d={gameId:n.gameId,channel:n.channel,matchId:n.matchId,...n.gameRoomId===void 0?{}:{gameRoomId:n.gameRoomId}},u=zt({client:i,gameId:()=>d.gameId}),c=d.gameRoomId,g=n.endMatch,S=n.log,w=_e({client:i,clock:t,gameId:d.gameId,...typeof S=="function"?{log:y=>S.call(n,y)}:{}});return {identity:d,client:i,api:u,match:{end:async()=>{if(g===void 0)throw new Error("this runtime cannot end the match: the server image running this bundle predates host.endMatch, and only the platform half holds the allocation proof an end needs.");await g.call(n);},setBackfill:async(y,x)=>{let A=await u.setMatchBackfill(d.matchId,{open:y.open,...y.seats===void 0?{}:{seats:y.seats}},x===void 0?{}:{signal:x});return {open:A.open,seats:A.seats??null}},reportPlayers:async(y,x)=>(await u.reportMatchPlayers(d.matchId,{players:y.map(P=>({player_id:P.playerId,state:P.state}))},x===void 0?{}:{signal:x})).players.map(P=>({playerId:P.player_id,outcome:P.outcome}))},analytics:w,functions:new M(u.invokeFunction),challenges:Se(u.listChallenges),...c===void 0?{}:{room:{get:y=>u.getGameRoomV2(c,y),args:async y=>{let x=await u.getGameRoomV2(c,y?.signal===void 0?{}:{signal:y.signal}),A=x.modified?x.body:void 0;if(A?.room_args==null||A.room_args_template==null)throw new p("not_found",404,"this room's template declares no room args",void 0,"room_args_not_defined");return {room_args:A.room_args,room_args_template:A.room_args_template}}}},dispose:()=>{w.dispose(),o.dispose();}}}var Kt=["explicit","stale_cleanup","game_room_closed","replaced","migration_failed","host_left","insufficient_players","all_left","expired","migration_rate_exceeded","game_room_gone","failed","idle","reclaimed"],Yt=new Set(Kt);function xe(n){return typeof n=="string"&&Yt.has(n)?n:"unknown"}var Ae="[gem: use gem.text.toPlain()]",we=new Set,ke;function Jt(n){try{if(we.has(n))return;let e=globalThis.location;if(ke??=!!e?.port&&ce(e.hostname??""),!ke)return;we.add(n),console.warn(`[gem] ${n} is PlayerText, turned into a string: players see ${Ae}. Render text.toPlain(value) (text is in @indiegems/gem-web-sdk/sdk).
|
|
1
|
+
var Le=Object.defineProperty;var qe=(n,e)=>{for(var t in e)Le(n,t,{get:e[t],enumerable:true});};globalThis.__gemWebSdkVersion="[gem-web-sdk:sdkVersion:19.0.1]";var Me={initialDelayMs:2e3,maxDelayMs:6e4};function $e(n,e){return e!==void 0?!e:n==="chain_exhausted"}var U=class{constructor(e){this.options=e;}options;grant=null;state="pending";failure=null;generation=0;inFlight=null;rejected=false;retry=null;failures=0;notBefore=0;disposed=false;get currentState(){return this.state}get lastFailure(){return this.failure}async get(){if(this.state==="lost")throw new h(this.failure??"unavailable","the session cannot be renewed");let e=this.seconds();if(this.grant&&e<this.grant.expiresAt-this.renewBefore())return this.grant.token;if(this.pastChainCeiling())throw new h("chain_exhausted","the token chain reached its ceiling");if(this.inFlight===null&&this.options.clock.now()<this.notBefore)throw new h(this.failure??"unavailable","the embedder asked for no new token yet; one is asked for when that wait is over");return this.refresh(this.nextReason())}pastChainCeiling(){return this.grant===null||this.seconds()<this.grant.chainEndsAt?false:(this.enter("lost","chain_exhausted"),true)}nextReason(){return this.rejected?"rejected":this.grant?"expiring":"initial"}invalidate(e){e!==void 0&&this.grant!==null&&this.grant.token!==e||this.rejected&&this.grant===null||(this.grant=null,this.generation+=1,this.inFlight=null,this.rejected=true,this.state!=="lost"&&this.enter("pending"));}accept(e){this.state!=="lost"&&(this.grant=e,this.rejected=false,this.enter("ready"));}close(e="unavailable"){this.grant=null,this.generation+=1,this.inFlight=null,this.enter("lost",e);}dispose(){this.disposed=true,this.cancelRetry();}scheduleRetry(e){if(this.cancelRetry(),this.failures+=1,this.notBefore=e===void 0?0:this.options.clock.now()+e,this.disposed)return;let{initialDelayMs:t,maxDelayMs:r}=Me,o=Math.min(r,t*2**(this.failures-1)),a=Math.max(o/2,e??0)+Math.random()*(o/2);this.retry={handle:this.options.clock.setTimeout(()=>this.retryNow(),a)};}retryNow(){this.retry=null,this.notBefore=0,!(this.state==="lost"||this.pastChainCeiling())&&this.refresh(this.nextReason()).catch(()=>{});}cancelRetry(){this.retry!==null&&(this.options.clock.clearTimeout(this.retry.handle),this.retry=null);}refresh(e){if(this.inFlight)return this.inFlight;this.cancelRetry();let t=this.generation;this.enter("pending");let r=this.options.request(e).then(o=>{if(t!==this.generation)throw new h("internal","token arrived for a superseded generation");return this.grant=o,this.rejected=false,this.enter("ready"),o.token}).catch(o=>{let a=je(o),{retryable:i,retryAfterMs:d}=o??{};throw t===this.generation&&($e(a,typeof i=="boolean"?i:void 0)?this.enter("lost",a):(this.scheduleRetry(typeof d=="number"&&Number.isFinite(d)&&d>0?d:void 0),this.enter("degraded",a))),o instanceof h?o:new h(a,String(o))}).finally(()=>{this.inFlight===r&&(this.inFlight=null);});return this.inFlight=r,r}enter(e,t){(e==="ready"||e==="lost")&&this.cancelRetry(),e==="ready"&&(this.failures=0,this.notBefore=0),this.failure=t??(e==="ready"?null:this.failure),this.state!==e&&(this.state=e,this.options.onStateChange?.(e,t));}renewBefore(){return this.options.renewBeforeSeconds??60}seconds(){return Math.floor(this.options.clock.now()/1e3)}},h=class n extends Error{constructor(t,r){super(`auth ${t}: ${r}`);this.reason=t;this.name="AuthError";}reason;static isAuthError(t){if(t instanceof n)return true;let r=t;return r?.name==="AuthError"&&typeof r.reason=="string"}};function je(n){if(n instanceof h)return n.reason;let e=n?.reason;return typeof e=="string"&&["chain_exhausted","unavailable","timeout","internal"].includes(e)?e:"internal"}var f=class n extends Error{retryable=false;constructor(e){super(e),this.name="TransportRefusal";}static isRefusal(e){if(e instanceof n)return true;let t=e;return t?.name==="TransportRefusal"&&t.retryable===false}},D=["if-match","if-none-match"],Q=4096;function Be(n){if(!n)return;let e={};for(let[t,r]of Object.entries(n)){let o=t.toLowerCase();if(!D.includes(o)||r===void 0)continue;let a=typeof r=="string"?Fe(r):r;if(typeof a!="string"||a.length>Q||!Ue(a))throw new f(`the ${o} header value cannot be sent \u2014 it is not a string, is longer than ${Q} characters, or contains a character outside the range an HTTP header value may carry. This is a malformed request, not a server failure; the value is withheld here rather than written to logs.`);a!==""&&(e[o]=a);}return Object.freeze(e)}function Fe(n){let e=o=>o===32||o===9||o===10||o===13,t=0,r=n.length;for(;t<r&&e(n.charCodeAt(t));)t++;for(;r>t&&e(n.charCodeAt(r-1));)r--;return n.slice(t,r)}function Ue(n){for(let e=0;e<n.length;e++){let t=n.charCodeAt(e);if(t!==9&&(t<32||t===127||t>255))return false}return true}function De(n){let{bytes:e}=n;if(e!==void 0){if(Object.prototype.toString.call(e)!=="[object Uint8Array]")throw new f("the raw body is not a Uint8Array, so it cannot be sent as bytes. This is a malformed request, not a server failure.");if(n.body!==void 0)throw new f("the request carries both a JSON body and a raw body, and only one can be sent. This is a malformed request, not a server failure.");return new Uint8Array(e)}}function Z(n,e){let t=e.replayUnauthorizedOnce??true;return {async request(r){let o={...r},a=Be(o.headers),i=De(o),d=Object.freeze({...o,headers:a,...i===void 0?{}:{bytes:i}}),u=await e.tokenSource.get(),c=await n(d,u);if(c.status!==401||!t)return c;e.tokenSource.invalidate(u);let g=await e.tokenSource.get(),S=await n(d,g);if(S.status===401)throw e.tokenSource.close("unavailable"),new h("unavailable","the server refused a freshly minted token");return S}}}function ee(n){let e=typeof n=="string"?new TextEncoder().encode(n):n;return btoa(Ne(e))}function Ne(n){let t="";for(let r=0;r<n.length;r+=32768)t+=String.fromCharCode(...n.subarray(r,r+32768));return t}var p=class extends Error{constructor(t,r,o,a,i){super(`${t} (${r}): ${o}`);this.reason=t;this.status=r;this.detail=o;this.retryAfterSeconds=a;this.code=i;this.name="GemApiError";}reason;status;detail;retryAfterSeconds;code;get retryable(){return this.reason==="unavailable"||this.reason==="rate_limited"}},re=new WeakMap;function oe(n){return re.get(n)??{}}var He=new Set([408,429,500,502,503,504]),Ve=6e4,We=new WeakMap;function ne(n){return n!==null&&(n.reason==="rate_limited"||n.retryAfterSeconds!==void 0)}function ze(n){if(n===void 0)return 2;if(!Number.isInteger(n)||n<0||n>10)throw new f(`maxRetries must be a whole number between 0 and 10; received ${JSON.stringify(n)}. This is a configuration fault, not a server failure.`);return n}var L=class{constructor(e){this.options=e;}options;async get(e,t){return this.send({method:"GET",path:e,signal:t},true)}async getWithEtag(e,t={}){let r=await this.sendRaw({method:"GET",path:e,...t.signal===void 0?{}:{signal:t.signal},...t.ifNoneMatch===void 0?{}:{headers:{"if-none-match":t.ifNoneMatch}}},true),o=r.etag===void 0?{}:{etag:r.etag};return r.status===304?{modified:false,...o}:{modified:true,body:r.body,...o}}async put(e,t,r,o={}){return this.send({method:"PUT",path:e,body:t,signal:r,...$(o)},o.replaySafe===true,o.retryRateLimited!==false)}async post(e,t,r,o={}){return this.send({method:"POST",path:e,body:t,signal:r,...$(o)},o.replaySafe===true,o.retryRateLimited!==false)}async postBytes(e,t,r,o={}){let a=await this.sendRaw({method:"POST",path:e,bytes:t,responseType:"bytes",signal:r,...$(o)},o.replaySafe===true,o.retryRateLimited!==false);return {bytes:Ke(a.body),...a.invocationId===void 0?{}:{invocationId:a.invocationId}}}async patch(e,t,r,o={}){return this.send({method:"PATCH",path:e,body:t,signal:r,...$(o)},o.replaySafe===true,o.retryRateLimited!==false)}async delete(e,t,r={}){return this.send({method:"DELETE",path:e,signal:t,...$(r)},r.replaySafe===true,r.retryRateLimited!==false)}async send(e,t,r=true){return (await this.sendRaw(e,t,r)).body}async sendRaw(e,t,r=true){let o=t?ze(this.options.maxRetries)+1:1,a=null;if(e.signal?.aborted)throw te(e.signal);let i=e.signal===void 0?void 0:We.get(e.signal);for(let d=0;d<o;d++){if(d>0){let g=this.backoffMs(d,a);if(ne(a)&&i!==void 0&&g>=i())throw a;await this.backoff(g,e.signal);}if(e.signal?.aborted)throw ne(a)&&i!==void 0&&i()<=0?a:te(e.signal);let u;try{u=await this.options.transport.request(e);}catch(g){if(h.isAuthError(g)||f.isRefusal(g)||e.signal?.aborted||Ye(g))throw g;a=new p("unavailable",0,String(g));continue}if(u.status>=200&&u.status<300||u.status===304)return u;let c=Je(u);if(!He.has(u.status)||u.status===429&&!r)throw c;a=c;}throw a??new p("unavailable",0,"no attempt was made")}backoffMs(e,t){let r=t?.retryAfterSeconds,o=r!==void 0?r*1e3:2**(e-1)*250,a=2**(e-1)*250;return Math.min(Math.max(o,a),Ve)}backoff(e,t){return t?.aborted?Promise.resolve():new Promise(r=>{let o=this.options.clock,a=false,i=false,d,u=()=>{a||(a=true,i&&o.clearTimeout(d),t?.removeEventListener("abort",u),r());};t?.addEventListener("abort",u,{once:true}),d=o.setTimeout(u,e),i=true,a&&o.clearTimeout(d);})}};function Ke(n){if(n instanceof Uint8Array)return n;if(n==null)return new Uint8Array(0);let e=typeof n=="string"?n:JSON.stringify(n);return new TextEncoder().encode(e)}function $(n){return {...n.keepalive===void 0?{}:{keepalive:n.keepalive},...n.ifMatch===void 0?{}:{headers:{"if-match":n.ifMatch}}}}function te(n){return n.reason!==void 0?n.reason:new DOMException("The operation was aborted.","AbortError")}function Ye(n){let e=n?.name;return e==="AbortError"||e==="TimeoutError"}function Je(n){let e=Qe(n),t=en(n.body),r={...t===void 0?{}:{details:t},...n.invocationId===void 0?{}:{invocationId:n.invocationId}};return Object.keys(r).length>0&&re.set(e,r),e}var Xe=new Map([["insufficient_funds","insufficient_funds"]]);function Qe(n){let{status:e,body:t}=n,r=Ze(t),o=n.retryAfterSeconds??tn(t),a=nn(t),i=a===void 0?void 0:Xe.get(a);if(i!==void 0)return new p(i,e,r,void 0,a);switch(e){case 304:return new p("not_modified",e,r);case 400:case 422:return new p("invalid",e,r,void 0,a);case 403:return new p("forbidden",e,r,void 0,a);case 404:return new p("not_found",e,r,void 0,a);case 402:return new p("insufficient_funds",e,r,void 0,a);case 409:return new p("conflict",e,r,void 0,a);case 412:return new p("precondition_failed",e,r,void 0,a);case 413:return new p("too_large",e,r,void 0,a);case 429:return new p("rate_limited",e,r,o,a);default:return new p("unavailable",e,r,o,a)}}function Ze(n){if(typeof n=="string")return n;let e=n?.message;if(typeof e=="string")return e;let t=n?.error;if(typeof t=="string")return t;let r=t?.message;return typeof r=="string"?r:"no detail"}function en(n){let t=n?.error?.details;return t===null?void 0:t}function nn(n){let t=n?.error?.code;return typeof t=="string"&&t.length>0?t:void 0}function tn(n){let e=n?.retryAfterSeconds;return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:void 0}function rn(n){let e=n.lastIndexOf("@");return (e===-1?n:`***@${n.slice(e+1)}`).slice(0,200)}var on=new Set(D);function an(n){if(!n)return {};let e={};for(let[t,r]of Object.entries(n))on.has(t.toLowerCase())&&(e[t.toLowerCase()]=r);return e}function ae(n){let e=n.fetch??globalThis.fetch.bind(globalThis);return Z(async(t,r)=>{let o;try{o=new URL(n.baseUrl.replace(/\/+$/,""));}catch{throw new f("the configured baseUrl is not a valid URL. Its value is withheld here rather than written to logs. This is a configuration fault, not a server failure.")}let a;try{a=new URL(o.href.replace(/\/+$/,"")+t.path);}catch{throw new f(`${JSON.stringify(typeof t.path=="string"?rn(t.path):"(a non-string path)")} does not form a valid URL against ${o.protocol}//${o.host}. This is a malformed request, not a server failure.`)}if(a.protocol!==o.protocol||a.host!==o.host)throw new f(`${JSON.stringify(a.pathname)} resolves to ${a.protocol}//${a.host}, not ${o.protocol}//${o.host}. A request path may not change the request's origin \u2014 it carries the play token.`);if(a.username!==""||a.password!==""){let R=o.username!==""||o.password!=="",y=a.username!==o.username||a.password!==o.password,x=R?y?"baseUrl (and possibly the request path)":"baseUrl":"request path";throw new f(`the ${x} puts credentials in the URL, which cannot be fetched (${t.method} ${a.pathname}). The value is withheld here rather than written to logs. This is a malformed request, not a server failure.`)}for(let[R,y]of Object.entries(n.defaultQuery??{}))a.searchParams.has(R)||a.searchParams.set(R,y);let i=t.bytes,d=t.bytes===void 0?void 0:"application/octet-stream";try{t.body!==void 0&&(i=JSON.stringify(t.body),d="application/json");}catch(R){throw new f(`the body of ${t.method} ${JSON.stringify(a.pathname)} could not be serialised to JSON: ${String(R)}. This is a bug in the request, not a server failure \u2014 retrying sends the same unserialisable value.`)}let u=await e(a.toString(),{method:t.method,headers:{authorization:`Bearer ${r}`,...d===void 0?{}:{"content-type":d},...an(t.headers)},body:i,signal:t.signal,...t.keepalive===void 0?{}:{keepalive:t.keepalive},credentials:"omit",mode:"cors",redirect:"error",cache:"no-store",referrerPolicy:"no-referrer"}),c=null;if(t.responseType==="bytes"&&u.status>=200&&u.status<300)c=new Uint8Array(await u.arrayBuffer());else {let R=await u.text();if(R.length>0)try{c=JSON.parse(R);}catch{c=R;}}let g=u.headers.get("etag"),S=sn(u.headers.get("retry-after")),w=u.headers.get("x-gem-invocation-id");return {status:u.status,body:c,...g===null?{}:{etag:g},...S===void 0?{}:{retryAfterSeconds:S},...w===null||w===""?{}:{invocationId:w}}},n)}function sn(n){if(n===null)return;let e=n.trim();if(!/^\d+$/.test(e))return;let t=Number(e);return Number.isFinite(t)?t:void 0}var ln="gem-web-bridge";var dn=65536,se=8,N=5e3,ie=1024;var H=Object.create(null);var le=Object.create(null);function un(n){let e=/^([a-z][a-z0-9+.-]*):\/\/([a-z0-9.-]+|\[[0-9a-f:.]+\])(:([0-9]{1,5}))?$/i.exec(n);return e===null?false:e[4]===void 0||Number(e[4])<=65535}function cn(n){let e;try{e=new URL(n);}catch{return false}return e.username!==""||e.password!==""?false:e.protocol==="https:"?true:e.protocol==="http:"&&(e.hostname==="localhost"||e.hostname==="127.0.0.1")}function mn(n){return /^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i.test(n)}function gn(n){return /^[a-z_]+$/.test(n)}function pn(n){return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(n)||/^[a-z0-9][a-z0-9-]{1,38}[a-z0-9]$/.test(n)&&!n.includes("--")}function W(n,e,t){if(e>se)return `nesting deeper than ${se}`;if(++t.nodes>N)return `more than ${N} values`;if(t.bytes>t.cap)return `over the ${t.cap} byte limit`;if(n==null)return t.bytes+=4,null;let r=typeof n;if(r==="boolean")return t.bytes+=5,null;if(r==="number")return t.bytes+=8,null;if(r==="string")return t.bytes+=n.length*3+2,null;if(r!=="object")return `${r} is not plain data`;let o=n;if(t.seen.has(o))return "a repeated or cyclic object reference";if(t.seen.add(o),Array.isArray(n)){if(n.length>ie)return `an array of ${n.length} entries, over the ${ie} limit`;t.bytes+=2;for(let d of n){let u=W(d,e+1,t);if(u)return u}return null}let a=Object.getPrototypeOf(n);if(a!==Object.prototype&&a!==null)return "a value that is not a plain object";t.bytes+=2;let i=n;for(let d in i){if(!Object.prototype.hasOwnProperty.call(i,d))continue;if(++t.nodes>N)return `more than ${N} values`;if(t.bytes+=d.length*3+4,t.bytes>t.cap)return `over the ${t.cap} byte limit`;let u=W(i[d],e+1,t);if(u)return u}return null}function yn(n,e=dn){let t={nodes:0,bytes:0,seen:new Set,cap:e},r=W(n,0,t);return r?`message contains ${r}`:t.bytes>e?`message is over the ${e} byte limit`:null}var fn={origin:[un,"not a well-formed origin"],url:[cn,"not a safe absolute http(s) URL"],bcp47:[mn,"not a well-formed BCP 47 tag"],code:[gn,"not a code of lower-case letters and underscores"],gameRef:[pn,"not a game id or web address"]};function de(n,e,t){for(let r of e){let o=t===""?r[0]:`${t}.${r[0]}`,a=n[r[0]];if(a==null){if(r[1]<"a")continue;return `${o}: required`}let i=z(a,r,o);if(i)return i}return null}function z(n,e,t){let r=e[1].toLowerCase();switch(r){case "u":return typeof n=="boolean"?null:z(n,typeof n=="string"?[e[0],"s",e[2]]:[e[0],"n",e[3],e[4]],t);case "s":{if(typeof n!="string")return `${t}: expected string`;if(n.length>e[2])return `${t}: exceeds ${e[2]} characters`;if(e[3]){let[o,a]=fn[e[3]];if(!o(n))return `${t}: ${a}`}return null}case "n":case "i":return typeof n!="number"||!(r=="i"?Number.isInteger:Number.isFinite)(n)?`${t}: expected ${r=="i"?"integer":"number"}`:n<e[2]||n>e[3]?`${t}: out of range ${e[2]}..${e[3]}`:null;case "b":return typeof n=="boolean"?null:`${t}: expected boolean`;case "e":{let o=e[2];return o.includes(n)?null:`${t}: not one of ${o.join("|")}`}case "o":return typeof n!="object"||n===null||Array.isArray(n)?`${t}: expected object`:de(n,e[2],t);case "j":return typeof n!="object"||n===null||Array.isArray(n)?`${t}: expected a plain object`:null;case "a":{if(!Array.isArray(n))return `${t}: expected array`;if(n.length>e[2])return `${t}: exceeds ${e[2]} items`;let o=e[3],a=`${t}[]`;for(let i of n){if(i==null){if(o[1]<"a")continue;return `${a}: required`}let d=z(i,o,a);if(d)return d}return null}default:return `${t}: unknown kind ${String(r)}`}}var ue=Object.create(null);function l(n,e,t,r,o){return H[n]=t,r&&(le[n]=r),ue[n]=a=>{let i=yn(a,o);if(i)return i;if(typeof a!="object"||a===null||Array.isArray(a))return "message: expected object";let d=a;return d.gem!==ln?"gem: wrong protocol marker":d.type!==n?`type: expected ${n}`:de(d,e,"")}}var m=["requestId","s",64],I=["outcome","e",["ok","declined","unavailable"]],E=["reason","S",64,"code"];l("gem.handshake",[["versions","o",[["min","i",1,1e3],["max","i",1,1e3]]],["capabilities","A",64,["","s",64]],["embedder","s",2048,"origin"],["unbidden","B"]],30);l("gem.handshake.accept",[["v","i",1,1e3],["capabilities","A",64,["","s",64]]],5);l("gem.token",[["token","s",4096],["requestId","S",64],["generation","i",0,2147483647],["apiBaseUrl","S",512,"url"],["playerId","s",64],["gameId","s",64],["channel","e",["dev","test","release"]],["gameVersion","S",64],["expiresAt","i",0,4102444800],["chainEndsAt","i",0,4102444800],["allowDevTools","B"]],30);l("gem.token.denied",[m,["retryable","b"],["retryAfterMs","I",0,36e5],["reason","e",["chain_exhausted","unavailable"]],["correlationId","s",64]],30);l("gem.player",[["untrusted","o",[["displayName","s",64],["displayTag","S",80],["displayHandle","s",80]]],["playerId","S",64],["discriminator","S",8],["avatarIconUrl","S",2048,"url"],["avatarIconId","S",64],["avatar3dId","S",64],["avatar3dModelUrl","S",2048,"url"],["avatar3dIconUrl","S",2048,"url"],["avatars3d","A",8,["","o",[["family","s",32],["id","s",64],["modelUrl","s",256,"url"],["iconUrl","s",256,"url"]]]],["badges","A",2,["","o",[["itemId","s",64],["iconUrl","s",2048,"url"]]]],["displayTag","s",8],["avatarUrl","S",2048,"url"],["boost","O",[["multipliers","a",8,["","o",[["currencyId","s",64],["currencySlug","s",32],["multiplierBp","i",1e4,1e6]]]],["expiresInDays","I",1,7]]]],12);l("gem.pause",[["paused","b"]],120);l("gem.prefs",[["reducedMotion","b"],["muted","b"],["showFrameStats","B"],["music","B"],["sounds","B"],["locale","s",35,"bcp47"],["recommended","O",[["volume","i",0,100],["batterySaver","b"],["keyboardLayout","e",["wasd","arrows"]],["gamepadConfirm","e",["south","east"]],["vibration","b"],["lookSensitivity","I",20,400],["gamepadLookSensitivity","I",20,400],["invertLookY","B"],["touchMovement","S",16,"code"],["graphicsQuality","S",16,"code"],["graphicsQualityAuto","B"],["colorHelp","B"]]]],60);l("gem.cohorts",[["cohorts","a",8,["","o",[["experimentId","s",36],["variantKey","s",32]]]]],12,"cohorts");l("gem.earnAllowanceChanged",[],30,"earnAllowance");l("gem.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"]],["matchId","s",64],["data","j"]],1800,"p2p");l("gem.dedicatedEvent",[["event","e",["answer","error","matchEnded"]],["matchId","s",64],["sdp","S",10240],["sessionId","S",64],["code","S",64],["message","S",256],["reason","S",64]],120,"dedicated");l("gem.partyResult",[m,["partyId","S",64]],30,"parties");l("gem.clusterTarget",[["clusterTargetId","s",64],["clusterTargetIds","A",3,["","s",64]]],12,"clusterTarget");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"]],["matchId","s",64],["data","j"]],1200,"p2p");l("gem.dedicatedOffer",[["matchId","s",64],["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],["expected","I",1,1e9],["origin","O",[["x","i",0,16384],["y","i",0,16384]]]],60,"rewardCue");l("gem.walletDisplay",[["visible","b"],["currencies","A",8,["","s",64]],["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",[["params","a",16,["","o",[["key","s",64],["value","s",512]]]]],6,"share");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]],12,"purchases");l("gem.requestAvatar3dPurchase",[m,["itemId","s",64],["currencySlug","s",32]],12,"avatar3dPurchases");l("gem.purchaseResult",[m,I,E,["purchaseId","S",64]],30,"purchases");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.requestAppLinks",[m],12,"appLinks");l("gem.appLinksResult",[m,I,E,["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,I,E],30,"appLinks");l("gem.requestOpenGame",[m,["ref","s",40,"gameRef"]],6,"openGame");l("gem.openGameResult",[m,I,E],30,"openGame");l("gem.requestSimilarGames",[m,["limit","I",1,24]],12,"openGame");l("gem.similarGamesResult",[m,I,E,["games","a",24,["","o",[["gameId","s",36,"gameRef"],["slug","S",40,"gameRef"],["iconUrl","s",1024,"url"],["capsuleLandscapeUrl","s",1024,"url"],["capsulePortraitUrl","s",1024,"url"],["previewVideoUrl","S",1024,"url"],["previewPosterUrl","S",1024,"url"],["untrusted","o",[["name","s",64],["tagline","s",64],["shortDescription","s",320],["tags","a",10,["","s",32]]]]]]]],30,"openGame",524288);l("gem.requestStoreOffers",[m],12,"store");l("gem.storeOffersResult",[m,I,E,["offers","a",32,["","o",[["skuId","s",64],["kind","e",["gem_pack","boost","pass","bundle"]],["name","s",80],["description","s",400],["imageUrl","S",1024,"url"],["priceDisplay","s",32],["grant","O",[["currency","s",32],["amount","i",1,1e9]]]]]]],30,"store",262144);l("gem.requestStorePurchase",[m,["skuId","s",64]],12,"store");l("gem.storePurchaseResult",[m,I,E],30,"store");l("gem.storePurchaseSettled",[["skuId","s",64]],30,"store");l("gem.requestStoreOfferSheet",[m,["skuId","s",64]],12,"storeOfferSheet");l("gem.storeOfferSheetResult",[m,I,E],30,"storeOfferSheet");Object.freeze(ue);H.__malformed=60;Object.freeze(H);Object.freeze(le);var q={now:()=>Date.now(),setTimeout:(n,e)=>setTimeout(n,e),clearTimeout:n=>clearTimeout(n)};function ce(n){let e=n.toLowerCase();return e==="localhost"||e.endsWith(".localhost")||e==="[::1]"||e==="::1"?true:/^127(\.\d{1,3}){3}$/.test(e)}var hn=1e4;function me(n,e){return K(n,e)}function K(n,e){if(typeof n.serverToken!="function"||typeof n.onServerToken!="function")throw new Error("this runtime delivers no game-server token: host.serverToken/onServerToken are missing. The server image running this bundle predates token delivery \u2014 the bundle cannot call gem-api on it.");let t=i=>({token:i.token,expiresAt:i.expiresAt,chainEndsAt:Number.POSITIVE_INFINITY}),r=null,o=new U({clock:e.clock,...e.onStateChange===void 0?{}:{onStateChange:e.onStateChange},request:()=>new Promise((i,d)=>{let u=e.clock.setTimeout(()=>{r=null,d({reason:"unavailable",retryable:true});},e.timeoutMs??hn);r={resolve:c=>{e.clock.clearTimeout(u),i(c);},reject:d,timer:u};})}),a=n.onServerToken(i=>{let d=t(i),u=r;if(u){r=null,u.resolve(d);return}o.accept(d);});return {source:o,dispose(){a(),o.dispose(),r&&(e.clock.clearTimeout(r.timer),r.reject({reason:"unavailable",retryable:false}),r=null);}}}var J={};qe(J,{acceptTransfer:()=>_n,addEntityProgression:()=>bn,adminAction:()=>Rn,cancelInventoryTransfer:()=>vn,claimEntityProgressionRewards:()=>Sn,closeGameRoom:()=>xn,createEntityBatchOrder:()=>wn,createEntityOrder:()=>kn,createSession:()=>An,deleteEntityGameSetting:()=>On,deleteEntitySave:()=>Pn,deleteSession:()=>Gn,deleteShowcaseValue:()=>Tn,executeEntityRecipe:()=>Cn,finalizeSaveUpload:()=>In,getChannelAssignment:()=>En,getDropRates:()=>Ln,getEntityCurrency:()=>qn,getEntityGameSetting:()=>Mn,getEntityInventory:()=>$n,getEntityInventoryItem:()=>jn,getEntityLeaderboard:()=>Bn,getEntityOrder:()=>Fn,getEntityProgression:()=>Un,getEntityRecipeAvailability:()=>Dn,getEntityRecipeUsage:()=>Nn,getEntitySave:()=>Hn,getEvent:()=>Vn,getGameRoomV2:()=>Wn,getLeaderboard:()=>zn,getPlayerGameProfile:()=>Kn,getPurchaseCatalog:()=>Yn,getResolvedTemplate:()=>Jn,getRoomArgs:()=>Xn,getShowcaseValue:()=>Qn,getTransferDetails:()=>Zn,ingestAnalyticsEvents:()=>Y,initiateInventoryTransfer:()=>et,invokeFunction:()=>nt,kickPlayer:()=>tt,listChallenges:()=>rt,listEntityGameSettings:()=>ot,listEntityOrders:()=>at,listEntityProgressions:()=>st,listEntitySaves:()=>it,listEvents:()=>lt,listGameRooms:()=>dt,listResolvedTemplates:()=>ut,listTransfers:()=>ct,maxEntityProgression:()=>mt,putEntityGameSetting:()=>gt,putRoomArgs:()=>pt,putShowcaseValue:()=>yt,rejectTransfer:()=>ft,reportMatchPlayers:()=>ht,requestSaveUploadUrl:()=>_t,resetEntityProgression:()=>bt,setMatchBackfill:()=>Rt,simulateEntityOrder:()=>vt,transferHostV2:()=>St,updateGameRoomV2:()=>xt});function s(n){let e=String(n);if(!/^[A-Za-z0-9_.-]{1,128}$/.test(e)||e==="."||e==="..")throw new TypeError(`${JSON.stringify(e)} is not a usable path segment \u2014 it is interpolated into a URL`);return encodeURIComponent(e)}async function _n(n,e,t){let r=`/v1/inventory/transfers/${s(e)}/accept`;return n.client.post(r,void 0,t?.signal)}async function bn(n,e,t,r,o,a){let i=`/v1/inventory/${s(e)}/${s(t)}/progressions/${s(r)}/add`;return n.client.post(i,o,a?.signal)}async function Rn(n,e,t,r){let o=`/v1/voice/sessions/${s(e)}/admin`;return n.client.post(o,t,r?.signal)}async function vn(n,e,t){let r=`/v1/inventory/transfers/${s(e)}/cancel`;return n.client.post(r,void 0,t?.signal)}async function Sn(n,e,t,r,o,a){let i=`/v1/inventory/${s(e)}/${s(t)}/progressions/${s(r)}/claim`;return n.client.post(i,o,a?.signal)}async function xn(n,e,t){let r=`/v1/games/${s(n.gameId())}/game-rooms/${s(e)}`;return n.client.delete(r,t?.signal)}async function wn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/orders/batch`;return n.client.post(a,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function kn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/orders`;return n.client.post(a,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function An(n,e,t){return n.client.post("/v1/voice/sessions",e,t?.signal)}async function On(n,e,t,r,o){let a=`/v1/settings/${s(e)}/${s(t)}/${s(r)}`;return n.client.delete(a,o?.signal)}async function Pn(n,e,t,r,o){let a=`/v1/saves/${s(e)}/${s(t)}/${s(r)}`;return n.client.delete(a,o?.signal)}async function Gn(n,e,t){let r=`/v1/voice/sessions/${s(e)}`;return n.client.delete(r,t?.signal)}async function Tn(n,e,t,r){let o=`/v1/showcase/players/${s(e)}/${s(t)}`;return n.client.delete(o,r?.signal)}async function Cn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/recipes/execute`;return n.client.post(a,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function In(n,e,t,r,o,a){let i=`/v1/saves/${s(e)}/${s(t)}/${s(r)}/finalize`;return n.client.post(i,o,a?.signal)}async function En(n,e,t){let r=`/v1/games/${s(n.gameId())}/config/channels/${s(e)}`;return n.client.getWithEtag(r,{...t?.signal===void 0?{}:{signal:t.signal},...t?.ifNoneMatch===void 0?{}:{ifNoneMatch:t.ifNoneMatch}})}async function Ln(n,e,t){let r=`/v1/inventory/loot-tables/${s(e)}/drop-rates`;return n.client.get(r,t?.signal)}async function qn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/currencies/${s(r)}`;return n.client.get(a,o?.signal)}async function Mn(n,e,t,r,o){let a=`/v1/settings/${s(e)}/${s(t)}/${s(r)}`;return n.client.getWithEtag(a,{...o?.signal===void 0?{}:{signal:o.signal},...o?.ifNoneMatch===void 0?{}:{ifNoneMatch:o.ifNoneMatch}})}async function $n(n,e,t,r){let o=new URLSearchParams;r?.include_buckets!==void 0&&o.set("include_buckets",String(r?.include_buckets)),r?.include_custom_data!==void 0&&o.set("include_custom_data",String(r?.include_custom_data)),r?.currency_limit!==void 0&&o.set("currency_limit",String(r?.currency_limit)),r?.currency_cursor!==void 0&&o.set("currency_cursor",String(r?.currency_cursor)),r?.item_limit!==void 0&&o.set("item_limit",String(r?.item_limit)),r?.item_cursor!==void 0&&o.set("item_cursor",String(r?.item_cursor)),r?.progression_limit!==void 0&&o.set("progression_limit",String(r?.progression_limit)),r?.progression_cursor!==void 0&&o.set("progression_cursor",String(r?.progression_cursor));let a=o.toString(),i=`/v1/inventory/${s(e)}/${s(t)}`+(a?`?${a}`:"");return n.client.get(i,r?.signal)}async function jn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/items/${s(r)}`;return n.client.get(a,o?.signal)}async function Bn(n,e,t,r,o){let a=new URLSearchParams;o?.bucket_1!==void 0&&a.set("bucket_1",String(o?.bucket_1)),o?.bucket_2!==void 0&&a.set("bucket_2",String(o?.bucket_2)),o?.limit!==void 0&&a.set("limit",String(o?.limit)),o?.periods_back!==void 0&&a.set("periods_back",String(o?.periods_back)),o?.period!==void 0&&a.set("period",String(o?.period)),o?.player_id!==void 0&&a.set("player_id",String(o?.player_id));let i=a.toString(),d=`/v1/leaderboards/${s(e)}/${s(t)}/${s(r)}`+(i?`?${i}`:"");return n.client.get(d,o?.signal)}async function Fn(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/orders/${s(r)}`;return n.client.get(a,o?.signal)}async function Un(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/progressions/${s(r)}`;return n.client.get(a,o?.signal)}async function Dn(n,e,t,r,o,a){let i=`/v1/inventory/${s(e)}/${s(t)}/catalogs/${s(r)}/recipes/${s(o)}/availability`;return n.client.get(i,a?.signal)}async function Nn(n,e,t,r){let o=new URLSearchParams;r?.limit!==void 0&&o.set("limit",String(r?.limit));let a=o.toString(),i=`/v1/inventory/${s(e)}/${s(t)}/recipe-usage`+(a?`?${a}`:"");return n.client.get(i,r?.signal)}async function Hn(n,e,t,r,o){let a=`/v1/saves/${s(e)}/${s(t)}/${s(r)}`;return n.client.getWithEtag(a,{...o?.signal===void 0?{}:{signal:o.signal},...o?.ifNoneMatch===void 0?{}:{ifNoneMatch:o.ifNoneMatch}})}async function Vn(n,e,t){let r=`/v1/events/${s(e)}`;return n.client.get(r,t?.signal)}async function Wn(n,e,t){let r=`/v2/games/${s(n.gameId())}/game-rooms/${s(e)}`;return n.client.getWithEtag(r,{...t?.signal===void 0?{}:{signal:t.signal},...t?.ifNoneMatch===void 0?{}:{ifNoneMatch:t.ifNoneMatch}})}async function zn(n,e,t){let r=new URLSearchParams;t?.bucket_1!==void 0&&r.set("bucket_1",String(t?.bucket_1)),t?.bucket_2!==void 0&&r.set("bucket_2",String(t?.bucket_2)),t?.periods_back!==void 0&&r.set("periods_back",String(t?.periods_back)),t?.period!==void 0&&r.set("period",String(t?.period)),t?.player_id!==void 0&&r.set("player_id",String(t?.player_id));let o=r.toString(),a=`/v1/leaderboards/${s(e)}`+(o?`?${o}`:"");return n.client.get(a,t?.signal)}async function Kn(n,e,t){let r=`/v1/profiles/players/${s(e)}`;return n.client.get(r,t?.signal)}async function Yn(n,e){let t=new URLSearchParams;e?.config_version!==void 0&&t.set("config_version",String(e?.config_version));let r=t.toString(),o="/v1/inventory/platform-funded-game-inventory-purchase-catalog"+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function Jn(n,e,t){let r=`/v1/game-room-templates/${s(e)}`;return n.client.get(r,t?.signal)}async function Xn(n,e,t){let r=`/v1/games/${s(n.gameId())}/game-rooms/${s(e)}/room-args`;return n.client.get(r,t?.signal)}async function Qn(n,e,t,r){let o=`/v1/showcase/players/${s(e)}/${s(t)}`;return n.client.get(o,r?.signal)}async function Zn(n,e,t){let r=`/v1/inventory/transfers/${s(e)}`;return n.client.get(r,t?.signal)}async function Y(n,e,t){let r=`/v1/games/${s(n.gameId())}/analytics/events`;return n.client.post(r,e,t?.signal,{replaySafe:true,retryRateLimited:false})}async function et(n,e,t){return n.client.post("/v1/inventory/transfers",e,t?.signal)}async function nt(n,e,t){return n.client.postBytes("/v1/functions/invoke",e,t?.signal)}async function tt(n,e,t,r){let o=`/v1/games/${s(n.gameId())}/game-rooms/${s(e)}/kick/${s(t)}`;return n.client.post(o,void 0,r?.signal)}async function rt(n,e){let t=new URLSearchParams;e?.periods_back!==void 0&&t.set("periods_back",String(e?.periods_back)),e?.player_id!==void 0&&t.set("player_id",String(e?.player_id));let r=t.toString(),o="/v1/challenges"+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function ot(n,e,t,r){let o=`/v1/settings/${s(e)}/${s(t)}`;return n.client.get(o,r?.signal)}async function at(n,e,t,r){let o=new URLSearchParams;r?.limit!==void 0&&o.set("limit",String(r?.limit)),r?.cursor!==void 0&&o.set("cursor",String(r?.cursor));let a=o.toString(),i=`/v1/inventory/${s(e)}/${s(t)}/orders`+(a?`?${a}`:"");return n.client.get(i,r?.signal)}async function st(n,e,t,r){let o=`/v1/inventory/${s(e)}/${s(t)}/progressions`;return n.client.get(o,r?.signal)}async function it(n,e,t,r){let o=new URLSearchParams;r?.limit!==void 0&&o.set("limit",String(r?.limit)),r?.cursor!==void 0&&o.set("cursor",String(r?.cursor));let a=o.toString(),i=`/v1/saves/${s(e)}/${s(t)}`+(a?`?${a}`:"");return n.client.get(i,r?.signal)}async function lt(n,e){let t=new URLSearchParams;e?.include_inactive!==void 0&&t.set("include_inactive",String(e?.include_inactive)),e?.limit!==void 0&&t.set("limit",String(e?.limit)),e?.offset!==void 0&&t.set("offset",String(e?.offset));let r=t.toString(),o="/v1/events"+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function dt(n,e){let t=new URLSearchParams;e?.status!==void 0&&t.set("status",String(e?.status)),e?.game_channel!==void 0&&t.set("game_channel",String(e?.game_channel)),e?.game_room_type!==void 0&&t.set("game_room_type",String(e?.game_room_type)),e?.template_id!==void 0&&t.set("template_id",String(e?.template_id)),e?.template_slug!==void 0&&t.set("template_slug",String(e?.template_slug)),e?.limit!==void 0&&t.set("limit",String(e?.limit)),e?.cursor!==void 0&&t.set("cursor",String(e?.cursor));let r=t.toString(),o=`/v1/games/${s(n.gameId())}/game-rooms`+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function ut(n,e){return n.client.get("/v1/game-room-templates",e?.signal)}async function ct(n,e){let t=new URLSearchParams;e.entity_type!==void 0&&t.set("entity_type",String(e.entity_type)),e.entity_id!==void 0&&t.set("entity_id",String(e.entity_id)),e?.direction!==void 0&&t.set("direction",String(e?.direction)),e?.status!==void 0&&t.set("status",String(e?.status)),e?.cursor!==void 0&&t.set("cursor",String(e?.cursor)),e?.limit!==void 0&&t.set("limit",String(e?.limit));let r=t.toString(),o="/v1/inventory/transfers"+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function mt(n,e,t,r,o,a){let i=`/v1/inventory/${s(e)}/${s(t)}/progressions/${s(r)}/max`;return n.client.post(i,o,a?.signal)}async function gt(n,e,t,r,o,a){let i=`/v1/settings/${s(e)}/${s(t)}/${s(r)}`;return n.client.put(i,o,a?.signal,{...a?.ifMatch===void 0?{}:{ifMatch:a.ifMatch}})}async function pt(n,e,t,r){let o=`/v1/games/${s(n.gameId())}/game-rooms/${s(e)}/room-args`;return n.client.put(o,t,r?.signal)}async function yt(n,e,t,r,o){let a=`/v1/showcase/players/${s(e)}/${s(t)}`;return n.client.put(a,r,o?.signal)}async function ft(n,e,t){let r=`/v1/inventory/transfers/${s(e)}/reject`;return n.client.post(r,void 0,t?.signal)}async function ht(n,e,t,r){let o=`/v1/games/${s(n.gameId())}/matches/${s(e)}/players/report`;return n.client.post(o,t,r?.signal)}async function _t(n,e,t,r,o,a){let i=`/v1/saves/${s(e)}/${s(t)}/${s(r)}/upload-url`;return n.client.post(i,o,a?.signal,{replaySafe:true})}async function bt(n,e,t,r,o,a){let i=`/v1/inventory/${s(e)}/${s(t)}/progressions/${s(r)}/reset`;return n.client.post(i,o,a?.signal)}async function Rt(n,e,t,r){let o=`/v1/games/${s(n.gameId())}/matches/${s(e)}/backfill`;return n.client.put(o,t,r?.signal)}async function vt(n,e,t,r,o){let a=`/v1/inventory/${s(e)}/${s(t)}/orders/simulate`;return n.client.post(a,r,o?.signal)}async function St(n,e,t,r){let o=`/v2/games/${s(n.gameId())}/game-rooms/${s(e)}/transfer/${s(t)}`;return n.client.post(o,void 0,r?.signal)}async function xt(n,e,t,r){let o=`/v2/games/${s(n.gameId())}/game-rooms/${s(e)}`;return n.client.patch(o,t,r?.signal,{...r?.ifMatch===void 0?{}:{ifMatch:r.ifMatch}})}var ge="gem_";function pe(n,e){let t=e?.retryAfterSeconds,r=typeof t=="number"&&Number.isFinite(t)&&t>0?t*1e3:0,o=1e4*2**Math.min(Math.max(0,n-1),16);return Math.min(Math.max(r,o),3e5)}var At=1e4,Ot=50,Pt=1e3,Gt=65536-4*1024,ye=n=>typeof n=="number"?n:0,Tt=n=>typeof n=="string"?n:"";function fe(){let n=globalThis.crypto;return typeof n?.randomUUID=="function"?n.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{let t=Math.floor(Math.random()*16);return (e==="x"?t:t&3|8).toString(16)})}function Ct(n){return n?.retryable===true}function It(n,e){let t=n??{},r=Array.isArray(t.rejected)?t.rejected.map(o=>{let a=o??{};return {index:ye(a.index),code:Tt(a.code)}}):[];return {accepted:ye(t.accepted),rejected:r,dropped:e,duplicate:t.duplicate===true}}function he(n,e){return {event_uid:n.uid,name:n.name,offset_ms:Math.round(n.atMs)-e,player_id:n.playerId,dimensions:n.dimensions,measures:n.measures}}function _e(n){let e=Math.max(1,Math.floor(n.maxQueue??Pt)),t={client:n.client,gameId:()=>n.gameId},r=[],o=0,a=null,i=false,d=null,u=0,c=0,g=false,S=false,w=_=>{n.log?.(_);},R=()=>{a!==null&&(n.clock.clearTimeout(a),a=null);},y=()=>Math.max(0,c-n.clock.now()),x=()=>{a!==null||i||d!==null||(a=n.clock.setTimeout(()=>{a=null,P().catch(()=>{});},Math.max(At,y())));},A=()=>{let _=Math.min(r.length,100),b=128;for(let G=0;G<_;G+=1){let T=r[G];if(T===void 0)break;if(b+=JSON.stringify(he(T,0)).length+1,b>Gt)return Math.max(1,G)}return _};async function P(_){for(;d!==null;)await d.catch(()=>{});if(r.length===0)return {accepted:0,rejected:[],dropped:0,duplicate:false};let b=Ie(_);d=b;try{return await b}finally{d===b&&(d=null),r.length>0&&x();}}async function Ie(_){R();let b=r.splice(0,A()),G=o;o=0;let T=Math.round(n.clock.now()),F={batch_id:fe(),sent_at_ms:T,events:b.map(k=>he(k,T))};try{let k=await Y(t,F,_===void 0?void 0:{signal:_}),C=It(k,G);u=0,c=0;for(let Ee of C.rejected)w(`[gem] analytics: an event was refused (${Ee.code}). See the analytics_events section of your game config.`);return C}catch(k){if(Ct(k)){for(r=[...b,...r],o+=G;r.length>e;)r.shift(),o+=1;u+=1,c=n.clock.now()+pe(u,k);}else w(`[gem] analytics: ${b.length} event(s) were discarded \u2014 the platform refused the batch and will refuse it again: ${String(k)}`);throw k}}return {track(_,b,G={}){if(i)return;if(typeof _!="string"||_===""){S||(S=true,w(`[gem] analytics: '${b}' was not recorded \u2014 an event from a server has to name the player it is about. A game-server token names no player, so the platform cannot infer one; pass the id from join() or host.players().`));return}if(b.startsWith(ge)){g||(g=true,w(`[gem] analytics: '${b}' was not recorded \u2014 the gem_ prefix is reserved, and the platform's own events are client-sourced, so a server may not emit one at all. Name your event something else.`));return}let T={},F={};for(let[k,C]of Object.entries(G))typeof C=="string"?T[k]=C:typeof C=="number"&&Number.isFinite(C)&&(F[k]=C);for(;r.length>=e;)r.shift(),o+=1;r.push({uid:fe(),playerId:_,name:b,atMs:n.clock.now(),dimensions:T,measures:F}),r.length>=Ot&&d===null&&y()===0?P().catch(()=>{}):x();},flush:_=>P(_),get pending(){return r.length},dispose(){i=true,R(),r=[],o=0;}}}var Et=new Map([["function_error",false],["function_failed",false],["function_timeout",false],["function_not_published",false],["function_input_too_large",false],["functions_not_configured",false],["forbidden",false],["function_capacity_unavailable",true],["function_host_unreachable",true],["function_host_error",true],["rate_limited",true],["service_unavailable",true]]),j=class extends p{constructor(e,t){super(e.reason,e.status,e.detail,e.retryAfterSeconds,e.code),this.name="GemFunctionError",Object.assign(this,t);}get retryable(){return (this.code===void 0?void 0:Et.get(this.code))??super.retryable}},M=class{#e;constructor(e){this.#e=e;}async invoke(e,t={}){let r=Lt(e),o;try{o=await this.#e(r,t.signal===void 0?{}:{signal:t.signal});}catch(a){throw a instanceof p?Mt(a):a}return qt(o)}};function Lt(n){if(n instanceof ArrayBuffer)return new Uint8Array(n);if(ArrayBuffer.isView(n))return new Uint8Array(n.buffer,n.byteOffset,n.byteLength);let e;try{e=JSON.stringify(n);}catch(t){throw new f(`the function input could not be serialised to JSON: ${String(t)}. Pass bytes, or a value JSON can carry. This is a bug in the call, not a server failure.`)}if(e===void 0)throw new f(`the function input is ${typeof n}, which JSON cannot carry. Pass bytes \u2014 an empty Uint8Array for no input \u2014 or a JSON value. This is a bug in the call, not a server failure.`);return new TextEncoder().encode(e)}function qt(n){let{bytes:e}=n,t=()=>new TextDecoder("utf-8",{fatal:true}).decode(e);return {bytes:e,...n.invocationId===void 0?{}:{invocationId:n.invocationId},text:t,json:()=>JSON.parse(t())}}function Mt(n){let{details:e,invocationId:t}=oe(n),o=e?.untrusted?.message,a=e?.reason;return new j(n,{...t===void 0?{}:{invocationId:t},...n.code==="function_error"&&typeof o=="string"?{functionMessage:o}:{},...n.code==="function_failed"&&typeof a=="string"?{failure:a}:{}})}var O=n=>typeof n=="string"?n:"",$t=/(?:Z|[+-]\d{2}:?\d{2})$/i;function be(n){let e=O(n);if(!$t.test(e))return 0;let t=Date.parse(e);return Number.isFinite(t)?Math.floor(t/1e3):0}var jt=/^[0-9a-f]{1,64}$/,Bt=/^[0-9a-f]{16}$/,Ft=/^[A-Za-z][A-Za-z0-9_+\-/]{0,63}$/,Ut=/^(?:[01]\d|2[0-3]):[0-5]\d$/;function Dt(n){let e=O(n),t=/^(\d{4})-(\d{2})-(\d{2})$/.exec(e);if(!t)return;let[r,o,a]=[Number(t[1]),Number(t[2]),Number(t[3])],i=new Date(Date.UTC(r,o-1,a));return i.getUTCFullYear()===r&&i.getUTCMonth()===o-1&&i.getUTCDate()===a?e:void 0}var Nt=4096,Ht=new TextEncoder;function Vt(n){let e=O(n.challenge_data),t=O(n.challenge_data_hash);return e===""||!Bt.test(t)?{}:Ht.encode(e).length>Nt?{}:{data:e,dataHash:t}}function Wt(n){let e=n??{},t=be(e.period_start_at),r=be(e.period_ends_at);if(t===0||r===0)return;let o=O(e.slug),a=O(e.seed),i=Dt(e.period_local_date),d=O(e.boundary),u=O(e.reset_time);return {id:O(e.progression_definition_id),...o===""?{}:{slug:o},window:O(e.window),periodStartAt:t,periodEndsAt:r,...i===void 0?{}:{periodLocalDate:i},boundary:Ft.test(d)?d:"",resetTime:Ut.test(u)?u:"",seed:jt.test(a)?a:"",...Vt(e)}}function Re(n){if(n!==void 0&&(!Number.isInteger(n)||n<0||n>400))throw new TypeError(`periodsBack must be an integer between 0 and 400, got ${String(n)}`)}function ve(n){let e=n??{};return Array.isArray(e.challenges)?e.challenges.map(Wt).filter(t=>t!==void 0):[]}function Se(n){return {async list(e){let{playerId:t,periodsBack:r,signal:o}=e??{};if(typeof t!="string"||t==="")throw new TypeError("gem.challenges.list needs { playerId }: a game-server token names no player, so the platform cannot tell whose period you mean. Pass the id from join() or gem.players().");Re(r);let a=await n({player_id:t,...r===void 0?{}:{periods_back:r},...o===void 0?{}:{signal:o}});return ve(a)}}}function zt(n){let e={};for(let[t,r]of Object.entries(J))if(typeof r=="function"){let o=r;e[t]=(...a)=>o(n,...a);}return e}function V(n,e={}){let t=e.clock??q,r=e.baseUrl??n.apiBaseUrl;if(!r)throw new Error("this runtime names no gem-api host (host.apiBaseUrl is missing). The server image running this bundle predates token delivery \u2014 the bundle cannot call gem-api on it.");let o=K(n,{clock:t,...e.onAuthStateChange===void 0?{}:{onStateChange:e.onAuthStateChange}}),a=ae({baseUrl:r,tokenSource:o.source,defaultQuery:{game_id:n.gameId,channel:n.channel},...e.fetch===void 0?{}:{fetch:e.fetch}}),i=new L({transport:a,clock:t}),d={gameId:n.gameId,channel:n.channel,matchId:n.matchId,...n.gameRoomId===void 0?{}:{gameRoomId:n.gameRoomId}},u=zt({client:i,gameId:()=>d.gameId}),c=d.gameRoomId,g=n.endMatch,S=n.log,w=_e({client:i,clock:t,gameId:d.gameId,...typeof S=="function"?{log:y=>S.call(n,y)}:{}});return {identity:d,client:i,api:u,match:{end:async()=>{if(g===void 0)throw new Error("this runtime cannot end the match: the server image running this bundle predates host.endMatch, and only the platform half holds the allocation proof an end needs.");await g.call(n);},setBackfill:async(y,x)=>{let A=await u.setMatchBackfill(d.matchId,{open:y.open,...y.seats===void 0?{}:{seats:y.seats}},x===void 0?{}:{signal:x});return {open:A.open,seats:A.seats??null}},reportPlayers:async(y,x)=>(await u.reportMatchPlayers(d.matchId,{players:y.map(P=>({player_id:P.playerId,state:P.state}))},x===void 0?{}:{signal:x})).players.map(P=>({playerId:P.player_id,outcome:P.outcome}))},analytics:w,functions:new M(u.invokeFunction),challenges:Se(u.listChallenges),...c===void 0?{}:{room:{get:y=>u.getGameRoomV2(c,y),args:async y=>{let x=await u.getGameRoomV2(c,y?.signal===void 0?{}:{signal:y.signal}),A=x.modified?x.body:void 0;if(A?.room_args==null||A.room_args_template==null)throw new p("not_found",404,"this room's template declares no room args",void 0,"room_args_not_defined");return {room_args:A.room_args,room_args_template:A.room_args_template}}}},dispose:()=>{w.dispose(),o.dispose();}}}var Kt=["explicit","stale_cleanup","game_room_closed","replaced","migration_failed","host_left","insufficient_players","all_left","expired","migration_rate_exceeded","game_room_gone","failed","idle","reclaimed"],Yt=new Set(Kt);function xe(n){return typeof n=="string"&&Yt.has(n)?n:"unknown"}var Ae="[gem: use gem.text.toPlain()]",we=new Set,ke;function Jt(n){try{if(we.has(n))return;let e=globalThis.location;if(ke??=!!e?.port&&ce(e.hostname??""),!ke)return;we.add(n),console.warn(`[gem] ${n} is PlayerText, turned into a string: players see ${Ae}. Render text.toPlain(value) (text is in @indiegems/gem-web-sdk/sdk).
|
|
2
2
|
${new Error().stack}`);}catch{}}var v=class{#e;#n;constructor(e,t="player text"){this.#e=e,this.#n=t,Object.freeze(this);}toString(){return Jt(this.#n),Ae}toJSON(){return this.toString()}get[Symbol.toStringTag](){return "PlayerText"}static unwrap(e){return e.#e}};function B(n,e){return new v(n,e)}var Oe={toPlain(n){return v.unwrap(n)},compare(n,e,t){let r=n instanceof v?v.unwrap(n):n,o=e instanceof v?v.unwrap(e):e;if(typeof Intl>"u"||typeof Intl.Collator!="function")return r<o?-1:r>o?1:0;let a;try{a=new Intl.Collator(t);}catch{a=new Intl.Collator;}return a.compare(r,o)},equals(n,e){let t=n instanceof v?v.unwrap(n):n,r=e instanceof v?v.unwrap(e):e;return t.normalize("NFC")===r.normalize("NFC")}};var Pe="the match has not started yet: the runtime hands over the host at `init`, and this was read before that. Read it from `init` or later \u2014 a bundle that needs a value at module scope is reading it one call too early.";function X(n,e={}){let t=e.clock??q,r=()=>{let d=n();if(d===null)throw new Error(Pe);return d},o=null,a=()=>{if(o===null)throw new Error(Pe);return o};return {server:{get identity(){return a().identity},get client(){return a().client},get api(){return a().api},get match(){return a().match},get analytics(){return a().analytics},get functions(){return a().functions},get challenges(){return a().challenges},get room(){return a().room},dispose(){o?.dispose();},get sizeClass(){return r().sizeClass},get roomArgs(){return r().roomArgs},get roster(){return r().roster},players(){return r().players()},profile(d){let c=r().profile?.(d);if(!c)return null;let g=c.displayName;return typeof g!="string"||g===""?null:{displayName:B(g,"profile.displayName"),...typeof c.displayTag=="string"&&c.displayTag!==""?{displayTag:B(c.displayTag,"profile.displayTag")}:{},...typeof c.discriminator=="string"?{discriminator:c.discriminator}:{}}},playerNumber(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=V(r(),{...e,clock:t});}}}function Ge(n,e={}){let{server:t,attach:r}=X(()=>n,e);return r(),t}function Xt(n){if(n===void 0||typeof n.reason!="string"||n.reason==="")return;let e=n.platform_reason??n.endedReason;return {reason:n.reason,...e===void 0?{}:{endedReason:xe(e)}}}var Qt=1e4;function Zt(n){let e=false;return t=>{if(e)return;let r;try{r=n.match.reportPlayers([{playerId:t,state:"connected"}],AbortSignal.timeout(Qt));}catch{return}r.catch(o=>{o instanceof p&&o.status>=400&&o.status<500&&(e=o.status!==429);});}}function Te(n,e={}){return ()=>{let t=null,{server:r,attach:o}=X(()=>t,e),a=n(r),i={async init(u){t=u,o(),await a.init?.();},async shutdown(u){let c=Xt(u);try{await a.shutdown?.(c);}finally{r.dispose();}}},d=Zt(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 er=new Set(["unlocked","already_unlocked","suppressed"]);function Ce(n){let e=n?.changes;if(!Array.isArray(e))return [];let t=[];for(let r of e){let o=r??{};if(o.type!=="achievement_unlocked"||typeof o.outcome!="string"||!er.has(o.outcome)||typeof o.achievement_id!="string"||o.achievement_id==="")continue;let a=o.outcome;t.push({achievementId:o.achievement_id,progressionDefinitionId:typeof o.progression_definition_id=="string"?o.progression_definition_id:"",points:a==="unlocked"&&typeof o.points=="number"&&Number.isFinite(o.points)?o.points:0,outcome:a,...typeof o.reason=="string"?{reason:o.reason}:{}});}return t}export{h as AuthError,D as CONDITIONAL_HEADERS,M as FunctionsApi,p as GemApiError,L as GemClient,j as GemFunctionError,v as PlayerText,f as TransportRefusal,Ce as achievementReceipts,B as asPlayerText,V as createGemServer,me as createHostTokenSource,Ge as createMatchServer,Te as defineServer,q as systemClock,Oe as text,ee as toBase64};//# sourceMappingURL=gem-web-sdk.server.js.map
|
|
3
3
|
//# sourceMappingURL=gem-web-sdk.server.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The function surface — API reference
|
|
2
2
|
|
|
3
|
-
Generated from `@indiegems/gem-web-sdk/function` v19.0.
|
|
3
|
+
Generated from `@indiegems/gem-web-sdk/function` v19.0.1, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
|
|
4
4
|
|
|
5
5
|
`@indiegems/gem-web-sdk/function` exports exactly the symbols on this page and nothing else.
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The browser surface — API reference
|
|
2
2
|
|
|
3
|
-
Generated from `@indiegems/gem-web-sdk/sdk` v19.0.
|
|
3
|
+
Generated from `@indiegems/gem-web-sdk/sdk` v19.0.1, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
|
|
4
4
|
|
|
5
5
|
`@indiegems/gem-web-sdk/sdk` is the one import a game writes, wherever its code runs. `@indiegems/gem-web-sdk/game` exports exactly the symbols on this page and nothing else, for a build that wants only this half.
|
|
6
6
|
|
|
@@ -9886,6 +9886,11 @@ them when the arcade unmutes. You write nothing for it.
|
|
|
9886
9886
|
**Create your audio after `createGem`.** A graph connected to the speakers
|
|
9887
9887
|
before this call is out of the SDK's reach.
|
|
9888
9888
|
|
|
9889
|
+
It also brings your sound back after iOS cuts it off — the player leaving
|
|
9890
|
+
the app and returning: on their next tap in your frame, it resumes your
|
|
9891
|
+
`AudioContext`s and replays the media elements that were playing, leaving
|
|
9892
|
+
alone any you suspended or paused yourself.
|
|
9893
|
+
|
|
9889
9894
|
Turn it off only if you silence yourself in `onPrefs` — to fade your music
|
|
9890
9895
|
rather than cut it, say. The arcade shows its mute button for your game
|
|
9891
9896
|
either way where it shows one, so `false` is a promise that your handler goes quiet on
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The server surface — API reference
|
|
2
2
|
|
|
3
|
-
Generated from `@indiegems/gem-web-sdk/sdk` v19.0.
|
|
3
|
+
Generated from `@indiegems/gem-web-sdk/sdk` v19.0.1, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
|
|
4
4
|
|
|
5
5
|
`@indiegems/gem-web-sdk/sdk` is the one import a game writes, wherever its code runs. `@indiegems/gem-web-sdk/server` exports exactly the symbols on this page and nothing else, for a build that wants only this half.
|
|
6
6
|
|
package/docs/api/reference.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schema_version": 2,
|
|
3
3
|
"source": {
|
|
4
4
|
"repo": "IndieGems/gem-web-sdk",
|
|
5
|
-
"version": "19.0.
|
|
5
|
+
"version": "19.0.1"
|
|
6
6
|
},
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -11491,7 +11491,7 @@
|
|
|
11491
11491
|
"group": "start",
|
|
11492
11492
|
"signature": "readonly manageAudio?: boolean",
|
|
11493
11493
|
"documented": true,
|
|
11494
|
-
"summary": "Whether the SDK silences your game itself when the player mutes the\narcade. Default `true`.\n\nWith it on, `muted: true` turns every Web Audio graph and every\n`<audio>`/`<video>` element in your page down to silence, and `false` turns\nthem back up — without stopping your `AudioContext`'s clock, and without\ntouching your own volume or mute settings, which are exactly where you left\nthem when the arcade unmutes. You write nothing for it.\n\n**Create your audio after `createGem`.** A graph connected to the speakers\nbefore this call is out of the SDK's reach.\n\nTurn it off only if you silence yourself in `onPrefs` — to fade your music\nrather than cut it, say. The arcade shows its mute button for your game\neither way where it shows one, so `false` is a promise that your handler goes quiet on\n`muted: true`, and the release checklist holds you to it.",
|
|
11494
|
+
"summary": "Whether the SDK silences your game itself when the player mutes the\narcade. Default `true`.\n\nWith it on, `muted: true` turns every Web Audio graph and every\n`<audio>`/`<video>` element in your page down to silence, and `false` turns\nthem back up — without stopping your `AudioContext`'s clock, and without\ntouching your own volume or mute settings, which are exactly where you left\nthem when the arcade unmutes. You write nothing for it.\n\n**Create your audio after `createGem`.** A graph connected to the speakers\nbefore this call is out of the SDK's reach.\n\nIt also brings your sound back after iOS cuts it off — the player leaving\nthe app and returning: on their next tap in your frame, it resumes your\n`AudioContext`s and replays the media elements that were playing, leaving\nalone any you suspended or paused yourself.\n\nTurn it off only if you silence yourself in `onPrefs` — to fade your music\nrather than cut it, say. The arcade shows its mute button for your game\neither way where it shows one, so `false` is a promise that your handler goes quiet on\n`muted: true`, and the release checklist holds you to it.",
|
|
11495
11495
|
"deprecated": null,
|
|
11496
11496
|
"params": [],
|
|
11497
11497
|
"returns": null,
|
package/docs/arcade-and-store.md
CHANGED
|
@@ -465,15 +465,11 @@ without a listener, call `list()` yourself at those moments; it is always fresh.
|
|
|
465
465
|
The platform has a read for this,
|
|
466
466
|
`GET /v1/games/{game_id}/matches/{match_id}/players/{player_id}/passes`, with the same body, for a
|
|
467
467
|
player in your live match. **A server bundle cannot call it yet**, and the SDK has no method for it,
|
|
468
|
-
|
|
468
|
+
because it needs the allocation nonce: the route requires `X-Alloc-Nonce`, which the platform's
|
|
469
|
+
runtime holds and never hands to your bundle. The boost read has the same limit. Reaching it takes a
|
|
470
|
+
hook in the runtime, like the one behind `gem.match.end()`.
|
|
469
471
|
|
|
470
|
-
|
|
471
|
-
holds and never hands to your bundle. The boost read has the same limit. Reaching it takes a hook in
|
|
472
|
-
the runtime, like the one behind `gem.match.end()`.
|
|
473
|
-
- **No game server is allowed to yet.** It answers `403` `client_permission_denied` to every caller
|
|
474
|
-
until the platform grants game servers `passes.read`, which ships after the route itself.
|
|
475
|
-
|
|
476
|
-
Until both land, decide in a function, or leave a VIP door out of a dedicated-server match.
|
|
472
|
+
Until then, decide in a function, or leave a VIP door out of a dedicated-server match.
|
|
477
473
|
|
|
478
474
|
## 12. Outcomes and reasons
|
|
479
475
|
|
package/docs/changelog.md
CHANGED
|
@@ -16,6 +16,12 @@ 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
|
+
## 19.0.1
|
|
20
|
+
|
|
21
|
+
Upgrading from 19.0.0. Impact: none.
|
|
22
|
+
|
|
23
|
+
Nothing in this release asks anything of a game.
|
|
24
|
+
|
|
19
25
|
## 19.0.0
|
|
20
26
|
|
|
21
27
|
Upgrading from 18.1.1. Impact: required.
|
package/docs/getting-started.md
CHANGED
|
@@ -198,6 +198,19 @@ Read every instance of a definition without walking the whole bag:
|
|
|
198
198
|
const swords = await gem.me.inventory.instances('iron-sword');
|
|
199
199
|
```
|
|
200
200
|
|
|
201
|
+
⚠️ **`instanceId` is never a key on its own.** A fungible item has one row per definition, and every
|
|
202
|
+
one of those rows carries the same placeholder, `__stack__`, so all of a player's fungible items
|
|
203
|
+
share one `instanceId`. A live game removed repeated rows while paging the bag by `instanceId`
|
|
204
|
+
alone: only the last fungible item survived, every other look the player had bought read as not
|
|
205
|
+
owned, and the game offered them for sale again. Key a row by its definition and instance
|
|
206
|
+
together, and answer "does the player hold this?" from `itemDefinitionId` and `quantity`:
|
|
207
|
+
|
|
208
|
+
```js
|
|
209
|
+
const rowKey = (item) => `${item.itemDefinitionId}:${item.instanceId}`;
|
|
210
|
+
const holds = (bag, itemDefinitionId) =>
|
|
211
|
+
bag.items.data.some((item) => item.itemDefinitionId === itemDefinitionId && item.quantity > 0);
|
|
212
|
+
```
|
|
213
|
+
|
|
201
214
|
⚠️ **An item's `properties` and `customData` are untrusted, and rendering them wrong is a
|
|
202
215
|
cross-player attack.** They are typed `unknown` **because the platform does not validate their
|
|
203
216
|
contents** — every read of them is a parse, not a trusted object. And a transfer moves an instance
|
package/docs/manifest.json
CHANGED
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
"file": "arcade-and-store.md",
|
|
21
|
-
"sha256": "
|
|
22
|
-
"updated": "2026-10-
|
|
21
|
+
"sha256": "aee6e00fa7e0f463cb09174a9afdffe10d66ed1036546e584b341e4c11bb1e27",
|
|
22
|
+
"updated": "2026-10-31T19:43:30Z"
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
25
|
"file": "arcade-avatars.md",
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
50
|
"file": "changelog.md",
|
|
51
|
-
"sha256": "
|
|
52
|
-
"updated": "2026-
|
|
51
|
+
"sha256": "069554f114dab51df5461c7b4e7b65339886bc0bc1c455baad83688aad3ee4fa",
|
|
52
|
+
"updated": "2026-11-02T15:26:17Z"
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
"file": "daily-challenges.md",
|
|
@@ -78,13 +78,13 @@
|
|
|
78
78
|
},
|
|
79
79
|
{
|
|
80
80
|
"file": "getting-started.md",
|
|
81
|
-
"sha256": "
|
|
82
|
-
"updated": "2026-
|
|
81
|
+
"sha256": "1175cae0795051d2b2f0d736c49e60ba455197273bcb09c3e2c565ab529be4b6",
|
|
82
|
+
"updated": "2026-11-02T15:26:17Z"
|
|
83
83
|
},
|
|
84
84
|
{
|
|
85
85
|
"file": "inventory-and-catalogs.md",
|
|
86
|
-
"sha256": "
|
|
87
|
-
"updated": "2026-
|
|
86
|
+
"sha256": "a4763fe2418c0e24639ca58c27f30ffc416f07528857402a6f9ab3fee147f4f6",
|
|
87
|
+
"updated": "2026-11-01T21:49:36Z"
|
|
88
88
|
},
|
|
89
89
|
{
|
|
90
90
|
"file": "leaderboards.md",
|
|
@@ -138,8 +138,8 @@
|
|
|
138
138
|
},
|
|
139
139
|
{
|
|
140
140
|
"file": "server-bundles.md",
|
|
141
|
-
"sha256": "
|
|
142
|
-
"updated": "2026-
|
|
141
|
+
"sha256": "e3e49043fa4c6744df9c7f4c5e901511a4e9832d7f46f6880f1995648bacbf09",
|
|
142
|
+
"updated": "2026-11-02T15:26:17Z"
|
|
143
143
|
},
|
|
144
144
|
{
|
|
145
145
|
"file": "serverless-functions-js.md",
|
|
@@ -163,8 +163,8 @@
|
|
|
163
163
|
},
|
|
164
164
|
{
|
|
165
165
|
"file": "what-a-game-must-do.md",
|
|
166
|
-
"sha256": "
|
|
167
|
-
"updated": "2026-
|
|
166
|
+
"sha256": "17df2ebdafe56ac5eafdf4eba783c97025ddd9e0ee88b7b43d25718908496b2a",
|
|
167
|
+
"updated": "2026-11-02T14:57:41Z"
|
|
168
168
|
}
|
|
169
169
|
]
|
|
170
170
|
}
|
package/docs/server-bundles.md
CHANGED
|
@@ -80,8 +80,8 @@ To check the download yourself: the package npm serves is, byte for byte, the fi
|
|
|
80
80
|
also publishes on its download host, with the hash beside it:
|
|
81
81
|
|
|
82
82
|
```bash
|
|
83
|
-
curl -fsSL -O https://downloads.gemarcade.com/sdk/v19.0.
|
|
84
|
-
curl -fsSL https://downloads.gemarcade.com/sdk/v19.0.
|
|
83
|
+
curl -fsSL -O https://downloads.gemarcade.com/sdk/v19.0.1/gem-web-sdk.tgz
|
|
84
|
+
curl -fsSL https://downloads.gemarcade.com/sdk/v19.0.1/gem-web-sdk.tgz.sri
|
|
85
85
|
openssl dgst -sha384 -binary gem-web-sdk.tgz | openssl base64 -A
|
|
86
86
|
```
|
|
87
87
|
|
|
@@ -1687,7 +1687,8 @@ startMusic(ctx); // start it now: it plays at once where sound is allowed, and f
|
|
|
1687
1687
|
// context say when it is running rather than deciding from the first read.
|
|
1688
1688
|
const LIFTS = ['pointerup', 'touchend', 'click', 'keydown'];
|
|
1689
1689
|
const unlock = () => {
|
|
1690
|
-
|
|
1690
|
+
// 'interrupted' is how some WebKit versions report a context iOS is holding.
|
|
1691
|
+
if (ctx.state === 'suspended' || ctx.state === 'interrupted') void ctx.resume();
|
|
1691
1692
|
};
|
|
1692
1693
|
const settled = () => {
|
|
1693
1694
|
if (ctx.state !== 'running') return;
|
|
@@ -1703,6 +1704,26 @@ if (ctx.state !== 'running') {
|
|
|
1703
1704
|
A `<audio>` or `<video>` element works the same way. Call `play()` straight away, and only if it
|
|
1704
1705
|
rejects, call it again from the first lift.
|
|
1705
1706
|
|
|
1707
|
+
**Coming back from the background is the SDK's.** On an iPhone, a player who swipes your game away
|
|
1708
|
+
and comes back finds its sound cut off: iOS leaves the `AudioContext` `suspended` or `interrupted`,
|
|
1709
|
+
stops your media elements, and restarts neither. The snippet above has stopped listening by then, so
|
|
1710
|
+
the SDK does this part for you. After the page was hidden, or a context left `running` without your
|
|
1711
|
+
asking, it listens again for the player's next lift in your frame, resumes the contexts that were
|
|
1712
|
+
running and replays the elements that were playing when the sound was cut off, then stops
|
|
1713
|
+
listening. You write nothing for it. It stays out of your way:
|
|
1714
|
+
|
|
1715
|
+
- **A context you `suspend()` yourself is left alone** until you call `resume()`. If you pause your
|
|
1716
|
+
audio when the page is hidden and resume it when it comes back, keep doing that: the SDK steps in
|
|
1717
|
+
only when your own resume did not take, which on iOS it often does not without a tap.
|
|
1718
|
+
- **An element you `pause()` is not replayed**, and nothing is restarted while the Arcade has your
|
|
1719
|
+
game paused: your `onPause(false)` handler decides what plays when the menu closes.
|
|
1720
|
+
- **The Arcade's mute still holds.** A context the SDK resumes is still silent while the player has
|
|
1721
|
+
the Arcade muted.
|
|
1722
|
+
|
|
1723
|
+
It reaches the audio the mute does: created after `createGem`, with `manageAudio` left on. With
|
|
1724
|
+
`manageAudio: false` it is yours: listen for the lift again on `visibilitychange` and on the
|
|
1725
|
+
context's `statechange`, rather than once.
|
|
1726
|
+
|
|
1706
1727
|
Never block the first frame on audio, never show an error for it, and do not ask the player to "tap
|
|
1707
1728
|
to start" just to unlock sound.
|
|
1708
1729
|
|