@indiegems/gem-web-sdk 15.3.0 → 15.3.2
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 +12 -0
- package/brand/ticket-hero-128.png +0 -0
- package/brand/ticket-hero-256.png +0 -0
- package/brand/ticket-hero-384.png +0 -0
- package/brand/ticket-hero-512.png +0 -0
- package/brand/ticket-hero-768.png +0 -0
- package/brand/ticket-icon-20-1.5x.png +0 -0
- package/brand/ticket-icon-20-1x.png +0 -0
- package/brand/ticket-icon-20-2x.png +0 -0
- package/brand/ticket-icon-20-3x.png +0 -0
- package/brand/ticket-icon-32-1.5x.png +0 -0
- package/brand/ticket-icon-32-1x.png +0 -0
- package/brand/ticket-icon-32-2x.png +0 -0
- package/brand/ticket-icon-32-3x.png +0 -0
- package/dist/gem-web-sdk.bridge.js +2 -2
- package/dist/gem-web-sdk.conformance.js +3 -3
- package/dist/gem-web-sdk.esm.js +3 -3
- package/dist/gem-web-sdk.function.js +1 -1
- package/dist/gem-web-sdk.game.js +3 -3
- package/dist/gem-web-sdk.min.js +3 -3
- package/dist/gem-web-sdk.sdk.js +3 -3
- package/dist/gem-web-sdk.server.js +1 -1
- package/docs/api/api-reference-function.md +1 -1
- package/docs/api/api-reference-game.md +1 -1
- package/docs/api/api-reference-server.md +1 -1
- package/docs/api/reference.json +1 -1
- package/docs/arcade-economy.md +17 -11
- package/docs/brand-art.md +13 -12
- package/docs/changelog.md +12 -0
- package/docs/game-economy-tutorial.md +2 -2
- package/docs/getting-started.md +1 -1
- package/docs/inventory-and-catalogs.md +10 -8
- package/docs/manifest.json +14 -14
- package/docs/server-bundles.md +2 -2
- 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:15.3.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:"music",k:"b",o:1},{n:"sounds",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},{n:"colorHelp",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:15.3.2]";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:"music",k:"b",o:1},{n:"sounds",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},{n:"colorHelp",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` v15.3.
|
|
3
|
+
Generated from `@indiegems/gem-web-sdk/function` v15.3.2, 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` v15.3.
|
|
3
|
+
Generated from `@indiegems/gem-web-sdk/sdk` v15.3.2, 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
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The server surface — API reference
|
|
2
2
|
|
|
3
|
-
Generated from `@indiegems/gem-web-sdk/sdk` v15.3.
|
|
3
|
+
Generated from `@indiegems/gem-web-sdk/sdk` v15.3.2, 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
package/docs/arcade-economy.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
The arcade runs three things across every game, and a player should be able to tell them apart at
|
|
4
4
|
a glance:
|
|
5
5
|
|
|
6
|
-
> **Gems = progress. Coins = cosmetics. Achievement Points = prestige.**
|
|
6
|
+
> **Gems = progress. Coins = what play earns: cosmetics, and play items too where the platform allows. Achievement Points = prestige.**
|
|
7
7
|
|
|
8
8
|
You do not have to use any of them. A game with no platform currency and no achievements is a
|
|
9
9
|
complete game, and the currencies your core loop runs on — gold, XP, energy, materials, cards — are
|
|
@@ -16,16 +16,17 @@ most of them are enforced at upload, so a design that ignores them is refused ra
|
|
|
16
16
|
|
|
17
17
|
| | **Gems** (`GEMS`) | **Coins** (`ARCADE_TICKETS`) | **Achievement Points** |
|
|
18
18
|
| ------------------ | ------------------------------------------------------ | ----------------------------------------------- | --------------------------------------------------------- |
|
|
19
|
-
| What it is | the arcade's progression currency | the arcade's
|
|
19
|
+
| What it is | the arcade's progression currency | the arcade's everyday currency, earned by play | permanent prestige: the **Achievement Score** |
|
|
20
20
|
| Which games pay it | any game with a server or a serverless function | any game with a server or a serverless function | an achievement, from any game with a server or a function |
|
|
21
|
-
| What it buys | anything a game prices in it |
|
|
21
|
+
| What it buys | anything a game prices in it | cosmetics; play items too, as its spend scope allows (§5) | nothing — it is never spent |
|
|
22
22
|
| Sold for money | by the arcade's own store only, never by a game | never | never |
|
|
23
23
|
| A Boost raises it | yes — the grants and the caps | yes — the grants and the caps | never |
|
|
24
24
|
|
|
25
25
|
A player earns Gems across the arcade's games and spends them on progress anywhere: upgrades, unlocks,
|
|
26
26
|
extra attempts, resources, characters, cards. A player earns Arcade Coins by playing almost anything and
|
|
27
27
|
spends them on how they look: skins, outfits, visual effects, decorations, emotes, profile
|
|
28
|
-
cosmetics
|
|
28
|
+
cosmetics, and since 25 Oct 2026 on play items too, wherever the platform's spend scope for Coins
|
|
29
|
+
admits them (§5). Achievement points are what a player has done, summed across every game into the
|
|
29
30
|
Achievement Score; they are never bought, boosted or spent, and nothing takes them away except the
|
|
30
31
|
platform, for fraud or moderation.
|
|
31
32
|
|
|
@@ -48,7 +49,7 @@ platform-wide currency of your own:
|
|
|
48
49
|
meta-currency — "Crystals" that buy your upgrades, "Shards" that buy your skins, earned and hoarded
|
|
49
50
|
the way a player would earn and hoard the arcade's — competes with the arcade's own, splits the
|
|
50
51
|
player between two wallets that mean the same thing, and sidesteps every rule on this page: the Gem
|
|
51
|
-
Source approval, the
|
|
52
|
+
Source approval, the spend-scope line and the platform's caps. The release review checks for one.
|
|
52
53
|
A currency that is part of play is fine: gold picked up in a level and spent in that run's shop,
|
|
53
54
|
energy that paces a session, materials a crafting tree consumes.
|
|
54
55
|
|
|
@@ -122,17 +123,22 @@ currency may price is a platform setting on that currency, its **spend scope**:
|
|
|
122
123
|
|
|
123
124
|
- **Gems — `any`.** Price progress in `GEMS`: an extra life, an upgrade, a character, a pack of
|
|
124
125
|
cards, another attempt.
|
|
125
|
-
- **Coins — `cosmetic_only
|
|
126
|
+
- **Coins — `cosmetic_only` today.** Since 25 Oct 2026 Coins may price play items as well as
|
|
127
|
+
cosmetics, and the platform moves Coins' scope to `any` to allow it; read the scope in
|
|
128
|
+
`gemctl platform config`. While it is `cosmetic_only`, a Coins price is accepted only on an item your config declares
|
|
126
129
|
`category: cosmetic`, or on a recipe that grants cosmetic items and nothing else. A Coins price
|
|
127
130
|
on anything that grants a currency, moves a progression, grants a non-cosmetic item, opens into
|
|
128
131
|
other items (a bundle or a loot box) or rolls a loot table is refused at upload — a loot table
|
|
129
132
|
even when every entry in it is cosmetic.
|
|
130
133
|
|
|
131
|
-
So a Coins price on an item is always the pair
|
|
132
|
-
`category: cosmetic`; on a recipe, every item it grants declares
|
|
134
|
+
So while the scope is `cosmetic_only`, a Coins price on an item is always the pair
|
|
135
|
+
`currency: ARCADE_TICKETS` and `category: cosmetic`; on a recipe, every item it grants declares
|
|
136
|
+
`category: cosmetic`. Once it is `any`, a play item may carry a Coins price and keeps
|
|
137
|
+
`category: progression`.
|
|
133
138
|
|
|
134
|
-
**How much to charge: 500 Coins is worth about $1.** Price
|
|
135
|
-
worth in dollars, times 500: a $1 emote is 500 Coins, a $3 outfit 1,500, a $10 skin 5,000.
|
|
139
|
+
**How much to charge: 500 Coins is worth about $1.** Price anything in Coins at what it would be
|
|
140
|
+
worth in dollars, times 500: a $1 emote is 500 Coins, a $3 outfit 1,500, a $10 skin 5,000. A play
|
|
141
|
+
item is worth what its counterpart costs in the hit games of its kind. At the
|
|
136
142
|
earn rate in [§4](#4-earning-needs-server-authority), that is about an hour of play for each dollar.
|
|
137
143
|
Coins are never sold for money, so the dollar is your yardstick only: never show a dollar figure
|
|
138
144
|
beside a Coins price. The release review lists every Coins price with its dollar value and hours
|
|
@@ -266,7 +272,7 @@ never computes the score, restates it, or turns it into a currency of its own.
|
|
|
266
272
|
| ---------------------------------------------------------- | --------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
|
|
267
273
|
| a mapping refused, naming the currencies your game may pay | the platform does not let your game grant that currency | target one it lists — `gemctl platform config` has the current set |
|
|
268
274
|
| a receipt `suppressed`, reason `not_allowlisted…` | the platform stopped letting your game grant that currency | target a currency `gemctl platform config` lists; paid balances stay |
|
|
269
|
-
| a price refused, naming the spend scope `cosmetic_only` | a Coins price on something that is not a cosmetic | price it in `GEMS`, or mark the item `category: cosmetic` if it changes
|
|
275
|
+
| a price refused, naming the spend scope `cosmetic_only` | a Coins price on something that is not a cosmetic | price it in `GEMS` while Coins' scope is `cosmetic_only`, or mark the item `category: cosmetic` only if it changes nothing but looks |
|
|
270
276
|
| a receipt `suppressed`, reason `functions_not_opted_in` | your function wrote a paying progression that has not opted in | read [serverless-functions.md](serverless-functions.md), then set `function_may_grant: true` |
|
|
271
277
|
| a receipt `suppressed`, reason `function_gems_not_enabled` | an older receipt, from before functions could pay Gems | nothing — a function pays Gems now, so its next firing pays |
|
|
272
278
|
| `403 function_foreign_entity_write` | a function a player called wrote another player | take the player from the call's context, never its input |
|
package/docs/brand-art.md
CHANGED
|
@@ -11,14 +11,13 @@ draws Gems or Coins only in the three places §5 allows — an amount on offer o
|
|
|
11
11
|
screen, and how much more your game can still pay (the earn allowance) — and never a balance of its
|
|
12
12
|
own. §5 is the creator's ruling and is not optional.
|
|
13
13
|
|
|
14
|
-
> **The Coins art is a 3D render, open to a designer pass.**
|
|
15
|
-
>
|
|
16
|
-
>
|
|
17
|
-
>
|
|
18
|
-
>
|
|
19
|
-
>
|
|
20
|
-
>
|
|
21
|
-
> drawing.
|
|
14
|
+
> **The Coins art is a 3D render, open to a designer pass.** It is a gold coin with the platform's
|
|
15
|
+
> gem in relief at its centre, a raised rim and a ridged edge, so a player reads it as the Arcade's
|
|
16
|
+
> currency in every game rather than one game's gold. It replaced the tangerine coin of 2026-10-21,
|
|
17
|
+
> which replaced the tangerine ticket of 2026-09-28. The files keep their `ticket-*` names, as the
|
|
18
|
+
> currency keeps its slug `ARCADE_TICKETS`. If the art is redrawn again, the new art replaces these
|
|
19
|
+
> files **under the same names** in a later SDK release, so a game that imports them picks it up on
|
|
20
|
+
> its next SDK update. Lay your screens out from the sizes on this page, not from the drawing.
|
|
22
21
|
|
|
23
22
|
## 1. Two kinds of currency art: pick by the ROLE of the screen
|
|
24
23
|
|
|
@@ -108,10 +107,12 @@ outline weight — 1.5 px at 20, 2 px at 32.
|
|
|
108
107
|
| | | `ticket-icon-32-2x.png` | 64 × 64 |
|
|
109
108
|
| | | `ticket-icon-32-3x.png` | 96 × 96 |
|
|
110
109
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
inside the
|
|
114
|
-
|
|
110
|
+
Like the Gems icon, each size is **its own render** of the hero's coin, not the hero scaled down.
|
|
111
|
+
The coin is turned a little so its edge shows, and the lines that part its rim, field and gem — a
|
|
112
|
+
groove inside the rim, a crease above the edge, a channel round the gem — are drawn wider and
|
|
113
|
+
darker the smaller the size, so they still read in a few pixels. The 20 px coin has a slightly
|
|
114
|
+
smaller gem and no ridges on its edge. Each is drawn on its own pixel grid inside the gem icon's
|
|
115
|
+
violet outline. The arcade's wallet draws the same files.
|
|
115
116
|
|
|
116
117
|
## 3. The hero art
|
|
117
118
|
|
package/docs/changelog.md
CHANGED
|
@@ -16,6 +16,18 @@ Its entries are grouped under up to five headings:
|
|
|
16
16
|
- **Rebuild**: a type changed. Recompile against the new version; code that compiles today keeps compiling unless the entry says otherwise.
|
|
17
17
|
- **New capability**: something a game can now do. Nothing changes unless you use it.
|
|
18
18
|
|
|
19
|
+
## 15.3.2
|
|
20
|
+
|
|
21
|
+
Upgrading from 15.3.1. Impact: none.
|
|
22
|
+
|
|
23
|
+
Nothing in this release asks anything of a game.
|
|
24
|
+
|
|
25
|
+
## 15.3.1
|
|
26
|
+
|
|
27
|
+
Upgrading from 15.3.0. Impact: none.
|
|
28
|
+
|
|
29
|
+
Nothing in this release asks anything of a game.
|
|
30
|
+
|
|
19
31
|
## 15.3.0
|
|
20
32
|
|
|
21
33
|
Upgrading from 15.2.0. Impact: required.
|
|
@@ -208,8 +208,8 @@ the one you attempted, rather than resending the purchase.
|
|
|
208
208
|
## Selling a cosmetic for Coins
|
|
209
209
|
|
|
210
210
|
Your shop can also sell for the arcade's own currencies, and the platform draws one line through
|
|
211
|
-
them
|
|
212
|
-
is `
|
|
211
|
+
them by spend scope. **Gems buy anything; Coins buy cosmetics, and play items too once Coins'
|
|
212
|
+
scope is `any`** (allowed since 25 Oct 2026; Coins' scope was `cosmetic_only` then). Which currencies your game may price in, and what each may buy,
|
|
213
213
|
is `gemctl platform config`'s answer. Mark a cosmetic in the config, and price it in
|
|
214
214
|
`ARCADE_TICKETS`:
|
|
215
215
|
|
package/docs/getting-started.md
CHANGED
|
@@ -551,8 +551,8 @@ nobody else can touch them. The arcade also has currencies that span every game,
|
|
|
551
551
|
That changes what a shop can be. A player earns in someone else's game and spends in yours.
|
|
552
552
|
|
|
553
553
|
There are two such currencies, and they are not interchangeable: **Gems** (`GEMS`) buy progress and
|
|
554
|
-
**Coins** (`ARCADE_TICKETS`) buy cosmetics
|
|
555
|
-
to use for what.
|
|
554
|
+
**Coins** (`ARCADE_TICKETS`) buy cosmetics, and play items too where Coins' spend scope allows.
|
|
555
|
+
[arcade-economy.md](arcade-economy.md) says which to use for what.
|
|
556
556
|
|
|
557
557
|
### Awarding one
|
|
558
558
|
|
|
@@ -829,14 +829,15 @@ that looks like the arcade's purchase sheet or wallet. A game screen shaped like
|
|
|
829
829
|
chrome is an imitation of it. Your Buy button is yours; asking a player to add currency or pay is
|
|
830
830
|
the arcade's alone.
|
|
831
831
|
|
|
832
|
-
### Coins
|
|
832
|
+
### What Coins and Gems may buy: the spend scope
|
|
833
833
|
|
|
834
834
|
The arcade has two currencies a player spends: **Gems**, for progress, and **Coins**
|
|
835
|
-
(`ARCADE_TICKETS`), for cosmetics
|
|
836
|
-
|
|
837
|
-
set.
|
|
835
|
+
(`ARCADE_TICKETS`), earned by play, for cosmetics and, since 25 Oct 2026, play items too. What
|
|
836
|
+
each may price is decided by two settings: each platform currency's **spend scope**, which the
|
|
837
|
+
platform sets, and each of your items' **category**, which you set.
|
|
838
838
|
|
|
839
|
-
- A currency whose spend scope is **`cosmetic_only`** may price cosmetics only. Coins' is
|
|
839
|
+
- A currency whose spend scope is **`cosmetic_only`** may price cosmetics only. Coins' is, until
|
|
840
|
+
the platform moves it to `any` to let Coins price play items.
|
|
840
841
|
- A currency whose spend scope is **`any`** may price anything. Gems' is.
|
|
841
842
|
|
|
842
843
|
The platform owns each currency's scope and can change it, so do not hard-code which is which: a
|
|
@@ -884,7 +885,8 @@ purchase catalog stops listing that currency's price on anything the scope does
|
|
|
884
885
|
purchase naming such a price is refused `not_purchasable` before anything is charged.
|
|
885
886
|
|
|
886
887
|
The category is a declaration the platform takes at your word, and the release review checks it.
|
|
887
|
-
Labelling something that affects play `cosmetic` so it can be sold for Coins breaks platform policy
|
|
888
|
+
Labelling something that affects play `cosmetic` so it can be sold for Coins breaks platform policy,
|
|
889
|
+
whatever the scope: a play item sold for Coins keeps `category: progression`.
|
|
888
890
|
|
|
889
891
|
**To sell a cosmetic that needs game progress first, sell it through a recipe.** An item's own
|
|
890
892
|
`platform_prices` cannot carry prerequisites; a recipe's can. Grant the cosmetic from a recipe that
|