@indiegems/gem-web-sdk 14.0.0 → 14.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.esm.js +1 -1
- package/dist/gem-web-sdk.function.js +1 -1
- package/dist/gem-web-sdk.game.js +2 -2
- package/dist/gem-web-sdk.min.js +2 -2
- package/dist/gem-web-sdk.sdk.js +2 -2
- 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 +52 -19
- package/docs/api/api-reference-server.md +1 -1
- package/docs/api/reference.json +9 -9
- package/docs/changelog.md +6 -0
- package/docs/getting-started.md +3 -3
- package/docs/manifest.json +8 -8
- package/docs/server-bundles.md +2 -2
- package/docs/what-a-game-must-do.md +47 -26
- package/package.json +1 -1
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var Ee=Object.defineProperty;var Ie=(n,e)=>{for(var t in e)Ee(n,t,{get:e[t],enumerable:true});};globalThis.__gemWebSdkVersion="[gem-web-sdk:sdkVersion:14.0.0]";var Me={initialDelayMs:2e3,maxDelayMs:6e4};function Le(n,e){return e!==void 0?!e:n==="chain_exhausted"}var B=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 b(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 b("chain_exhausted","the token chain reached its ceiling");if(this.inFlight===null&&this.options.clock.now()<this.notBefore)throw new b(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 b("internal","token arrived for a superseded generation");return this.grant=o,this.rejected=false,this.enter("ready"),o.token}).catch(o=>{let a=qe(o),{retryable:s,retryAfterMs:l}=o??{};throw t===this.generation&&(Le(a,typeof s=="boolean"?s:void 0)?this.enter("lost",a):(this.scheduleRetry(typeof l=="number"&&Number.isFinite(l)&&l>0?l:void 0),this.enter("degraded",a))),o instanceof b?o:new b(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)}},b=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 qe(n){if(n instanceof b)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}},U=["if-match","if-none-match"],X=4096;function $e(n){if(!n)return;let e={};for(let[t,r]of Object.entries(n)){let o=t.toLowerCase();if(!U.includes(o)||r===void 0)continue;let a=typeof r=="string"?je(r):r;if(typeof a!="string"||a.length>X||!Fe(a))throw new f(`the ${o} header value cannot be sent \u2014 it is not a string, is longer than ${X} 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 je(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 Fe(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 Be(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 Q(n,e){let t=e.replayUnauthorizedOnce??true;return {async request(r){let o={...r},a=$e(o.headers),s=Be(o),l=Object.freeze({...o,headers:a,...s===void 0?{}:{bytes:s}}),u=await e.tokenSource.get(),c=await n(l,u);if(c.status!==401||!t)return c;e.tokenSource.invalidate(u);let g=await e.tokenSource.get(),_=await n(l,g);if(_.status===401)throw e.tokenSource.close("unavailable"),new b("unavailable","the server refused a freshly minted token");return _}}}function Z(n){let e=typeof n=="string"?new TextEncoder().encode(n):n;return btoa(Ue(e))}function Ue(n){let t="";for(let r=0;r<n.length;r+=32768)t+=String.fromCharCode(...n.subarray(r,r+32768));return t}var m=class extends Error{constructor(t,r,o,a,s){super(`${t} (${r}): ${o}`);this.reason=t;this.status=r;this.detail=o;this.retryAfterSeconds=a;this.code=s;this.name="GemApiError";}reason;status;detail;retryAfterSeconds;code;get retryable(){return this.reason==="unavailable"||this.reason==="rate_limited"}},ne=new WeakMap;function te(n){return ne.get(n)??{}}var Ne=new Set([408,429,500,502,503,504]),De=6e4;function He(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 E=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,...q(o)},o.replaySafe===true,o.retryRateLimited!==false)}async post(e,t,r,o={}){return this.send({method:"POST",path:e,body:t,signal:r,...q(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,...q(o)},o.replaySafe===true,o.retryRateLimited!==false);return {bytes:Ve(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,...q(o)},o.replaySafe===true,o.retryRateLimited!==false)}async delete(e,t,r={}){return this.send({method:"DELETE",path:e,signal:t,...q(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?He(this.options.maxRetries)+1:1,a=null;if(e.signal?.aborted)throw ee(e.signal);for(let s=0;s<o;s++){if(s>0&&await this.backoff(s,a,e.signal),e.signal?.aborted)throw ee(e.signal);let l;try{l=await this.options.transport.request(e);}catch(c){if(b.isAuthError(c)||f.isRefusal(c)||e.signal?.aborted||We(c))throw c;a=new m("unavailable",0,String(c));continue}if(l.status>=200&&l.status<300||l.status===304)return l;let u=ze(l);if(!Ne.has(l.status)||l.status===429&&!r)throw u;a=u;}throw a??new m("unavailable",0,"no attempt was made")}backoff(e,t,r){if(r?.aborted)return Promise.resolve();let o=t?.retryAfterSeconds,a=o!==void 0?o*1e3:2**(e-1)*250,s=2**(e-1)*250,l=Math.min(Math.max(a,s),De);return new Promise(u=>{let c=this.options.clock,g=false,_=false,v,h=()=>{g||(g=true,_&&c.clearTimeout(v),r?.removeEventListener("abort",h),u());};r?.addEventListener("abort",h,{once:true}),v=c.setTimeout(h,l),_=true,g&&c.clearTimeout(v);})}};function Ve(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 q(n){return {...n.keepalive===void 0?{}:{keepalive:n.keepalive},...n.ifMatch===void 0?{}:{headers:{"if-match":n.ifMatch}}}}function ee(n){return n.reason!==void 0?n.reason:new DOMException("The operation was aborted.","AbortError")}function We(n){let e=n?.name;return e==="AbortError"||e==="TimeoutError"}function ze(n){let e=Ye(n),t=Xe(n.body),r={...t===void 0?{}:{details:t},...n.invocationId===void 0?{}:{invocationId:n.invocationId}};return Object.keys(r).length>0&&ne.set(e,r),e}var Ke=new Map([["insufficient_funds","insufficient_funds"]]);function Ye(n){let{status:e,body:t}=n,r=Je(t),o=n.retryAfterSeconds??Ze(t),a=Qe(t),s=a===void 0?void 0:Ke.get(a);if(s!==void 0)return new m(s,e,r,void 0,a);switch(e){case 304:return new m("not_modified",e,r);case 400:case 422:return new m("invalid",e,r,void 0,a);case 403:return new m("forbidden",e,r,void 0,a);case 404:return new m("not_found",e,r,void 0,a);case 402:return new m("insufficient_funds",e,r,void 0,a);case 409:return new m("conflict",e,r,void 0,a);case 412:return new m("precondition_failed",e,r,void 0,a);case 413:return new m("too_large",e,r,void 0,a);case 429:return new m("rate_limited",e,r,o,a);default:return new m("unavailable",e,r,o,a)}}function Je(n){if(typeof n=="string")return n;let e=n?.message;if(typeof e=="string")return e;let t=n?.error;if(typeof t=="string")return t;let r=t?.message;return typeof r=="string"?r:"no detail"}function Xe(n){let t=n?.error?.details;return t===null?void 0:t}function Qe(n){let t=n?.error?.code;return typeof t=="string"&&t.length>0?t:void 0}function Ze(n){let e=n?.retryAfterSeconds;return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:void 0}function en(n){let e=n.lastIndexOf("@");return (e===-1?n:`***@${n.slice(e+1)}`).slice(0,200)}var nn=new Set(U);function tn(n){if(!n)return {};let e={};for(let[t,r]of Object.entries(n))nn.has(t.toLowerCase())&&(e[t.toLowerCase()]=r);return e}function re(n){let e=n.fetch??globalThis.fetch.bind(globalThis);return Q(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"?en(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 h=o.username!==""||o.password!=="",y=a.username!==o.username||a.password!==o.password,S=h?y?"baseUrl (and possibly the request path)":"baseUrl":"request path";throw new f(`the ${S} 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[h,y]of Object.entries(n.defaultQuery??{}))a.searchParams.has(h)||a.searchParams.set(h,y);let s=t.bytes,l=t.bytes===void 0?void 0:"application/octet-stream";try{t.body!==void 0&&(s=JSON.stringify(t.body),l="application/json");}catch(h){throw new f(`the body of ${t.method} ${JSON.stringify(a.pathname)} could not be serialised to JSON: ${String(h)}. This is a bug in the request, not a server failure \u2014 retrying sends the same unserialisable value.`)}let u=await e(a.toString(),{method:t.method,headers:{authorization:`Bearer ${r}`,...l===void 0?{}:{"content-type":l},...tn(t.headers)},body:s,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 h=await u.text();if(h.length>0)try{c=JSON.parse(h);}catch{c=h;}}let g=u.headers.get("etag"),_=rn(u.headers.get("retry-after")),v=u.headers.get("x-gem-invocation-id");return {status:u.status,body:c,...g===null?{}:{etag:g},..._===void 0?{}:{retryAfterSeconds:_},...v===null||v===""?{}:{invocationId:v}}},n)}function rn(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 on="gem-web-bridge";var I=65536,oe=8,N=5e3,ae=1024;var D=Object.create(null);var ie=Object.create(null);function an(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 sn(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 ln(n){return /^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i.test(n)}function dn(n){return /^[a-z_]+$/.test(n)}function V(n,e,t){if(e>oe)return `nesting deeper than ${oe}`;if(++t.nodes>N)return `more than ${N} values`;if(t.bytes>I)return `over the ${I} 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>ae)return `an array of ${n.length} entries, over the ${ae} limit`;t.bytes+=2;for(let l of n){let u=V(l,e+1,t);if(u)return u}return null}let a=Object.getPrototypeOf(n);if(a!==Object.prototype&&a!==null)return "a value that is not a plain object";t.bytes+=2;let s=n;for(let l in s){if(!Object.prototype.hasOwnProperty.call(s,l))continue;if(++t.nodes>N)return `more than ${N} values`;if(t.bytes+=l.length*3+4,t.bytes>I)return `over the ${I} byte limit`;let u=V(s[l],e+1,t);if(u)return u}return null}function un(n){let e={nodes:0,bytes:0,seen:new Set},t=V(n,0,e);return t?`message contains ${t}`:e.bytes>I?`message is over the ${I} byte limit`:null}var cn={origin:[an,"not a well-formed origin"],url:[sn,"not a safe absolute http(s) URL"],bcp47:[ln,"not a well-formed BCP 47 tag"],code:[dn,"not a code of lower-case letters and underscores"]};function se(n,e,t){for(let r of e){let o=t===""?r.n:`${t}.${r.n}`,a=n[r.n];if(a==null){if(r.o)continue;return `${o}: required`}let s=W(a,r,o);if(s)return s}return null}function W(n,e,t){switch(e.k){case "u":return typeof n=="boolean"?null:W(n,{...e,k:typeof n=="string"?"s":"n"},t);case "s":{if(typeof n!="string")return `${t}: expected string`;if(n.length>e.max)return `${t}: exceeds ${e.max} characters`;if(e.f){let[r,o]=cn[e.f];if(!r(n))return `${t}: ${o}`}return null}case "n":case "i":return typeof n!="number"||!(e.k=="i"?Number.isInteger:Number.isFinite)(n)?`${t}: expected ${e.k=="i"?"integer":"number"}`:n<e.lo||n>e.hi?`${t}: out of range ${e.lo}..${e.hi}`:null;case "b":return typeof n=="boolean"?null:`${t}: expected boolean`;case "e":{let r=e.v;return r.includes(n)?null:`${t}: not one of ${r.join("|")}`}case "o":return typeof n!="object"||n===null||Array.isArray(n)?`${t}: expected object`:se(n,e.fs,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.max)return `${t}: exceeds ${e.max} items`;let r=e.it,o=`${t}[]`;for(let a of n){if(a==null){if(r.o)continue;return `${o}: required`}let s=W(a,r,o);if(s)return s}return null}default:{let r=e.k;return `${t}: unknown kind ${String(r)}`}}}var le=Object.create(null);function d(n,e,t,r){return D[n]=t,r&&(ie[n]=r),le[n]=o=>{let a=un(o);if(a)return a;if(typeof o!="object"||o===null||Array.isArray(o))return "message: expected object";let s=o;return s.gem!==on?"gem: wrong protocol marker":s.type!==n?`type: expected ${n}`:se(s,e,"")}}var p={n:"requestId",k:"s",max:64};d("gem.handshake",[{n:"versions",k:"o",fs:[{n:"min",k:"i",lo:1,hi:1e3},{n:"max",k:"i",lo:1,hi:1e3}]},{n:"capabilities",k:"a",o:1,max:64,it:{n:"",k:"s",max:64}},{n:"embedder",k:"s",max:2048,f:"origin"},{n:"unbidden",k:"b",o:1}],30);d("gem.handshake.accept",[{n:"v",k:"i",lo:1,hi:1e3},{n:"capabilities",k:"a",o:1,max:64,it:{n:"",k:"s",max:64}}],5);d("gem.token",[{n:"token",k:"s",max:4096},{n:"requestId",k:"s",o:1,max:64},{n:"generation",k:"i",lo:0,hi:2147483647},{n:"apiBaseUrl",k:"s",o:1,max:512,f:"url"},{n:"playerId",k:"s",max:64},{n:"gameId",k:"s",max:64},{n:"channel",k:"e",v:["dev","test","release"]},{n:"gameVersion",k:"s",o:1,max:64},{n:"expiresAt",k:"i",lo:0,hi:4102444800},{n:"chainEndsAt",k:"i",lo:0,hi:4102444800},{n:"allowDevTools",k:"b",o:1}],30);d("gem.token.denied",[p,{n:"retryable",k:"b"},{n:"retryAfterMs",k:"i",o:1,lo:0,hi:36e5},{n:"reason",k:"e",v:["chain_exhausted","unavailable"]},{n:"correlationId",k:"s",max:64}],30);d("gem.player",[{n:"untrusted",k:"o",fs:[{n:"displayName",k:"s",max:64},{n:"displayTag",k:"s",o:1,max:80},{n:"displayHandle",k:"s",max:80}]},{n:"playerId",k:"s",o:1,max:64},{n:"discriminator",k:"s",o:1,max:8},{n:"avatarIconUrl",k:"s",o:1,max:2048,f:"url"},{n:"avatarIconId",k:"s",o:1,max:64},{n:"avatar3dId",k:"s",o:1,max:64},{n:"avatar3dModelUrl",k:"s",o:1,max:2048,f:"url"},{n:"avatar3dIconUrl",k:"s",o:1,max:2048,f:"url"},{n:"avatars3d",k:"a",o:1,max:8,it:{n:"",k:"o",fs:[{n:"family",k:"s",max:32},{n:"id",k:"s",max:64},{n:"modelUrl",k:"s",max:256,f:"url"},{n:"iconUrl",k:"s",max:256,f:"url"}]}},{n:"badges",k:"a",o:1,max:2,it:{n:"",k:"o",fs:[{n:"itemId",k:"s",max:64},{n:"iconUrl",k:"s",max:2048,f:"url"}]}},{n:"displayTag",k:"s",max:8},{n:"avatarUrl",k:"s",o:1,max:2048,f:"url"},{n:"boost",k:"o",o:1,fs:[{n:"multipliers",k:"a",max:8,it:{n:"",k:"o",fs:[{n:"currencyId",k:"s",max:64},{n:"currencySlug",k:"s",max:32},{n:"multiplierBp",k:"i",lo:1e4,hi:1e6}]}},{n:"expiresInDays",k:"i",o:1,lo:1,hi:7}]}],12);d("gem.pause",[{n:"paused",k:"b"}],120);d("gem.prefs",[{n:"reducedMotion",k:"b"},{n:"muted",k:"b"},{n:"showFrameStats",k:"b",o:1},{n:"locale",k:"s",max:35,f:"bcp47"},{n:"recommended",k:"o",o:1,fs:[{n:"volume",k:"i",lo:0,hi:100},{n:"batterySaver",k:"b"},{n:"keyboardLayout",k:"e",v:["wasd","arrows"]},{n:"gamepadConfirm",k:"e",v:["south","east"]},{n:"vibration",k:"b"},{n:"lookSensitivity",k:"i",o:1,lo:20,hi:400},{n:"gamepadLookSensitivity",k:"i",o:1,lo:20,hi:400},{n:"invertLookY",k:"b",o:1},{n:"touchMovement",k:"s",o:1,max:16,f:"code"},{n:"graphicsQuality",k:"s",o:1,max:16,f:"code"},{n:"graphicsQualityAuto",k:"b",o:1}]}],60);d("gem.cohorts",[{n:"cohorts",k:"a",max:8,it:{n:"",k:"o",fs:[{n:"experimentId",k:"s",max:36},{n:"variantKey",k:"s",max:32}]}}],12,"cohorts");d("gem.earnAllowanceChanged",[],30,"earnAllowance");d("gem.viewport",[{n:"insets",k:"o",fs:[{n:"top",k:"i",lo:0,hi:4096},{n:"right",k:"i",lo:0,hi:4096},{n:"bottom",k:"i",lo:0,hi:4096},{n:"left",k:"i",lo:0,hi:4096}]},{n:"reserved",k:"a",o:1,max:4,it:{n:"",k:"o",fs:[{n:"x",k:"i",lo:0,hi:16384},{n:"y",k:"i",lo:0,hi:16384},{n:"width",k:"i",lo:0,hi:16384},{n:"height",k:"i",lo:0,hi:16384},{n:"control",k:"o",o:1,fs:[{n:"x",k:"i",lo:0,hi:16384},{n:"y",k:"i",lo:0,hi:16384},{n:"width",k:"i",lo:0,hi:16384},{n:"height",k:"i",lo:0,hi:16384}]}]}}],60,"viewport");d("gem.deviceSettings",[{n:"settings",k:"j",o:1}],12,"deviceSettings");d("gem.willTerminate",[{n:"reason",k:"e",v:["grant_expiring","session_ended","navigating","kill_switch"]},{n:"graceMs",k:"i",lo:0,hi:6e4}],10);d("gem.roomEvent",[{n:"event",k:"e",v:["updated","match_started","match_ready","match_failed","version_stale"]},{n:"roomId",k:"s",max:64},{n:"matchId",k:"s",o:1,max:64},{n:"version",k:"i",o:1,lo:0,hi:2147483647},{n:"reason",k:"s",o:1,max:64},{n:"platform",k:"e",o:1,v:["universal","mobile"]}],120,"rooms");d("gem.socketState",[{n:"connected",k:"b"},{n:"reason",k:"e",o:1,v:["connecting","dropped","watchdog","terminal"]}],12,"socketState");d("gem.seatedEvent",[{n:"roomId",k:"s",max:64}],60,"partySeating");d("gem.autoStartFailedEvent",[{n:"roomId",k:"s",max:64},{n:"code",k:"s",max:64}],30,"autoStartFailure");d("gem.ticketEvent",[{n:"event",k:"e",v:["queued","matched","expired","cancelled","failed"]},{n:"ticketId",k:"s",max:64},{n:"partySize",k:"i",o:1,lo:1,hi:64},{n:"queuedAt",k:"i",o:1,lo:0,hi:4102444800},{n:"expiresAt",k:"i",o:1,lo:0,hi:4102444800},{n:"reason",k:"s",o:1,max:64},{n:"roomId",k:"s",o:1,max:64}],60,"ticketEvents");d("gem.signalEvent",[{n:"event",k:"e",v:["hello","offer","answer","ice","peerJoined","peerLeft","migration","matchEnded","error"]},{n:"matchId",k:"s",max:64},{n:"data",k:"j"}],1800,"p2p");d("gem.dedicatedEvent",[{n:"event",k:"e",v:["answer","error","matchEnded"]},{n:"matchId",k:"s",max:64},{n:"sdp",k:"s",o:1,max:10240},{n:"sessionId",k:"s",o:1,max:64},{n:"code",k:"s",o:1,max:64},{n:"message",k:"s",o:1,max:256},{n:"reason",k:"s",o:1,max:64}],120,"dedicated");d("gem.partyResult",[p,{n:"partyId",k:"s",o:1,max:64}],30,"parties");d("gem.clusterTarget",[{n:"clusterTargetId",k:"s",max:64},{n:"clusterTargetIds",k:"a",o:1,max:3,it:{n:"",k:"s",max:64}}],12,"clusterTarget");d("gem.devtools",[{n:"action",k:"e",v:["open","close","toggle"]}],30,"devtools");d("gem.screenshot",[{n:"maxWidth",k:"i",lo:1,hi:7680},{n:"maxHeight",k:"i",lo:1,hi:4320}],6,"screenshot");d("gem.screenshot.denied",[{n:"reason",k:"e",v:["not_wired","no_source","unsupported","unreadable","tainted","too_large","busy","declined","failed"]},{n:"retryable",k:"b"}],12,"screenshot");d("gem.requestContext",[],12,"feedbackContext");d("gem.gameContext",[{n:"context",k:"j"}],12,"feedbackContext");d("gem.signal",[{n:"signal",k:"e",v:["join","offer","answer","ice","migrationAck","hostUnreachable"]},{n:"matchId",k:"s",max:64},{n:"data",k:"j"}],1200,"p2p");d("gem.dedicatedOffer",[{n:"matchId",k:"s",max:64},{n:"sdp",k:"s",max:10240},{n:"intent",k:"e",v:["initial","ice_restart","full_reconnect"]}],60,"dedicated");d("gem.partyRequest",[p],12,"parties");d("gem.ready",[],5);d("gem.engaged",[],5,"engagement");d("gem.progress",[{n:"loaded",k:"i",lo:0,hi:1099511627776},{n:"total",k:"i",lo:0,hi:1099511627776}],600);d("gem.requestToken",[p,{n:"reason",k:"e",v:["initial","expiring","rejected"]}],12);d("gem.requestLocalServer",[p,{n:"gameRoomId",k:"s",max:64}],6,"localHost");d("gem.localServer",[p,{n:"serverId",k:"s",o:1,max:128}],30,"localHost");d("gem.localServer.denied",[p,{n:"retryable",k:"b"},{n:"reason",k:"e",v:["refused","unavailable"]}],30,"localHost");d("gem.exit",[{n:"reason",k:"s",o:1,max:64}],5);d("gem.openExternal",[{n:"url",k:"s",max:2048,f:"url"}],6);d("gem.requestFullscreen",[{n:"enabled",k:"b"}],30);d("gem.audioState",[{n:"muted",k:"b"}],120,"audioState");d("gem.rewardCue",[{n:"currencySlug",k:"s",max:32},{n:"expected",k:"i",o:1,lo:1,hi:1e9},{n:"origin",k:"o",o:1,fs:[{n:"x",k:"i",lo:0,hi:16384},{n:"y",k:"i",lo:0,hi:16384}]}],60,"rewardCue");d("gem.walletDisplay",[{n:"visible",k:"b"},{n:"currencies",k:"a",o:1,max:8,it:{n:"",k:"s",max:64}},{n:"score",k:"b",o:1}],60,"walletDisplay");d("gem.controlsDeclare",[{n:"uses",k:"o",fs:[{n:"lookSensitivity",k:"s",o:1,max:16,f:"code"},{n:"gamepadLookSensitivity",k:"s",o:1,max:16,f:"code"},{n:"invertLookY",k:"s",o:1,max:16,f:"code"},{n:"touchMovement",k:"s",o:1,max:16,f:"code"}]}],60,"controls");d("gem.menu",[{n:"settings",k:"b"},{n:"items",k:"a",o:1,max:4,it:{n:"",k:"o",fs:[{n:"id",k:"s",max:32},{n:"label",k:"s",max:40}]}}],60,"gameMenu");d("gem.menuSelect",[{n:"entry",k:"e",v:["settings","item"]},{n:"id",k:"s",o:1,max:32}],60,"gameMenu");d("gem.gemCorner",[{n:"corner",k:"e",v:["top-left","top-right","bottom-left","bottom-right"]}],12,"gemCorner");d("gem.settingsDeclare",[{n:"settings",k:"a",max:8,it:{n:"",k:"o",fs:[{n:"id",k:"s",max:40},{n:"label",k:"s",max:40},{n:"kind",k:"e",v:["toggle","slider","choice"]},{n:"value",k:"u",max:40,lo:-1e6,hi:1e6},{n:"quick",k:"b",o:1},{n:"icon",k:"s",o:1,max:16,f:"code"},{n:"min",k:"n",o:1,lo:-1e6,hi:1e6},{n:"max",k:"n",o:1,lo:-1e6,hi:1e6},{n:"step",k:"n",o:1,lo:0,hi:1e6},{n:"options",k:"a",o:1,max:4,it:{n:"",k:"o",fs:[{n:"id",k:"s",max:40},{n:"label",k:"s",max:40}]}}]}}],120,"gameSettings");d("gem.settingChange",[{n:"id",k:"s",max:40},{n:"value",k:"u",max:40,lo:-1e6,hi:1e6}],120,"gameSettings");d("gem.requestShare",[{n:"params",k:"a",max:16,it:{n:"",k:"o",fs:[{n:"key",k:"s",max:64},{n:"value",k:"s",max:512}]}}],6,"share");d("gem.requestAvatarPicker",[{n:"tab",k:"e",o:1,v:["2d","3d"]}],6,"avatarPicker");d("gem.vibrate",[{n:"pattern",k:"a",max:99,it:{n:"",k:"i",lo:0,hi:1e4}}],600,"vibration");d("gem.frameStats",[{n:"fps",k:"i",lo:0,hi:1e3},{n:"frameTimeP95Ms",k:"i",lo:0,hi:1e5},{n:"counts",k:"e",o:1,v:["pageFrames","gameDraws"]}],120,"frameStats");d("gem.portraitBorders",[{n:"name",k:"s",o:1,max:40}],60,"portraitBorders");d("gem.error",[{n:"code",k:"e",v:["version_mismatch","handshake_timeout","handshake_duplicate","invalid_message","rate_limited","token_unavailable","unsupported","unsupported_capability","internal"]},{n:"message",k:"s",o:1,max:256}],60);d("gem.requestPurchase",[p,{n:"purchaseKind",k:"e",v:["item","recipe"]},{n:"targetId",k:"s",max:64},{n:"currencySlug",k:"s",max:32},{n:"quantity",k:"i",o:1,lo:1,hi:10},{n:"catalogId",k:"s",o:1,max:64}],12,"purchases");d("gem.requestAvatar3dPurchase",[p,{n:"itemId",k:"s",max:64},{n:"currencySlug",k:"s",max:32}],12,"avatar3dPurchases");d("gem.purchaseResult",[p,{n:"outcome",k:"e",v:["ok","declined","unavailable"]},{n:"reason",k:"s",o:1,max:64,f:"code"},{n:"purchaseId",k:"s",o:1,max:64}],30,"purchases");d("gem.deviceSettings.put",[p,{n:"settings",k:"j"}],30,"deviceSettings");d("gem.deviceSettings.result",[p,{n:"outcome",k:"e",v:["stored","too_large","unavailable"]}],30,"deviceSettings");d("gem.requestAd",[p,{n:"placement",k:"s",max:32},{n:"format",k:"e",v:["interstitial","rewarded"]}],6,"ads");d("gem.adResult",[p,{n:"outcome",k:"e",v:["shown","no_ad","unavailable"]}],12,"ads");d("gem.signalMoment",[p,{n:"kind",k:"e",v:["level_end","run_end","match_end","menu_return","other_break"]},{n:"placement",k:"s",o:1,max:32}],6,"moments");d("gem.momentResult",[p,{n:"shown",k:"b"}],12,"moments");d("gem.requestSignIn",[p],6,"signIn");d("gem.signInResult",[p,{n:"outcome",k:"e",v:["signed_in","declined","unavailable"]}],12,"signIn");d("gem.requestFriendChallenge",[p,{n:"playerId",k:"s",max:64},{n:"template",k:"s",max:64},{n:"params",k:"j",o:1}],12,"friendChallenges");d("gem.friendChallengeResult",[p,{n:"outcome",k:"e",v:["accepted","cancelled","refused","unavailable","rate_limited","invalid"]},{n:"code",k:"s",o:1,max:64},{n:"param",k:"s",o:1,max:64},{n:"channel",k:"s",o:1,max:16},{n:"configVersion",k:"i",o:1,lo:0,hi:9007199254740991},{n:"retryAfterMs",k:"i",o:1,lo:0,hi:864e5},{n:"detail",k:"s",o:1,max:300}],30,"friendChallenges");Object.freeze(le);D.__malformed=60;Object.freeze(D);Object.freeze(ie);var M={now:()=>Date.now(),setTimeout:(n,e)=>setTimeout(n,e),clearTimeout:n=>clearTimeout(n)};function de(n){let e=n.toLowerCase();return e==="localhost"||e.endsWith(".localhost")||e==="[::1]"||e==="::1"?true:/^127(\.\d{1,3}){3}$/.test(e)}var mn=1e4;function ue(n,e){return z(n,e)}function z(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=s=>({token:s.token,expiresAt:s.expiresAt,chainEndsAt:Number.POSITIVE_INFINITY}),r=null,o=new B({clock:e.clock,...e.onStateChange===void 0?{}:{onStateChange:e.onStateChange},request:()=>new Promise((s,l)=>{let u=e.clock.setTimeout(()=>{r=null,l({reason:"unavailable",retryable:true});},e.timeoutMs??mn);r={resolve:c=>{e.clock.clearTimeout(u),s(c);},reject:l,timer:u};})}),a=n.onServerToken(s=>{let l=t(s),u=r;if(u){r=null,u.resolve(l);return}o.accept(l);});return {source:o,dispose(){a(),o.dispose(),r&&(e.clock.clearTimeout(r.timer),r.reject({reason:"unavailable",retryable:false}),r=null);}}}var Y={};Ie(Y,{acceptTransfer:()=>gn,addEntityProgression:()=>pn,adminAction:()=>yn,cancelInventoryTransfer:()=>fn,claimEntityProgressionRewards:()=>hn,closeGameRoom:()=>_n,createEntityBatchOrder:()=>bn,createEntityOrder:()=>vn,createSession:()=>Rn,deleteEntityGameSetting:()=>xn,deleteEntitySave:()=>kn,deleteSession:()=>Sn,deleteShowcaseValue:()=>wn,executeEntityRecipe:()=>An,finalizeSaveUpload:()=>Pn,getChannelAssignment:()=>On,getDropRates:()=>Tn,getEntityCurrency:()=>Gn,getEntityGameSetting:()=>Cn,getEntityInventory:()=>En,getEntityInventoryItem:()=>In,getEntityLeaderboard:()=>Mn,getEntityOrder:()=>Ln,getEntityProgression:()=>qn,getEntityRecipeAvailability:()=>$n,getEntityRecipeUsage:()=>jn,getEntitySave:()=>Fn,getEvent:()=>Bn,getGameRoomV2:()=>Un,getLeaderboard:()=>Nn,getPlayerGameProfile:()=>Dn,getPurchaseCatalog:()=>Hn,getResolvedTemplate:()=>Vn,getRoomArgs:()=>Wn,getShowcaseValue:()=>zn,getTransferDetails:()=>Kn,ingestAnalyticsEvents:()=>K,initiateInventoryTransfer:()=>Yn,invokeFunction:()=>Jn,kickPlayer:()=>Xn,listChallenges:()=>Qn,listEntityGameSettings:()=>Zn,listEntityOrders:()=>et,listEntityProgressions:()=>nt,listEntitySaves:()=>tt,listEvents:()=>rt,listGameRooms:()=>ot,listResolvedTemplates:()=>at,listTransfers:()=>it,maxEntityProgression:()=>st,putEntityGameSetting:()=>lt,putRoomArgs:()=>dt,putShowcaseValue:()=>ut,rejectTransfer:()=>ct,reportMatchPlayers:()=>mt,requestSaveUploadUrl:()=>gt,resetEntityProgression:()=>pt,setMatchBackfill:()=>yt,simulateEntityOrder:()=>ft,transferHostV2:()=>ht,updateGameRoomV2:()=>_t});function i(n){let e=String(n);if(!/^[A-Za-z0-9_.-]{1,128}$/.test(e)||e==="."||e==="..")throw new TypeError(`${JSON.stringify(e)} is not a usable path segment \u2014 it is interpolated into a URL`);return encodeURIComponent(e)}async function gn(n,e,t){let r=`/v1/inventory/transfers/${i(e)}/accept`;return n.client.post(r,void 0,t?.signal)}async function pn(n,e,t,r,o,a){let s=`/v1/inventory/${i(e)}/${i(t)}/progressions/${i(r)}/add`;return n.client.post(s,o,a?.signal)}async function yn(n,e,t,r){let o=`/v1/voice/sessions/${i(e)}/admin`;return n.client.post(o,t,r?.signal)}async function fn(n,e,t){let r=`/v1/inventory/transfers/${i(e)}/cancel`;return n.client.post(r,void 0,t?.signal)}async function hn(n,e,t,r,o,a){let s=`/v1/inventory/${i(e)}/${i(t)}/progressions/${i(r)}/claim`;return n.client.post(s,o,a?.signal)}async function _n(n,e,t){let r=`/v1/games/${i(n.gameId())}/game-rooms/${i(e)}`;return n.client.delete(r,t?.signal)}async function bn(n,e,t,r,o){let a=`/v1/inventory/${i(e)}/${i(t)}/orders/batch`;return n.client.post(a,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function vn(n,e,t,r,o){let a=`/v1/inventory/${i(e)}/${i(t)}/orders`;return n.client.post(a,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function Rn(n,e,t){return n.client.post("/v1/voice/sessions",e,t?.signal)}async function xn(n,e,t,r,o){let a=`/v1/settings/${i(e)}/${i(t)}/${i(r)}`;return n.client.delete(a,o?.signal)}async function kn(n,e,t,r,o){let a=`/v1/saves/${i(e)}/${i(t)}/${i(r)}`;return n.client.delete(a,o?.signal)}async function Sn(n,e,t){let r=`/v1/voice/sessions/${i(e)}`;return n.client.delete(r,t?.signal)}async function wn(n,e,t,r){let o=`/v1/showcase/players/${i(e)}/${i(t)}`;return n.client.delete(o,r?.signal)}async function An(n,e,t,r,o){let a=`/v1/inventory/${i(e)}/${i(t)}/recipes/execute`;return n.client.post(a,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function Pn(n,e,t,r,o,a){let s=`/v1/saves/${i(e)}/${i(t)}/${i(r)}/finalize`;return n.client.post(s,o,a?.signal)}async function On(n,e,t){let r=`/v1/games/${i(n.gameId())}/config/channels/${i(e)}`;return n.client.getWithEtag(r,{...t?.signal===void 0?{}:{signal:t.signal},...t?.ifNoneMatch===void 0?{}:{ifNoneMatch:t.ifNoneMatch}})}async function Tn(n,e,t){let r=`/v1/inventory/loot-tables/${i(e)}/drop-rates`;return n.client.get(r,t?.signal)}async function Gn(n,e,t,r,o){let a=`/v1/inventory/${i(e)}/${i(t)}/currencies/${i(r)}`;return n.client.get(a,o?.signal)}async function Cn(n,e,t,r,o){let a=`/v1/settings/${i(e)}/${i(t)}/${i(r)}`;return n.client.getWithEtag(a,{...o?.signal===void 0?{}:{signal:o.signal},...o?.ifNoneMatch===void 0?{}:{ifNoneMatch:o.ifNoneMatch}})}async function En(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(),s=`/v1/inventory/${i(e)}/${i(t)}`+(a?`?${a}`:"");return n.client.get(s,r?.signal)}async function In(n,e,t,r,o){let a=`/v1/inventory/${i(e)}/${i(t)}/items/${i(r)}`;return n.client.get(a,o?.signal)}async function Mn(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 s=a.toString(),l=`/v1/leaderboards/${i(e)}/${i(t)}/${i(r)}`+(s?`?${s}`:"");return n.client.get(l,o?.signal)}async function Ln(n,e,t,r,o){let a=`/v1/inventory/${i(e)}/${i(t)}/orders/${i(r)}`;return n.client.get(a,o?.signal)}async function qn(n,e,t,r,o){let a=`/v1/inventory/${i(e)}/${i(t)}/progressions/${i(r)}`;return n.client.get(a,o?.signal)}async function $n(n,e,t,r,o,a){let s=`/v1/inventory/${i(e)}/${i(t)}/catalogs/${i(r)}/recipes/${i(o)}/availability`;return n.client.get(s,a?.signal)}async function jn(n,e,t,r){let o=new URLSearchParams;r?.limit!==void 0&&o.set("limit",String(r?.limit));let a=o.toString(),s=`/v1/inventory/${i(e)}/${i(t)}/recipe-usage`+(a?`?${a}`:"");return n.client.get(s,r?.signal)}async function Fn(n,e,t,r,o){let a=`/v1/saves/${i(e)}/${i(t)}/${i(r)}`;return n.client.getWithEtag(a,{...o?.signal===void 0?{}:{signal:o.signal},...o?.ifNoneMatch===void 0?{}:{ifNoneMatch:o.ifNoneMatch}})}async function Bn(n,e,t){let r=`/v1/events/${i(e)}`;return n.client.get(r,t?.signal)}async function Un(n,e,t){let r=`/v2/games/${i(n.gameId())}/game-rooms/${i(e)}`;return n.client.getWithEtag(r,{...t?.signal===void 0?{}:{signal:t.signal},...t?.ifNoneMatch===void 0?{}:{ifNoneMatch:t.ifNoneMatch}})}async function Nn(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/${i(e)}`+(o?`?${o}`:"");return n.client.get(a,t?.signal)}async function Dn(n,e,t){let r=`/v1/profiles/players/${i(e)}`;return n.client.get(r,t?.signal)}async function Hn(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 Vn(n,e,t){let r=`/v1/game-room-templates/${i(e)}`;return n.client.get(r,t?.signal)}async function Wn(n,e,t){let r=`/v1/games/${i(n.gameId())}/game-rooms/${i(e)}/room-args`;return n.client.get(r,t?.signal)}async function zn(n,e,t,r){let o=`/v1/showcase/players/${i(e)}/${i(t)}`;return n.client.get(o,r?.signal)}async function Kn(n,e,t){let r=`/v1/inventory/transfers/${i(e)}`;return n.client.get(r,t?.signal)}async function K(n,e,t){let r=`/v1/games/${i(n.gameId())}/analytics/events`;return n.client.post(r,e,t?.signal,{replaySafe:true,retryRateLimited:false})}async function Yn(n,e,t){return n.client.post("/v1/inventory/transfers",e,t?.signal)}async function Jn(n,e,t){return n.client.postBytes("/v1/functions/invoke",e,t?.signal)}async function Xn(n,e,t,r){let o=`/v1/games/${i(n.gameId())}/game-rooms/${i(e)}/kick/${i(t)}`;return n.client.post(o,void 0,r?.signal)}async function Qn(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 Zn(n,e,t,r){let o=`/v1/settings/${i(e)}/${i(t)}`;return n.client.get(o,r?.signal)}async function et(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(),s=`/v1/inventory/${i(e)}/${i(t)}/orders`+(a?`?${a}`:"");return n.client.get(s,r?.signal)}async function nt(n,e,t,r){let o=`/v1/inventory/${i(e)}/${i(t)}/progressions`;return n.client.get(o,r?.signal)}async function tt(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(),s=`/v1/saves/${i(e)}/${i(t)}`+(a?`?${a}`:"");return n.client.get(s,r?.signal)}async function rt(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 ot(n,e){let t=new URLSearchParams;e?.status!==void 0&&t.set("status",String(e?.status)),e?.game_channel!==void 0&&t.set("game_channel",String(e?.game_channel)),e?.game_room_type!==void 0&&t.set("game_room_type",String(e?.game_room_type)),e?.template_id!==void 0&&t.set("template_id",String(e?.template_id)),e?.template_slug!==void 0&&t.set("template_slug",String(e?.template_slug)),e?.limit!==void 0&&t.set("limit",String(e?.limit)),e?.cursor!==void 0&&t.set("cursor",String(e?.cursor));let r=t.toString(),o=`/v1/games/${i(n.gameId())}/game-rooms`+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function at(n,e){return n.client.get("/v1/game-room-templates",e?.signal)}async function it(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 st(n,e,t,r,o,a){let s=`/v1/inventory/${i(e)}/${i(t)}/progressions/${i(r)}/max`;return n.client.post(s,o,a?.signal)}async function lt(n,e,t,r,o,a){let s=`/v1/settings/${i(e)}/${i(t)}/${i(r)}`;return n.client.put(s,o,a?.signal,{...a?.ifMatch===void 0?{}:{ifMatch:a.ifMatch}})}async function dt(n,e,t,r){let o=`/v1/games/${i(n.gameId())}/game-rooms/${i(e)}/room-args`;return n.client.put(o,t,r?.signal)}async function ut(n,e,t,r,o){let a=`/v1/showcase/players/${i(e)}/${i(t)}`;return n.client.put(a,r,o?.signal)}async function ct(n,e,t){let r=`/v1/inventory/transfers/${i(e)}/reject`;return n.client.post(r,void 0,t?.signal)}async function mt(n,e,t,r){let o=`/v1/games/${i(n.gameId())}/matches/${i(e)}/players/report`;return n.client.post(o,t,r?.signal)}async function gt(n,e,t,r,o,a){let s=`/v1/saves/${i(e)}/${i(t)}/${i(r)}/upload-url`;return n.client.post(s,o,a?.signal,{replaySafe:true})}async function pt(n,e,t,r,o,a){let s=`/v1/inventory/${i(e)}/${i(t)}/progressions/${i(r)}/reset`;return n.client.post(s,o,a?.signal)}async function yt(n,e,t,r){let o=`/v1/games/${i(n.gameId())}/matches/${i(e)}/backfill`;return n.client.put(o,t,r?.signal)}async function ft(n,e,t,r,o){let a=`/v1/inventory/${i(e)}/${i(t)}/orders/simulate`;return n.client.post(a,r,o?.signal)}async function ht(n,e,t,r){let o=`/v2/games/${i(n.gameId())}/game-rooms/${i(e)}/transfer/${i(t)}`;return n.client.post(o,void 0,r?.signal)}async function _t(n,e,t,r){let o=`/v2/games/${i(n.gameId())}/game-rooms/${i(e)}`;return n.client.patch(o,t,r?.signal,{...r?.ifMatch===void 0?{}:{ifMatch:r.ifMatch}})}var ce="gem_";function me(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 Rt=1e4,xt=50,kt=1e3,St=65536-4*1024,ge=n=>typeof n=="number"?n:0,wt=n=>typeof n=="string"?n:"";function pe(){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 At(n){return n?.retryable===true}function Pt(n,e){let t=n??{},r=Array.isArray(t.rejected)?t.rejected.map(o=>{let a=o??{};return {index:ge(a.index),code:wt(a.code)}}):[];return {accepted:ge(t.accepted),rejected:r,dropped:e,duplicate:t.duplicate===true}}function ye(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 fe(n){let e=Math.max(1,Math.floor(n.maxQueue??kt)),t={client:n.client,gameId:()=>n.gameId},r=[],o=0,a=null,s=false,l=null,u=0,c=0,g=false,_=false,v=R=>{n.log?.(R);},h=()=>{a!==null&&(n.clock.clearTimeout(a),a=null);},y=()=>Math.max(0,c-n.clock.now()),S=()=>{a!==null||s||l!==null||(a=n.clock.setTimeout(()=>{a=null,O().catch(()=>{});},Math.max(Rt,y())));},A=()=>{let R=Math.min(r.length,100),x=128;for(let T=0;T<R;T+=1){let G=r[T];if(G===void 0)break;if(x+=JSON.stringify(ye(G,0)).length+1,x>St)return Math.max(1,T)}return R};async function O(R){for(;l!==null;)await l.catch(()=>{});if(r.length===0)return {accepted:0,rejected:[],dropped:0,duplicate:false};let x=Ge(R);l=x;try{return await x}finally{l===x&&(l=null),r.length>0&&S();}}async function Ge(R){h();let x=r.splice(0,A()),T=o;o=0;let G=Math.round(n.clock.now()),F={batch_id:pe(),sent_at_ms:G,events:x.map(w=>ye(w,G))};try{let w=await K(t,F,R===void 0?void 0:{signal:R}),C=Pt(w,T);u=0,c=0;for(let Ce of C.rejected)v(`[gem] analytics: an event was refused (${Ce.code}). See the analytics_events section of your game config.`);return C}catch(w){if(At(w)){for(r=[...x,...r],o+=T;r.length>e;)r.shift(),o+=1;u+=1,c=n.clock.now()+me(u,w);}else v(`[gem] analytics: ${x.length} event(s) were discarded \u2014 the platform refused the batch and will refuse it again: ${String(w)}`);throw w}}return {track(R,x,T={}){if(s)return;if(typeof R!="string"||R===""){_||(_=true,v(`[gem] analytics: '${x}' 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(x.startsWith(ce)){g||(g=true,v(`[gem] analytics: '${x}' 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 G={},F={};for(let[w,C]of Object.entries(T))typeof C=="string"?G[w]=C:typeof C=="number"&&Number.isFinite(C)&&(F[w]=C);for(;r.length>=e;)r.shift(),o+=1;r.push({uid:pe(),playerId:R,name:x,atMs:n.clock.now(),dimensions:G,measures:F}),r.length>=xt&&l===null&&y()===0?O().catch(()=>{}):S();},flush:R=>O(R),get pending(){return r.length},dispose(){s=true,h(),r=[],o=0;}}}var Ot=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]]),$=class extends m{constructor(e,t){super(e.reason,e.status,e.detail,e.retryAfterSeconds,e.code),this.name="GemFunctionError",Object.assign(this,t);}get retryable(){return (this.code===void 0?void 0:Ot.get(this.code))??super.retryable}},L=class{#e;constructor(e){this.#e=e;}async invoke(e,t={}){let r=Tt(e),o;try{o=await this.#e(r,t.signal===void 0?{}:{signal:t.signal});}catch(a){throw a instanceof m?Ct(a):a}return Gt(o)}};function Tt(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 Gt(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 Ct(n){let{details:e,invocationId:t}=te(n),o=e?.untrusted?.message,a=e?.reason;return new $(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 P=n=>typeof n=="string"?n:"",Et=/(?:Z|[+-]\d{2}:?\d{2})$/i;function he(n){let e=P(n);if(!Et.test(e))return 0;let t=Date.parse(e);return Number.isFinite(t)?Math.floor(t/1e3):0}var It=/^[0-9a-f]{1,64}$/,Mt=/^[0-9a-f]{16}$/,Lt=/^[A-Za-z][A-Za-z0-9_+\-/]{0,63}$/,qt=/^(?:[01]\d|2[0-3]):[0-5]\d$/;function $t(n){let e=P(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])],s=new Date(Date.UTC(r,o-1,a));return s.getUTCFullYear()===r&&s.getUTCMonth()===o-1&&s.getUTCDate()===a?e:void 0}var jt=4096,Ft=new TextEncoder;function Bt(n){let e=P(n.challenge_data),t=P(n.challenge_data_hash);return e===""||!Mt.test(t)?{}:Ft.encode(e).length>jt?{}:{data:e,dataHash:t}}function Ut(n){let e=n??{},t=he(e.period_start_at),r=he(e.period_ends_at);if(t===0||r===0)return;let o=P(e.slug),a=P(e.seed),s=$t(e.period_local_date),l=P(e.boundary),u=P(e.reset_time);return {id:P(e.progression_definition_id),...o===""?{}:{slug:o},window:P(e.window),periodStartAt:t,periodEndsAt:r,...s===void 0?{}:{periodLocalDate:s},boundary:Lt.test(l)?l:"",resetTime:qt.test(u)?u:"",seed:It.test(a)?a:"",...Bt(e)}}function _e(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 be(n){let e=n??{};return Array.isArray(e.challenges)?e.challenges.map(Ut).filter(t=>t!==void 0):[]}function ve(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().");_e(r);let a=await n({player_id:t,...r===void 0?{}:{periods_back:r},...o===void 0?{}:{signal:o}});return be(a)}}}function Nt(n){let e={};for(let[t,r]of Object.entries(Y))if(typeof r=="function"){let o=r;e[t]=(...a)=>o(n,...a);}return e}function H(n,e={}){let t=e.clock??M,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=z(n,{clock:t,...e.onAuthStateChange===void 0?{}:{onStateChange:e.onAuthStateChange}}),a=re({baseUrl:r,tokenSource:o.source,defaultQuery:{game_id:n.gameId,channel:n.channel},...e.fetch===void 0?{}:{fetch:e.fetch}}),s=new E({transport:a,clock:t}),l={gameId:n.gameId,channel:n.channel,matchId:n.matchId,...n.gameRoomId===void 0?{}:{gameRoomId:n.gameRoomId}},u=Nt({client:s,gameId:()=>l.gameId}),c=l.gameRoomId,g=n.endMatch,_=n.log,v=fe({client:s,clock:t,gameId:l.gameId,...typeof _=="function"?{log:y=>_.call(n,y)}:{}});return {identity:l,client:s,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,S)=>{let A=await u.setMatchBackfill(l.matchId,{open:y.open,...y.seats===void 0?{}:{seats:y.seats}},S===void 0?{}:{signal:S});return {open:A.open,seats:A.seats??null}},reportPlayers:async(y,S)=>(await u.reportMatchPlayers(l.matchId,{players:y.map(O=>({player_id:O.playerId,state:O.state}))},S===void 0?{}:{signal:S})).players.map(O=>({playerId:O.player_id,outcome:O.outcome}))},analytics:v,functions:new L(u.invokeFunction),challenges:ve(u.listChallenges),...c===void 0?{}:{room:{get:y=>u.getGameRoomV2(c,y),args:async y=>{let S=await u.getGameRoomV2(c,y?.signal===void 0?{}:{signal:y.signal}),A=S.modified?S.body:void 0;if(A?.room_args==null||A.room_args_template==null)throw new m("not_found",404,"this room's template declares no room args",void 0,"room_args_not_defined");return {room_args:A.room_args,room_args_template:A.room_args_template}}}},dispose:()=>{v.dispose(),o.dispose();}}}var Dt=["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"],Ht=new Set(Dt);function Re(n){return typeof n=="string"&&Ht.has(n)?n:"unknown"}var Se="[gem: use gem.text.toPlain()]",xe=new Set,ke;function Vt(n){try{if(xe.has(n))return;let e=globalThis.location;if(ke??=!!e?.port&&de(e.hostname??""),!ke)return;xe.add(n),console.warn(`[gem] ${n} is PlayerText, turned into a string: players see ${Se}. Render text.toPlain(value) (text is in @indiegems/gem-web-sdk/sdk).
|
|
1
|
+
var Ee=Object.defineProperty;var Ie=(n,e)=>{for(var t in e)Ee(n,t,{get:e[t],enumerable:true});};globalThis.__gemWebSdkVersion="[gem-web-sdk:sdkVersion:14.0.1]";var Me={initialDelayMs:2e3,maxDelayMs:6e4};function Le(n,e){return e!==void 0?!e:n==="chain_exhausted"}var B=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 b(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 b("chain_exhausted","the token chain reached its ceiling");if(this.inFlight===null&&this.options.clock.now()<this.notBefore)throw new b(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 b("internal","token arrived for a superseded generation");return this.grant=o,this.rejected=false,this.enter("ready"),o.token}).catch(o=>{let a=qe(o),{retryable:s,retryAfterMs:l}=o??{};throw t===this.generation&&(Le(a,typeof s=="boolean"?s:void 0)?this.enter("lost",a):(this.scheduleRetry(typeof l=="number"&&Number.isFinite(l)&&l>0?l:void 0),this.enter("degraded",a))),o instanceof b?o:new b(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)}},b=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 qe(n){if(n instanceof b)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}},U=["if-match","if-none-match"],X=4096;function $e(n){if(!n)return;let e={};for(let[t,r]of Object.entries(n)){let o=t.toLowerCase();if(!U.includes(o)||r===void 0)continue;let a=typeof r=="string"?je(r):r;if(typeof a!="string"||a.length>X||!Fe(a))throw new f(`the ${o} header value cannot be sent \u2014 it is not a string, is longer than ${X} 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 je(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 Fe(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 Be(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 Q(n,e){let t=e.replayUnauthorizedOnce??true;return {async request(r){let o={...r},a=$e(o.headers),s=Be(o),l=Object.freeze({...o,headers:a,...s===void 0?{}:{bytes:s}}),u=await e.tokenSource.get(),c=await n(l,u);if(c.status!==401||!t)return c;e.tokenSource.invalidate(u);let g=await e.tokenSource.get(),_=await n(l,g);if(_.status===401)throw e.tokenSource.close("unavailable"),new b("unavailable","the server refused a freshly minted token");return _}}}function Z(n){let e=typeof n=="string"?new TextEncoder().encode(n):n;return btoa(Ue(e))}function Ue(n){let t="";for(let r=0;r<n.length;r+=32768)t+=String.fromCharCode(...n.subarray(r,r+32768));return t}var m=class extends Error{constructor(t,r,o,a,s){super(`${t} (${r}): ${o}`);this.reason=t;this.status=r;this.detail=o;this.retryAfterSeconds=a;this.code=s;this.name="GemApiError";}reason;status;detail;retryAfterSeconds;code;get retryable(){return this.reason==="unavailable"||this.reason==="rate_limited"}},ne=new WeakMap;function te(n){return ne.get(n)??{}}var Ne=new Set([408,429,500,502,503,504]),De=6e4;function He(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 E=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,...q(o)},o.replaySafe===true,o.retryRateLimited!==false)}async post(e,t,r,o={}){return this.send({method:"POST",path:e,body:t,signal:r,...q(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,...q(o)},o.replaySafe===true,o.retryRateLimited!==false);return {bytes:Ve(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,...q(o)},o.replaySafe===true,o.retryRateLimited!==false)}async delete(e,t,r={}){return this.send({method:"DELETE",path:e,signal:t,...q(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?He(this.options.maxRetries)+1:1,a=null;if(e.signal?.aborted)throw ee(e.signal);for(let s=0;s<o;s++){if(s>0&&await this.backoff(s,a,e.signal),e.signal?.aborted)throw ee(e.signal);let l;try{l=await this.options.transport.request(e);}catch(c){if(b.isAuthError(c)||f.isRefusal(c)||e.signal?.aborted||We(c))throw c;a=new m("unavailable",0,String(c));continue}if(l.status>=200&&l.status<300||l.status===304)return l;let u=ze(l);if(!Ne.has(l.status)||l.status===429&&!r)throw u;a=u;}throw a??new m("unavailable",0,"no attempt was made")}backoff(e,t,r){if(r?.aborted)return Promise.resolve();let o=t?.retryAfterSeconds,a=o!==void 0?o*1e3:2**(e-1)*250,s=2**(e-1)*250,l=Math.min(Math.max(a,s),De);return new Promise(u=>{let c=this.options.clock,g=false,_=false,v,h=()=>{g||(g=true,_&&c.clearTimeout(v),r?.removeEventListener("abort",h),u());};r?.addEventListener("abort",h,{once:true}),v=c.setTimeout(h,l),_=true,g&&c.clearTimeout(v);})}};function Ve(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 q(n){return {...n.keepalive===void 0?{}:{keepalive:n.keepalive},...n.ifMatch===void 0?{}:{headers:{"if-match":n.ifMatch}}}}function ee(n){return n.reason!==void 0?n.reason:new DOMException("The operation was aborted.","AbortError")}function We(n){let e=n?.name;return e==="AbortError"||e==="TimeoutError"}function ze(n){let e=Ye(n),t=Xe(n.body),r={...t===void 0?{}:{details:t},...n.invocationId===void 0?{}:{invocationId:n.invocationId}};return Object.keys(r).length>0&&ne.set(e,r),e}var Ke=new Map([["insufficient_funds","insufficient_funds"]]);function Ye(n){let{status:e,body:t}=n,r=Je(t),o=n.retryAfterSeconds??Ze(t),a=Qe(t),s=a===void 0?void 0:Ke.get(a);if(s!==void 0)return new m(s,e,r,void 0,a);switch(e){case 304:return new m("not_modified",e,r);case 400:case 422:return new m("invalid",e,r,void 0,a);case 403:return new m("forbidden",e,r,void 0,a);case 404:return new m("not_found",e,r,void 0,a);case 402:return new m("insufficient_funds",e,r,void 0,a);case 409:return new m("conflict",e,r,void 0,a);case 412:return new m("precondition_failed",e,r,void 0,a);case 413:return new m("too_large",e,r,void 0,a);case 429:return new m("rate_limited",e,r,o,a);default:return new m("unavailable",e,r,o,a)}}function Je(n){if(typeof n=="string")return n;let e=n?.message;if(typeof e=="string")return e;let t=n?.error;if(typeof t=="string")return t;let r=t?.message;return typeof r=="string"?r:"no detail"}function Xe(n){let t=n?.error?.details;return t===null?void 0:t}function Qe(n){let t=n?.error?.code;return typeof t=="string"&&t.length>0?t:void 0}function Ze(n){let e=n?.retryAfterSeconds;return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:void 0}function en(n){let e=n.lastIndexOf("@");return (e===-1?n:`***@${n.slice(e+1)}`).slice(0,200)}var nn=new Set(U);function tn(n){if(!n)return {};let e={};for(let[t,r]of Object.entries(n))nn.has(t.toLowerCase())&&(e[t.toLowerCase()]=r);return e}function re(n){let e=n.fetch??globalThis.fetch.bind(globalThis);return Q(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"?en(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 h=o.username!==""||o.password!=="",y=a.username!==o.username||a.password!==o.password,S=h?y?"baseUrl (and possibly the request path)":"baseUrl":"request path";throw new f(`the ${S} 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[h,y]of Object.entries(n.defaultQuery??{}))a.searchParams.has(h)||a.searchParams.set(h,y);let s=t.bytes,l=t.bytes===void 0?void 0:"application/octet-stream";try{t.body!==void 0&&(s=JSON.stringify(t.body),l="application/json");}catch(h){throw new f(`the body of ${t.method} ${JSON.stringify(a.pathname)} could not be serialised to JSON: ${String(h)}. This is a bug in the request, not a server failure \u2014 retrying sends the same unserialisable value.`)}let u=await e(a.toString(),{method:t.method,headers:{authorization:`Bearer ${r}`,...l===void 0?{}:{"content-type":l},...tn(t.headers)},body:s,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 h=await u.text();if(h.length>0)try{c=JSON.parse(h);}catch{c=h;}}let g=u.headers.get("etag"),_=rn(u.headers.get("retry-after")),v=u.headers.get("x-gem-invocation-id");return {status:u.status,body:c,...g===null?{}:{etag:g},..._===void 0?{}:{retryAfterSeconds:_},...v===null||v===""?{}:{invocationId:v}}},n)}function rn(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 on="gem-web-bridge";var I=65536,oe=8,N=5e3,ae=1024;var D=Object.create(null);var ie=Object.create(null);function an(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 sn(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 ln(n){return /^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i.test(n)}function dn(n){return /^[a-z_]+$/.test(n)}function V(n,e,t){if(e>oe)return `nesting deeper than ${oe}`;if(++t.nodes>N)return `more than ${N} values`;if(t.bytes>I)return `over the ${I} 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>ae)return `an array of ${n.length} entries, over the ${ae} limit`;t.bytes+=2;for(let l of n){let u=V(l,e+1,t);if(u)return u}return null}let a=Object.getPrototypeOf(n);if(a!==Object.prototype&&a!==null)return "a value that is not a plain object";t.bytes+=2;let s=n;for(let l in s){if(!Object.prototype.hasOwnProperty.call(s,l))continue;if(++t.nodes>N)return `more than ${N} values`;if(t.bytes+=l.length*3+4,t.bytes>I)return `over the ${I} byte limit`;let u=V(s[l],e+1,t);if(u)return u}return null}function un(n){let e={nodes:0,bytes:0,seen:new Set},t=V(n,0,e);return t?`message contains ${t}`:e.bytes>I?`message is over the ${I} byte limit`:null}var cn={origin:[an,"not a well-formed origin"],url:[sn,"not a safe absolute http(s) URL"],bcp47:[ln,"not a well-formed BCP 47 tag"],code:[dn,"not a code of lower-case letters and underscores"]};function se(n,e,t){for(let r of e){let o=t===""?r.n:`${t}.${r.n}`,a=n[r.n];if(a==null){if(r.o)continue;return `${o}: required`}let s=W(a,r,o);if(s)return s}return null}function W(n,e,t){switch(e.k){case "u":return typeof n=="boolean"?null:W(n,{...e,k:typeof n=="string"?"s":"n"},t);case "s":{if(typeof n!="string")return `${t}: expected string`;if(n.length>e.max)return `${t}: exceeds ${e.max} characters`;if(e.f){let[r,o]=cn[e.f];if(!r(n))return `${t}: ${o}`}return null}case "n":case "i":return typeof n!="number"||!(e.k=="i"?Number.isInteger:Number.isFinite)(n)?`${t}: expected ${e.k=="i"?"integer":"number"}`:n<e.lo||n>e.hi?`${t}: out of range ${e.lo}..${e.hi}`:null;case "b":return typeof n=="boolean"?null:`${t}: expected boolean`;case "e":{let r=e.v;return r.includes(n)?null:`${t}: not one of ${r.join("|")}`}case "o":return typeof n!="object"||n===null||Array.isArray(n)?`${t}: expected object`:se(n,e.fs,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.max)return `${t}: exceeds ${e.max} items`;let r=e.it,o=`${t}[]`;for(let a of n){if(a==null){if(r.o)continue;return `${o}: required`}let s=W(a,r,o);if(s)return s}return null}default:{let r=e.k;return `${t}: unknown kind ${String(r)}`}}}var le=Object.create(null);function d(n,e,t,r){return D[n]=t,r&&(ie[n]=r),le[n]=o=>{let a=un(o);if(a)return a;if(typeof o!="object"||o===null||Array.isArray(o))return "message: expected object";let s=o;return s.gem!==on?"gem: wrong protocol marker":s.type!==n?`type: expected ${n}`:se(s,e,"")}}var p={n:"requestId",k:"s",max:64};d("gem.handshake",[{n:"versions",k:"o",fs:[{n:"min",k:"i",lo:1,hi:1e3},{n:"max",k:"i",lo:1,hi:1e3}]},{n:"capabilities",k:"a",o:1,max:64,it:{n:"",k:"s",max:64}},{n:"embedder",k:"s",max:2048,f:"origin"},{n:"unbidden",k:"b",o:1}],30);d("gem.handshake.accept",[{n:"v",k:"i",lo:1,hi:1e3},{n:"capabilities",k:"a",o:1,max:64,it:{n:"",k:"s",max:64}}],5);d("gem.token",[{n:"token",k:"s",max:4096},{n:"requestId",k:"s",o:1,max:64},{n:"generation",k:"i",lo:0,hi:2147483647},{n:"apiBaseUrl",k:"s",o:1,max:512,f:"url"},{n:"playerId",k:"s",max:64},{n:"gameId",k:"s",max:64},{n:"channel",k:"e",v:["dev","test","release"]},{n:"gameVersion",k:"s",o:1,max:64},{n:"expiresAt",k:"i",lo:0,hi:4102444800},{n:"chainEndsAt",k:"i",lo:0,hi:4102444800},{n:"allowDevTools",k:"b",o:1}],30);d("gem.token.denied",[p,{n:"retryable",k:"b"},{n:"retryAfterMs",k:"i",o:1,lo:0,hi:36e5},{n:"reason",k:"e",v:["chain_exhausted","unavailable"]},{n:"correlationId",k:"s",max:64}],30);d("gem.player",[{n:"untrusted",k:"o",fs:[{n:"displayName",k:"s",max:64},{n:"displayTag",k:"s",o:1,max:80},{n:"displayHandle",k:"s",max:80}]},{n:"playerId",k:"s",o:1,max:64},{n:"discriminator",k:"s",o:1,max:8},{n:"avatarIconUrl",k:"s",o:1,max:2048,f:"url"},{n:"avatarIconId",k:"s",o:1,max:64},{n:"avatar3dId",k:"s",o:1,max:64},{n:"avatar3dModelUrl",k:"s",o:1,max:2048,f:"url"},{n:"avatar3dIconUrl",k:"s",o:1,max:2048,f:"url"},{n:"avatars3d",k:"a",o:1,max:8,it:{n:"",k:"o",fs:[{n:"family",k:"s",max:32},{n:"id",k:"s",max:64},{n:"modelUrl",k:"s",max:256,f:"url"},{n:"iconUrl",k:"s",max:256,f:"url"}]}},{n:"badges",k:"a",o:1,max:2,it:{n:"",k:"o",fs:[{n:"itemId",k:"s",max:64},{n:"iconUrl",k:"s",max:2048,f:"url"}]}},{n:"displayTag",k:"s",max:8},{n:"avatarUrl",k:"s",o:1,max:2048,f:"url"},{n:"boost",k:"o",o:1,fs:[{n:"multipliers",k:"a",max:8,it:{n:"",k:"o",fs:[{n:"currencyId",k:"s",max:64},{n:"currencySlug",k:"s",max:32},{n:"multiplierBp",k:"i",lo:1e4,hi:1e6}]}},{n:"expiresInDays",k:"i",o:1,lo:1,hi:7}]}],12);d("gem.pause",[{n:"paused",k:"b"}],120);d("gem.prefs",[{n:"reducedMotion",k:"b"},{n:"muted",k:"b"},{n:"showFrameStats",k:"b",o:1},{n:"locale",k:"s",max:35,f:"bcp47"},{n:"recommended",k:"o",o:1,fs:[{n:"volume",k:"i",lo:0,hi:100},{n:"batterySaver",k:"b"},{n:"keyboardLayout",k:"e",v:["wasd","arrows"]},{n:"gamepadConfirm",k:"e",v:["south","east"]},{n:"vibration",k:"b"},{n:"lookSensitivity",k:"i",o:1,lo:20,hi:400},{n:"gamepadLookSensitivity",k:"i",o:1,lo:20,hi:400},{n:"invertLookY",k:"b",o:1},{n:"touchMovement",k:"s",o:1,max:16,f:"code"},{n:"graphicsQuality",k:"s",o:1,max:16,f:"code"},{n:"graphicsQualityAuto",k:"b",o:1}]}],60);d("gem.cohorts",[{n:"cohorts",k:"a",max:8,it:{n:"",k:"o",fs:[{n:"experimentId",k:"s",max:36},{n:"variantKey",k:"s",max:32}]}}],12,"cohorts");d("gem.earnAllowanceChanged",[],30,"earnAllowance");d("gem.viewport",[{n:"insets",k:"o",fs:[{n:"top",k:"i",lo:0,hi:4096},{n:"right",k:"i",lo:0,hi:4096},{n:"bottom",k:"i",lo:0,hi:4096},{n:"left",k:"i",lo:0,hi:4096}]},{n:"reserved",k:"a",o:1,max:4,it:{n:"",k:"o",fs:[{n:"x",k:"i",lo:0,hi:16384},{n:"y",k:"i",lo:0,hi:16384},{n:"width",k:"i",lo:0,hi:16384},{n:"height",k:"i",lo:0,hi:16384},{n:"control",k:"o",o:1,fs:[{n:"x",k:"i",lo:0,hi:16384},{n:"y",k:"i",lo:0,hi:16384},{n:"width",k:"i",lo:0,hi:16384},{n:"height",k:"i",lo:0,hi:16384}]}]}}],60,"viewport");d("gem.deviceSettings",[{n:"settings",k:"j",o:1}],12,"deviceSettings");d("gem.willTerminate",[{n:"reason",k:"e",v:["grant_expiring","session_ended","navigating","kill_switch"]},{n:"graceMs",k:"i",lo:0,hi:6e4}],10);d("gem.roomEvent",[{n:"event",k:"e",v:["updated","match_started","match_ready","match_failed","version_stale"]},{n:"roomId",k:"s",max:64},{n:"matchId",k:"s",o:1,max:64},{n:"version",k:"i",o:1,lo:0,hi:2147483647},{n:"reason",k:"s",o:1,max:64},{n:"platform",k:"e",o:1,v:["universal","mobile"]}],120,"rooms");d("gem.socketState",[{n:"connected",k:"b"},{n:"reason",k:"e",o:1,v:["connecting","dropped","watchdog","terminal"]}],12,"socketState");d("gem.seatedEvent",[{n:"roomId",k:"s",max:64}],60,"partySeating");d("gem.autoStartFailedEvent",[{n:"roomId",k:"s",max:64},{n:"code",k:"s",max:64}],30,"autoStartFailure");d("gem.ticketEvent",[{n:"event",k:"e",v:["queued","matched","expired","cancelled","failed"]},{n:"ticketId",k:"s",max:64},{n:"partySize",k:"i",o:1,lo:1,hi:64},{n:"queuedAt",k:"i",o:1,lo:0,hi:4102444800},{n:"expiresAt",k:"i",o:1,lo:0,hi:4102444800},{n:"reason",k:"s",o:1,max:64},{n:"roomId",k:"s",o:1,max:64}],60,"ticketEvents");d("gem.signalEvent",[{n:"event",k:"e",v:["hello","offer","answer","ice","peerJoined","peerLeft","migration","matchEnded","error"]},{n:"matchId",k:"s",max:64},{n:"data",k:"j"}],1800,"p2p");d("gem.dedicatedEvent",[{n:"event",k:"e",v:["answer","error","matchEnded"]},{n:"matchId",k:"s",max:64},{n:"sdp",k:"s",o:1,max:10240},{n:"sessionId",k:"s",o:1,max:64},{n:"code",k:"s",o:1,max:64},{n:"message",k:"s",o:1,max:256},{n:"reason",k:"s",o:1,max:64}],120,"dedicated");d("gem.partyResult",[p,{n:"partyId",k:"s",o:1,max:64}],30,"parties");d("gem.clusterTarget",[{n:"clusterTargetId",k:"s",max:64},{n:"clusterTargetIds",k:"a",o:1,max:3,it:{n:"",k:"s",max:64}}],12,"clusterTarget");d("gem.devtools",[{n:"action",k:"e",v:["open","close","toggle"]}],30,"devtools");d("gem.screenshot",[{n:"maxWidth",k:"i",lo:1,hi:7680},{n:"maxHeight",k:"i",lo:1,hi:4320}],6,"screenshot");d("gem.screenshot.denied",[{n:"reason",k:"e",v:["not_wired","no_source","unsupported","unreadable","tainted","too_large","busy","declined","failed"]},{n:"retryable",k:"b"}],12,"screenshot");d("gem.requestContext",[],12,"feedbackContext");d("gem.gameContext",[{n:"context",k:"j"}],12,"feedbackContext");d("gem.signal",[{n:"signal",k:"e",v:["join","offer","answer","ice","migrationAck","hostUnreachable"]},{n:"matchId",k:"s",max:64},{n:"data",k:"j"}],1200,"p2p");d("gem.dedicatedOffer",[{n:"matchId",k:"s",max:64},{n:"sdp",k:"s",max:10240},{n:"intent",k:"e",v:["initial","ice_restart","full_reconnect"]}],60,"dedicated");d("gem.partyRequest",[p],12,"parties");d("gem.ready",[],5);d("gem.engaged",[],5,"engagement");d("gem.progress",[{n:"loaded",k:"i",lo:0,hi:1099511627776},{n:"total",k:"i",lo:0,hi:1099511627776}],600);d("gem.requestToken",[p,{n:"reason",k:"e",v:["initial","expiring","rejected"]}],12);d("gem.requestLocalServer",[p,{n:"gameRoomId",k:"s",max:64}],6,"localHost");d("gem.localServer",[p,{n:"serverId",k:"s",o:1,max:128}],30,"localHost");d("gem.localServer.denied",[p,{n:"retryable",k:"b"},{n:"reason",k:"e",v:["refused","unavailable"]}],30,"localHost");d("gem.exit",[{n:"reason",k:"s",o:1,max:64}],5);d("gem.openExternal",[{n:"url",k:"s",max:2048,f:"url"}],6);d("gem.requestFullscreen",[{n:"enabled",k:"b"}],30);d("gem.audioState",[{n:"muted",k:"b"}],120,"audioState");d("gem.rewardCue",[{n:"currencySlug",k:"s",max:32},{n:"expected",k:"i",o:1,lo:1,hi:1e9},{n:"origin",k:"o",o:1,fs:[{n:"x",k:"i",lo:0,hi:16384},{n:"y",k:"i",lo:0,hi:16384}]}],60,"rewardCue");d("gem.walletDisplay",[{n:"visible",k:"b"},{n:"currencies",k:"a",o:1,max:8,it:{n:"",k:"s",max:64}},{n:"score",k:"b",o:1}],60,"walletDisplay");d("gem.controlsDeclare",[{n:"uses",k:"o",fs:[{n:"lookSensitivity",k:"s",o:1,max:16,f:"code"},{n:"gamepadLookSensitivity",k:"s",o:1,max:16,f:"code"},{n:"invertLookY",k:"s",o:1,max:16,f:"code"},{n:"touchMovement",k:"s",o:1,max:16,f:"code"}]}],60,"controls");d("gem.menu",[{n:"settings",k:"b"},{n:"items",k:"a",o:1,max:4,it:{n:"",k:"o",fs:[{n:"id",k:"s",max:32},{n:"label",k:"s",max:40}]}}],60,"gameMenu");d("gem.menuSelect",[{n:"entry",k:"e",v:["settings","item"]},{n:"id",k:"s",o:1,max:32}],60,"gameMenu");d("gem.gemCorner",[{n:"corner",k:"e",v:["top-left","top-right","bottom-left","bottom-right"]}],12,"gemCorner");d("gem.settingsDeclare",[{n:"settings",k:"a",max:8,it:{n:"",k:"o",fs:[{n:"id",k:"s",max:40},{n:"label",k:"s",max:40},{n:"kind",k:"e",v:["toggle","slider","choice"]},{n:"value",k:"u",max:40,lo:-1e6,hi:1e6},{n:"quick",k:"b",o:1},{n:"icon",k:"s",o:1,max:16,f:"code"},{n:"min",k:"n",o:1,lo:-1e6,hi:1e6},{n:"max",k:"n",o:1,lo:-1e6,hi:1e6},{n:"step",k:"n",o:1,lo:0,hi:1e6},{n:"options",k:"a",o:1,max:4,it:{n:"",k:"o",fs:[{n:"id",k:"s",max:40},{n:"label",k:"s",max:40}]}}]}}],120,"gameSettings");d("gem.settingChange",[{n:"id",k:"s",max:40},{n:"value",k:"u",max:40,lo:-1e6,hi:1e6}],120,"gameSettings");d("gem.requestShare",[{n:"params",k:"a",max:16,it:{n:"",k:"o",fs:[{n:"key",k:"s",max:64},{n:"value",k:"s",max:512}]}}],6,"share");d("gem.requestAvatarPicker",[{n:"tab",k:"e",o:1,v:["2d","3d"]}],6,"avatarPicker");d("gem.vibrate",[{n:"pattern",k:"a",max:99,it:{n:"",k:"i",lo:0,hi:1e4}}],600,"vibration");d("gem.frameStats",[{n:"fps",k:"i",lo:0,hi:1e3},{n:"frameTimeP95Ms",k:"i",lo:0,hi:1e5},{n:"counts",k:"e",o:1,v:["pageFrames","gameDraws"]}],120,"frameStats");d("gem.portraitBorders",[{n:"name",k:"s",o:1,max:40}],60,"portraitBorders");d("gem.error",[{n:"code",k:"e",v:["version_mismatch","handshake_timeout","handshake_duplicate","invalid_message","rate_limited","token_unavailable","unsupported","unsupported_capability","internal"]},{n:"message",k:"s",o:1,max:256}],60);d("gem.requestPurchase",[p,{n:"purchaseKind",k:"e",v:["item","recipe"]},{n:"targetId",k:"s",max:64},{n:"currencySlug",k:"s",max:32},{n:"quantity",k:"i",o:1,lo:1,hi:10},{n:"catalogId",k:"s",o:1,max:64}],12,"purchases");d("gem.requestAvatar3dPurchase",[p,{n:"itemId",k:"s",max:64},{n:"currencySlug",k:"s",max:32}],12,"avatar3dPurchases");d("gem.purchaseResult",[p,{n:"outcome",k:"e",v:["ok","declined","unavailable"]},{n:"reason",k:"s",o:1,max:64,f:"code"},{n:"purchaseId",k:"s",o:1,max:64}],30,"purchases");d("gem.deviceSettings.put",[p,{n:"settings",k:"j"}],30,"deviceSettings");d("gem.deviceSettings.result",[p,{n:"outcome",k:"e",v:["stored","too_large","unavailable"]}],30,"deviceSettings");d("gem.requestAd",[p,{n:"placement",k:"s",max:32},{n:"format",k:"e",v:["interstitial","rewarded"]}],6,"ads");d("gem.adResult",[p,{n:"outcome",k:"e",v:["shown","no_ad","unavailable"]}],12,"ads");d("gem.signalMoment",[p,{n:"kind",k:"e",v:["level_end","run_end","match_end","menu_return","other_break"]},{n:"placement",k:"s",o:1,max:32}],6,"moments");d("gem.momentResult",[p,{n:"shown",k:"b"}],12,"moments");d("gem.requestSignIn",[p],6,"signIn");d("gem.signInResult",[p,{n:"outcome",k:"e",v:["signed_in","declined","unavailable"]}],12,"signIn");d("gem.requestFriendChallenge",[p,{n:"playerId",k:"s",max:64},{n:"template",k:"s",max:64},{n:"params",k:"j",o:1}],12,"friendChallenges");d("gem.friendChallengeResult",[p,{n:"outcome",k:"e",v:["accepted","cancelled","refused","unavailable","rate_limited","invalid"]},{n:"code",k:"s",o:1,max:64},{n:"param",k:"s",o:1,max:64},{n:"channel",k:"s",o:1,max:16},{n:"configVersion",k:"i",o:1,lo:0,hi:9007199254740991},{n:"retryAfterMs",k:"i",o:1,lo:0,hi:864e5},{n:"detail",k:"s",o:1,max:300}],30,"friendChallenges");Object.freeze(le);D.__malformed=60;Object.freeze(D);Object.freeze(ie);var M={now:()=>Date.now(),setTimeout:(n,e)=>setTimeout(n,e),clearTimeout:n=>clearTimeout(n)};function de(n){let e=n.toLowerCase();return e==="localhost"||e.endsWith(".localhost")||e==="[::1]"||e==="::1"?true:/^127(\.\d{1,3}){3}$/.test(e)}var mn=1e4;function ue(n,e){return z(n,e)}function z(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=s=>({token:s.token,expiresAt:s.expiresAt,chainEndsAt:Number.POSITIVE_INFINITY}),r=null,o=new B({clock:e.clock,...e.onStateChange===void 0?{}:{onStateChange:e.onStateChange},request:()=>new Promise((s,l)=>{let u=e.clock.setTimeout(()=>{r=null,l({reason:"unavailable",retryable:true});},e.timeoutMs??mn);r={resolve:c=>{e.clock.clearTimeout(u),s(c);},reject:l,timer:u};})}),a=n.onServerToken(s=>{let l=t(s),u=r;if(u){r=null,u.resolve(l);return}o.accept(l);});return {source:o,dispose(){a(),o.dispose(),r&&(e.clock.clearTimeout(r.timer),r.reject({reason:"unavailable",retryable:false}),r=null);}}}var Y={};Ie(Y,{acceptTransfer:()=>gn,addEntityProgression:()=>pn,adminAction:()=>yn,cancelInventoryTransfer:()=>fn,claimEntityProgressionRewards:()=>hn,closeGameRoom:()=>_n,createEntityBatchOrder:()=>bn,createEntityOrder:()=>vn,createSession:()=>Rn,deleteEntityGameSetting:()=>xn,deleteEntitySave:()=>kn,deleteSession:()=>Sn,deleteShowcaseValue:()=>wn,executeEntityRecipe:()=>An,finalizeSaveUpload:()=>Pn,getChannelAssignment:()=>On,getDropRates:()=>Tn,getEntityCurrency:()=>Gn,getEntityGameSetting:()=>Cn,getEntityInventory:()=>En,getEntityInventoryItem:()=>In,getEntityLeaderboard:()=>Mn,getEntityOrder:()=>Ln,getEntityProgression:()=>qn,getEntityRecipeAvailability:()=>$n,getEntityRecipeUsage:()=>jn,getEntitySave:()=>Fn,getEvent:()=>Bn,getGameRoomV2:()=>Un,getLeaderboard:()=>Nn,getPlayerGameProfile:()=>Dn,getPurchaseCatalog:()=>Hn,getResolvedTemplate:()=>Vn,getRoomArgs:()=>Wn,getShowcaseValue:()=>zn,getTransferDetails:()=>Kn,ingestAnalyticsEvents:()=>K,initiateInventoryTransfer:()=>Yn,invokeFunction:()=>Jn,kickPlayer:()=>Xn,listChallenges:()=>Qn,listEntityGameSettings:()=>Zn,listEntityOrders:()=>et,listEntityProgressions:()=>nt,listEntitySaves:()=>tt,listEvents:()=>rt,listGameRooms:()=>ot,listResolvedTemplates:()=>at,listTransfers:()=>it,maxEntityProgression:()=>st,putEntityGameSetting:()=>lt,putRoomArgs:()=>dt,putShowcaseValue:()=>ut,rejectTransfer:()=>ct,reportMatchPlayers:()=>mt,requestSaveUploadUrl:()=>gt,resetEntityProgression:()=>pt,setMatchBackfill:()=>yt,simulateEntityOrder:()=>ft,transferHostV2:()=>ht,updateGameRoomV2:()=>_t});function i(n){let e=String(n);if(!/^[A-Za-z0-9_.-]{1,128}$/.test(e)||e==="."||e==="..")throw new TypeError(`${JSON.stringify(e)} is not a usable path segment \u2014 it is interpolated into a URL`);return encodeURIComponent(e)}async function gn(n,e,t){let r=`/v1/inventory/transfers/${i(e)}/accept`;return n.client.post(r,void 0,t?.signal)}async function pn(n,e,t,r,o,a){let s=`/v1/inventory/${i(e)}/${i(t)}/progressions/${i(r)}/add`;return n.client.post(s,o,a?.signal)}async function yn(n,e,t,r){let o=`/v1/voice/sessions/${i(e)}/admin`;return n.client.post(o,t,r?.signal)}async function fn(n,e,t){let r=`/v1/inventory/transfers/${i(e)}/cancel`;return n.client.post(r,void 0,t?.signal)}async function hn(n,e,t,r,o,a){let s=`/v1/inventory/${i(e)}/${i(t)}/progressions/${i(r)}/claim`;return n.client.post(s,o,a?.signal)}async function _n(n,e,t){let r=`/v1/games/${i(n.gameId())}/game-rooms/${i(e)}`;return n.client.delete(r,t?.signal)}async function bn(n,e,t,r,o){let a=`/v1/inventory/${i(e)}/${i(t)}/orders/batch`;return n.client.post(a,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function vn(n,e,t,r,o){let a=`/v1/inventory/${i(e)}/${i(t)}/orders`;return n.client.post(a,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function Rn(n,e,t){return n.client.post("/v1/voice/sessions",e,t?.signal)}async function xn(n,e,t,r,o){let a=`/v1/settings/${i(e)}/${i(t)}/${i(r)}`;return n.client.delete(a,o?.signal)}async function kn(n,e,t,r,o){let a=`/v1/saves/${i(e)}/${i(t)}/${i(r)}`;return n.client.delete(a,o?.signal)}async function Sn(n,e,t){let r=`/v1/voice/sessions/${i(e)}`;return n.client.delete(r,t?.signal)}async function wn(n,e,t,r){let o=`/v1/showcase/players/${i(e)}/${i(t)}`;return n.client.delete(o,r?.signal)}async function An(n,e,t,r,o){let a=`/v1/inventory/${i(e)}/${i(t)}/recipes/execute`;return n.client.post(a,r,o?.signal,{...o?.ifMatch===void 0?{}:{ifMatch:o.ifMatch}})}async function Pn(n,e,t,r,o,a){let s=`/v1/saves/${i(e)}/${i(t)}/${i(r)}/finalize`;return n.client.post(s,o,a?.signal)}async function On(n,e,t){let r=`/v1/games/${i(n.gameId())}/config/channels/${i(e)}`;return n.client.getWithEtag(r,{...t?.signal===void 0?{}:{signal:t.signal},...t?.ifNoneMatch===void 0?{}:{ifNoneMatch:t.ifNoneMatch}})}async function Tn(n,e,t){let r=`/v1/inventory/loot-tables/${i(e)}/drop-rates`;return n.client.get(r,t?.signal)}async function Gn(n,e,t,r,o){let a=`/v1/inventory/${i(e)}/${i(t)}/currencies/${i(r)}`;return n.client.get(a,o?.signal)}async function Cn(n,e,t,r,o){let a=`/v1/settings/${i(e)}/${i(t)}/${i(r)}`;return n.client.getWithEtag(a,{...o?.signal===void 0?{}:{signal:o.signal},...o?.ifNoneMatch===void 0?{}:{ifNoneMatch:o.ifNoneMatch}})}async function En(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(),s=`/v1/inventory/${i(e)}/${i(t)}`+(a?`?${a}`:"");return n.client.get(s,r?.signal)}async function In(n,e,t,r,o){let a=`/v1/inventory/${i(e)}/${i(t)}/items/${i(r)}`;return n.client.get(a,o?.signal)}async function Mn(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 s=a.toString(),l=`/v1/leaderboards/${i(e)}/${i(t)}/${i(r)}`+(s?`?${s}`:"");return n.client.get(l,o?.signal)}async function Ln(n,e,t,r,o){let a=`/v1/inventory/${i(e)}/${i(t)}/orders/${i(r)}`;return n.client.get(a,o?.signal)}async function qn(n,e,t,r,o){let a=`/v1/inventory/${i(e)}/${i(t)}/progressions/${i(r)}`;return n.client.get(a,o?.signal)}async function $n(n,e,t,r,o,a){let s=`/v1/inventory/${i(e)}/${i(t)}/catalogs/${i(r)}/recipes/${i(o)}/availability`;return n.client.get(s,a?.signal)}async function jn(n,e,t,r){let o=new URLSearchParams;r?.limit!==void 0&&o.set("limit",String(r?.limit));let a=o.toString(),s=`/v1/inventory/${i(e)}/${i(t)}/recipe-usage`+(a?`?${a}`:"");return n.client.get(s,r?.signal)}async function Fn(n,e,t,r,o){let a=`/v1/saves/${i(e)}/${i(t)}/${i(r)}`;return n.client.getWithEtag(a,{...o?.signal===void 0?{}:{signal:o.signal},...o?.ifNoneMatch===void 0?{}:{ifNoneMatch:o.ifNoneMatch}})}async function Bn(n,e,t){let r=`/v1/events/${i(e)}`;return n.client.get(r,t?.signal)}async function Un(n,e,t){let r=`/v2/games/${i(n.gameId())}/game-rooms/${i(e)}`;return n.client.getWithEtag(r,{...t?.signal===void 0?{}:{signal:t.signal},...t?.ifNoneMatch===void 0?{}:{ifNoneMatch:t.ifNoneMatch}})}async function Nn(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/${i(e)}`+(o?`?${o}`:"");return n.client.get(a,t?.signal)}async function Dn(n,e,t){let r=`/v1/profiles/players/${i(e)}`;return n.client.get(r,t?.signal)}async function Hn(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 Vn(n,e,t){let r=`/v1/game-room-templates/${i(e)}`;return n.client.get(r,t?.signal)}async function Wn(n,e,t){let r=`/v1/games/${i(n.gameId())}/game-rooms/${i(e)}/room-args`;return n.client.get(r,t?.signal)}async function zn(n,e,t,r){let o=`/v1/showcase/players/${i(e)}/${i(t)}`;return n.client.get(o,r?.signal)}async function Kn(n,e,t){let r=`/v1/inventory/transfers/${i(e)}`;return n.client.get(r,t?.signal)}async function K(n,e,t){let r=`/v1/games/${i(n.gameId())}/analytics/events`;return n.client.post(r,e,t?.signal,{replaySafe:true,retryRateLimited:false})}async function Yn(n,e,t){return n.client.post("/v1/inventory/transfers",e,t?.signal)}async function Jn(n,e,t){return n.client.postBytes("/v1/functions/invoke",e,t?.signal)}async function Xn(n,e,t,r){let o=`/v1/games/${i(n.gameId())}/game-rooms/${i(e)}/kick/${i(t)}`;return n.client.post(o,void 0,r?.signal)}async function Qn(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 Zn(n,e,t,r){let o=`/v1/settings/${i(e)}/${i(t)}`;return n.client.get(o,r?.signal)}async function et(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(),s=`/v1/inventory/${i(e)}/${i(t)}/orders`+(a?`?${a}`:"");return n.client.get(s,r?.signal)}async function nt(n,e,t,r){let o=`/v1/inventory/${i(e)}/${i(t)}/progressions`;return n.client.get(o,r?.signal)}async function tt(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(),s=`/v1/saves/${i(e)}/${i(t)}`+(a?`?${a}`:"");return n.client.get(s,r?.signal)}async function rt(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 ot(n,e){let t=new URLSearchParams;e?.status!==void 0&&t.set("status",String(e?.status)),e?.game_channel!==void 0&&t.set("game_channel",String(e?.game_channel)),e?.game_room_type!==void 0&&t.set("game_room_type",String(e?.game_room_type)),e?.template_id!==void 0&&t.set("template_id",String(e?.template_id)),e?.template_slug!==void 0&&t.set("template_slug",String(e?.template_slug)),e?.limit!==void 0&&t.set("limit",String(e?.limit)),e?.cursor!==void 0&&t.set("cursor",String(e?.cursor));let r=t.toString(),o=`/v1/games/${i(n.gameId())}/game-rooms`+(r?`?${r}`:"");return n.client.get(o,e?.signal)}async function at(n,e){return n.client.get("/v1/game-room-templates",e?.signal)}async function it(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 st(n,e,t,r,o,a){let s=`/v1/inventory/${i(e)}/${i(t)}/progressions/${i(r)}/max`;return n.client.post(s,o,a?.signal)}async function lt(n,e,t,r,o,a){let s=`/v1/settings/${i(e)}/${i(t)}/${i(r)}`;return n.client.put(s,o,a?.signal,{...a?.ifMatch===void 0?{}:{ifMatch:a.ifMatch}})}async function dt(n,e,t,r){let o=`/v1/games/${i(n.gameId())}/game-rooms/${i(e)}/room-args`;return n.client.put(o,t,r?.signal)}async function ut(n,e,t,r,o){let a=`/v1/showcase/players/${i(e)}/${i(t)}`;return n.client.put(a,r,o?.signal)}async function ct(n,e,t){let r=`/v1/inventory/transfers/${i(e)}/reject`;return n.client.post(r,void 0,t?.signal)}async function mt(n,e,t,r){let o=`/v1/games/${i(n.gameId())}/matches/${i(e)}/players/report`;return n.client.post(o,t,r?.signal)}async function gt(n,e,t,r,o,a){let s=`/v1/saves/${i(e)}/${i(t)}/${i(r)}/upload-url`;return n.client.post(s,o,a?.signal,{replaySafe:true})}async function pt(n,e,t,r,o,a){let s=`/v1/inventory/${i(e)}/${i(t)}/progressions/${i(r)}/reset`;return n.client.post(s,o,a?.signal)}async function yt(n,e,t,r){let o=`/v1/games/${i(n.gameId())}/matches/${i(e)}/backfill`;return n.client.put(o,t,r?.signal)}async function ft(n,e,t,r,o){let a=`/v1/inventory/${i(e)}/${i(t)}/orders/simulate`;return n.client.post(a,r,o?.signal)}async function ht(n,e,t,r){let o=`/v2/games/${i(n.gameId())}/game-rooms/${i(e)}/transfer/${i(t)}`;return n.client.post(o,void 0,r?.signal)}async function _t(n,e,t,r){let o=`/v2/games/${i(n.gameId())}/game-rooms/${i(e)}`;return n.client.patch(o,t,r?.signal,{...r?.ifMatch===void 0?{}:{ifMatch:r.ifMatch}})}var ce="gem_";function me(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 Rt=1e4,xt=50,kt=1e3,St=65536-4*1024,ge=n=>typeof n=="number"?n:0,wt=n=>typeof n=="string"?n:"";function pe(){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 At(n){return n?.retryable===true}function Pt(n,e){let t=n??{},r=Array.isArray(t.rejected)?t.rejected.map(o=>{let a=o??{};return {index:ge(a.index),code:wt(a.code)}}):[];return {accepted:ge(t.accepted),rejected:r,dropped:e,duplicate:t.duplicate===true}}function ye(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 fe(n){let e=Math.max(1,Math.floor(n.maxQueue??kt)),t={client:n.client,gameId:()=>n.gameId},r=[],o=0,a=null,s=false,l=null,u=0,c=0,g=false,_=false,v=R=>{n.log?.(R);},h=()=>{a!==null&&(n.clock.clearTimeout(a),a=null);},y=()=>Math.max(0,c-n.clock.now()),S=()=>{a!==null||s||l!==null||(a=n.clock.setTimeout(()=>{a=null,O().catch(()=>{});},Math.max(Rt,y())));},A=()=>{let R=Math.min(r.length,100),x=128;for(let T=0;T<R;T+=1){let G=r[T];if(G===void 0)break;if(x+=JSON.stringify(ye(G,0)).length+1,x>St)return Math.max(1,T)}return R};async function O(R){for(;l!==null;)await l.catch(()=>{});if(r.length===0)return {accepted:0,rejected:[],dropped:0,duplicate:false};let x=Ge(R);l=x;try{return await x}finally{l===x&&(l=null),r.length>0&&S();}}async function Ge(R){h();let x=r.splice(0,A()),T=o;o=0;let G=Math.round(n.clock.now()),F={batch_id:pe(),sent_at_ms:G,events:x.map(w=>ye(w,G))};try{let w=await K(t,F,R===void 0?void 0:{signal:R}),C=Pt(w,T);u=0,c=0;for(let Ce of C.rejected)v(`[gem] analytics: an event was refused (${Ce.code}). See the analytics_events section of your game config.`);return C}catch(w){if(At(w)){for(r=[...x,...r],o+=T;r.length>e;)r.shift(),o+=1;u+=1,c=n.clock.now()+me(u,w);}else v(`[gem] analytics: ${x.length} event(s) were discarded \u2014 the platform refused the batch and will refuse it again: ${String(w)}`);throw w}}return {track(R,x,T={}){if(s)return;if(typeof R!="string"||R===""){_||(_=true,v(`[gem] analytics: '${x}' 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(x.startsWith(ce)){g||(g=true,v(`[gem] analytics: '${x}' 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 G={},F={};for(let[w,C]of Object.entries(T))typeof C=="string"?G[w]=C:typeof C=="number"&&Number.isFinite(C)&&(F[w]=C);for(;r.length>=e;)r.shift(),o+=1;r.push({uid:pe(),playerId:R,name:x,atMs:n.clock.now(),dimensions:G,measures:F}),r.length>=xt&&l===null&&y()===0?O().catch(()=>{}):S();},flush:R=>O(R),get pending(){return r.length},dispose(){s=true,h(),r=[],o=0;}}}var Ot=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]]),$=class extends m{constructor(e,t){super(e.reason,e.status,e.detail,e.retryAfterSeconds,e.code),this.name="GemFunctionError",Object.assign(this,t);}get retryable(){return (this.code===void 0?void 0:Ot.get(this.code))??super.retryable}},L=class{#e;constructor(e){this.#e=e;}async invoke(e,t={}){let r=Tt(e),o;try{o=await this.#e(r,t.signal===void 0?{}:{signal:t.signal});}catch(a){throw a instanceof m?Ct(a):a}return Gt(o)}};function Tt(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 Gt(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 Ct(n){let{details:e,invocationId:t}=te(n),o=e?.untrusted?.message,a=e?.reason;return new $(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 P=n=>typeof n=="string"?n:"",Et=/(?:Z|[+-]\d{2}:?\d{2})$/i;function he(n){let e=P(n);if(!Et.test(e))return 0;let t=Date.parse(e);return Number.isFinite(t)?Math.floor(t/1e3):0}var It=/^[0-9a-f]{1,64}$/,Mt=/^[0-9a-f]{16}$/,Lt=/^[A-Za-z][A-Za-z0-9_+\-/]{0,63}$/,qt=/^(?:[01]\d|2[0-3]):[0-5]\d$/;function $t(n){let e=P(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])],s=new Date(Date.UTC(r,o-1,a));return s.getUTCFullYear()===r&&s.getUTCMonth()===o-1&&s.getUTCDate()===a?e:void 0}var jt=4096,Ft=new TextEncoder;function Bt(n){let e=P(n.challenge_data),t=P(n.challenge_data_hash);return e===""||!Mt.test(t)?{}:Ft.encode(e).length>jt?{}:{data:e,dataHash:t}}function Ut(n){let e=n??{},t=he(e.period_start_at),r=he(e.period_ends_at);if(t===0||r===0)return;let o=P(e.slug),a=P(e.seed),s=$t(e.period_local_date),l=P(e.boundary),u=P(e.reset_time);return {id:P(e.progression_definition_id),...o===""?{}:{slug:o},window:P(e.window),periodStartAt:t,periodEndsAt:r,...s===void 0?{}:{periodLocalDate:s},boundary:Lt.test(l)?l:"",resetTime:qt.test(u)?u:"",seed:It.test(a)?a:"",...Bt(e)}}function _e(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 be(n){let e=n??{};return Array.isArray(e.challenges)?e.challenges.map(Ut).filter(t=>t!==void 0):[]}function ve(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().");_e(r);let a=await n({player_id:t,...r===void 0?{}:{periods_back:r},...o===void 0?{}:{signal:o}});return be(a)}}}function Nt(n){let e={};for(let[t,r]of Object.entries(Y))if(typeof r=="function"){let o=r;e[t]=(...a)=>o(n,...a);}return e}function H(n,e={}){let t=e.clock??M,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=z(n,{clock:t,...e.onAuthStateChange===void 0?{}:{onStateChange:e.onAuthStateChange}}),a=re({baseUrl:r,tokenSource:o.source,defaultQuery:{game_id:n.gameId,channel:n.channel},...e.fetch===void 0?{}:{fetch:e.fetch}}),s=new E({transport:a,clock:t}),l={gameId:n.gameId,channel:n.channel,matchId:n.matchId,...n.gameRoomId===void 0?{}:{gameRoomId:n.gameRoomId}},u=Nt({client:s,gameId:()=>l.gameId}),c=l.gameRoomId,g=n.endMatch,_=n.log,v=fe({client:s,clock:t,gameId:l.gameId,...typeof _=="function"?{log:y=>_.call(n,y)}:{}});return {identity:l,client:s,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,S)=>{let A=await u.setMatchBackfill(l.matchId,{open:y.open,...y.seats===void 0?{}:{seats:y.seats}},S===void 0?{}:{signal:S});return {open:A.open,seats:A.seats??null}},reportPlayers:async(y,S)=>(await u.reportMatchPlayers(l.matchId,{players:y.map(O=>({player_id:O.playerId,state:O.state}))},S===void 0?{}:{signal:S})).players.map(O=>({playerId:O.player_id,outcome:O.outcome}))},analytics:v,functions:new L(u.invokeFunction),challenges:ve(u.listChallenges),...c===void 0?{}:{room:{get:y=>u.getGameRoomV2(c,y),args:async y=>{let S=await u.getGameRoomV2(c,y?.signal===void 0?{}:{signal:y.signal}),A=S.modified?S.body:void 0;if(A?.room_args==null||A.room_args_template==null)throw new m("not_found",404,"this room's template declares no room args",void 0,"room_args_not_defined");return {room_args:A.room_args,room_args_template:A.room_args_template}}}},dispose:()=>{v.dispose(),o.dispose();}}}var Dt=["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"],Ht=new Set(Dt);function Re(n){return typeof n=="string"&&Ht.has(n)?n:"unknown"}var Se="[gem: use gem.text.toPlain()]",xe=new Set,ke;function Vt(n){try{if(xe.has(n))return;let e=globalThis.location;if(ke??=!!e?.port&&de(e.hostname??""),!ke)return;xe.add(n),console.warn(`[gem] ${n} is PlayerText, turned into a string: players see ${Se}. Render text.toPlain(value) (text is in @indiegems/gem-web-sdk/sdk).
|
|
2
2
|
${new Error().stack}`);}catch{}}var k=class{#e;#n;constructor(e,t="player text"){this.#e=e,this.#n=t,Object.freeze(this);}toString(){return Vt(this.#n),Se}toJSON(){return this.toString()}get[Symbol.toStringTag](){return "PlayerText"}static unwrap(e){return e.#e}};function j(n,e){return new k(n,e)}var we={toPlain(n){return k.unwrap(n)},compare(n,e,t){let r=n instanceof k?k.unwrap(n):n,o=e instanceof k?k.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 k?k.unwrap(n):n,r=e instanceof k?k.unwrap(e):e;return t.normalize("NFC")===r.normalize("NFC")}};var Ae="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 J(n,e={}){let t=e.clock??M,r=()=>{let l=n();if(l===null)throw new Error(Ae);return l},o=null,a=()=>{if(o===null)throw new Error(Ae);return o};return {server:{get identity(){return a().identity},get client(){return a().client},get api(){return a().api},get match(){return a().match},get analytics(){return a().analytics},get functions(){return a().functions},get challenges(){return a().challenges},get room(){return a().room},dispose(){o?.dispose();},get sizeClass(){return r().sizeClass},get roomArgs(){return r().roomArgs},get roster(){return r().roster},players(){return r().players()},profile(l){let c=r().profile?.(l);if(!c)return null;let g=c.displayName;return typeof g!="string"||g===""?null:{displayName:j(g,"profile.displayName"),...typeof c.displayTag=="string"&&c.displayTag!==""?{displayTag:j(c.displayTag,"profile.displayTag")}:{},...typeof c.discriminator=="string"?{discriminator:c.discriminator}:{}}},playerNumber(l){return r().playerNumber?.(l)},send(l,u,c){c===void 0?r().send(l,u):r().send(l,u,c);},broadcast(l,u){u===void 0?r().broadcast(l):r().broadcast(l,u);},kick(l,u){u===void 0?r().kick(l):r().kick(l,u);},log(l){r().log(l);},warn(l){r().warn(l);}},attach:()=>{o=H(r(),{...e,clock:t});}}}function Pe(n,e={}){let{server:t,attach:r}=J(()=>n,e);return r(),t}function Wt(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:Re(e)}}}var zt=1e4;function Kt(n){let e=false;return t=>{if(e)return;let r;try{r=n.match.reportPlayers([{playerId:t,state:"connected"}],AbortSignal.timeout(zt));}catch{return}r.catch(o=>{o instanceof m&&o.status>=400&&o.status<500&&(e=o.status!==429);});}}function Oe(n,e={}){return ()=>{let t=null,{server:r,attach:o}=J(()=>t,e),a=n(r),s={async init(u){t=u,o(),await a.init?.();},async shutdown(u){let c=Wt(u);try{await a.shutdown?.(c);}finally{r.dispose();}}},l=Kt(r);return s.join=(u,c)=>(l(u),a.join?.(u,c)),a.leave&&(s.leave=(u,c)=>a.leave?.(u,c)),a.message&&(s.message=(u,c,g,_)=>a.message?.(u,c,g,_)),s}}var Yt=new Set(["unlocked","already_unlocked","suppressed"]);function Te(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"||!Yt.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{b as AuthError,U as CONDITIONAL_HEADERS,L as FunctionsApi,m as GemApiError,E as GemClient,$ as GemFunctionError,k as PlayerText,f as TransportRefusal,Te as achievementReceipts,j as asPlayerText,H as createGemServer,ue as createHostTokenSource,Pe as createMatchServer,Oe as defineServer,M as systemClock,we as text,Z 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` v14.0.
|
|
3
|
+
Generated from `@indiegems/gem-web-sdk/function` v14.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` v14.0.
|
|
3
|
+
Generated from `@indiegems/gem-web-sdk/sdk` v14.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
|
|
|
@@ -7312,6 +7312,11 @@ readonly icon?: GemGameSettingIcon
|
|
|
7312
7312
|
One of the Arcade's icon codes; a code this SDK does not know is left out
|
|
7313
7313
|
(with a warning) and the setting is kept with the generic glyph.
|
|
7314
7314
|
|
|
7315
|
+
In the Gem Arcade the icon also fills its fixed quick row (Music, Sound,
|
|
7316
|
+
Color, Vibration): the first **toggle** with `'music'` is the Music slot
|
|
7317
|
+
and the first toggle with `'eye'` is the Color slot. Give those two icons
|
|
7318
|
+
to your music on/off and colour-help toggles, and to no other setting.
|
|
7319
|
+
|
|
7315
7320
|
<a id="gemgametogglesetting"></a>
|
|
7316
7321
|
|
|
7317
7322
|
## GemGameToggleSetting
|
|
@@ -7356,6 +7361,11 @@ readonly icon?: GemGameSettingIcon
|
|
|
7356
7361
|
One of the Arcade's icon codes; a code this SDK does not know is left out
|
|
7357
7362
|
(with a warning) and the setting is kept with the generic glyph.
|
|
7358
7363
|
|
|
7364
|
+
In the Gem Arcade the icon also fills its fixed quick row (Music, Sound,
|
|
7365
|
+
Color, Vibration): the first **toggle** with `'music'` is the Music slot
|
|
7366
|
+
and the first toggle with `'eye'` is the Color slot. Give those two icons
|
|
7367
|
+
to your music on/off and colour-help toggles, and to no other setting.
|
|
7368
|
+
|
|
7359
7369
|
<a id="gemgametogglesetting-kind"></a>
|
|
7360
7370
|
|
|
7361
7371
|
## GemGameToggleSetting.kind
|
|
@@ -7384,9 +7394,11 @@ Whether it is on now.
|
|
|
7384
7394
|
readonly quick?: boolean
|
|
7385
7395
|
```
|
|
7386
7396
|
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
|
|
7397
|
+
**Ignored by the Gem Arcade**, whose quick row is fixed — Music, Sound,
|
|
7398
|
+
Color, Vibration — and filled by [GemGameSettingBase.icon](#gemgamesettingbase-icon)
|
|
7399
|
+
(`'music'`, `'eye'`), not by this flag. Kept for other embedders, which
|
|
7400
|
+
may show the first two toggles that ask in a quick row of their own;
|
|
7401
|
+
leaving it out is fine.
|
|
7390
7402
|
|
|
7391
7403
|
<a id="gemgameslidersetting"></a>
|
|
7392
7404
|
|
|
@@ -7432,6 +7444,11 @@ readonly icon?: GemGameSettingIcon
|
|
|
7432
7444
|
One of the Arcade's icon codes; a code this SDK does not know is left out
|
|
7433
7445
|
(with a warning) and the setting is kept with the generic glyph.
|
|
7434
7446
|
|
|
7447
|
+
In the Gem Arcade the icon also fills its fixed quick row (Music, Sound,
|
|
7448
|
+
Color, Vibration): the first **toggle** with `'music'` is the Music slot
|
|
7449
|
+
and the first toggle with `'eye'` is the Color slot. Give those two icons
|
|
7450
|
+
to your music on/off and colour-help toggles, and to no other setting.
|
|
7451
|
+
|
|
7435
7452
|
<a id="gemgameslidersetting-kind"></a>
|
|
7436
7453
|
|
|
7437
7454
|
## GemGameSliderSetting.kind
|
|
@@ -7557,6 +7574,11 @@ readonly icon?: GemGameSettingIcon
|
|
|
7557
7574
|
One of the Arcade's icon codes; a code this SDK does not know is left out
|
|
7558
7575
|
(with a warning) and the setting is kept with the generic glyph.
|
|
7559
7576
|
|
|
7577
|
+
In the Gem Arcade the icon also fills its fixed quick row (Music, Sound,
|
|
7578
|
+
Color, Vibration): the first **toggle** with `'music'` is the Music slot
|
|
7579
|
+
and the first toggle with `'eye'` is the Color slot. Give those two icons
|
|
7580
|
+
to your music on/off and colour-help toggles, and to no other setting.
|
|
7581
|
+
|
|
7560
7582
|
<a id="gemgamechoicesetting-kind"></a>
|
|
7561
7583
|
|
|
7562
7584
|
## GemGameChoiceSetting.kind
|
|
@@ -7637,9 +7659,9 @@ inside a slider's range and on its step, an option's `id` for a choice.
|
|
|
7637
7659
|
interface GameSettingsApi
|
|
7638
7660
|
```
|
|
7639
7661
|
|
|
7640
|
-
`gem.settings` — mirror
|
|
7662
|
+
`gem.settings` — mirror your game's own settings, up to eight, into the
|
|
7641
7663
|
Arcade's Gem menu. Your own settings button and screen stay: this is a
|
|
7642
|
-
second door to
|
|
7664
|
+
second door to the same settings, never the only one.
|
|
7643
7665
|
|
|
7644
7666
|
<a id="gamesettingsapi-declare"></a>
|
|
7645
7667
|
|
|
@@ -7655,20 +7677,28 @@ all back out.
|
|
|
7655
7677
|
|
|
7656
7678
|
```js
|
|
7657
7679
|
gem.settings.declare([
|
|
7658
|
-
{ id: 'music', label: t('Music'), kind: 'toggle', value: music.on,
|
|
7680
|
+
{ id: 'music', label: t('Music'), kind: 'toggle', value: music.on, icon: 'music' },
|
|
7681
|
+
{ id: 'colors', label: t('Color help'), kind: 'toggle', value: colorHelp, icon: 'eye' },
|
|
7659
7682
|
{ id: 'speed', label: t('Game speed'), kind: 'slider', value: speed, min: 0.5, max: 2, step: 0.25 },
|
|
7660
7683
|
]);
|
|
7661
7684
|
```
|
|
7662
7685
|
|
|
7663
7686
|
**Keep your own settings button and screen** — top-right, on every screen.
|
|
7664
|
-
This mirrors
|
|
7665
|
-
|
|
7687
|
+
This mirrors those settings; it never replaces them, and an embedder that
|
|
7688
|
+
draws no game settings shows none of it.
|
|
7689
|
+
|
|
7690
|
+
The Gem Arcade's Settings screen lists **every** setting you declare, so
|
|
7691
|
+
declare all of yours. Its quick row is fixed — Music, Sound, Color and
|
|
7692
|
+
Vibration (phones and tablets), with the Arcade's own labels: your first
|
|
7693
|
+
toggle with `icon: 'music'` fills Music, your first with `icon: 'eye'`
|
|
7694
|
+
fills Color, and a slot you do not fill stays greyed. It ignores `quick`.
|
|
7666
7695
|
|
|
7667
7696
|
**Declare again whenever your own screen changes a value**, so the menu
|
|
7668
|
-
never shows a stale one.
|
|
7669
|
-
|
|
7670
|
-
|
|
7671
|
-
the
|
|
7697
|
+
never shows a stale one. **Never declare a second mute or vibration
|
|
7698
|
+
switch** — the quick row has the Arcade's own. Your game's own volume,
|
|
7699
|
+
music and sound-effects levels are yours to declare; graphics quality and
|
|
7700
|
+
the controls defaults stay the Arcade's and reach you as
|
|
7701
|
+
`gem.prefs.recommended`.
|
|
7672
7702
|
|
|
7673
7703
|
An entry that breaks a rule is left out, with a warning through your
|
|
7674
7704
|
`log`; nothing throws.
|
|
@@ -9794,13 +9824,15 @@ See the guide's "Camera and look controls" section.
|
|
|
9794
9824
|
readonly settings: GameSettingsApi
|
|
9795
9825
|
```
|
|
9796
9826
|
|
|
9797
|
-
Mirror
|
|
9827
|
+
Mirror your game's own settings, up to eight — Music, Color help, Game
|
|
9798
9828
|
speed — into the Arcade's Gem menu, and hear when the player changes one
|
|
9799
|
-
there.
|
|
9829
|
+
there. The Arcade's Settings screen lists every one; its fixed quick row
|
|
9830
|
+
takes your first toggle with `icon: 'music'` as Music and your first with
|
|
9831
|
+
`icon: 'eye'` as Color (`quick` is ignored by the Gem Arcade).
|
|
9800
9832
|
|
|
9801
9833
|
```js
|
|
9802
9834
|
gem.settings.declare([
|
|
9803
|
-
{ id: 'music', label: t('Music'), kind: 'toggle', value: music.on,
|
|
9835
|
+
{ id: 'music', label: t('Music'), kind: 'toggle', value: music.on, icon: 'music' },
|
|
9804
9836
|
]);
|
|
9805
9837
|
gem.settings.onChange(({ id, value }) => {
|
|
9806
9838
|
if (id === 'music') setMusic(value === true); // even while paused
|
|
@@ -9809,9 +9841,10 @@ gem.settings.onChange(({ id, value }) => {
|
|
|
9809
9841
|
|
|
9810
9842
|
**A mirror, never a replacement: your game still draws its own settings
|
|
9811
9843
|
button and screen**, and every setting you declare is on that screen too.
|
|
9812
|
-
Declare again whenever your screen changes a value. Never declare
|
|
9813
|
-
|
|
9814
|
-
|
|
9844
|
+
Declare again whenever your screen changes a value. Never declare a
|
|
9845
|
+
second mute or vibration switch — the Arcade's quick row has them; your
|
|
9846
|
+
own volume and music or sound-effects levels are fine, and graphics and
|
|
9847
|
+
controls defaults stay the Arcade's (`gem.prefs.recommended`).
|
|
9815
9848
|
|
|
9816
9849
|
See the guide's "Game settings" section.
|
|
9817
9850
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The server surface — API reference
|
|
2
2
|
|
|
3
|
-
Generated from `@indiegems/gem-web-sdk/sdk` v14.0.
|
|
3
|
+
Generated from `@indiegems/gem-web-sdk/sdk` v14.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": "14.0.
|
|
5
|
+
"version": "14.0.1"
|
|
6
6
|
},
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -8449,7 +8449,7 @@
|
|
|
8449
8449
|
"group": "gameSettings",
|
|
8450
8450
|
"signature": "readonly icon?: GemGameSettingIcon",
|
|
8451
8451
|
"documented": true,
|
|
8452
|
-
"summary": "One of the Arcade's icon codes; a code this SDK does not know is left out\n(with a warning) and the setting is kept with the generic glyph.",
|
|
8452
|
+
"summary": "One of the Arcade's icon codes; a code this SDK does not know is left out\n(with a warning) and the setting is kept with the generic glyph.\n\nIn the Gem Arcade the icon also fills its fixed quick row (Music, Sound,\nColor, Vibration): the first **toggle** with `'music'` is the Music slot\nand the first toggle with `'eye'` is the Color slot. Give those two icons\nto your music on/off and colour-help toggles, and to no other setting.",
|
|
8453
8453
|
"deprecated": null,
|
|
8454
8454
|
"params": [],
|
|
8455
8455
|
"returns": null,
|
|
@@ -8513,7 +8513,7 @@
|
|
|
8513
8513
|
"group": "gameSettings",
|
|
8514
8514
|
"signature": "readonly icon?: GemGameSettingIcon",
|
|
8515
8515
|
"documented": true,
|
|
8516
|
-
"summary": "One of the Arcade's icon codes; a code this SDK does not know is left out\n(with a warning) and the setting is kept with the generic glyph.",
|
|
8516
|
+
"summary": "One of the Arcade's icon codes; a code this SDK does not know is left out\n(with a warning) and the setting is kept with the generic glyph.\n\nIn the Gem Arcade the icon also fills its fixed quick row (Music, Sound,\nColor, Vibration): the first **toggle** with `'music'` is the Music slot\nand the first toggle with `'eye'` is the Color slot. Give those two icons\nto your music on/off and colour-help toggles, and to no other setting.",
|
|
8517
8517
|
"deprecated": null,
|
|
8518
8518
|
"params": [],
|
|
8519
8519
|
"returns": null,
|
|
@@ -8561,7 +8561,7 @@
|
|
|
8561
8561
|
"group": "gameSettings",
|
|
8562
8562
|
"signature": "readonly quick?: boolean",
|
|
8563
8563
|
"documented": true,
|
|
8564
|
-
"summary": "
|
|
8564
|
+
"summary": "**Ignored by the Gem Arcade**, whose quick row is fixed — Music, Sound,\nColor, Vibration — and filled by [GemGameSettingBase.icon](api-reference-game.md#gemgamesettingbase-icon)\n(`'music'`, `'eye'`), not by this flag. Kept for other embedders, which\nmay show the first two toggles that ask in a quick row of their own;\nleaving it out is fine.",
|
|
8565
8565
|
"deprecated": null,
|
|
8566
8566
|
"params": [],
|
|
8567
8567
|
"returns": null,
|
|
@@ -8625,7 +8625,7 @@
|
|
|
8625
8625
|
"group": "gameSettings",
|
|
8626
8626
|
"signature": "readonly icon?: GemGameSettingIcon",
|
|
8627
8627
|
"documented": true,
|
|
8628
|
-
"summary": "One of the Arcade's icon codes; a code this SDK does not know is left out\n(with a warning) and the setting is kept with the generic glyph.",
|
|
8628
|
+
"summary": "One of the Arcade's icon codes; a code this SDK does not know is left out\n(with a warning) and the setting is kept with the generic glyph.\n\nIn the Gem Arcade the icon also fills its fixed quick row (Music, Sound,\nColor, Vibration): the first **toggle** with `'music'` is the Music slot\nand the first toggle with `'eye'` is the Color slot. Give those two icons\nto your music on/off and colour-help toggles, and to no other setting.",
|
|
8629
8629
|
"deprecated": null,
|
|
8630
8630
|
"params": [],
|
|
8631
8631
|
"returns": null,
|
|
@@ -8817,7 +8817,7 @@
|
|
|
8817
8817
|
"group": "gameSettings",
|
|
8818
8818
|
"signature": "readonly icon?: GemGameSettingIcon",
|
|
8819
8819
|
"documented": true,
|
|
8820
|
-
"summary": "One of the Arcade's icon codes; a code this SDK does not know is left out\n(with a warning) and the setting is kept with the generic glyph.",
|
|
8820
|
+
"summary": "One of the Arcade's icon codes; a code this SDK does not know is left out\n(with a warning) and the setting is kept with the generic glyph.\n\nIn the Gem Arcade the icon also fills its fixed quick row (Music, Sound,\nColor, Vibration): the first **toggle** with `'music'` is the Music slot\nand the first toggle with `'eye'` is the Color slot. Give those two icons\nto your music on/off and colour-help toggles, and to no other setting.",
|
|
8821
8821
|
"deprecated": null,
|
|
8822
8822
|
"params": [],
|
|
8823
8823
|
"returns": null,
|
|
@@ -8945,7 +8945,7 @@
|
|
|
8945
8945
|
"group": "gameSettings",
|
|
8946
8946
|
"signature": "interface GameSettingsApi",
|
|
8947
8947
|
"documented": true,
|
|
8948
|
-
"summary": "`gem.settings` — mirror
|
|
8948
|
+
"summary": "`gem.settings` — mirror your game's own settings, up to eight, into the\nArcade's Gem menu. Your own settings button and screen stay: this is a\nsecond door to the same settings, never the only one.",
|
|
8949
8949
|
"deprecated": null,
|
|
8950
8950
|
"params": [],
|
|
8951
8951
|
"returns": null,
|
|
@@ -8961,7 +8961,7 @@
|
|
|
8961
8961
|
"group": "gameSettings",
|
|
8962
8962
|
"signature": "declare(settings: readonly GemGameSetting[]): boolean",
|
|
8963
8963
|
"documented": true,
|
|
8964
|
-
"summary": "Show up to eight of your settings in the Arcade's menu, in this order — the\nwhole list each time, the latest call winning. `declare([])` takes them\nall back out.\n\n```js\ngem.settings.declare([\n { id: 'music', label: t('Music'), kind: 'toggle', value: music.on,
|
|
8964
|
+
"summary": "Show up to eight of your settings in the Arcade's menu, in this order — the\nwhole list each time, the latest call winning. `declare([])` takes them\nall back out.\n\n```js\ngem.settings.declare([\n { id: 'music', label: t('Music'), kind: 'toggle', value: music.on, icon: 'music' },\n { id: 'colors', label: t('Color help'), kind: 'toggle', value: colorHelp, icon: 'eye' },\n { id: 'speed', label: t('Game speed'), kind: 'slider', value: speed, min: 0.5, max: 2, step: 0.25 },\n]);\n```\n\n**Keep your own settings button and screen** — top-right, on every screen.\nThis mirrors those settings; it never replaces them, and an embedder that\ndraws no game settings shows none of it.\n\nThe Gem Arcade's Settings screen lists **every** setting you declare, so\ndeclare all of yours. Its quick row is fixed — Music, Sound, Color and\nVibration (phones and tablets), with the Arcade's own labels: your first\ntoggle with `icon: 'music'` fills Music, your first with `icon: 'eye'`\nfills Color, and a slot you do not fill stays greyed. It ignores `quick`.\n\n**Declare again whenever your own screen changes a value**, so the menu\nnever shows a stale one. **Never declare a second mute or vibration\nswitch** — the quick row has the Arcade's own. Your game's own volume,\nmusic and sound-effects levels are yours to declare; graphics quality and\nthe controls defaults stay the Arcade's and reach you as\n`gem.prefs.recommended`.\n\nAn entry that breaks a rule is left out, with a warning through your\n`log`; nothing throws.",
|
|
8965
8965
|
"deprecated": null,
|
|
8966
8966
|
"params": [
|
|
8967
8967
|
{
|
|
@@ -11055,7 +11055,7 @@
|
|
|
11055
11055
|
"group": "start",
|
|
11056
11056
|
"signature": "readonly settings: GameSettingsApi",
|
|
11057
11057
|
"documented": true,
|
|
11058
|
-
"summary": "Mirror
|
|
11058
|
+
"summary": "Mirror your game's own settings, up to eight — Music, Color help, Game\nspeed — into the Arcade's Gem menu, and hear when the player changes one\nthere. The Arcade's Settings screen lists every one; its fixed quick row\ntakes your first toggle with `icon: 'music'` as Music and your first with\n`icon: 'eye'` as Color (`quick` is ignored by the Gem Arcade).\n\n```js\ngem.settings.declare([\n { id: 'music', label: t('Music'), kind: 'toggle', value: music.on, icon: 'music' },\n]);\ngem.settings.onChange(({ id, value }) => {\n if (id === 'music') setMusic(value === true); // even while paused\n});\n```\n\n**A mirror, never a replacement: your game still draws its own settings\nbutton and screen**, and every setting you declare is on that screen too.\nDeclare again whenever your screen changes a value. Never declare a\nsecond mute or vibration switch — the Arcade's quick row has them; your\nown volume and music or sound-effects levels are fine, and graphics and\ncontrols defaults stay the Arcade's (`gem.prefs.recommended`).\n\nSee the guide's \"Game settings\" section.",
|
|
11059
11059
|
"deprecated": null,
|
|
11060
11060
|
"params": [],
|
|
11061
11061
|
"returns": null,
|
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
|
+
## 14.0.1
|
|
20
|
+
|
|
21
|
+
Upgrading from 14.0.0. Impact: none.
|
|
22
|
+
|
|
23
|
+
Nothing in this release asks anything of a game.
|
|
24
|
+
|
|
19
25
|
## 14.0.0
|
|
20
26
|
|
|
21
27
|
Upgrading from 13.4.3. Impact: required.
|
package/docs/getting-started.md
CHANGED
|
@@ -50,7 +50,7 @@ either way.
|
|
|
50
50
|
```jsonc
|
|
51
51
|
// package.json
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@indiegems/gem-web-sdk": "14.0.
|
|
53
|
+
"@indiegems/gem-web-sdk": "14.0.1"
|
|
54
54
|
}
|
|
55
55
|
```
|
|
56
56
|
|
|
@@ -178,8 +178,8 @@ And draw a settings button of your own — top-right, with your Back button just
|
|
|
178
178
|
([the top of the screen](what-a-game-must-do.md#the-top-of-the-screen)) — whose values start from
|
|
179
179
|
the player's Arcade-wide defaults, `gem.prefs.recommended`, until the player chooses their own
|
|
180
180
|
([what a game must do](what-a-game-must-do.md#game-settings)). The Arcade's menu does not open
|
|
181
|
-
your settings screen;
|
|
182
|
-
|
|
181
|
+
your settings screen; declare your settings to it with `gem.settings.declare` too, so its
|
|
182
|
+
Settings screen lists them all, but never instead of your own button. Outside the Arcade there is no Arcade menu at all, so also give players a way out — a
|
|
183
183
|
control that calls `gem.exit()`. A game a player cannot leave is one they leave by closing the tab.
|
|
184
184
|
|
|
185
185
|
## 6. Play it
|