@indiegems/gem-web-sdk 21.1.1 → 22.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -16,6 +16,20 @@ 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
+ ## 22.0.0
20
+
21
+ Upgrading from 21.1.1. Impact: required.
22
+
23
+ ### Rebuild
24
+
25
+ - The function invoke options gained an optional cueId field, which changes the signatures of the functions API constructor, the server API invoke function member and the standalone invoke function. Nothing is required of existing calls; recompiling is enough.
26
+ - The frame message union, the list of frame-to-parent messages and the capability type each gained a reward presentation entry. Recompiling is enough, unless your code switches exhaustively over these types, in which case add a case for the new entry.
27
+
28
+ ### New capability
29
+
30
+ - A game can now make one id per award and pass it to both the reward cue call and the function invoke call, so the Arcade pairs the cue with its payout and the reward flies once. An id that is malformed is left out with a console warning and never throws. Passing an id is optional and existing calls behave as before.
31
+ - A server-paid game whose reward moment comes after the payout can now declare that its own reward cue decides when the payout is shown, instead of leaving the timing to the Arcade. Under the game choice the Arcade holds each payout's presentation until a cue releases it, and a payout that no cue releases within a limited time lands quietly. Only the presentation changes; what is paid, when it is paid, and every limit stay the same. The declaration is remembered until the Arcade connection is ready and sent again after each reconnect, and it takes effect only when the Arcade offers the matching capability.
32
+
19
33
  ## 21.1.1
20
34
 
21
35
  Upgrading from 21.1.0. Impact: none.
@@ -1052,6 +1052,7 @@ interface GemFunction {
1052
1052
  declare function createGem(options?: unknown): GemFunction;
1053
1053
  interface FunctionInvokeOptions {
1054
1054
  readonly signal?: AbortSignal;
1055
+ readonly cueId?: string;
1055
1056
  }
1056
1057
  interface FunctionResult {
1057
1058
  readonly bytes: Uint8Array;
package/dist/game.d.ts CHANGED
@@ -1487,6 +1487,7 @@ declare class ProfilesApi {
1487
1487
  }
1488
1488
  interface FunctionInvokeOptions {
1489
1489
  readonly signal?: AbortSignal;
1490
+ readonly cueId?: string;
1490
1491
  }
1491
1492
  interface FunctionResult {
1492
1493
  readonly bytes: Uint8Array;
@@ -1510,6 +1511,7 @@ declare class FunctionsApi {
1510
1511
  #private;
1511
1512
  constructor(invoke: (body: Uint8Array, options?: {
1512
1513
  signal?: AbortSignal;
1514
+ cue_id?: string;
1513
1515
  }) => Promise<BytesResponse>);
1514
1516
  invoke(input: unknown, options?: FunctionInvokeOptions): Promise<FunctionResult>;
1515
1517
  }
@@ -3129,6 +3131,7 @@ interface PlayerBoost {
3129
3131
  }
3130
3132
  interface RewardCue {
3131
3133
  currencySlug: string;
3134
+ cueId?: string;
3132
3135
  expected?: number;
3133
3136
  origin?: {
3134
3137
  x: number;
@@ -3136,6 +3139,7 @@ interface RewardCue {
3136
3139
  };
3137
3140
  }
3138
3141
  type GemCorner = "top-left" | "top-right" | "bottom-left" | "bottom-right";
3142
+ type RewardPresentation = "arcade" | "game";
3139
3143
  interface MenuStyle {
3140
3144
  readonly ground: string;
3141
3145
  readonly accent: string;
@@ -3245,6 +3249,7 @@ declare class GemFrame {
3245
3249
  }>): boolean;
3246
3250
  declareSettings(settings: GemSettingsDeclare["settings"]): boolean;
3247
3251
  setGemCorner(corner: GemCorner): boolean;
3252
+ setRewardPresentation(mode: RewardPresentation): boolean;
3248
3253
  setMenuStyle(style: MenuStyle | null): boolean;
3249
3254
  requestShare(params: ReadonlyArray<{
3250
3255
  readonly key: string;
@@ -3699,6 +3704,7 @@ interface Gem {
3699
3704
  reportMuted(muted: boolean): void;
3700
3705
  showPortraitBorders(name: string | null): void;
3701
3706
  cueReward(cue: RewardCue): boolean;
3707
+ setRewardPresentation(mode: RewardPresentation): boolean;
3702
3708
  setWalletVisible(visible: boolean, options?: WalletVisibleOptions): boolean;
3703
3709
  setMenu(menu: GameMenu): boolean;
3704
3710
  setGemCorner(corner: GemCorner): boolean;
@@ -3729,4 +3735,4 @@ interface ExitAnalytics {
3729
3735
  }
3730
3736
  declare function leaveAndExit(rooms: ExitRooms, bridge: ExitBridge | null, reason?: string, analytics?: ExitAnalytics): Promise<void>;
3731
3737
  declare function createGem(options?: GemOptions): Gem;
3732
- export { ARCADE_EMBEDDERS, AVATAR_RIGS, type AccountApi, type AdFormat, type AdOutcome, type AdOutcomeKind, type AdRequest, type AdsApi, AnalyticsApi, type AnalyticsFlushOptions, type AnalyticsFlushResult, type AnalyticsOptions, type AnalyticsRejection, type AnalyticsValue, type AppLinksOutcome, type AppListing, type AppStore, type ArcadeApi, type ArcadeAvailability, type ArcadeOffer, type ArcadeOutcome, type ArcadeOutcomeKind, AuthError, type AuthFailure, type AuthState, type Avatar3dFamily, type Avatar3dOffer, type Avatar3dPrice, type Avatar3dPurchaseRequest, type AvatarRigNode, type AvatarRigs, type Avatars3dApi, type BootMark, type BootTimeline, type BrandingApi, type BrandingAsset, type BrandingAssetOptions, type BrandingCurrency, type BrandingImageOptions, type BrandingList, type BrandingLookup, type BrandingTheme, type BrandingVariant, type Challenge, type ChallengeWindow, ChallengesApi, type ConfiguredPurchasePayment, type ConfiguredPurchaseRequest, type ConfiguredPurchaseResult, type ControlsApi, DEVICE_SETTINGS_MAX_BYTES, DedicatedServerError, type DedicatedServerFailure, type DedicatedServerSession, type DevToolsOpener, type DeviceSettings, type DeviceSettingsApi, type DeviceSettingsPutOutcome, type DirectPurchaseRequest, type DirectPurchaseResult, type EarnAllowance, type EarnAllowanceEvent, type EarnAllowancePeriod, type EarnAllowanceReadOptions, type EntityLeaderboard, type EntityLeaderboardEntry, type EntityLeaderboardOptions, type EntityType, type ExitAnalytics, type ExitBridge, type ExitRooms, type FrameState, type Friend, type FriendChallenge, FriendChallengeError, type FriendChallengeErrorCode, type FriendChallengeOutcome, type FriendChallengeOutcomeKind, type FriendChallengeRequest, type FriendChallengesPage, FriendsApi, type FriendsPage, type FunctionFailure, type FunctionInvokeOptions, type FunctionResult, FunctionsApi, type GameCard, type GameConfig, type GameMenu, type GameMenuItem, type GamePass, type GameServerLink, type GameSettingsApi, type Gem, GemApiError, type GemAudioChannels, GemClient, type GemCohort, type GemCohorts, GemConfigError, type GemControlBox, type GemCorner, type GemDevTools, GemFrame, GemFunctionError, type GemGameChoiceSetting, type GemGameSetting, type GemGameSettingBase, type GemGameSettingChange, type GemGameSettingIcon, type GemGameSettingOption, type GemGameSettingValue, type GemGameSliderSetting, type GemGameToggleSetting, type GemGraphicsQuality, type GemGraphicsRoute, type GemGraphicsRouteEntry, type GemIdentity, type GemInsets, type GemLook, type GemLookBase, type GemLookDelta, type GemLookOptions, type GemLookSpeed, type GemMatchApi, type GemMatchServerModule, type GemOptions, type GemPlayer, type GemPreferredRoute, type GemPrefs, type GemRecommendedSettings, type GemReservedArea, GemSaveError, type GemServerBundle, type GemServerFactory, type GemServerHost, type GemServerHostProfile, type GemServerLifecycle, type GemTerminationNotice, GemUnframedError, type GemViewport, type GetLeaderboardOptions, type GraphicsApi, type JoinWelcome, type Leaderboard, type LeaderboardEntry, type LeaderboardPeriod, LeaderboardsApi, type ListChallengesOptions, type ListFriendChallengesOptions, type ListFriendsOptions, MAX_PERIODS_BACK, type MatchConnectOptions, type MatchConnection, type MatchHosting, type MatchHostingMode, type MatchServeOptions, type MatchTransport, type MenuStyle, type MessageMeta, type MomentKind, type MomentResult, type MomentSignal, type MomentsApi, type MultiTransportSession, PLATFORM_EVENTS, type PassesApi, type PassesEvent, type PeriodOptions, PlatformApi, PlatformCurrenciesApi, type PlatformCurrency, type PlatformCurrencyAccess, type PlatformCurrencyPurchasePayment, type PlatformCurrencyPurchaseRequest, type PlatformCurrencyPurchaseResult, type PlatformCurrencyReadOptions, PlatformEarnAllowanceApi, type PlatformEventName, type PlayerBadge, type PlayerBoost, type PlayerBoostMultiplier, type PlayerIdentity, type PlayerProfile, type PlayerScope, PlayerText, type PreferredRouteOptions, type ProfileCallOptions, type ProfileShowcaseEntry, ProfilesApi, type PurchaseApi, type PurchaseOptions, type PurchaseOutcome, PurchaseRefusal, type PurchaseRefusalCode, type PurchaseRequest, type PurchaseSettlement, type PutBytesOptions, type PutSaveOptions, type RankedRow, type RecipeAvailability, type RecipeLock, type RewardCue, type RewardedStatus, type SavePage, type SaveRecord, type SendOptions$1 as SendOptions, type ServerTokenGrant, type SessionEndReason, type ShareApi, ShareRefusal, type ShareRequest, ShowcaseApi, type ShowcaseCallOptions, type ShowcaseFriendEntry, type ShowcaseFriends, type ShowcaseValue, type SignInOutcome, type SignInOutcomeKind, type SimilarGamesOutcome, type SnapshotCurrency, type SnapshotItem, type StoreApi, type StoreOffersOutcome, type StoreSettlement, type TransportAdvert, type TransportKind, TransportRefusal, UNRELIABLE_CHANNEL_LABEL, type VibrationApi, type WalletVisibleOptions, type WornAvatar3d, asPlayerText, createBootTimeline, createGem, experimentSelection, leaveAndExit, mapIdentity, markOnResolve, platformIconUrl, presentJoinCredential, readTemplateTransports, readTransportAdvert, reportOnResolve, text, webTransportAvailable };
3738
+ export { ARCADE_EMBEDDERS, AVATAR_RIGS, type AccountApi, type AdFormat, type AdOutcome, type AdOutcomeKind, type AdRequest, type AdsApi, AnalyticsApi, type AnalyticsFlushOptions, type AnalyticsFlushResult, type AnalyticsOptions, type AnalyticsRejection, type AnalyticsValue, type AppLinksOutcome, type AppListing, type AppStore, type ArcadeApi, type ArcadeAvailability, type ArcadeOffer, type ArcadeOutcome, type ArcadeOutcomeKind, AuthError, type AuthFailure, type AuthState, type Avatar3dFamily, type Avatar3dOffer, type Avatar3dPrice, type Avatar3dPurchaseRequest, type AvatarRigNode, type AvatarRigs, type Avatars3dApi, type BootMark, type BootTimeline, type BrandingApi, type BrandingAsset, type BrandingAssetOptions, type BrandingCurrency, type BrandingImageOptions, type BrandingList, type BrandingLookup, type BrandingTheme, type BrandingVariant, type Challenge, type ChallengeWindow, ChallengesApi, type ConfiguredPurchasePayment, type ConfiguredPurchaseRequest, type ConfiguredPurchaseResult, type ControlsApi, DEVICE_SETTINGS_MAX_BYTES, DedicatedServerError, type DedicatedServerFailure, type DedicatedServerSession, type DevToolsOpener, type DeviceSettings, type DeviceSettingsApi, type DeviceSettingsPutOutcome, type DirectPurchaseRequest, type DirectPurchaseResult, type EarnAllowance, type EarnAllowanceEvent, type EarnAllowancePeriod, type EarnAllowanceReadOptions, type EntityLeaderboard, type EntityLeaderboardEntry, type EntityLeaderboardOptions, type EntityType, type ExitAnalytics, type ExitBridge, type ExitRooms, type FrameState, type Friend, type FriendChallenge, FriendChallengeError, type FriendChallengeErrorCode, type FriendChallengeOutcome, type FriendChallengeOutcomeKind, type FriendChallengeRequest, type FriendChallengesPage, FriendsApi, type FriendsPage, type FunctionFailure, type FunctionInvokeOptions, type FunctionResult, FunctionsApi, type GameCard, type GameConfig, type GameMenu, type GameMenuItem, type GamePass, type GameServerLink, type GameSettingsApi, type Gem, GemApiError, type GemAudioChannels, GemClient, type GemCohort, type GemCohorts, GemConfigError, type GemControlBox, type GemCorner, type GemDevTools, GemFrame, GemFunctionError, type GemGameChoiceSetting, type GemGameSetting, type GemGameSettingBase, type GemGameSettingChange, type GemGameSettingIcon, type GemGameSettingOption, type GemGameSettingValue, type GemGameSliderSetting, type GemGameToggleSetting, type GemGraphicsQuality, type GemGraphicsRoute, type GemGraphicsRouteEntry, type GemIdentity, type GemInsets, type GemLook, type GemLookBase, type GemLookDelta, type GemLookOptions, type GemLookSpeed, type GemMatchApi, type GemMatchServerModule, type GemOptions, type GemPlayer, type GemPreferredRoute, type GemPrefs, type GemRecommendedSettings, type GemReservedArea, GemSaveError, type GemServerBundle, type GemServerFactory, type GemServerHost, type GemServerHostProfile, type GemServerLifecycle, type GemTerminationNotice, GemUnframedError, type GemViewport, type GetLeaderboardOptions, type GraphicsApi, type JoinWelcome, type Leaderboard, type LeaderboardEntry, type LeaderboardPeriod, LeaderboardsApi, type ListChallengesOptions, type ListFriendChallengesOptions, type ListFriendsOptions, MAX_PERIODS_BACK, type MatchConnectOptions, type MatchConnection, type MatchHosting, type MatchHostingMode, type MatchServeOptions, type MatchTransport, type MenuStyle, type MessageMeta, type MomentKind, type MomentResult, type MomentSignal, type MomentsApi, type MultiTransportSession, PLATFORM_EVENTS, type PassesApi, type PassesEvent, type PeriodOptions, PlatformApi, PlatformCurrenciesApi, type PlatformCurrency, type PlatformCurrencyAccess, type PlatformCurrencyPurchasePayment, type PlatformCurrencyPurchaseRequest, type PlatformCurrencyPurchaseResult, type PlatformCurrencyReadOptions, PlatformEarnAllowanceApi, type PlatformEventName, type PlayerBadge, type PlayerBoost, type PlayerBoostMultiplier, type PlayerIdentity, type PlayerProfile, type PlayerScope, PlayerText, type PreferredRouteOptions, type ProfileCallOptions, type ProfileShowcaseEntry, ProfilesApi, type PurchaseApi, type PurchaseOptions, type PurchaseOutcome, PurchaseRefusal, type PurchaseRefusalCode, type PurchaseRequest, type PurchaseSettlement, type PutBytesOptions, type PutSaveOptions, type RankedRow, type RecipeAvailability, type RecipeLock, type RewardCue, type RewardPresentation, type RewardedStatus, type SavePage, type SaveRecord, type SendOptions$1 as SendOptions, type ServerTokenGrant, type SessionEndReason, type ShareApi, ShareRefusal, type ShareRequest, ShowcaseApi, type ShowcaseCallOptions, type ShowcaseFriendEntry, type ShowcaseFriends, type ShowcaseValue, type SignInOutcome, type SignInOutcomeKind, type SimilarGamesOutcome, type SnapshotCurrency, type SnapshotItem, type StoreApi, type StoreOffersOutcome, type StoreSettlement, type TransportAdvert, type TransportKind, TransportRefusal, UNRELIABLE_CHANNEL_LABEL, type VibrationApi, type WalletVisibleOptions, type WornAvatar3d, asPlayerText, createBootTimeline, createGem, experimentSelection, leaveAndExit, mapIdentity, markOnResolve, platformIconUrl, presentJoinCredential, readTemplateTransports, readTransportAdvert, reportOnResolve, text, webTransportAvailable };
@@ -1,2 +1,2 @@
1
- var GemWebSdkBridgeBundle=(function(){'use strict';var j="GemWebSdkHandshake";function se(){return typeof document>"u"?void 0:document.readyState}var B=()=>Date.now();function N(n={}){let e=n.win??window,t=e,r=t[j];if(r!==void 0)return r;let o=n.readyState??se,s=n.now??B,d=[],i=[],u=y=>{let c=y.data;!c||c.type!=="gem.handshake"||(d.length>=4&&(d.shift(),i.shift(),p.dropped+=1),d.push(y),i.push(s()));};e.addEventListener("message",u);let p={events:d,times:i,dropped:0,late:o()==="complete",uninstall(){e.removeEventListener("message",u);}};return t[j]=p,p}function W(n,e,t={}){let r=n[j];if(r===void 0)return null;let o=t.ttlMs??9500,s=t.now??B,d=r.events.splice(0),i=r.times?.splice(0),u=0,p=0,y=false,c=s()-o;for(let h=d.length-1;h>=0;h--){let R=i?.[h];if(R!==void 0&&R<c){p+=1;continue}if(u+=1,e(d[h])===true){y=true;break}}return r.uninstall(),{capture:r,delivered:u,stale:p,accepted:y}}var l="gem-web-bridge",S={min:1,max:1},ie=65536,z=8,x=5e3,V=1024;var b=Object.create(null),P="__malformed";var F=Object.create(null),le=Object.freeze([["gem.asyncOpponents.","asyncOpponents"],["gem.vibration.","vibration"],["gem.viewport.","reservedAreas"],["gem.moments.","moments"],["gem.prefs.","audioChannels"],["gem.share.","shareRemap"]]);function C(n){let e=F[n];if(e!==void 0)return e;for(let[t,r]of le)if(n.startsWith(t))return r}function de(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 me(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 ue(n){return /^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i.test(n)}function ce(n){return /^[a-z_]+$/.test(n)}function ge(n){return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(n)||/^[a-z0-9][a-z0-9-]{1,38}[a-z0-9]$/.test(n)&&!n.includes("--")}function D(n,e,t){if(e>z)return `nesting deeper than ${z}`;if(++t.nodes>x)return `more than ${x} values`;if(t.bytes>t.cap)return `over the ${t.cap} byte limit`;if(n==null)return t.bytes+=4,null;let r=typeof n;if(r==="boolean")return t.bytes+=5,null;if(r==="number")return t.bytes+=8,null;if(r==="string")return t.bytes+=n.length*3+2,null;if(r!=="object")return `${r} is not plain data`;let o=n;if(t.seen.has(o))return "a repeated or cyclic object reference";if(t.seen.add(o),Array.isArray(n)){if(n.length>V)return `an array of ${n.length} entries, over the ${V} limit`;t.bytes+=2;for(let i of n){let u=D(i,e+1,t);if(u)return u}return null}let s=Object.getPrototypeOf(n);if(s!==Object.prototype&&s!==null)return "a value that is not a plain object";t.bytes+=2;let d=n;for(let i in d){if(!Object.prototype.hasOwnProperty.call(d,i))continue;if(++t.nodes>x)return `more than ${x} values`;if(t.bytes+=i.length*3+4,t.bytes>t.cap)return `over the ${t.cap} byte limit`;let u=D(d[i],e+1,t);if(u)return u}return null}function pe(n,e=ie){let t={nodes:0,bytes:0,seen:new Set,cap:e},r=D(n,0,t);return r?`message contains ${r}`:t.bytes>e?`message is over the ${e} byte limit`:null}var ye={origin:[de,"not a well-formed origin"],url:[me,"not a safe absolute http(s) URL"],bcp47:[ue,"not a well-formed BCP 47 tag"],code:[ce,"not a code of lower-case letters and underscores"],gameRef:[ge,"not a game id or web address"]};function K(n,e,t){for(let r of e){let o=t===""?r[0]:`${t}.${r[0]}`,s=n[r[0]];if(s==null){if(r[1]<"a")continue;return `${o}: required`}let d=M(s,r,o);if(d)return d}return null}function M(n,e,t){let r=e[1].toLowerCase();switch(r){case "u":return typeof n=="boolean"?null:M(n,typeof n=="string"?[e[0],"s",e[2]]:[e[0],"n",e[3],e[4]],t);case "s":{if(typeof n!="string")return `${t}: expected string`;if(n.length>e[2])return `${t}: exceeds ${e[2]} characters`;if(e[3]){let[o,s]=ye[e[3]];if(!o(n))return `${t}: ${s}`}return null}case "n":case "i":return typeof n!="number"||!(r=="i"?Number.isInteger:Number.isFinite)(n)?`${t}: expected ${r=="i"?"integer":"number"}`:n<e[2]||n>e[3]?`${t}: out of range ${e[2]}..${e[3]}`:null;case "b":return typeof n=="boolean"?null:`${t}: expected boolean`;case "e":{let o=e[2];return o.includes(n)?null:`${t}: not one of ${o.join("|")}`}case "o":return typeof n!="object"||n===null||Array.isArray(n)?`${t}: expected object`:K(n,e[2],t);case "j":return typeof n!="object"||n===null||Array.isArray(n)?`${t}: expected a plain object`:null;case "a":{if(!Array.isArray(n))return `${t}: expected array`;if(n.length>e[2])return `${t}: exceeds ${e[2]} items`;let o=e[3],s=`${t}[]`;for(let d of n){if(d==null){if(o[1]<"a")continue;return `${s}: required`}let i=M(d,o,s);if(i)return i}return null}default:return `${t}: unknown kind ${String(r)}`}}var Y=Object.create(null);function a(n,e,t,r,o){return b[n]=t,r&&(F[n]=r),Y[n]=s=>{let d=pe(s,o);if(d)return d;if(typeof s!="object"||s===null||Array.isArray(s))return "message: expected object";let i=s;return i.gem!==l?"gem: wrong protocol marker":i.type!==n?`type: expected ${n}`:K(i,e,"")}}var w=["","s",64],m=["requestId","s",64],G=["matchId","s",64],f=["reason","S",64,"code"],v=["outcome","e",["ok","declined","unavailable"]];a("gem.handshake",[["versions","o",[["min","i",1,1e3],["max","i",1,1e3]]],["capabilities","A",64,w],["embedder","s",2048,"origin"],["unbidden","B"]],30);a("gem.handshake.accept",[["v","i",1,1e3],["capabilities","A",64,w]],5);a("gem.token",[["token","s",4096],["requestId","S",64],["generation","i",0,2147483647],["apiBaseUrl","S",512,"url"],["playerId","s",64],["gameId","s",64],["channel","e",["dev","test","release"]],["gameVersion","S",64],["expiresAt","i",0,4102444800],["chainEndsAt","i",0,4102444800],["allowDevTools","B"]],30);a("gem.token.denied",[m,["retryable","b"],["retryAfterMs","I",0,36e5],["reason","e",["chain_exhausted","unavailable"]],["correlationId","s",64]],30);a("gem.player",[["untrusted","o",[["displayName","s",64],["displayTag","S",80],["displayHandle","s",80]]],["playerId","S",64],["discriminator","S",8],["avatarIconUrl","S",2048,"url"],["avatarIconId","S",64],["avatar3dId","S",64],["avatar3dModelUrl","S",2048,"url"],["avatar3dIconUrl","S",2048,"url"],["avatars3d","A",8,["","o",[["family","s",32],["id","s",64],["modelUrl","s",256,"url"],["iconUrl","s",256,"url"]]]],["badges","A",2,["","o",[["itemId","s",64],["iconUrl","s",2048,"url"]]]],["displayTag","s",8],["avatarUrl","S",2048,"url"],["boost","O",[["multipliers","a",8,["","o",[["currencyId","s",64],["currencySlug","s",32],["multiplierBp","i",1e4,1e6]]]],["expiresInDays","I",1,7]]]],12);a("gem.pause",[["paused","b"]],120);a("gem.prefs",[["reducedMotion","b"],["muted","b"],["showFrameStats","B"],["music","B"],["sounds","B"],["locale","s",35,"bcp47"],["recommended","O",[["volume","i",0,100],["batterySaver","b"],["keyboardLayout","e",["wasd","arrows"]],["gamepadConfirm","e",["south","east"]],["vibration","b"],["lookSensitivity","I",20,400],["gamepadLookSensitivity","I",20,400],["invertLookY","B"],["touchMovement","S",16,"code"],["graphicsQuality","S",16,"code"],["graphicsQualityAuto","B"],["colorHelp","B"]]]],60);a("gem.cohorts",[["cohorts","a",8,["","o",[["experimentId","s",36],["variantKey","s",32]]]]],12,"cohorts");a("gem.earnAllowanceChanged",[],30,"earnAllowance");a("gem.viewport",[["insets","o",[["top","i",0,4096],["right","i",0,4096],["bottom","i",0,4096],["left","i",0,4096]]],["reserved","A",4,["","o",[["x","i",0,16384],["y","i",0,16384],["width","i",0,16384],["height","i",0,16384],["control","O",[["x","i",0,16384],["y","i",0,16384],["width","i",0,16384],["height","i",0,16384]]]]]]],60,"viewport");a("gem.deviceSettings",[["settings","J"]],12,"deviceSettings");a("gem.willTerminate",[["reason","e",["grant_expiring","session_ended","navigating","kill_switch"]],["graceMs","i",0,6e4]],10);a("gem.roomEvent",[["event","e",["updated","match_started","match_ready","match_failed","version_stale"]],["roomId","s",64],["matchId","S",64],["version","I",0,2147483647],["reason","S",64],["platform","E",["universal","mobile"]]],120,"rooms");a("gem.socketState",[["connected","b"],["reason","E",["connecting","dropped","watchdog","terminal"]]],12,"socketState");a("gem.seatedEvent",[["roomId","s",64]],60,"partySeating");a("gem.autoStartFailedEvent",[["roomId","s",64],["code","s",64]],30,"autoStartFailure");a("gem.ticketEvent",[["event","e",["queued","matched","expired","cancelled","failed"]],["ticketId","s",64],["partySize","I",1,64],["queuedAt","I",0,4102444800],["expiresAt","I",0,4102444800],["reason","S",64],["roomId","S",64]],60,"ticketEvents");a("gem.signalEvent",[["event","e",["hello","offer","answer","ice","peerJoined","peerLeft","migration","matchEnded","error"]],G,["data","j"]],1800,"p2p");a("gem.relayDraining",[G,["clusterTargetId","s",64],["relayIps","a",16,w],["drainingSince","s",40],["deadline","s",40]],60,"p2pRelayDrain");a("gem.dedicatedEvent",[["event","e",["answer","error","matchEnded"]],G,["sdp","S",10240],["sessionId","S",64],["code","S",64],["message","S",256],["reason","S",64]],120,"dedicated");a("gem.partyResult",[m,["partyId","S",64]],30,"parties");a("gem.clusterTarget",[["clusterTargetId","s",64],["clusterTargetIds","A",3,w]],12,"clusterTarget");a("gem.graphicsRoutes",[["entries","a",32,["","o",[["gpu","s",32],["route","S",32],["host","S",32]]]]],12,"graphicsRoutes");a("gem.devtools",[["action","e",["open","close","toggle"]]],30,"devtools");a("gem.screenshot",[["maxWidth","i",1,7680],["maxHeight","i",1,4320]],6,"screenshot");a("gem.screenshot.denied",[["reason","e",["not_wired","no_source","unsupported","unreadable","tainted","too_large","busy","declined","failed"]],["retryable","b"]],12,"screenshot");a("gem.requestContext",[],12,"feedbackContext");a("gem.gameContext",[["context","j"]],12,"feedbackContext");a("gem.signal",[["signal","e",["join","offer","answer","ice","migrationAck","hostUnreachable"]],G,["data","j"]],1200,"p2p");a("gem.dedicatedOffer",[G,["sdp","s",10240],["intent","e",["initial","ice_restart","full_reconnect"]]],60,"dedicated");a("gem.partyRequest",[m],12,"parties");a("gem.ready",[],5);a("gem.engaged",[],5,"engagement");a("gem.progress",[["loaded","i",0,1099511627776],["total","i",0,1099511627776]],600);a("gem.requestToken",[m,["reason","e",["initial","expiring","rejected"]]],12);a("gem.requestLocalServer",[m,["gameRoomId","s",64]],6,"localHost");a("gem.localServer",[m,["serverId","S",128]],30,"localHost");a("gem.localServer.denied",[m,["retryable","b"],["reason","e",["refused","unavailable"]]],30,"localHost");a("gem.exit",[["reason","S",64]],5);a("gem.openExternal",[["url","s",2048,"url"]],6);a("gem.requestFullscreen",[["enabled","b"]],30);a("gem.audioState",[["muted","b"]],120,"audioState");a("gem.rewardCue",[["currencySlug","s",32],["expected","I",1,1e9],["origin","O",[["x","i",0,16384],["y","i",0,16384]]]],60,"rewardCue");a("gem.walletDisplay",[["visible","b"],["currencies","A",8,w],["score","B"]],60,"walletDisplay");a("gem.controlsDeclare",[["uses","o",[["lookSensitivity","S",16,"code"],["gamepadLookSensitivity","S",16,"code"],["invertLookY","S",16,"code"],["touchMovement","S",16,"code"]]]],60,"controls");a("gem.menu",[["settings","b"],["items","A",4,["","o",[["id","s",32],["label","s",40]]]]],60,"gameMenu");a("gem.menuSelect",[["entry","e",["settings","item"]],["id","S",32]],60,"gameMenu");a("gem.gemCorner",[["corner","e",["top-left","top-right","bottom-left","bottom-right"]]],12,"gemCorner");a("gem.menuStyle",[["ground","S",7],["accent","S",7]],12,"menuStyle");a("gem.settingsDeclare",[["settings","a",8,["","o",[["id","s",40],["label","s",40],["kind","e",["toggle","slider","choice"]],["value","u",40,-1e6,1e6],["quick","B"],["icon","S",16,"code"],["min","N",-1e6,1e6],["max","N",-1e6,1e6],["step","N",0,1e6],["options","A",4,["","o",[["id","s",40],["label","s",40]]]]]]]],120,"gameSettings");a("gem.settingChange",[["id","s",40],["value","u",40,-1e6,1e6]],120,"gameSettings");a("gem.requestShare",[["requestId","S",64],["params","a",16,["","o",[["key","s",64],["value","s",512]]]]],6,"share");a("gem.shareResult",[m,["outcome","e",["accepted","refused"]],f,["key","S",64]],30,"shareResult");a("gem.requestAvatarPicker",[["tab","E",["2d","3d"]]],6,"avatarPicker");a("gem.vibrate",[["pattern","a",99,["","i",0,1e4]]],600,"vibration");a("gem.frameStats",[["fps","i",0,1e3],["frameTimeP95Ms","i",0,1e5],["counts","E",["pageFrames","gameDraws"]]],120,"frameStats");a("gem.portraitBorders",[["name","S",40]],60,"portraitBorders");a("gem.error",[["code","e",["version_mismatch","handshake_timeout","handshake_duplicate","invalid_message","rate_limited","token_unavailable","unsupported","unsupported_capability","internal"]],["message","S",256]],60);a("gem.requestPurchase",[m,["purchaseKind","e",["item","recipe"]],["targetId","s",64],["currencySlug","s",32],["quantity","I",1,10],["catalogId","S",64],["origin","E",["sheet","direct_refused"]]],12,"purchases");a("gem.requestAvatar3dPurchase",[m,["itemId","s",64],["currencySlug","s",32]],12,"avatar3dPurchases");a("gem.purchaseResult",[m,v,f,["purchaseId","S",64]],30,"purchases");a("gem.purchaseSettled",[["purchaseKind","e",["item","recipe"]],["targetId","s",64],["catalogId","S",64],["quantity","i",1,10],["purchaseId","S",64]],30,"purchaseSettled");a("gem.deviceSettings.put",[m,["settings","j"]],30,"deviceSettings");a("gem.deviceSettings.result",[m,["outcome","e",["stored","too_large","unavailable"]]],30,"deviceSettings");a("gem.requestAd",[m,["placement","s",32],["format","e",["interstitial","rewarded"]]],6,"ads");a("gem.adResult",[m,["outcome","e",["shown","no_ad","unavailable"]]],12,"ads");a("gem.signalMoment",[m,["kind","e",["level_end","run_end","match_end","menu_return","other_break"]],["placement","S",32],["wall","B"]],6,"moments");a("gem.momentResult",[m,["shown","b"]],12,"moments");a("gem.requestSignIn",[m],6,"signIn");a("gem.signInResult",[m,["outcome","e",["signed_in","declined","unavailable"]]],12,"signIn");a("gem.requestFriendChallenge",[m,["playerId","s",64],["template","s",64],["params","J"]],12,"friendChallenges");a("gem.friendChallengeResult",[m,["outcome","e",["accepted","cancelled","refused","unavailable","rate_limited","invalid"]],["code","S",64],["param","S",64],["channel","S",16],["configVersion","I",0,9007199254740991],["retryAfterMs","I",0,864e5],["detail","S",300]],30,"friendChallenges");a("gem.requestAppLinks",[m],12,"appLinks");a("gem.appLinksResult",[m,v,f,["arcade","O",[["store","e",["app_store","google_play"]]]],["game","O",[["store","e",["app_store","google_play"]]]]],30,"appLinks");a("gem.requestOpenApp",[m,["target","e",["arcade","game"]]],6,"appLinks");a("gem.openAppResult",[m,v,f],30,"appLinks");a("gem.requestOpenGame",[m,["ref","s",40,"gameRef"]],6,"openGame");a("gem.openGameResult",[m,v,f],30,"openGame");a("gem.requestSimilarGames",[m,["limit","I",1,24]],12,"openGame");a("gem.similarGamesResult",[m,v,f,["games","a",24,["","o",[["gameId","s",36,"gameRef"],["slug","S",40,"gameRef"],["iconUrl","s",1024,"url"],["capsuleLandscapeUrl","s",1024,"url"],["capsulePortraitUrl","s",1024,"url"],["previewVideoUrl","S",1024,"url"],["previewPosterUrl","S",1024,"url"],["untrusted","o",[["name","s",64],["tagline","s",64],["shortDescription","s",320],["tags","a",10,["","s",32]]]]]]]],30,"openGame",524288);a("gem.requestStoreOffers",[m],12,"store");a("gem.storeOffersResult",[m,v,f,["offers","a",32,["","o",[["skuId","s",64],["kind","e",["gem_pack","boost","pass","bundle"]],["name","s",80],["description","s",400],["imageUrl","S",1024,"url"],["priceDisplay","s",32],["grant","O",[["currency","s",32],["amount","i",1,1e9]]]]]]],30,"store",262144);a("gem.requestStorePurchase",[m,["skuId","s",64]],12,"store");a("gem.storePurchaseResult",[m,v,f],30,"store");a("gem.storePurchaseSettled",[["skuId","s",64]],30,"store");a("gem.requestStoreOfferSheet",[m,["skuId","s",64]],12,"storeOfferSheet");a("gem.storeOfferSheetResult",[m,v,f],30,"storeOfferSheet");var T=Object.freeze(Y);b.__malformed=60;Object.freeze(b);Object.freeze(F);var fe=/^[a-z0-9][a-z0-9_-]{0,39}$/;function he(n){return typeof n=="string"&&fe.test(n)}function J(n){if(n===null||he(n))return n;let e=typeof n=="string"?JSON.stringify(n.length>48?`${n.slice(0,48)}\u2026`:n):`a value of type ${typeof n}`;console.warn(`[gem] showPortraitBorders: ${e} is not a border name, so nothing was sent. A name is 1 to 40 of a-z, 0-9, _ and -, starting with a letter or digit, exactly as your store page declares it under media.portrait_borders. Pass null for no art.`);}var $={now:()=>Date.now(),setTimeout:(n,e)=>setTimeout(n,e),clearTimeout:n=>clearTimeout(n)},k=class{constructor(e=$){this.clock=e;}clock;tokens=new Map;lastRefill=new Map;allow(e){let t=b[e];if(t===void 0)return false;let r=this.clock.now(),o=this.lastRefill.get(e)??r,s=this.tokens.get(e)??t,d=Math.max(0,r-o),i=Math.min(t,s+d*t/6e4);return i<1?(this.tokens.set(e,i),this.lastRefill.set(e,r),false):(this.tokens.set(e,i-1),this.lastRefill.set(e,r),true)}};function q(n,e){return n.toLowerCase()===e.toLowerCase()}function I(n){let e=n.toLowerCase();return e==="localhost"||e.endsWith(".localhost")||e==="[::1]"||e==="::1"?true:/^127(\.\d{1,3}){3}$/.test(e)}function Q(n,e){if(typeof e!="string"||e==="")return false;let t,r;try{t=new URL(n),r=new URL(e);}catch{return false}return t.protocol!=="http:"&&t.protocol!=="https:"||r.protocol!=="http:"&&r.protocol!=="https:"||t.username!==""||t.password!==""||t.pathname!=="/"||t.search!==""||t.hash!==""||t.port===""?false:I(t.hostname)&&I(r.hostname)}function X(n,e){if(n.min>n.max||e.min>e.max)return null;let t=Math.min(n.max,e.max),r=Math.max(n.min,e.min);return t>=r?t:null}var te="[gem: use gem.text.toPlain()]",Z=new Set,ee;function ve(n){try{if(Z.has(n))return;let e=globalThis.location;if(ee??=!!e?.port&&I(e.hostname??""),!ee)return;Z.add(n),console.warn(`[gem] ${n} is PlayerText, turned into a string: players see ${te}. Render text.toPlain(value) (text is in @indiegems/gem-web-sdk/sdk).
2
- ${new Error().stack}`);}catch{}}var U=class{#e;#t;constructor(e,t="player text"){this.#e=e,this.#t=t,Object.freeze(this);}toString(){return ve(this.#t),te}toJSON(){return this.toString()}get[Symbol.toStringTag](){return "PlayerText"}static unwrap(e){return e.#e}};function H(n,e){return new U(n,e)}function ne(n){return Math.min(16384,Math.max(0,Math.round(Number.isFinite(n)?n:0)))}function Re(n,e){if(n!==true)return {visible:false};let t=[],r=false;for(let o of Array.isArray(e)?e:[])o==="score"?r=true:typeof o=="string"&&o.length>0&&o.length<=64&&!t.includes(o)&&t.push(o);return !r&&t.length===0?{visible:true}:{visible:true,currencies:t.slice(0,8),score:r}}function Se(n){let e=[];for(let t of Array.isArray(n)?n:[]){if(e.length===4)break;if(typeof t!="object"||t===null)continue;let{id:r,label:o}=t;typeof r!="string"||r.length===0||r.length>32||typeof o!="string"||o.trim().length===0||e.some(s=>s.id===r)||e.push({id:r,label:o.trim().slice(0,40)});}return e.length===0?{settings:false}:{settings:false,items:e}}function re(n,e){return Math.min(e,Math.max(0,Math.round(Number.isFinite(n)?n:0)))}function be(n){let e=n.untrusted,t=H(e.displayName,"gem.player.displayName"),r=e.displayTag||e.displayHandle,o=r?H(r,"gem.player.displayTag"):void 0,s=n.discriminator||n.displayTag,d=s&&/^[0-9]{1,8}$/.test(s)?s:void 0,i=n.avatarIconUrl||n.avatarUrl,u=/^[\da-f]{8}(-[\da-f]{4}){3}-[\da-f]{12}$/i,p=n.avatarIconId,y=n.avatar3dId,c={displayName:t,displayHandle:o??t,badges:(n.badges??[]).map(g=>({itemId:g.itemId,iconUrl:g.iconUrl}))};n.playerId&&(c.playerId=n.playerId),d&&(c.discriminator=d),o&&(c.displayTag=o),i&&(c.avatarIconUrl=c.avatarUrl=i),p&&u.test(p)&&(c.avatarIconId=p),y&&u.test(y)&&(c.avatar3dId=y),n.avatar3dModelUrl&&(c.avatar3dModelUrl=n.avatar3dModelUrl),n.avatar3dIconUrl&&(c.avatar3dIconUrl=n.avatar3dIconUrl),n.avatars3d&&(c.avatars3d=n.avatars3d.filter(g=>u.test(g.id)&&/^[a-z][a-z0-9_]*$/.test(g.family)).filter((g,A,L)=>L.findIndex(_=>_.family==g.family)==A).map(({family:g,id:A,modelUrl:L,iconUrl:_})=>({family:g,id:A,modelUrl:L,iconUrl:_})));let h=n.boost,R=(h?.multipliers??[]).map(g=>({currencyId:g.currencyId,currencySlug:g.currencySlug,multiplier:g.multiplierBp/1e4})),E=R.some(g=>g.multiplier>1);return c.boost=E&&h?.expiresInDays?{active:E,multipliers:R,expiresInDays:h.expiresInDays}:{active:E,multipliers:R},c}var we=1e4,Ge=["appLinks","openGame","store","storeOfferSheet"],ke=["token","pause","menuSelect","settingChange","prefs","cohorts","viewport","willTerminate","localServer","roomEvent","seatedEvent","autoStartFailedEvent","ticketEvent","socketState","signalEvent","relayDraining","dedicatedEvent","clusterTarget","graphicsRoutes","partyResult","purchaseResult","purchaseSettled","shareResult","deviceSettings","adResult","momentResult","signInResult","friendChallengeResult"],Oe=new WeakMap;var O=class{constructor(e){this.options=e;if(e.expectedSource===void 0||e.expectedSource===null)throw new Error("GemFrame: expectedSource is required and must not be null \u2014 pass window.parent. The handshake transfers the MessagePort, and origin alone does not say WHICH document on that origin sent it.");this.expectedSource=e.expectedSource,this.clock=e.clock??$,this.inbound=new k(this.clock),this.outbound=new k(this.clock);}options;state="waiting";port=null;version=null;peerCapabilities=[];unbidden=false;engagedSent=false;readyPending=false;readySent=false;settleWaiters=[];clock;inbound;outbound;expectedSource;get currentState(){return this.state}get parentCapabilities(){return this.peerCapabilities}parentSupports(e){return this.peerCapabilities.includes(e)}get protocolVersion(){return this.version}get unbiddenLaunch(){return this.unbidden}handleWindowMessage(e){if(e.source!==this.expectedSource)return this.refuse(e,"handshake did not come from the expected embedder window"),false;if(!(this.options.allowedEmbedders.some(i=>q(i,e.origin))||Q(e.origin,this.options.selfOrigin)||(Oe.get(this)??[]).some(i=>q(i,e.origin))))return this.refuse(e,`embedder '${e.origin}' is not in allowedEmbedders`),this.state==="waiting"&&this.transition("refused"),false;if(this.state==="connected")return this.fail("handshake_duplicate","this document already has a port"),false;if(this.state!=="waiting")return false;let r=T["gem.handshake"]?.(e.data);if(r)return this.refuse(e,`malformed handshake: ${r}`),false;let o=e.data;if(!q(o.embedder,e.origin))return this.refuse(e,`handshake claims embedder '${o.embedder}' but arrived from '${e.origin}'`),false;let s=e.ports?.[0];if(!s)return this.refuse(e,"handshake transferred no MessagePort"),false;let d=X(S,o.versions);return d===null?(s.onmessage=null,s.postMessage({gem:l,type:"gem.error",code:"version_mismatch",message:`frame supports v${S.min}..v${S.max}`}),s.close(),this.transition("refused"),this.options.onError?.("version_mismatch"),false):(this.port=s,this.version=d,s.onmessage=i=>this.receive(i.data,i.ports??[]),s.start?.(),this.peerCapabilities=o.capabilities??[],this.unbidden=o.unbidden===true,s.postMessage({gem:l,type:"gem.handshake.accept",v:d,...this.options.capabilities===void 0?{}:{capabilities:[...this.options.capabilities]}}),this.transition("connected"),this.readyPending&&(this.readyPending=false,this.ready()),true)}ready(){if(this.state!=="connected"||!this.port){this.readyPending=true;return}if(this.readySent){this.options.onDropped?.("internal","gem.ready was already sent; duplicate suppressed");return}this.readySent=true,this.send({gem:l,type:"gem.ready"});}settled(e=we){return this.state!=="waiting"?Promise.resolve(this.state):new Promise(t=>{let r=s=>{this.clock.clearTimeout(o),t(s);},o=this.clock.setTimeout(()=>{let s=this.settleWaiters.indexOf(r);s>=0&&this.settleWaiters.splice(s,1),t(this.state);},e);this.settleWaiters.push(r);})}progress(e,t){this.send({gem:l,type:"gem.progress",loaded:e,total:t});}requestToken(e,t){this.send({gem:l,type:"gem.requestToken",requestId:e,reason:t});}requestLocalServer(e,t){return this.parentSupports("localHost")?(this.send({gem:l,type:"gem.requestLocalServer",requestId:e,gameRoomId:t}),true):false}exit(e){this.send(e===void 0?{gem:l,type:"gem.exit"}:{gem:l,type:"gem.exit",reason:e});}openExternal(e){this.send({gem:l,type:"gem.openExternal",url:e});}requestFullscreen(e){this.send({gem:l,type:"gem.requestFullscreen",enabled:e});}reportMuted(e){return this.gated("audioState")?(this.send({gem:l,type:"gem.audioState",muted:e}),true):false}reportEngaged(){return this.engagedSent||!this.gated("engagement")||!this.send({gem:l,type:"gem.engaged"})?false:(this.engagedSent=true,true)}cueReward(e){if(!this.gated("rewardCue"))return false;let t={gem:l,type:"gem.rewardCue",currencySlug:String(e.currencySlug).slice(0,32)};return e.expected!==void 0&&Number.isFinite(e.expected)&&e.expected>=1&&(t.expected=Math.min(1e9,Math.round(e.expected))),e.origin&&(t.origin={x:ne(e.origin.x),y:ne(e.origin.y)}),this.send(t),true}showPortraitBorders(e){let t=J(e);return t===void 0||!this.gated("portraitBorders")?false:this.send(t===null?{gem:l,type:"gem.portraitBorders"}:{gem:l,type:"gem.portraitBorders",name:t})}setWalletVisible(e,t){return this.gated("walletDisplay")?this.send({gem:l,type:"gem.walletDisplay",...Re(e,t?.only)}):false}setMenu(e){return this.gated("gameMenu")?this.send({gem:l,type:"gem.menu",...Se(e)}):false}declareSettings(e){return this.gated("gameSettings")?this.send({gem:l,type:"gem.settingsDeclare",settings:e}):false}setGemCorner(e){return this.gated("gemCorner")?this.send({gem:l,type:"gem.gemCorner",corner:e}):false}setMenuStyle(e){return this.gated("menuStyle")?this.send(e===null?{gem:l,type:"gem.menuStyle"}:{gem:l,type:"gem.menuStyle",ground:e.ground,accent:e.accent}):false}requestShare(e,t){return this.gated("share")?this.send({gem:l,type:"gem.requestShare",...t===void 0?{}:{requestId:t},params:e.map(({key:r,value:o})=>({key:r,value:o}))}):false}requestAvatarPicker(e){return this.gated("avatarPicker")?this.send({gem:l,type:"gem.requestAvatarPicker",...e==="2d"||e==="3d"?{tab:e}:{}}):false}requestVibrate(e){return this.gated("vibration")?this.send({gem:l,type:"gem.vibrate",pattern:[...e]}):false}reportFrameStats(e){return this.gated("frameStats")?(this.send({gem:l,type:"gem.frameStats",fps:re(e.fps,1e3),frameTimeP95Ms:re(e.frameTimeP95Ms,1e5),counts:e.counts==="gameDraws"?"gameDraws":"pageFrames"}),true):false}sendGameContext(e){return this.state!=="connected"?false:(this.send({gem:l,type:"gem.gameContext",context:e}),true)}signal(e,t,r){this.send({gem:l,type:"gem.signal",signal:e,matchId:t,data:r});}dedicatedOffer(e,t,r){this.send({gem:l,type:"gem.dedicatedOffer",matchId:e,sdp:t,intent:r});}requestParty(e){return this.send({gem:l,type:"gem.partyRequest",requestId:e})}requestPurchase(e,t,r,o,s,d,i){return this.send({gem:l,type:"gem.requestPurchase",requestId:e,purchaseKind:t,targetId:r,currencySlug:o,...s===void 0?{}:{quantity:s},...d===void 0?{}:{catalogId:d},...i===void 0?{}:{origin:i}})}requestAvatar3dPurchase(e,t,r){return this.parentSupports("avatar3dPurchases")?this.send({gem:l,type:"gem.requestAvatar3dPurchase",requestId:e,itemId:t,currencySlug:r}):false}putDeviceSettings(e,t){return this.send({gem:l,type:"gem.deviceSettings.put",requestId:e,settings:t})}requestAd(e,t,r){return this.send({gem:l,type:"gem.requestAd",requestId:e,placement:t,format:r})}signalMoment(e,t,r,o){return this.send({gem:l,type:"gem.signalMoment",requestId:e,kind:t,...r===void 0?{}:{placement:r},...o===true?{wall:true}:{}})}readyCalled(){return this.readySent||this.readyPending}requestSignIn(e){return this.send({gem:l,type:"gem.requestSignIn",requestId:e})}requestFriendChallenge(e,t,r,o){return this.send({gem:l,type:"gem.requestFriendChallenge",requestId:e,playerId:t,template:r,...o===void 0?{}:{params:o}})}requestArcade(e){return this.gated(C(e.type))&&this.send({gem:l,...e})}close(){this.port&&(this.port.onmessage=null,this.port.close(),this.port=null),this.state!=="refused"&&this.transition("closed");}transition(e){if(this.state!==e){this.state=e;for(let t of this.settleWaiters.splice(0))t(e);this.options.onStateChange?.(e);}}refuseMalformed(e,t){if(!this.inbound.allow(P)){this.options.onDropped?.(e,t);return}this.fail(e,t);}dropUnknownType(e){this.inbound.allow(P)&&this.options.onDropped?.("unsupported",`ignored unknown message type '${e}'`);}refuse(e,t){e.ports?.[0]?.close?.(),this.inbound.allow(P)&&this.options.onRefused?.(t);}fail(e,t){this.options.onError?.(e,t),this.state==="connected"&&this.port&&this.send({gem:l,type:"gem.error",code:e,...t===void 0?{}:{message:t}});}gated(e){return this.state==="connected"&&this.parentSupports(e)}send(e){if(this.state!=="connected"||!this.port)return this.options.onDropped?.("internal",`dropped ${String(e.type)} before connect`),false;let t=e.type;if(!this.outbound.allow(t))return this.options.onError?.("rate_limited",`frame exceeded its own limit for ${t}`),false;let r=T[t]?.(e);return r?(this.options.onError?.("internal",`refusing to send malformed ${t}: ${r}`),false):(this.port.postMessage(this.version===null?e:{...e,v:this.version}),true)}receive(e,t=[]){let r=false;try{r=this.dispatchInbound(e,t);}finally{r||ae(t);}}dispatchInbound(e,t){if(this.state!=="connected")return false;let r=typeof e=="object"&&e!==null?e.type:void 0;if(typeof r!="string")return this.refuseMalformed("invalid_message","message has no type"),false;let o=T[r];if(!o)return this.dropUnknownType(r),false;if(!this.inbound.allow(r))return this.fail("rate_limited",`parent exceeded the limit for ${r}`),false;let s=C(r);if(s!==void 0&&!this.options.capabilities?.includes(s))return this.fail("unsupported_capability",`${r} requires the '${s}' capability, which this frame did not advertise`),false;let d=o(e);if(d)return this.fail("invalid_message",`${r}: ${d}`),false;let i=e;if(i.v!==this.version)return this.fail("invalid_message",`${r}: expected v ${String(this.version)}`),false;switch(r){case "gem.earnAllowanceChanged":this.options.onEarnAllowanceChanged?.();break;case "gem.devtools":this.options.onDevtools?.(i.action);break;case "gem.requestContext":this.options.onRequestContext?.();break;case "gem.screenshot":{let u=t[0];if(!u){this.options.onError?.("invalid_message","gem.screenshot transferred no MessagePort");break}let p={maxWidth:i.maxWidth,maxHeight:i.maxHeight};if(!this.options.onScreenshot){u.close(),this.screenshotDenied("not_wired",false);break}return ae(t.slice(1)),this.options.onScreenshot(p,u,(y,c)=>this.screenshotDenied(y,c)),true}case "gem.token.denied":this.options.onTokenDenied?.(i);break;case "gem.localServer.denied":this.options.onLocalServerDenied?.(i);break;case "gem.player":{this.options.onPlayer?.(be(i));break}case "gem.deviceSettings.result":this.options.onDeviceSettingsResult?.(i);break;case "gem.error":this.options.onError?.(i.code,i.message);break;default:if(ke.includes(r.slice(4))){this.options[`on${r[4].toUpperCase()}${r.slice(5)}`]?.(i);break}if(Ge.includes(C(r))){this.options.onArcadeAnswer?.(i);break}this.fail("unsupported",`no frame handler for '${r}'`);}return false}screenshotDenied(e,t){this.send({gem:l,type:"gem.screenshot.denied",reason:e,retryable:t});}};function ae(n){for(let e of n)try{e?.close?.();}catch{}}N();function xe(n){if((n.expectedSource??window.parent)===window)throw new Error("GemWebSdkBridge.connect: this document is not framed (window.parent === window), so there is no embedder to hand it a port. A game runs inside the Gem Arcade iframe; opening it directly will never complete a handshake.");let e=new O({...n,expectedSource:n.expectedSource??window.parent}),t=r=>{let o=e.handleWindowMessage({data:r.data,origin:r.origin,source:r.source,ports:r.ports});return o&&window.removeEventListener("message",t),o};return window.addEventListener("message",t),W(window,t),e}var oe={connect:xe,GemFrame:O,PROTOCOL:l,SUPPORTED_VERSIONS:S};window.GemWebSdkBridge=oe;var wn=oe;return wn;})();
1
+ var GemWebSdkBridgeBundle=(function(){'use strict';var j="GemWebSdkHandshake";function ie(){return typeof document>"u"?void 0:document.readyState}var B=()=>Date.now();function N(n={}){let e=n.win??window,t=e,r=t[j];if(r!==void 0)return r;let o=n.readyState??ie,s=n.now??B,d=[],i=[],u=y=>{let c=y.data;!c||c.type!=="gem.handshake"||(d.length>=4&&(d.shift(),i.shift(),p.dropped+=1),d.push(y),i.push(s()));};e.addEventListener("message",u);let p={events:d,times:i,dropped:0,late:o()==="complete",uninstall(){e.removeEventListener("message",u);}};return t[j]=p,p}function W(n,e,t={}){let r=n[j];if(r===void 0)return null;let o=t.ttlMs??9500,s=t.now??B,d=r.events.splice(0),i=r.times?.splice(0),u=0,p=0,y=false,c=s()-o;for(let h=d.length-1;h>=0;h--){let R=i?.[h];if(R!==void 0&&R<c){p+=1;continue}if(u+=1,e(d[h])===true){y=true;break}}return r.uninstall(),{capture:r,delivered:u,stale:p,accepted:y}}var l="gem-web-bridge",S={min:1,max:1},le=65536,z=8,x=5e3,V=1024;var w=Object.create(null),P="__malformed";var F=Object.create(null),de=Object.freeze([["gem.asyncOpponents.","asyncOpponents"],["gem.vibration.","vibration"],["gem.viewport.","reservedAreas"],["gem.moments.","moments"],["gem.prefs.","audioChannels"],["gem.share.","shareRemap"]]);function C(n){let e=F[n];if(e!==void 0)return e;for(let[t,r]of de)if(n.startsWith(t))return r}function me(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 ue(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 ce(n){return /^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i.test(n)}function ge(n){return /^[a-z_]+$/.test(n)}function pe(n){return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(n)||/^[a-z0-9][a-z0-9-]{1,38}[a-z0-9]$/.test(n)&&!n.includes("--")}function D(n,e,t){if(e>z)return `nesting deeper than ${z}`;if(++t.nodes>x)return `more than ${x} values`;if(t.bytes>t.cap)return `over the ${t.cap} byte limit`;if(n==null)return t.bytes+=4,null;let r=typeof n;if(r==="boolean")return t.bytes+=5,null;if(r==="number")return t.bytes+=8,null;if(r==="string")return t.bytes+=n.length*3+2,null;if(r!=="object")return `${r} is not plain data`;let o=n;if(t.seen.has(o))return "a repeated or cyclic object reference";if(t.seen.add(o),Array.isArray(n)){if(n.length>V)return `an array of ${n.length} entries, over the ${V} limit`;t.bytes+=2;for(let i of n){let u=D(i,e+1,t);if(u)return u}return null}let s=Object.getPrototypeOf(n);if(s!==Object.prototype&&s!==null)return "a value that is not a plain object";t.bytes+=2;let d=n;for(let i in d){if(!Object.prototype.hasOwnProperty.call(d,i))continue;if(++t.nodes>x)return `more than ${x} values`;if(t.bytes+=i.length*3+4,t.bytes>t.cap)return `over the ${t.cap} byte limit`;let u=D(d[i],e+1,t);if(u)return u}return null}function ye(n,e=le){let t={nodes:0,bytes:0,seen:new Set,cap:e},r=D(n,0,t);return r?`message contains ${r}`:t.bytes>e?`message is over the ${e} byte limit`:null}var fe={origin:[me,"not a well-formed origin"],url:[ue,"not a safe absolute http(s) URL"],bcp47:[ce,"not a well-formed BCP 47 tag"],code:[ge,"not a code of lower-case letters and underscores"],gameRef:[pe,"not a game id or web address"]};function K(n,e,t){for(let r of e){let o=t===""?r[0]:`${t}.${r[0]}`,s=n[r[0]];if(s==null){if(r[1]<"a")continue;return `${o}: required`}let d=M(s,r,o);if(d)return d}return null}function M(n,e,t){let r=e[1].toLowerCase();switch(r){case "u":return typeof n=="boolean"?null:M(n,typeof n=="string"?[e[0],"s",e[2]]:[e[0],"n",e[3],e[4]],t);case "s":{if(typeof n!="string")return `${t}: expected string`;if(n.length>e[2])return `${t}: exceeds ${e[2]} characters`;if(e[3]){let[o,s]=fe[e[3]];if(!o(n))return `${t}: ${s}`}return null}case "n":case "i":return typeof n!="number"||!(r=="i"?Number.isInteger:Number.isFinite)(n)?`${t}: expected ${r=="i"?"integer":"number"}`:n<e[2]||n>e[3]?`${t}: out of range ${e[2]}..${e[3]}`:null;case "b":return typeof n=="boolean"?null:`${t}: expected boolean`;case "e":{let o=e[2];return o.includes(n)?null:`${t}: not one of ${o.join("|")}`}case "o":return typeof n!="object"||n===null||Array.isArray(n)?`${t}: expected object`:K(n,e[2],t);case "j":return typeof n!="object"||n===null||Array.isArray(n)?`${t}: expected a plain object`:null;case "a":{if(!Array.isArray(n))return `${t}: expected array`;if(n.length>e[2])return `${t}: exceeds ${e[2]} items`;let o=e[3],s=`${t}[]`;for(let d of n){if(d==null){if(o[1]<"a")continue;return `${s}: required`}let i=M(d,o,s);if(i)return i}return null}default:return `${t}: unknown kind ${String(r)}`}}var Y=Object.create(null);function a(n,e,t,r,o){return w[n]=t,r&&(F[n]=r),Y[n]=s=>{let d=ye(s,o);if(d)return d;if(typeof s!="object"||s===null||Array.isArray(s))return "message: expected object";let i=s;return i.gem!==l?"gem: wrong protocol marker":i.type!==n?`type: expected ${n}`:K(i,e,"")}}var b=["","s",64],m=["requestId","s",64],G=["matchId","s",64],f=["reason","S",64,"code"],v=["outcome","e",["ok","declined","unavailable"]];a("gem.handshake",[["versions","o",[["min","i",1,1e3],["max","i",1,1e3]]],["capabilities","A",64,b],["embedder","s",2048,"origin"],["unbidden","B"]],30);a("gem.handshake.accept",[["v","i",1,1e3],["capabilities","A",64,b]],5);a("gem.token",[["token","s",4096],["requestId","S",64],["generation","i",0,2147483647],["apiBaseUrl","S",512,"url"],["playerId","s",64],["gameId","s",64],["channel","e",["dev","test","release"]],["gameVersion","S",64],["expiresAt","i",0,4102444800],["chainEndsAt","i",0,4102444800],["allowDevTools","B"]],30);a("gem.token.denied",[m,["retryable","b"],["retryAfterMs","I",0,36e5],["reason","e",["chain_exhausted","unavailable"]],["correlationId","s",64]],30);a("gem.player",[["untrusted","o",[["displayName","s",64],["displayTag","S",80],["displayHandle","s",80]]],["playerId","S",64],["discriminator","S",8],["avatarIconUrl","S",2048,"url"],["avatarIconId","S",64],["avatar3dId","S",64],["avatar3dModelUrl","S",2048,"url"],["avatar3dIconUrl","S",2048,"url"],["avatars3d","A",8,["","o",[["family","s",32],["id","s",64],["modelUrl","s",256,"url"],["iconUrl","s",256,"url"]]]],["badges","A",2,["","o",[["itemId","s",64],["iconUrl","s",2048,"url"]]]],["displayTag","s",8],["avatarUrl","S",2048,"url"],["boost","O",[["multipliers","a",8,["","o",[["currencyId","s",64],["currencySlug","s",32],["multiplierBp","i",1e4,1e6]]]],["expiresInDays","I",1,7]]]],12);a("gem.pause",[["paused","b"]],120);a("gem.prefs",[["reducedMotion","b"],["muted","b"],["showFrameStats","B"],["music","B"],["sounds","B"],["locale","s",35,"bcp47"],["recommended","O",[["volume","i",0,100],["batterySaver","b"],["keyboardLayout","e",["wasd","arrows"]],["gamepadConfirm","e",["south","east"]],["vibration","b"],["lookSensitivity","I",20,400],["gamepadLookSensitivity","I",20,400],["invertLookY","B"],["touchMovement","S",16,"code"],["graphicsQuality","S",16,"code"],["graphicsQualityAuto","B"],["colorHelp","B"]]]],60);a("gem.cohorts",[["cohorts","a",8,["","o",[["experimentId","s",36],["variantKey","s",32]]]]],12,"cohorts");a("gem.earnAllowanceChanged",[],30,"earnAllowance");a("gem.viewport",[["insets","o",[["top","i",0,4096],["right","i",0,4096],["bottom","i",0,4096],["left","i",0,4096]]],["reserved","A",4,["","o",[["x","i",0,16384],["y","i",0,16384],["width","i",0,16384],["height","i",0,16384],["control","O",[["x","i",0,16384],["y","i",0,16384],["width","i",0,16384],["height","i",0,16384]]]]]]],60,"viewport");a("gem.deviceSettings",[["settings","J"]],12,"deviceSettings");a("gem.willTerminate",[["reason","e",["grant_expiring","session_ended","navigating","kill_switch"]],["graceMs","i",0,6e4]],10);a("gem.roomEvent",[["event","e",["updated","match_started","match_ready","match_failed","version_stale"]],["roomId","s",64],["matchId","S",64],["version","I",0,2147483647],["reason","S",64],["platform","E",["universal","mobile"]]],120,"rooms");a("gem.socketState",[["connected","b"],["reason","E",["connecting","dropped","watchdog","terminal"]]],12,"socketState");a("gem.seatedEvent",[["roomId","s",64]],60,"partySeating");a("gem.autoStartFailedEvent",[["roomId","s",64],["code","s",64]],30,"autoStartFailure");a("gem.ticketEvent",[["event","e",["queued","matched","expired","cancelled","failed"]],["ticketId","s",64],["partySize","I",1,64],["queuedAt","I",0,4102444800],["expiresAt","I",0,4102444800],["reason","S",64],["roomId","S",64]],60,"ticketEvents");a("gem.signalEvent",[["event","e",["hello","offer","answer","ice","peerJoined","peerLeft","migration","matchEnded","error"]],G,["data","j"]],1800,"p2p");a("gem.relayDraining",[G,["clusterTargetId","s",64],["relayIps","a",16,b],["drainingSince","s",40],["deadline","s",40]],60,"p2pRelayDrain");a("gem.dedicatedEvent",[["event","e",["answer","error","matchEnded"]],G,["sdp","S",10240],["sessionId","S",64],["code","S",64],["message","S",256],["reason","S",64]],120,"dedicated");a("gem.partyResult",[m,["partyId","S",64]],30,"parties");a("gem.clusterTarget",[["clusterTargetId","s",64],["clusterTargetIds","A",3,b]],12,"clusterTarget");a("gem.graphicsRoutes",[["entries","a",32,["","o",[["gpu","s",32],["route","S",32],["host","S",32]]]]],12,"graphicsRoutes");a("gem.devtools",[["action","e",["open","close","toggle"]]],30,"devtools");a("gem.screenshot",[["maxWidth","i",1,7680],["maxHeight","i",1,4320]],6,"screenshot");a("gem.screenshot.denied",[["reason","e",["not_wired","no_source","unsupported","unreadable","tainted","too_large","busy","declined","failed"]],["retryable","b"]],12,"screenshot");a("gem.requestContext",[],12,"feedbackContext");a("gem.gameContext",[["context","j"]],12,"feedbackContext");a("gem.signal",[["signal","e",["join","offer","answer","ice","migrationAck","hostUnreachable"]],G,["data","j"]],1200,"p2p");a("gem.dedicatedOffer",[G,["sdp","s",10240],["intent","e",["initial","ice_restart","full_reconnect"]]],60,"dedicated");a("gem.partyRequest",[m],12,"parties");a("gem.ready",[],5);a("gem.engaged",[],5,"engagement");a("gem.progress",[["loaded","i",0,1099511627776],["total","i",0,1099511627776]],600);a("gem.requestToken",[m,["reason","e",["initial","expiring","rejected"]]],12);a("gem.requestLocalServer",[m,["gameRoomId","s",64]],6,"localHost");a("gem.localServer",[m,["serverId","S",128]],30,"localHost");a("gem.localServer.denied",[m,["retryable","b"],["reason","e",["refused","unavailable"]]],30,"localHost");a("gem.exit",[["reason","S",64]],5);a("gem.openExternal",[["url","s",2048,"url"]],6);a("gem.requestFullscreen",[["enabled","b"]],30);a("gem.audioState",[["muted","b"]],120,"audioState");a("gem.rewardCue",[["currencySlug","s",32],["cueId","S",64],["expected","I",1,1e9],["origin","O",[["x","i",0,16384],["y","i",0,16384]]]],60,"rewardCue");a("gem.rewardPresentation",[["mode","e",["arcade","game"]]],12,"rewardPresentation");a("gem.walletDisplay",[["visible","b"],["currencies","A",8,b],["score","B"]],60,"walletDisplay");a("gem.controlsDeclare",[["uses","o",[["lookSensitivity","S",16,"code"],["gamepadLookSensitivity","S",16,"code"],["invertLookY","S",16,"code"],["touchMovement","S",16,"code"]]]],60,"controls");a("gem.menu",[["settings","b"],["items","A",4,["","o",[["id","s",32],["label","s",40]]]]],60,"gameMenu");a("gem.menuSelect",[["entry","e",["settings","item"]],["id","S",32]],60,"gameMenu");a("gem.gemCorner",[["corner","e",["top-left","top-right","bottom-left","bottom-right"]]],12,"gemCorner");a("gem.menuStyle",[["ground","S",7],["accent","S",7]],12,"menuStyle");a("gem.settingsDeclare",[["settings","a",8,["","o",[["id","s",40],["label","s",40],["kind","e",["toggle","slider","choice"]],["value","u",40,-1e6,1e6],["quick","B"],["icon","S",16,"code"],["min","N",-1e6,1e6],["max","N",-1e6,1e6],["step","N",0,1e6],["options","A",4,["","o",[["id","s",40],["label","s",40]]]]]]]],120,"gameSettings");a("gem.settingChange",[["id","s",40],["value","u",40,-1e6,1e6]],120,"gameSettings");a("gem.requestShare",[["requestId","S",64],["params","a",16,["","o",[["key","s",64],["value","s",512]]]]],6,"share");a("gem.shareResult",[m,["outcome","e",["accepted","refused"]],f,["key","S",64]],30,"shareResult");a("gem.requestAvatarPicker",[["tab","E",["2d","3d"]]],6,"avatarPicker");a("gem.vibrate",[["pattern","a",99,["","i",0,1e4]]],600,"vibration");a("gem.frameStats",[["fps","i",0,1e3],["frameTimeP95Ms","i",0,1e5],["counts","E",["pageFrames","gameDraws"]]],120,"frameStats");a("gem.portraitBorders",[["name","S",40]],60,"portraitBorders");a("gem.error",[["code","e",["version_mismatch","handshake_timeout","handshake_duplicate","invalid_message","rate_limited","token_unavailable","unsupported","unsupported_capability","internal"]],["message","S",256]],60);a("gem.requestPurchase",[m,["purchaseKind","e",["item","recipe"]],["targetId","s",64],["currencySlug","s",32],["quantity","I",1,10],["catalogId","S",64],["origin","E",["sheet","direct_refused"]]],12,"purchases");a("gem.requestAvatar3dPurchase",[m,["itemId","s",64],["currencySlug","s",32]],12,"avatar3dPurchases");a("gem.purchaseResult",[m,v,f,["purchaseId","S",64]],30,"purchases");a("gem.purchaseSettled",[["purchaseKind","e",["item","recipe"]],["targetId","s",64],["catalogId","S",64],["quantity","i",1,10],["purchaseId","S",64]],30,"purchaseSettled");a("gem.deviceSettings.put",[m,["settings","j"]],30,"deviceSettings");a("gem.deviceSettings.result",[m,["outcome","e",["stored","too_large","unavailable"]]],30,"deviceSettings");a("gem.requestAd",[m,["placement","s",32],["format","e",["interstitial","rewarded"]]],6,"ads");a("gem.adResult",[m,["outcome","e",["shown","no_ad","unavailable"]]],12,"ads");a("gem.signalMoment",[m,["kind","e",["level_end","run_end","match_end","menu_return","other_break"]],["placement","S",32],["wall","B"]],6,"moments");a("gem.momentResult",[m,["shown","b"]],12,"moments");a("gem.requestSignIn",[m],6,"signIn");a("gem.signInResult",[m,["outcome","e",["signed_in","declined","unavailable"]]],12,"signIn");a("gem.requestFriendChallenge",[m,["playerId","s",64],["template","s",64],["params","J"]],12,"friendChallenges");a("gem.friendChallengeResult",[m,["outcome","e",["accepted","cancelled","refused","unavailable","rate_limited","invalid"]],["code","S",64],["param","S",64],["channel","S",16],["configVersion","I",0,9007199254740991],["retryAfterMs","I",0,864e5],["detail","S",300]],30,"friendChallenges");a("gem.requestAppLinks",[m],12,"appLinks");a("gem.appLinksResult",[m,v,f,["arcade","O",[["store","e",["app_store","google_play"]]]],["game","O",[["store","e",["app_store","google_play"]]]]],30,"appLinks");a("gem.requestOpenApp",[m,["target","e",["arcade","game"]]],6,"appLinks");a("gem.openAppResult",[m,v,f],30,"appLinks");a("gem.requestOpenGame",[m,["ref","s",40,"gameRef"]],6,"openGame");a("gem.openGameResult",[m,v,f],30,"openGame");a("gem.requestSimilarGames",[m,["limit","I",1,24]],12,"openGame");a("gem.similarGamesResult",[m,v,f,["games","a",24,["","o",[["gameId","s",36,"gameRef"],["slug","S",40,"gameRef"],["iconUrl","s",1024,"url"],["capsuleLandscapeUrl","s",1024,"url"],["capsulePortraitUrl","s",1024,"url"],["previewVideoUrl","S",1024,"url"],["previewPosterUrl","S",1024,"url"],["untrusted","o",[["name","s",64],["tagline","s",64],["shortDescription","s",320],["tags","a",10,["","s",32]]]]]]]],30,"openGame",524288);a("gem.requestStoreOffers",[m],12,"store");a("gem.storeOffersResult",[m,v,f,["offers","a",32,["","o",[["skuId","s",64],["kind","e",["gem_pack","boost","pass","bundle"]],["name","s",80],["description","s",400],["imageUrl","S",1024,"url"],["priceDisplay","s",32],["grant","O",[["currency","s",32],["amount","i",1,1e9]]]]]]],30,"store",262144);a("gem.requestStorePurchase",[m,["skuId","s",64]],12,"store");a("gem.storePurchaseResult",[m,v,f],30,"store");a("gem.storePurchaseSettled",[["skuId","s",64]],30,"store");a("gem.requestStoreOfferSheet",[m,["skuId","s",64]],12,"storeOfferSheet");a("gem.storeOfferSheetResult",[m,v,f],30,"storeOfferSheet");var T=Object.freeze(Y);w.__malformed=60;Object.freeze(w);Object.freeze(F);var he=/^[a-z0-9][a-z0-9_-]{0,39}$/;function ve(n){return typeof n=="string"&&he.test(n)}function J(n){if(n===null||ve(n))return n;let e=typeof n=="string"?JSON.stringify(n.length>48?`${n.slice(0,48)}\u2026`:n):`a value of type ${typeof n}`;console.warn(`[gem] showPortraitBorders: ${e} is not a border name, so nothing was sent. A name is 1 to 40 of a-z, 0-9, _ and -, starting with a letter or digit, exactly as your store page declares it under media.portrait_borders. Pass null for no art.`);}function Q(n){return typeof n=="string"&&/^[\w-]{1,64}$/.test(n)}var $={now:()=>Date.now(),setTimeout:(n,e)=>setTimeout(n,e),clearTimeout:n=>clearTimeout(n)},k=class{constructor(e=$){this.clock=e;}clock;tokens=new Map;lastRefill=new Map;allow(e){let t=w[e];if(t===void 0)return false;let r=this.clock.now(),o=this.lastRefill.get(e)??r,s=this.tokens.get(e)??t,d=Math.max(0,r-o),i=Math.min(t,s+d*t/6e4);return i<1?(this.tokens.set(e,i),this.lastRefill.set(e,r),false):(this.tokens.set(e,i-1),this.lastRefill.set(e,r),true)}};function q(n,e){return n.toLowerCase()===e.toLowerCase()}function I(n){let e=n.toLowerCase();return e==="localhost"||e.endsWith(".localhost")||e==="[::1]"||e==="::1"?true:/^127(\.\d{1,3}){3}$/.test(e)}function X(n,e){if(typeof e!="string"||e==="")return false;let t,r;try{t=new URL(n),r=new URL(e);}catch{return false}return t.protocol!=="http:"&&t.protocol!=="https:"||r.protocol!=="http:"&&r.protocol!=="https:"||t.username!==""||t.password!==""||t.pathname!=="/"||t.search!==""||t.hash!==""||t.port===""?false:I(t.hostname)&&I(r.hostname)}function Z(n,e){if(n.min>n.max||e.min>e.max)return null;let t=Math.min(n.max,e.max),r=Math.max(n.min,e.min);return t>=r?t:null}var ne="[gem: use gem.text.toPlain()]",ee=new Set,te;function Re(n){try{if(ee.has(n))return;let e=globalThis.location;if(te??=!!e?.port&&I(e.hostname??""),!te)return;ee.add(n),console.warn(`[gem] ${n} is PlayerText, turned into a string: players see ${ne}. Render text.toPlain(value) (text is in @indiegems/gem-web-sdk/sdk).
2
+ ${new Error().stack}`);}catch{}}var U=class{#e;#t;constructor(e,t="player text"){this.#e=e,this.#t=t,Object.freeze(this);}toString(){return Re(this.#t),ne}toJSON(){return this.toString()}get[Symbol.toStringTag](){return "PlayerText"}static unwrap(e){return e.#e}};function H(n,e){return new U(n,e)}function re(n){return Math.min(16384,Math.max(0,Math.round(Number.isFinite(n)?n:0)))}function Se(n,e){if(n!==true)return {visible:false};let t=[],r=false;for(let o of Array.isArray(e)?e:[])o==="score"?r=true:typeof o=="string"&&o.length>0&&o.length<=64&&!t.includes(o)&&t.push(o);return !r&&t.length===0?{visible:true}:{visible:true,currencies:t.slice(0,8),score:r}}function we(n){let e=[];for(let t of Array.isArray(n)?n:[]){if(e.length===4)break;if(typeof t!="object"||t===null)continue;let{id:r,label:o}=t;typeof r!="string"||r.length===0||r.length>32||typeof o!="string"||o.trim().length===0||e.some(s=>s.id===r)||e.push({id:r,label:o.trim().slice(0,40)});}return e.length===0?{settings:false}:{settings:false,items:e}}function ae(n,e){return Math.min(e,Math.max(0,Math.round(Number.isFinite(n)?n:0)))}function be(n){let e=n.untrusted,t=H(e.displayName,"gem.player.displayName"),r=e.displayTag||e.displayHandle,o=r?H(r,"gem.player.displayTag"):void 0,s=n.discriminator||n.displayTag,d=s&&/^[0-9]{1,8}$/.test(s)?s:void 0,i=n.avatarIconUrl||n.avatarUrl,u=/^[\da-f]{8}(-[\da-f]{4}){3}-[\da-f]{12}$/i,p=n.avatarIconId,y=n.avatar3dId,c={displayName:t,displayHandle:o??t,badges:(n.badges??[]).map(g=>({itemId:g.itemId,iconUrl:g.iconUrl}))};n.playerId&&(c.playerId=n.playerId),d&&(c.discriminator=d),o&&(c.displayTag=o),i&&(c.avatarIconUrl=c.avatarUrl=i),p&&u.test(p)&&(c.avatarIconId=p),y&&u.test(y)&&(c.avatar3dId=y),n.avatar3dModelUrl&&(c.avatar3dModelUrl=n.avatar3dModelUrl),n.avatar3dIconUrl&&(c.avatar3dIconUrl=n.avatar3dIconUrl),n.avatars3d&&(c.avatars3d=n.avatars3d.filter(g=>u.test(g.id)&&/^[a-z][a-z0-9_]*$/.test(g.family)).filter((g,A,L)=>L.findIndex(_=>_.family==g.family)==A).map(({family:g,id:A,modelUrl:L,iconUrl:_})=>({family:g,id:A,modelUrl:L,iconUrl:_})));let h=n.boost,R=(h?.multipliers??[]).map(g=>({currencyId:g.currencyId,currencySlug:g.currencySlug,multiplier:g.multiplierBp/1e4})),E=R.some(g=>g.multiplier>1);return c.boost=E&&h?.expiresInDays?{active:E,multipliers:R,expiresInDays:h.expiresInDays}:{active:E,multipliers:R},c}var Ge=1e4,ke=["appLinks","openGame","store","storeOfferSheet"],Oe=["token","pause","menuSelect","settingChange","prefs","cohorts","viewport","willTerminate","localServer","roomEvent","seatedEvent","autoStartFailedEvent","ticketEvent","socketState","signalEvent","relayDraining","dedicatedEvent","clusterTarget","graphicsRoutes","partyResult","purchaseResult","purchaseSettled","shareResult","deviceSettings","adResult","momentResult","signInResult","friendChallengeResult"],xe=new WeakMap;var O=class{constructor(e){this.options=e;if(e.expectedSource===void 0||e.expectedSource===null)throw new Error("GemFrame: expectedSource is required and must not be null \u2014 pass window.parent. The handshake transfers the MessagePort, and origin alone does not say WHICH document on that origin sent it.");this.expectedSource=e.expectedSource,this.clock=e.clock??$,this.inbound=new k(this.clock),this.outbound=new k(this.clock);}options;state="waiting";port=null;version=null;peerCapabilities=[];unbidden=false;engagedSent=false;readyPending=false;readySent=false;settleWaiters=[];clock;inbound;outbound;expectedSource;get currentState(){return this.state}get parentCapabilities(){return this.peerCapabilities}parentSupports(e){return this.peerCapabilities.includes(e)}get protocolVersion(){return this.version}get unbiddenLaunch(){return this.unbidden}handleWindowMessage(e){if(e.source!==this.expectedSource)return this.refuse(e,"handshake did not come from the expected embedder window"),false;if(!(this.options.allowedEmbedders.some(i=>q(i,e.origin))||X(e.origin,this.options.selfOrigin)||(xe.get(this)??[]).some(i=>q(i,e.origin))))return this.refuse(e,`embedder '${e.origin}' is not in allowedEmbedders`),this.state==="waiting"&&this.transition("refused"),false;if(this.state==="connected")return this.fail("handshake_duplicate","this document already has a port"),false;if(this.state!=="waiting")return false;let r=T["gem.handshake"]?.(e.data);if(r)return this.refuse(e,`malformed handshake: ${r}`),false;let o=e.data;if(!q(o.embedder,e.origin))return this.refuse(e,`handshake claims embedder '${o.embedder}' but arrived from '${e.origin}'`),false;let s=e.ports?.[0];if(!s)return this.refuse(e,"handshake transferred no MessagePort"),false;let d=Z(S,o.versions);return d===null?(s.onmessage=null,s.postMessage({gem:l,type:"gem.error",code:"version_mismatch",message:`frame supports v${S.min}..v${S.max}`}),s.close(),this.transition("refused"),this.options.onError?.("version_mismatch"),false):(this.port=s,this.version=d,s.onmessage=i=>this.receive(i.data,i.ports??[]),s.start?.(),this.peerCapabilities=o.capabilities??[],this.unbidden=o.unbidden===true,s.postMessage({gem:l,type:"gem.handshake.accept",v:d,...this.options.capabilities===void 0?{}:{capabilities:[...this.options.capabilities]}}),this.transition("connected"),this.readyPending&&(this.readyPending=false,this.ready()),true)}ready(){if(this.state!=="connected"||!this.port){this.readyPending=true;return}if(this.readySent){this.options.onDropped?.("internal","gem.ready was already sent; duplicate suppressed");return}this.readySent=true,this.send({gem:l,type:"gem.ready"});}settled(e=Ge){return this.state!=="waiting"?Promise.resolve(this.state):new Promise(t=>{let r=s=>{this.clock.clearTimeout(o),t(s);},o=this.clock.setTimeout(()=>{let s=this.settleWaiters.indexOf(r);s>=0&&this.settleWaiters.splice(s,1),t(this.state);},e);this.settleWaiters.push(r);})}progress(e,t){this.send({gem:l,type:"gem.progress",loaded:e,total:t});}requestToken(e,t){this.send({gem:l,type:"gem.requestToken",requestId:e,reason:t});}requestLocalServer(e,t){return this.parentSupports("localHost")?(this.send({gem:l,type:"gem.requestLocalServer",requestId:e,gameRoomId:t}),true):false}exit(e){this.send(e===void 0?{gem:l,type:"gem.exit"}:{gem:l,type:"gem.exit",reason:e});}openExternal(e){this.send({gem:l,type:"gem.openExternal",url:e});}requestFullscreen(e){this.send({gem:l,type:"gem.requestFullscreen",enabled:e});}reportMuted(e){return this.gated("audioState")?(this.send({gem:l,type:"gem.audioState",muted:e}),true):false}reportEngaged(){return this.engagedSent||!this.gated("engagement")||!this.send({gem:l,type:"gem.engaged"})?false:(this.engagedSent=true,true)}cueReward(e){if(!this.gated("rewardCue"))return false;let t={gem:l,type:"gem.rewardCue",currencySlug:String(e.currencySlug).slice(0,32)};return Q(e.cueId)&&(t.cueId=e.cueId),e.expected!==void 0&&Number.isFinite(e.expected)&&e.expected>=1&&(t.expected=Math.min(1e9,Math.round(e.expected))),e.origin&&(t.origin={x:re(e.origin.x),y:re(e.origin.y)}),this.send(t),true}showPortraitBorders(e){let t=J(e);return t===void 0||!this.gated("portraitBorders")?false:this.send(t===null?{gem:l,type:"gem.portraitBorders"}:{gem:l,type:"gem.portraitBorders",name:t})}setWalletVisible(e,t){return this.gated("walletDisplay")?this.send({gem:l,type:"gem.walletDisplay",...Se(e,t?.only)}):false}setMenu(e){return this.gated("gameMenu")?this.send({gem:l,type:"gem.menu",...we(e)}):false}declareSettings(e){return this.gated("gameSettings")?this.send({gem:l,type:"gem.settingsDeclare",settings:e}):false}setGemCorner(e){return this.gated("gemCorner")?this.send({gem:l,type:"gem.gemCorner",corner:e}):false}setRewardPresentation(e){return this.gated("rewardPresentation")?this.send({gem:l,type:"gem.rewardPresentation",mode:e}):false}setMenuStyle(e){return this.gated("menuStyle")?this.send(e===null?{gem:l,type:"gem.menuStyle"}:{gem:l,type:"gem.menuStyle",ground:e.ground,accent:e.accent}):false}requestShare(e,t){return this.gated("share")?this.send({gem:l,type:"gem.requestShare",...t===void 0?{}:{requestId:t},params:e.map(({key:r,value:o})=>({key:r,value:o}))}):false}requestAvatarPicker(e){return this.gated("avatarPicker")?this.send({gem:l,type:"gem.requestAvatarPicker",...e==="2d"||e==="3d"?{tab:e}:{}}):false}requestVibrate(e){return this.gated("vibration")?this.send({gem:l,type:"gem.vibrate",pattern:[...e]}):false}reportFrameStats(e){return this.gated("frameStats")?(this.send({gem:l,type:"gem.frameStats",fps:ae(e.fps,1e3),frameTimeP95Ms:ae(e.frameTimeP95Ms,1e5),counts:e.counts==="gameDraws"?"gameDraws":"pageFrames"}),true):false}sendGameContext(e){return this.state!=="connected"?false:(this.send({gem:l,type:"gem.gameContext",context:e}),true)}signal(e,t,r){this.send({gem:l,type:"gem.signal",signal:e,matchId:t,data:r});}dedicatedOffer(e,t,r){this.send({gem:l,type:"gem.dedicatedOffer",matchId:e,sdp:t,intent:r});}requestParty(e){return this.send({gem:l,type:"gem.partyRequest",requestId:e})}requestPurchase(e,t,r,o,s,d,i){return this.send({gem:l,type:"gem.requestPurchase",requestId:e,purchaseKind:t,targetId:r,currencySlug:o,...s===void 0?{}:{quantity:s},...d===void 0?{}:{catalogId:d},...i===void 0?{}:{origin:i}})}requestAvatar3dPurchase(e,t,r){return this.parentSupports("avatar3dPurchases")?this.send({gem:l,type:"gem.requestAvatar3dPurchase",requestId:e,itemId:t,currencySlug:r}):false}putDeviceSettings(e,t){return this.send({gem:l,type:"gem.deviceSettings.put",requestId:e,settings:t})}requestAd(e,t,r){return this.send({gem:l,type:"gem.requestAd",requestId:e,placement:t,format:r})}signalMoment(e,t,r,o){return this.send({gem:l,type:"gem.signalMoment",requestId:e,kind:t,...r===void 0?{}:{placement:r},...o===true?{wall:true}:{}})}readyCalled(){return this.readySent||this.readyPending}requestSignIn(e){return this.send({gem:l,type:"gem.requestSignIn",requestId:e})}requestFriendChallenge(e,t,r,o){return this.send({gem:l,type:"gem.requestFriendChallenge",requestId:e,playerId:t,template:r,...o===void 0?{}:{params:o}})}requestArcade(e){return this.gated(C(e.type))&&this.send({gem:l,...e})}close(){this.port&&(this.port.onmessage=null,this.port.close(),this.port=null),this.state!=="refused"&&this.transition("closed");}transition(e){if(this.state!==e){this.state=e;for(let t of this.settleWaiters.splice(0))t(e);this.options.onStateChange?.(e);}}refuseMalformed(e,t){if(!this.inbound.allow(P)){this.options.onDropped?.(e,t);return}this.fail(e,t);}dropUnknownType(e){this.inbound.allow(P)&&this.options.onDropped?.("unsupported",`ignored unknown message type '${e}'`);}refuse(e,t){e.ports?.[0]?.close?.(),this.inbound.allow(P)&&this.options.onRefused?.(t);}fail(e,t){this.options.onError?.(e,t),this.state==="connected"&&this.port&&this.send({gem:l,type:"gem.error",code:e,...t===void 0?{}:{message:t}});}gated(e){return this.state==="connected"&&this.parentSupports(e)}send(e){if(this.state!=="connected"||!this.port)return this.options.onDropped?.("internal",`dropped ${String(e.type)} before connect`),false;let t=e.type;if(!this.outbound.allow(t))return this.options.onError?.("rate_limited",`frame exceeded its own limit for ${t}`),false;let r=T[t]?.(e);return r?(this.options.onError?.("internal",`refusing to send malformed ${t}: ${r}`),false):(this.port.postMessage(this.version===null?e:{...e,v:this.version}),true)}receive(e,t=[]){let r=false;try{r=this.dispatchInbound(e,t);}finally{r||oe(t);}}dispatchInbound(e,t){if(this.state!=="connected")return false;let r=typeof e=="object"&&e!==null?e.type:void 0;if(typeof r!="string")return this.refuseMalformed("invalid_message","message has no type"),false;let o=T[r];if(!o)return this.dropUnknownType(r),false;if(!this.inbound.allow(r))return this.fail("rate_limited",`parent exceeded the limit for ${r}`),false;let s=C(r);if(s!==void 0&&!this.options.capabilities?.includes(s))return this.fail("unsupported_capability",`${r} requires the '${s}' capability, which this frame did not advertise`),false;let d=o(e);if(d)return this.fail("invalid_message",`${r}: ${d}`),false;let i=e;if(i.v!==this.version)return this.fail("invalid_message",`${r}: expected v ${String(this.version)}`),false;switch(r){case "gem.earnAllowanceChanged":this.options.onEarnAllowanceChanged?.();break;case "gem.devtools":this.options.onDevtools?.(i.action);break;case "gem.requestContext":this.options.onRequestContext?.();break;case "gem.screenshot":{let u=t[0];if(!u){this.options.onError?.("invalid_message","gem.screenshot transferred no MessagePort");break}let p={maxWidth:i.maxWidth,maxHeight:i.maxHeight};if(!this.options.onScreenshot){u.close(),this.screenshotDenied("not_wired",false);break}return oe(t.slice(1)),this.options.onScreenshot(p,u,(y,c)=>this.screenshotDenied(y,c)),true}case "gem.token.denied":this.options.onTokenDenied?.(i);break;case "gem.localServer.denied":this.options.onLocalServerDenied?.(i);break;case "gem.player":{this.options.onPlayer?.(be(i));break}case "gem.deviceSettings.result":this.options.onDeviceSettingsResult?.(i);break;case "gem.error":this.options.onError?.(i.code,i.message);break;default:if(Oe.includes(r.slice(4))){this.options[`on${r[4].toUpperCase()}${r.slice(5)}`]?.(i);break}if(ke.includes(C(r))){this.options.onArcadeAnswer?.(i);break}this.fail("unsupported",`no frame handler for '${r}'`);}return false}screenshotDenied(e,t){this.send({gem:l,type:"gem.screenshot.denied",reason:e,retryable:t});}};function oe(n){for(let e of n)try{e?.close?.();}catch{}}N();function Pe(n){if((n.expectedSource??window.parent)===window)throw new Error("GemWebSdkBridge.connect: this document is not framed (window.parent === window), so there is no embedder to hand it a port. A game runs inside the Gem Arcade iframe; opening it directly will never complete a handshake.");let e=new O({...n,expectedSource:n.expectedSource??window.parent}),t=r=>{let o=e.handleWindowMessage({data:r.data,origin:r.origin,source:r.source,ports:r.ports});return o&&window.removeEventListener("message",t),o};return window.addEventListener("message",t),W(window,t),e}var se={connect:Pe,GemFrame:O,PROTOCOL:l,SUPPORTED_VERSIONS:S};window.GemWebSdkBridge=se;var xn=se;return xn;})();