@indiegems/gem-web-sdk 6.0.0 → 7.1.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.
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/dist/game.d.ts CHANGED
@@ -42,6 +42,8 @@ interface TransportRequest {
42
42
  readonly method: "GET" | "PUT" | "POST" | "PATCH" | "DELETE";
43
43
  readonly path: string;
44
44
  readonly body?: unknown;
45
+ readonly bytes?: Uint8Array;
46
+ readonly responseType?: "json" | "bytes";
45
47
  readonly headers?: ConditionalRequestHeaders;
46
48
  readonly signal?: AbortSignal;
47
49
  readonly keepalive?: boolean;
@@ -51,6 +53,7 @@ interface TransportResponse {
51
53
  readonly body: unknown;
52
54
  readonly etag?: string;
53
55
  readonly retryAfterSeconds?: number;
56
+ readonly invocationId?: string;
54
57
  }
55
58
  interface Transport {
56
59
  request(request: TransportRequest): Promise<TransportResponse>;
@@ -87,6 +90,10 @@ type VersionedResponse<T> = {
87
90
  readonly modified: false;
88
91
  readonly etag?: string;
89
92
  };
93
+ interface BytesResponse {
94
+ readonly bytes: Uint8Array;
95
+ readonly invocationId?: string;
96
+ }
90
97
  declare class GemClient {
91
98
  private readonly options;
92
99
  constructor(options: ClientOptions);
@@ -94,6 +101,7 @@ declare class GemClient {
94
101
  getWithEtag<T>(path: string, options?: VersionedGetOptions): Promise<VersionedResponse<T>>;
95
102
  put<T>(path: string, body: unknown, signal?: AbortSignal, options?: RequestOptions): Promise<T>;
96
103
  post<T>(path: string, body: unknown, signal?: AbortSignal, options?: RequestOptions): Promise<T>;
104
+ postBytes(path: string, bytes: Uint8Array, signal?: AbortSignal, options?: RequestOptions): Promise<BytesResponse>;
97
105
  patch<T>(path: string, body: unknown, signal?: AbortSignal, options?: RequestOptions): Promise<T>;
98
106
  delete<T>(path: string, signal?: AbortSignal, options?: RequestOptions): Promise<T>;
99
107
  private send;
@@ -104,6 +112,21 @@ interface GameApi {
104
112
  readonly client: GemClient;
105
113
  gameId(): string;
106
114
  }
115
+ type AchievementGrant = {
116
+ "description"?: string;
117
+ "display_name": string;
118
+ "hidden_hint"?: string | null;
119
+ "icon_url"?: string | null;
120
+ "id": string;
121
+ "localized"?: Record<string, unknown>;
122
+ "points"?: number;
123
+ "rewards"?: AchievementReward[];
124
+ "visibility"?: AchievementVisibility;
125
+ };
126
+ type AchievementReward = {
127
+ "item": string;
128
+ };
129
+ type AchievementVisibility = "visible" | "hidden";
107
130
  type Affix = {
108
131
  "group"?: string | null;
109
132
  "is_active"?: boolean;
@@ -178,6 +201,7 @@ type GameConfigSnapshot = {
178
201
  "run_types"?: SnapshotRunType[];
179
202
  "version": number;
180
203
  };
204
+ type ItemCategory = "cosmetic" | "progression";
181
205
  type ItemGeneration = {
182
206
  "affix_selections"?: AffixSelection[];
183
207
  "property_rolls"?: Record<string, unknown>;
@@ -185,6 +209,7 @@ type ItemGeneration = {
185
209
  type LevelDefinition = {
186
210
  "auto_claim"?: boolean;
187
211
  "level": number;
212
+ "platform_grants"?: PlatformGrant[];
188
213
  "rewards"?: RecipeOperation[];
189
214
  "threshold": number;
190
215
  };
@@ -207,10 +232,15 @@ type PityRule = {
207
232
  "threshold": number;
208
233
  };
209
234
  type PlatformDisplay = "none" | "challenge";
235
+ type PlatformGrant = PlatformGrantMapping | {
236
+ "achievement": AchievementGrant;
237
+ };
210
238
  type PlatformGrantMapping = {
211
239
  "amount"?: number | null;
240
+ "max_per_entity"?: number | null;
212
241
  "max_per_window"?: number | null;
213
242
  "mode": PlatformGrantMode;
243
+ "per_unit"?: number | null;
214
244
  "target": PlatformGrantTarget;
215
245
  };
216
246
  type PlatformGrantMode = "on_add" | "on_complete";
@@ -226,10 +256,11 @@ type PrerequisiteType = "owns_item" | "progression_complete" | "min_progression_
226
256
  type ProgressionConfig = {
227
257
  "client_writable"?: boolean;
228
258
  "completion_threshold"?: number | null;
259
+ "function_may_grant"?: boolean;
229
260
  "label"?: string | null;
230
261
  "max_completions"?: number | null;
231
262
  "platform_display"?: PlatformDisplay;
232
- "platform_grants"?: PlatformGrantMapping[];
263
+ "platform_grants"?: PlatformGrant[];
233
264
  "reset_schedule"?: null | ResetSchedule;
234
265
  "rewards_on_complete"?: RecipeOperation[];
235
266
  "tracks"?: TrackDefinition[];
@@ -405,6 +436,7 @@ type SnapshotGameRoomTemplate = {
405
436
  "transports"?: string[];
406
437
  };
407
438
  type SnapshotItem = {
439
+ "category"?: ItemCategory;
408
440
  "consumable": boolean;
409
441
  "description"?: string | null;
410
442
  "display_name"?: string | null;
@@ -602,6 +634,14 @@ interface RecipeAvailability {
602
634
  readonly reasons: readonly string[];
603
635
  readonly usesRemaining?: number;
604
636
  readonly cooldownExpiresAt?: string;
637
+ readonly locked: boolean;
638
+ readonly lockReasons: readonly RecipeLock[];
639
+ }
640
+ interface RecipeLock {
641
+ readonly prerequisiteType: string;
642
+ readonly referenceId: string;
643
+ readonly required: number;
644
+ readonly current: number;
605
645
  }
606
646
  interface RecipeUsage {
607
647
  readonly recipeId: string;
@@ -1026,6 +1066,8 @@ interface Challenge {
1026
1066
  readonly periodStartAt: number;
1027
1067
  readonly periodEndsAt: number;
1028
1068
  readonly seed: string;
1069
+ readonly data?: string;
1070
+ readonly dataHash?: string;
1029
1071
  }
1030
1072
  interface ListChallengesOptions {
1031
1073
  readonly periodsBack?: number;
@@ -1195,6 +1237,34 @@ declare class ProfilesApi {
1195
1237
  constructor(api: GameApi);
1196
1238
  of(playerId: string, options?: ProfileCallOptions): Promise<PlayerProfile | null>;
1197
1239
  }
1240
+ interface FunctionInvokeOptions {
1241
+ readonly signal?: AbortSignal;
1242
+ }
1243
+ interface FunctionResult {
1244
+ readonly bytes: Uint8Array;
1245
+ readonly invocationId?: string;
1246
+ text(): string;
1247
+ json<T = unknown>(): T;
1248
+ }
1249
+ type FunctionFailure = "trap" | "memory_exceeded" | "cpu_budget_exceeded" | "host_call_limit";
1250
+ declare class GemFunctionError extends GemApiError {
1251
+ readonly invocationId?: string;
1252
+ readonly functionMessage?: string;
1253
+ readonly failure?: FunctionFailure | (string & {});
1254
+ constructor(source: GemApiError, extra: {
1255
+ readonly invocationId?: string;
1256
+ readonly functionMessage?: string;
1257
+ readonly failure?: string;
1258
+ });
1259
+ get retryable(): boolean;
1260
+ }
1261
+ declare class FunctionsApi {
1262
+ #private;
1263
+ constructor(invoke: (body: Uint8Array, options?: {
1264
+ signal?: AbortSignal;
1265
+ }) => Promise<BytesResponse>);
1266
+ invoke(input: unknown, options?: FunctionInvokeOptions): Promise<FunctionResult>;
1267
+ }
1198
1268
  type SessionEndReason = "grant_expiring" | "session_ended" | "navigating" | "kill_switch" | "pagehide";
1199
1269
  type MatchTransport = "dedicated" | "p2p";
1200
1270
  type PlatformEventName = "gem_session_start" | "gem_session_end" | "gem_pause" | "gem_resume" | "gem_boot_ready" | "gem_match_started" | "gem_match_ended" | "gem_auth_lost";
@@ -1501,6 +1571,7 @@ interface Room {
1501
1571
  interface MatchAutoStartFailed {
1502
1572
  readonly roomId: string;
1503
1573
  readonly code: string;
1574
+ readonly handled: boolean;
1504
1575
  }
1505
1576
  interface RoomSummary {
1506
1577
  readonly id: string;
@@ -2392,6 +2463,16 @@ interface DeviceSettingsApi {
2392
2463
  wait(timeoutMs?: number): Promise<DeviceSettings | null>;
2393
2464
  put(settings: DeviceSettings): Promise<DeviceSettingsPutOutcome>;
2394
2465
  }
2466
+ interface PlayerBoostMultiplier {
2467
+ readonly currencyId: string;
2468
+ readonly currencySlug: string;
2469
+ readonly multiplier: number;
2470
+ }
2471
+ interface PlayerBoost {
2472
+ readonly active: boolean;
2473
+ readonly multipliers: readonly PlayerBoostMultiplier[];
2474
+ readonly expiresInDays?: number;
2475
+ }
2395
2476
  interface RewardCue {
2396
2477
  currencySlug: string;
2397
2478
  expected?: number;
@@ -2405,6 +2486,7 @@ interface FramePlayer extends PlayerIdentity {
2405
2486
  readonly displayName: PlayerText;
2406
2487
  readonly displayHandle: PlayerText;
2407
2488
  readonly avatarUrl?: string;
2489
+ readonly boost: PlayerBoost;
2408
2490
  }
2409
2491
  interface FrameCallbacks {
2410
2492
  onToken?(msg: GemToken): void;
@@ -2512,6 +2594,7 @@ interface GemOptions {
2512
2594
  readonly clientVersion?: ClientVersion;
2513
2595
  readonly pollRooms?: boolean;
2514
2596
  readonly recoverStaleMembership?: boolean;
2597
+ readonly retryAutoStart?: boolean;
2515
2598
  readonly watchSeats?: boolean;
2516
2599
  readonly seatPollIntervalMs?: number;
2517
2600
  readonly autoReconnect?: AutoReconnectOptions | false;
@@ -2538,6 +2621,7 @@ interface GemPlayer extends PlayerIdentity {
2538
2621
  readonly displayName: PlayerText;
2539
2622
  readonly displayHandle: PlayerText;
2540
2623
  readonly avatarUrl?: string;
2624
+ readonly boost: PlayerBoost;
2541
2625
  }
2542
2626
  interface GemPrefs {
2543
2627
  readonly reducedMotion: boolean;
@@ -2589,6 +2673,7 @@ interface Gem {
2589
2673
  readonly friends: FriendsApi;
2590
2674
  readonly platform: PlatformApi;
2591
2675
  readonly profiles: ProfilesApi;
2676
+ readonly functions: FunctionsApi;
2592
2677
  awaitPlayer(timeoutMs?: number): Promise<GemPlayer | null>;
2593
2678
  readonly prefs: GemPrefs | null;
2594
2679
  readonly cohorts: GemCohorts | null;
@@ -2621,4 +2706,4 @@ interface ExitAnalytics {
2621
2706
  }
2622
2707
  declare function leaveAndExit(rooms: ExitRooms, bridge: ExitBridge | null, reason?: string, analytics?: ExitAnalytics): Promise<void>;
2623
2708
  declare function createGem(options?: GemOptions): Gem;
2624
- export { ARCADE_EMBEDDERS, type AccountApi, type AdFormat, type AdOutcome, type AdOutcomeKind, type AdRequest, type AdsApi, AnalyticsApi, type AnalyticsFlushOptions, type AnalyticsFlushResult, type AnalyticsOptions, type AnalyticsRejection, type AnalyticsValue, AuthError, type AuthFailure, type AuthState, type BootMark, type BootTimeline, type Challenge, type ChallengeWindow, ChallengesApi, type ConfiguredPurchasePayment, type ConfiguredPurchaseRequest, type ConfiguredPurchaseResult, DEVICE_SETTINGS_MAX_BYTES, DedicatedServerError, type DedicatedServerFailure, type DedicatedServerSession, type DevToolsOpener, type DeviceSettings, type DeviceSettingsApi, type DeviceSettingsPutOutcome, type DirectPurchaseRequest, type DirectPurchaseResult, type EntityLeaderboard, type EntityLeaderboardEntry, type EntityLeaderboardOptions, type EntityType, type ExitAnalytics, type ExitBridge, type ExitRooms, type FrameState, type Friend, FriendsApi, type FriendsPage, type GameConfig, type GameServerLink, type Gem, GemApiError, GemClient, type GemCohort, type GemCohorts, GemConfigError, type GemDevTools, GemFrame, type GemIdentity, type GemInsets, type GemMatchApi, type GemMatchServerModule, type GemOptions, type GemPlayer, type GemPrefs, GemSaveError, type GemServerBundle, type GemServerFactory, type GemServerHost, type GemServerHostProfile, type GemServerLifecycle, type GemTerminationNotice, type GemViewport, type GetLeaderboardOptions, type JoinWelcome, type Leaderboard, type LeaderboardEntry, LeaderboardsApi, type ListChallengesOptions, type ListFriendsOptions, MAX_PERIODS_BACK, type MatchConnectOptions, type MatchConnection, type MatchHosting, type MatchHostingMode, type MatchServeOptions, type MatchTransport, type MessageMeta, type MultiTransportSession, PLATFORM_EVENTS, PlatformApi, PlatformCurrenciesApi, type PlatformCurrency, type PlatformCurrencyAccess, type PlatformCurrencyPurchasePayment, type PlatformCurrencyPurchaseRequest, type PlatformCurrencyPurchaseResult, type PlatformCurrencyReadOptions, type PlatformEventName, type PlayerBadge, type PlayerIdentity, type PlayerProfile, PlayerText, type ProfileCallOptions, type ProfileShowcaseEntry, ProfilesApi, type PurchaseApi, type PurchaseOptions, type PurchaseOutcome, type PurchaseRequest, type PutBytesOptions, type PutSaveOptions, type RankedRow, type RewardCue, type SavePage, type SaveRecord, type SendOptions$1 as SendOptions, type ServerTokenGrant, type SessionEndReason, ShowcaseApi, type ShowcaseCallOptions, type ShowcaseFriendEntry, type ShowcaseFriends, type ShowcaseValue, type SignInOutcome, type SignInOutcomeKind, type SnapshotCurrency, type SnapshotItem, type TransportAdvert, type TransportKind, TransportRefusal, UNRELIABLE_CHANNEL_LABEL, asPlayerText, createBootTimeline, createGem, leaveAndExit, mapIdentity, markOnResolve, platformIconUrl, presentJoinCredential, readTemplateTransports, readTransportAdvert, reportOnResolve, text, webTransportAvailable };
2709
+ export { ARCADE_EMBEDDERS, type AccountApi, type AdFormat, type AdOutcome, type AdOutcomeKind, type AdRequest, type AdsApi, AnalyticsApi, type AnalyticsFlushOptions, type AnalyticsFlushResult, type AnalyticsOptions, type AnalyticsRejection, type AnalyticsValue, AuthError, type AuthFailure, type AuthState, type BootMark, type BootTimeline, type Challenge, type ChallengeWindow, ChallengesApi, type ConfiguredPurchasePayment, type ConfiguredPurchaseRequest, type ConfiguredPurchaseResult, DEVICE_SETTINGS_MAX_BYTES, DedicatedServerError, type DedicatedServerFailure, type DedicatedServerSession, type DevToolsOpener, type DeviceSettings, type DeviceSettingsApi, type DeviceSettingsPutOutcome, type DirectPurchaseRequest, type DirectPurchaseResult, type EntityLeaderboard, type EntityLeaderboardEntry, type EntityLeaderboardOptions, type EntityType, type ExitAnalytics, type ExitBridge, type ExitRooms, type FrameState, type Friend, FriendsApi, type FriendsPage, type FunctionFailure, type FunctionInvokeOptions, type FunctionResult, FunctionsApi, type GameConfig, type GameServerLink, type Gem, GemApiError, GemClient, type GemCohort, type GemCohorts, GemConfigError, type GemDevTools, GemFrame, GemFunctionError, type GemIdentity, type GemInsets, type GemMatchApi, type GemMatchServerModule, type GemOptions, type GemPlayer, type GemPrefs, GemSaveError, type GemServerBundle, type GemServerFactory, type GemServerHost, type GemServerHostProfile, type GemServerLifecycle, type GemTerminationNotice, type GemViewport, type GetLeaderboardOptions, type JoinWelcome, type Leaderboard, type LeaderboardEntry, LeaderboardsApi, type ListChallengesOptions, type ListFriendsOptions, MAX_PERIODS_BACK, type MatchConnectOptions, type MatchConnection, type MatchHosting, type MatchHostingMode, type MatchServeOptions, type MatchTransport, type MessageMeta, type MultiTransportSession, PLATFORM_EVENTS, PlatformApi, PlatformCurrenciesApi, type PlatformCurrency, type PlatformCurrencyAccess, type PlatformCurrencyPurchasePayment, type PlatformCurrencyPurchaseRequest, type PlatformCurrencyPurchaseResult, type PlatformCurrencyReadOptions, type PlatformEventName, type PlayerBadge, type PlayerBoost, type PlayerBoostMultiplier, type PlayerIdentity, type PlayerProfile, PlayerText, type ProfileCallOptions, type ProfileShowcaseEntry, ProfilesApi, type PurchaseApi, type PurchaseOptions, type PurchaseOutcome, type PurchaseRequest, type PutBytesOptions, type PutSaveOptions, type RankedRow, type RecipeAvailability, type RecipeLock, type RewardCue, type SavePage, type SaveRecord, type SendOptions$1 as SendOptions, type ServerTokenGrant, type SessionEndReason, ShowcaseApi, type ShowcaseCallOptions, type ShowcaseFriendEntry, type ShowcaseFriends, type ShowcaseValue, type SignInOutcome, type SignInOutcomeKind, type SnapshotCurrency, type SnapshotItem, type TransportAdvert, type TransportKind, TransportRefusal, UNRELIABLE_CHANNEL_LABEL, asPlayerText, createBootTimeline, createGem, leaveAndExit, mapIdentity, markOnResolve, platformIconUrl, presentJoinCredential, readTemplateTransports, readTransportAdvert, reportOnResolve, text, webTransportAvailable };
@@ -1 +1 @@
1
- var GemWebSdkBridgeBundle=(function(){'use strict';var b="GemWebSdkHandshake";function z(){return typeof document>"u"?void 0:document.readyState}var C=()=>Date.now();function I(n={}){let e=n.win??window,t=e,r=t[b];if(r!==void 0)return r;let i=n.readyState??z,s=n.now??C,d=[],o=[],m=g=>{let u=g.data;!u||u.type!=="gem.handshake"||(d.length>=4&&(d.shift(),o.shift(),c.dropped+=1),d.push(g),o.push(s()));};e.addEventListener("message",m);let c={events:d,times:o,dropped:0,late:i()==="complete",uninstall(){e.removeEventListener("message",m);}};return t[b]=c,c}function q(n,e,t={}){let r=n[b];if(r===void 0)return null;let i=t.ttlMs??9500,s=t.now??C,d=r.events.splice(0),o=r.times?.splice(0),m=0,c=0,g=false,u=s()-i;for(let k=d.length-1;k>=0;k--){let P=o?.[k];if(P!==void 0&&P<u){c+=1;continue}if(m+=1,e(d[k])===true){g=true;break}}return r.uninstall(),{capture:r,delivered:m,stale:c,accepted:g}}var l="gem-web-bridge",y={min:1,max:1},p=65536,L=8,v=5e3,_=1024;function R(n){return Object.freeze(Object.assign(Object.create(null),n))}var j=R({"gem.handshake":30,"gem.handshake.accept":5,"gem.token":30,"gem.token.denied":30,"gem.player":12,"gem.pause":120,"gem.prefs":60,"gem.cohorts":12,"gem.viewport":60,"gem.deviceSettings":12,"gem.willTerminate":10,"gem.roomEvent":120,"gem.socketState":12,"gem.seatedEvent":60,"gem.autoStartFailedEvent":30,"gem.signalEvent":1800,"gem.dedicatedEvent":120,"gem.partyResult":30,"gem.clusterTarget":12,"gem.devtools":30,"gem.screenshot":6,"gem.screenshot.denied":12,"gem.requestContext":12,"gem.gameContext":12,"gem.signal":1200,"gem.dedicatedOffer":60,"gem.partyRequest":12,"gem.ready":5,"gem.progress":600,"gem.requestToken":12,"gem.requestLocalServer":6,"gem.localServer":30,"gem.localServer.denied":30,"gem.exit":5,"gem.openExternal":6,"gem.requestFullscreen":30,"gem.audioState":120,"gem.rewardCue":60,"gem.frameStats":120,"gem.error":60,"gem.requestPurchase":12,"gem.purchaseResult":30,"gem.deviceSettings.put":30,"gem.deviceSettings.result":30,"gem.requestAd":6,"gem.adResult":12,"gem.requestSignIn":6,"gem.signInResult":12,__malformed:60}),x="__malformed";var B=R({"gem.requestAd":"ads","gem.adResult":"ads","gem.requestSignIn":"signIn","gem.signInResult":"signIn","gem.requestPurchase":"purchases","gem.purchaseResult":"purchases","gem.devtools":"devtools","gem.screenshot":"screenshot","gem.screenshot.denied":"screenshot","gem.requestContext":"feedbackContext","gem.gameContext":"feedbackContext","gem.roomEvent":"rooms","gem.signal":"p2p","gem.signalEvent":"p2p","gem.dedicatedOffer":"dedicated","gem.dedicatedEvent":"dedicated","gem.clusterTarget":"clusterTarget","gem.partyRequest":"parties","gem.partyResult":"parties","gem.autoStartFailedEvent":"autoStartFailure","gem.seatedEvent":"partySeating","gem.socketState":"socketState","gem.audioState":"audioState","gem.rewardCue":"rewardCue","gem.frameStats":"frameStats","gem.viewport":"viewport","gem.requestLocalServer":"localHost","gem.localServer":"localHost","gem.localServer.denied":"localHost","gem.cohorts":"cohorts","gem.deviceSettings":"deviceSettings","gem.deviceSettings.put":"deviceSettings","gem.deviceSettings.result":"deviceSettings"}),K=Object.freeze([["gem.asyncOpponents.","asyncOpponents"]]);function A(n){let e=B[n];if(e!==void 0)return e;for(let[t,r]of K)if(n.startsWith(t))return r}function Y(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 X(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 J(n){return /^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i.test(n)}function S(n,e,t){if(e>L)return `nesting deeper than ${L}`;if(++t.nodes>v)return `more than ${v} values`;if(t.bytes>p)return `over the ${p} 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 i=n;if(t.seen.has(i))return "a repeated or cyclic object reference";if(t.seen.add(i),Array.isArray(n)){if(n.length>_)return `an array of ${n.length} entries, over the ${_} limit`;t.bytes+=2;for(let o of n){let m=S(o,e+1,t);if(m)return m}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 o in d){if(!Object.prototype.hasOwnProperty.call(d,o))continue;if(++t.nodes>v)return `more than ${v} values`;if(t.bytes+=o.length*3+4,t.bytes>p)return `over the ${p} byte limit`;let m=S(d[o],e+1,t);if(m)return m}return null}function Q(n){let e={nodes:0,bytes:0,seen:new Set},t=S(n,0,e);return t?`message contains ${t}`:e.bytes>p?`message is over the ${p} byte limit`:null}var Z={origin:[Y,"not a well-formed origin"],url:[X,"not a safe absolute http(s) URL"],bcp47:[J,"not a well-formed BCP 47 tag"]};function M(n,e,t){for(let r of e){let i=t===""?r.n:`${t}.${r.n}`,s=n[r.n];if(s==null){if(r.o)continue;return `${i}: required`}let d=D(s,r,i);if(d)return d}return null}function D(n,e,t){switch(e.k){case "string":{if(typeof n!="string")return `${t}: expected string`;if(n.length>e.max)return `${t}: exceeds ${e.max} characters`;if(e.f){let[r,i]=Z[e.f];if(!r(n))return `${t}: ${i}`}return null}case "int":return typeof n!="number"||!Number.isInteger(n)?`${t}: expected integer`:n<e.lo||n>e.hi?`${t}: out of range ${e.lo}..${e.hi}`:null;case "boolean":return typeof n=="boolean"?null:`${t}: expected boolean`;case "enum":{let r=e.v;return r.includes(n)?null:`${t}: not one of ${r.join("|")}`}case "object":return typeof n!="object"||n===null||Array.isArray(n)?`${t}: expected object`:M(n,e.fs,t);case "json":return typeof n!="object"||n===null||Array.isArray(n)?`${t}: expected a plain object`:null;case "array":{if(!Array.isArray(n))return `${t}: expected array`;if(n.length>e.max)return `${t}: exceeds ${e.max} items`;let r=e.it,i=`${t}[]`;for(let s of n){if(s==null){if(r.o)continue;return `${i}: required`}let d=D(s,r,i);if(d)return d}return null}default:{let r=e.k;return `${t}: unknown kind ${String(r)}`}}}function a(n,e){return t=>{let r=Q(t);if(r)return r;if(typeof t!="object"||t===null||Array.isArray(t))return "message: expected object";let i=t;return i.gem!==l?"gem: wrong protocol marker":i.type!==n?`type: expected ${n}`:M(i,e,"")}}var ee=a("gem.handshake",[{n:"versions",k:"object",fs:[{n:"min",k:"int",lo:1,hi:1e3},{n:"max",k:"int",lo:1,hi:1e3}]},{n:"capabilities",k:"array",o:1,max:64,it:{n:"",k:"string",max:64}},{n:"embedder",k:"string",max:2048,f:"origin"}]),te=a("gem.handshake.accept",[{n:"v",k:"int",lo:1,hi:1e3},{n:"capabilities",k:"array",o:1,max:64,it:{n:"",k:"string",max:64}}]),ne=a("gem.token",[{n:"token",k:"string",max:4096},{n:"requestId",k:"string",o:1,max:64},{n:"generation",k:"int",lo:0,hi:2147483647},{n:"apiBaseUrl",k:"string",o:1,max:512,f:"url"},{n:"playerId",k:"string",max:64},{n:"gameId",k:"string",max:64},{n:"channel",k:"enum",v:["dev","test","release"]},{n:"gameVersion",k:"string",o:1,max:64},{n:"expiresAt",k:"int",lo:0,hi:4102444800},{n:"chainEndsAt",k:"int",lo:0,hi:4102444800},{n:"allowDevTools",k:"boolean",o:1}]),re=a("gem.token.denied",[{n:"requestId",k:"string",max:64},{n:"retryable",k:"boolean"},{n:"retryAfterMs",k:"int",o:1,lo:0,hi:36e5},{n:"reason",k:"enum",v:["chain_exhausted","unavailable"]},{n:"correlationId",k:"string",max:64}]),oe=a("gem.player",[{n:"untrusted",k:"object",fs:[{n:"displayName",k:"string",max:64},{n:"displayTag",k:"string",o:1,max:80},{n:"displayHandle",k:"string",max:80}]},{n:"playerId",k:"string",o:1,max:64},{n:"discriminator",k:"string",o:1,max:8},{n:"avatarIconUrl",k:"string",o:1,max:2048,f:"url"},{n:"badges",k:"array",o:1,max:2,it:{n:"",k:"object",fs:[{n:"itemId",k:"string",max:64},{n:"iconUrl",k:"string",max:2048,f:"url"}]}},{n:"displayTag",k:"string",max:8},{n:"avatarUrl",k:"string",o:1,max:2048,f:"url"}]),ae=a("gem.pause",[{n:"paused",k:"boolean"}]),se=a("gem.prefs",[{n:"reducedMotion",k:"boolean"},{n:"muted",k:"boolean"},{n:"showFrameStats",k:"boolean",o:1},{n:"locale",k:"string",max:35,f:"bcp47"}]),ie=a("gem.cohorts",[{n:"cohorts",k:"array",max:8,it:{n:"",k:"object",fs:[{n:"experimentId",k:"string",max:36},{n:"variantKey",k:"string",max:32}]}}]),de=a("gem.viewport",[{n:"insets",k:"object",fs:[{n:"top",k:"int",lo:0,hi:4096},{n:"right",k:"int",lo:0,hi:4096},{n:"bottom",k:"int",lo:0,hi:4096},{n:"left",k:"int",lo:0,hi:4096}]}]),le=a("gem.deviceSettings",[{n:"settings",k:"json",o:1}]),me=a("gem.willTerminate",[{n:"reason",k:"enum",v:["grant_expiring","session_ended","navigating","kill_switch"]},{n:"graceMs",k:"int",lo:0,hi:6e4}]),ce=a("gem.roomEvent",[{n:"event",k:"enum",v:["updated","match_started","match_ready","match_failed","version_stale"]},{n:"roomId",k:"string",max:64},{n:"matchId",k:"string",o:1,max:64},{n:"version",k:"int",o:1,lo:0,hi:2147483647},{n:"reason",k:"string",o:1,max:64},{n:"platform",k:"enum",o:1,v:["universal","mobile"]}]),ge=a("gem.socketState",[{n:"connected",k:"boolean"},{n:"reason",k:"enum",o:1,v:["connecting","dropped","watchdog","terminal"]}]),ue=a("gem.seatedEvent",[{n:"roomId",k:"string",max:64}]),pe=a("gem.autoStartFailedEvent",[{n:"roomId",k:"string",max:64},{n:"code",k:"string",max:64}]),ye=a("gem.signalEvent",[{n:"event",k:"enum",v:["hello","offer","answer","ice","peerJoined","peerLeft","migration","matchEnded","error"]},{n:"matchId",k:"string",max:64},{n:"data",k:"json"}]),fe=a("gem.dedicatedEvent",[{n:"event",k:"enum",v:["answer","error","matchEnded"]},{n:"matchId",k:"string",max:64},{n:"sdp",k:"string",o:1,max:10240},{n:"sessionId",k:"string",o:1,max:64},{n:"code",k:"string",o:1,max:64},{n:"message",k:"string",o:1,max:256},{n:"reason",k:"string",o:1,max:64}]),he=a("gem.partyResult",[{n:"requestId",k:"string",max:64},{n:"partyId",k:"string",o:1,max:64}]),ke=a("gem.clusterTarget",[{n:"clusterTargetId",k:"string",max:64},{n:"clusterTargetIds",k:"array",o:1,max:3,it:{n:"",k:"string",max:64}}]),ve=a("gem.devtools",[{n:"action",k:"enum",v:["open","close","toggle"]}]),xe=a("gem.screenshot",[{n:"maxWidth",k:"int",lo:1,hi:7680},{n:"maxHeight",k:"int",lo:1,hi:4320}]),we=a("gem.screenshot.denied",[{n:"reason",k:"enum",v:["not_wired","no_source","unsupported","unreadable","tainted","too_large","busy","declined","failed"]},{n:"retryable",k:"boolean"}]),be=a("gem.requestContext",[]),Se=a("gem.gameContext",[{n:"context",k:"json"}]),Re=a("gem.signal",[{n:"signal",k:"enum",v:["join","offer","answer","ice","migrationAck","hostUnreachable"]},{n:"matchId",k:"string",max:64},{n:"data",k:"json"}]),Ge=a("gem.dedicatedOffer",[{n:"matchId",k:"string",max:64},{n:"sdp",k:"string",max:10240},{n:"intent",k:"enum",v:["initial","ice_restart","full_reconnect"]}]),Oe=a("gem.partyRequest",[{n:"requestId",k:"string",max:64}]),Te=a("gem.ready",[]),Ee=a("gem.progress",[{n:"loaded",k:"int",lo:0,hi:1099511627776},{n:"total",k:"int",lo:0,hi:1099511627776}]),Pe=a("gem.requestToken",[{n:"requestId",k:"string",max:64},{n:"reason",k:"enum",v:["initial","expiring","rejected"]}]),Ce=a("gem.requestLocalServer",[{n:"requestId",k:"string",max:64},{n:"gameRoomId",k:"string",max:64}]),Ie=a("gem.localServer",[{n:"requestId",k:"string",max:64},{n:"serverId",k:"string",o:1,max:128}]),qe=a("gem.localServer.denied",[{n:"requestId",k:"string",max:64},{n:"retryable",k:"boolean"},{n:"reason",k:"enum",v:["refused","unavailable"]}]),Le=a("gem.exit",[{n:"reason",k:"string",o:1,max:64}]),_e=a("gem.openExternal",[{n:"url",k:"string",max:2048,f:"url"}]),je=a("gem.requestFullscreen",[{n:"enabled",k:"boolean"}]),Ae=a("gem.audioState",[{n:"muted",k:"boolean"}]),Me=a("gem.rewardCue",[{n:"currencySlug",k:"string",max:32},{n:"expected",k:"int",o:1,lo:1,hi:1e9},{n:"origin",k:"object",o:1,fs:[{n:"x",k:"int",lo:0,hi:16384},{n:"y",k:"int",lo:0,hi:16384}]}]),De=a("gem.frameStats",[{n:"fps",k:"int",lo:0,hi:1e3},{n:"frameTimeP95Ms",k:"int",lo:0,hi:1e5}]),Fe=a("gem.error",[{n:"code",k:"enum",v:["version_mismatch","handshake_timeout","handshake_duplicate","invalid_message","rate_limited","token_unavailable","unsupported","unsupported_capability","internal"]},{n:"message",k:"string",o:1,max:256}]),$e=a("gem.requestPurchase",[{n:"requestId",k:"string",max:64},{n:"purchaseKind",k:"enum",v:["item","recipe"]},{n:"targetId",k:"string",max:64},{n:"currencySlug",k:"string",max:32},{n:"quantity",k:"int",o:1,lo:1,hi:10},{n:"catalogId",k:"string",o:1,max:64}]),He=a("gem.purchaseResult",[{n:"requestId",k:"string",max:64},{n:"outcome",k:"enum",v:["ok","declined","unavailable"]},{n:"purchaseId",k:"string",o:1,max:64}]),Ue=a("gem.deviceSettings.put",[{n:"requestId",k:"string",max:64},{n:"settings",k:"json"}]),We=a("gem.deviceSettings.result",[{n:"requestId",k:"string",max:64},{n:"outcome",k:"enum",v:["stored","too_large","unavailable"]}]),Ne=a("gem.requestAd",[{n:"requestId",k:"string",max:64},{n:"placement",k:"string",max:32},{n:"format",k:"enum",v:["interstitial","rewarded"]}]),Ve=a("gem.adResult",[{n:"requestId",k:"string",max:64},{n:"outcome",k:"enum",v:["shown","no_ad","unavailable"]}]),ze=a("gem.requestSignIn",[{n:"requestId",k:"string",max:64}]),Be=a("gem.signInResult",[{n:"requestId",k:"string",max:64},{n:"outcome",k:"enum",v:["signed_in","declined","unavailable"]}]),w=R({"gem.handshake":ee,"gem.handshake.accept":te,"gem.token":ne,"gem.token.denied":re,"gem.player":oe,"gem.pause":ae,"gem.prefs":se,"gem.cohorts":ie,"gem.viewport":de,"gem.deviceSettings":le,"gem.willTerminate":me,"gem.roomEvent":ce,"gem.socketState":ge,"gem.seatedEvent":ue,"gem.autoStartFailedEvent":pe,"gem.signalEvent":ye,"gem.dedicatedEvent":fe,"gem.partyResult":he,"gem.clusterTarget":ke,"gem.devtools":ve,"gem.screenshot":xe,"gem.screenshot.denied":we,"gem.requestContext":be,"gem.gameContext":Se,"gem.signal":Re,"gem.dedicatedOffer":Ge,"gem.partyRequest":Oe,"gem.ready":Te,"gem.progress":Ee,"gem.requestToken":Pe,"gem.requestLocalServer":Ce,"gem.localServer":Ie,"gem.localServer.denied":qe,"gem.exit":Le,"gem.openExternal":_e,"gem.requestFullscreen":je,"gem.audioState":Ae,"gem.rewardCue":Me,"gem.frameStats":De,"gem.error":Fe,"gem.requestPurchase":$e,"gem.purchaseResult":He,"gem.deviceSettings.put":Ue,"gem.deviceSettings.result":We,"gem.requestAd":Ne,"gem.adResult":Ve,"gem.requestSignIn":ze,"gem.signInResult":Be});var G=class{#e;constructor(e){this.#e=e,Object.freeze(this);}toString(){return "[gem: use gem.text.toPlain()]"}toJSON(){return this.toString()}get[Symbol.toStringTag](){return "PlayerText"}static unwrap(e){return e.#e}};function O(n){return new G(n)}var T={now:()=>Date.now(),setTimeout:(n,e)=>setTimeout(n,e),clearTimeout:n=>clearTimeout(n)},f=class{constructor(e=T){this.clock=e;}clock;tokens=new Map;lastRefill=new Map;allow(e){let t=j[e];if(t===void 0)return false;let r=this.clock.now(),i=this.lastRefill.get(e)??r,s=this.tokens.get(e)??t,d=Math.max(0,r-i),o=Math.min(t,s+d*t/6e4);return o<1?(this.tokens.set(e,o),this.lastRefill.set(e,r),false):(this.tokens.set(e,o-1),this.lastRefill.set(e,r),true)}};function E(n,e){return n.toLowerCase()===e.toLowerCase()}function F(n){let e=n.toLowerCase();return e==="localhost"||e.endsWith(".localhost")||e==="[::1]"||e==="::1"?true:/^127(\.\d{1,3}){3}$/.test(e)}function $(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:F(t.hostname)&&F(r.hostname)}function H(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}function U(n){return Math.min(16384,Math.max(0,Math.round(Number.isFinite(n)?n:0)))}function W(n,e){return Math.min(e,Math.max(0,Math.round(Number.isFinite(n)?n:0)))}function Ke(n){let e=n.untrusted,t=O(e.displayName),r=e.displayTag||e.displayHandle,i=r?O(r):void 0,s=n.discriminator||n.displayTag,d=s&&/^[0-9]{1,8}$/.test(s)?s:void 0,o=n.avatarIconUrl||n.avatarUrl,m={displayName:t,displayHandle:i??t,badges:(n.badges??[]).map(c=>({itemId:c.itemId,iconUrl:c.iconUrl}))};return n.playerId&&(m.playerId=n.playerId),d&&(m.discriminator=d),i&&(m.displayTag=i),o&&(m.avatarIconUrl=m.avatarUrl=o),m}var Ye=1e4,h=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??T,this.inbound=new f(this.clock),this.outbound=new f(this.clock);}options;state="waiting";port=null;version=null;peerCapabilities=[];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}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(o=>E(o,e.origin))||$(e.origin,this.options.selfOrigin)))return this.refuse(e,`embedder '${e.origin}' is not in allowedEmbedders`),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=w["gem.handshake"]?.(e.data);if(r)return this.refuse(e,`malformed handshake: ${r}`),false;let i=e.data;if(!E(i.embedder,e.origin))return this.refuse(e,`handshake claims embedder '${i.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=H(y,i.versions);return d===null?(s.onmessage=null,s.postMessage({gem:l,type:"gem.error",code:"version_mismatch",message:`frame supports v${y.min}..v${y.max}`}),s.close(),this.transition("refused"),this.options.onError?.("version_mismatch"),false):(this.port=s,this.version=d,s.onmessage=o=>this.receive(o.data,o.ports??[]),s.start?.(),this.peerCapabilities=i.capabilities??[],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=Ye){return this.state!=="waiting"?Promise.resolve(this.state):new Promise(t=>{let r=s=>{this.clock.clearTimeout(i),t(s);},i=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.state!=="connected"||!this.parentSupports("audioState")?false:(this.send({gem:l,type:"gem.audioState",muted:e}),true)}cueReward(e){if(this.state!=="connected"||!this.parentSupports("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:U(e.origin.x),y:U(e.origin.y)}),this.send(t),true}reportFrameStats(e){return this.state!=="connected"||!this.parentSupports("frameStats")?false:(this.send({gem:l,type:"gem.frameStats",fps:W(e.fps,1e3),frameTimeP95Ms:W(e.frameTimeP95Ms,1e5)}),true)}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,i,s,d){return this.send({gem:l,type:"gem.requestPurchase",requestId:e,purchaseKind:t,targetId:r,currencySlug:i,...s===void 0?{}:{quantity:s},...d===void 0?{}:{catalogId:d}})}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})}requestSignIn(e){return this.send({gem:l,type:"gem.requestSignIn",requestId: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(x)){this.options.onDropped?.(e,t);return}this.fail(e,t);}dropUnknownType(e){this.inbound.allow(x)&&this.options.onDropped?.("unsupported",`ignored unknown message type '${e}'`);}refuse(e,t){e.ports?.[0]?.close?.(),this.inbound.allow(x)&&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}});}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=w[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||N(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 i=w[r];if(!i)return this.dropUnknownType(r),false;if(!this.inbound.allow(r))return this.fail("rate_limited",`parent exceeded the limit for ${r}`),false;let s=A(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=i(e);if(d)return this.fail("invalid_message",`${r}: ${d}`),false;let o=e;if(o.v!==this.version)return this.fail("invalid_message",`${r}: expected v ${String(this.version)}`),false;switch(r){case "gem.token":this.options.onToken?.(o);break;case "gem.pause":this.options.onPause?.(o);break;case "gem.prefs":this.options.onPrefs?.(o);break;case "gem.cohorts":this.options.onCohorts?.(o);break;case "gem.viewport":this.options.onViewport?.(o);break;case "gem.willTerminate":this.options.onWillTerminate?.(o);break;case "gem.devtools":this.options.onDevtools?.(o.action);break;case "gem.requestContext":this.options.onRequestContext?.();break;case "gem.screenshot":{let m=t[0];if(!m){this.options.onError?.("invalid_message","gem.screenshot transferred no MessagePort");break}let c={maxWidth:o.maxWidth,maxHeight:o.maxHeight};if(!this.options.onScreenshot){m.close(),this.screenshotDenied("not_wired",false);break}return N(t.slice(1)),this.options.onScreenshot(c,m,(g,u)=>this.screenshotDenied(g,u)),true}case "gem.token.denied":this.options.onTokenDenied?.(o);break;case "gem.localServer":this.options.onLocalServer?.(o);break;case "gem.localServer.denied":this.options.onLocalServerDenied?.(o);break;case "gem.player":{this.options.onPlayer?.(Ke(o));break}case "gem.roomEvent":this.options.onRoomEvent?.(o);break;case "gem.seatedEvent":this.options.onSeatedEvent?.(o);break;case "gem.autoStartFailedEvent":this.options.onAutoStartFailedEvent?.(o);break;case "gem.socketState":this.options.onSocketState?.(o);break;case "gem.signalEvent":this.options.onSignalEvent?.(o);break;case "gem.dedicatedEvent":this.options.onDedicatedEvent?.(o);break;case "gem.clusterTarget":this.options.onClusterTarget?.(o);break;case "gem.partyResult":this.options.onPartyResult?.(o);break;case "gem.purchaseResult":this.options.onPurchaseResult?.(o);break;case "gem.deviceSettings":this.options.onDeviceSettings?.(o);break;case "gem.deviceSettings.result":this.options.onDeviceSettingsResult?.(o);break;case "gem.adResult":this.options.onAdResult?.(o);break;case "gem.signInResult":this.options.onSignInResult?.(o);break;case "gem.error":this.options.onError?.(o.code,o.message);break;default: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 N(n){for(let e of n)try{e?.close?.();}catch{}}I();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 h({...n,expectedSource:n.expectedSource??window.parent}),t=r=>{let i=e.handleWindowMessage({data:r.data,origin:r.origin,source:r.source,ports:r.ports});return i&&window.removeEventListener("message",t),i};return window.addEventListener("message",t),q(window,t),e}var V={connect:Xe,GemFrame:h,PROTOCOL:l,SUPPORTED_VERSIONS:y};window.GemWebSdkBridge=V;var lt=V;return lt;})();
1
+ var GemWebSdkBridgeBundle=(function(){'use strict';var b="GemWebSdkHandshake";function B(){return typeof document>"u"?void 0:document.readyState}var C=()=>Date.now();function I(n={}){let e=n.win??window,t=e,r=t[b];if(r!==void 0)return r;let i=n.readyState??B,s=n.now??C,d=[],o=[],m=g=>{let p=g.data;!p||p.type!=="gem.handshake"||(d.length>=4&&(d.shift(),o.shift(),u.dropped+=1),d.push(g),o.push(s()));};e.addEventListener("message",m);let u={events:d,times:o,dropped:0,late:i()==="complete",uninstall(){e.removeEventListener("message",m);}};return t[b]=u,u}function q(n,e,t={}){let r=n[b];if(r===void 0)return null;let i=t.ttlMs??9500,s=t.now??C,d=r.events.splice(0),o=r.times?.splice(0),m=0,u=0,g=false,p=s()-i;for(let c=d.length-1;c>=0;c--){let E=o?.[c];if(E!==void 0&&E<p){u+=1;continue}if(m+=1,e(d[c])===true){g=true;break}}return r.uninstall(),{capture:r,delivered:m,stale:u,accepted:g}}var l="gem-web-bridge",f={min:1,max:1},y=65536,L=8,v=5e3,_=1024;function R(n){return Object.freeze(Object.assign(Object.create(null),n))}var j=R({"gem.handshake":30,"gem.handshake.accept":5,"gem.token":30,"gem.token.denied":30,"gem.player":12,"gem.pause":120,"gem.prefs":60,"gem.cohorts":12,"gem.viewport":60,"gem.deviceSettings":12,"gem.willTerminate":10,"gem.roomEvent":120,"gem.socketState":12,"gem.seatedEvent":60,"gem.autoStartFailedEvent":30,"gem.signalEvent":1800,"gem.dedicatedEvent":120,"gem.partyResult":30,"gem.clusterTarget":12,"gem.devtools":30,"gem.screenshot":6,"gem.screenshot.denied":12,"gem.requestContext":12,"gem.gameContext":12,"gem.signal":1200,"gem.dedicatedOffer":60,"gem.partyRequest":12,"gem.ready":5,"gem.progress":600,"gem.requestToken":12,"gem.requestLocalServer":6,"gem.localServer":30,"gem.localServer.denied":30,"gem.exit":5,"gem.openExternal":6,"gem.requestFullscreen":30,"gem.audioState":120,"gem.rewardCue":60,"gem.frameStats":120,"gem.error":60,"gem.requestPurchase":12,"gem.purchaseResult":30,"gem.deviceSettings.put":30,"gem.deviceSettings.result":30,"gem.requestAd":6,"gem.adResult":12,"gem.requestSignIn":6,"gem.signInResult":12,__malformed:60}),x="__malformed";var z=R({"gem.requestAd":"ads","gem.adResult":"ads","gem.requestSignIn":"signIn","gem.signInResult":"signIn","gem.requestPurchase":"purchases","gem.purchaseResult":"purchases","gem.devtools":"devtools","gem.screenshot":"screenshot","gem.screenshot.denied":"screenshot","gem.requestContext":"feedbackContext","gem.gameContext":"feedbackContext","gem.roomEvent":"rooms","gem.signal":"p2p","gem.signalEvent":"p2p","gem.dedicatedOffer":"dedicated","gem.dedicatedEvent":"dedicated","gem.clusterTarget":"clusterTarget","gem.partyRequest":"parties","gem.partyResult":"parties","gem.autoStartFailedEvent":"autoStartFailure","gem.seatedEvent":"partySeating","gem.socketState":"socketState","gem.audioState":"audioState","gem.rewardCue":"rewardCue","gem.frameStats":"frameStats","gem.viewport":"viewport","gem.requestLocalServer":"localHost","gem.localServer":"localHost","gem.localServer.denied":"localHost","gem.cohorts":"cohorts","gem.deviceSettings":"deviceSettings","gem.deviceSettings.put":"deviceSettings","gem.deviceSettings.result":"deviceSettings"}),K=Object.freeze([["gem.asyncOpponents.","asyncOpponents"]]);function A(n){let e=z[n];if(e!==void 0)return e;for(let[t,r]of K)if(n.startsWith(t))return r}function Y(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 X(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 J(n){return /^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i.test(n)}function S(n,e,t){if(e>L)return `nesting deeper than ${L}`;if(++t.nodes>v)return `more than ${v} values`;if(t.bytes>y)return `over the ${y} 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 i=n;if(t.seen.has(i))return "a repeated or cyclic object reference";if(t.seen.add(i),Array.isArray(n)){if(n.length>_)return `an array of ${n.length} entries, over the ${_} limit`;t.bytes+=2;for(let o of n){let m=S(o,e+1,t);if(m)return m}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 o in d){if(!Object.prototype.hasOwnProperty.call(d,o))continue;if(++t.nodes>v)return `more than ${v} values`;if(t.bytes+=o.length*3+4,t.bytes>y)return `over the ${y} byte limit`;let m=S(d[o],e+1,t);if(m)return m}return null}function Q(n){let e={nodes:0,bytes:0,seen:new Set},t=S(n,0,e);return t?`message contains ${t}`:e.bytes>y?`message is over the ${y} byte limit`:null}var Z={origin:[Y,"not a well-formed origin"],url:[X,"not a safe absolute http(s) URL"],bcp47:[J,"not a well-formed BCP 47 tag"]};function D(n,e,t){for(let r of e){let i=t===""?r.n:`${t}.${r.n}`,s=n[r.n];if(s==null){if(r.o)continue;return `${i}: required`}let d=M(s,r,i);if(d)return d}return null}function M(n,e,t){switch(e.k){case "string":{if(typeof n!="string")return `${t}: expected string`;if(n.length>e.max)return `${t}: exceeds ${e.max} characters`;if(e.f){let[r,i]=Z[e.f];if(!r(n))return `${t}: ${i}`}return null}case "int":return typeof n!="number"||!Number.isInteger(n)?`${t}: expected integer`:n<e.lo||n>e.hi?`${t}: out of range ${e.lo}..${e.hi}`:null;case "boolean":return typeof n=="boolean"?null:`${t}: expected boolean`;case "enum":{let r=e.v;return r.includes(n)?null:`${t}: not one of ${r.join("|")}`}case "object":return typeof n!="object"||n===null||Array.isArray(n)?`${t}: expected object`:D(n,e.fs,t);case "json":return typeof n!="object"||n===null||Array.isArray(n)?`${t}: expected a plain object`:null;case "array":{if(!Array.isArray(n))return `${t}: expected array`;if(n.length>e.max)return `${t}: exceeds ${e.max} items`;let r=e.it,i=`${t}[]`;for(let s of n){if(s==null){if(r.o)continue;return `${i}: required`}let d=M(s,r,i);if(d)return d}return null}default:{let r=e.k;return `${t}: unknown kind ${String(r)}`}}}function a(n,e){return t=>{let r=Q(t);if(r)return r;if(typeof t!="object"||t===null||Array.isArray(t))return "message: expected object";let i=t;return i.gem!==l?"gem: wrong protocol marker":i.type!==n?`type: expected ${n}`:D(i,e,"")}}var ee=a("gem.handshake",[{n:"versions",k:"object",fs:[{n:"min",k:"int",lo:1,hi:1e3},{n:"max",k:"int",lo:1,hi:1e3}]},{n:"capabilities",k:"array",o:1,max:64,it:{n:"",k:"string",max:64}},{n:"embedder",k:"string",max:2048,f:"origin"}]),te=a("gem.handshake.accept",[{n:"v",k:"int",lo:1,hi:1e3},{n:"capabilities",k:"array",o:1,max:64,it:{n:"",k:"string",max:64}}]),ne=a("gem.token",[{n:"token",k:"string",max:4096},{n:"requestId",k:"string",o:1,max:64},{n:"generation",k:"int",lo:0,hi:2147483647},{n:"apiBaseUrl",k:"string",o:1,max:512,f:"url"},{n:"playerId",k:"string",max:64},{n:"gameId",k:"string",max:64},{n:"channel",k:"enum",v:["dev","test","release"]},{n:"gameVersion",k:"string",o:1,max:64},{n:"expiresAt",k:"int",lo:0,hi:4102444800},{n:"chainEndsAt",k:"int",lo:0,hi:4102444800},{n:"allowDevTools",k:"boolean",o:1}]),re=a("gem.token.denied",[{n:"requestId",k:"string",max:64},{n:"retryable",k:"boolean"},{n:"retryAfterMs",k:"int",o:1,lo:0,hi:36e5},{n:"reason",k:"enum",v:["chain_exhausted","unavailable"]},{n:"correlationId",k:"string",max:64}]),oe=a("gem.player",[{n:"untrusted",k:"object",fs:[{n:"displayName",k:"string",max:64},{n:"displayTag",k:"string",o:1,max:80},{n:"displayHandle",k:"string",max:80}]},{n:"playerId",k:"string",o:1,max:64},{n:"discriminator",k:"string",o:1,max:8},{n:"avatarIconUrl",k:"string",o:1,max:2048,f:"url"},{n:"badges",k:"array",o:1,max:2,it:{n:"",k:"object",fs:[{n:"itemId",k:"string",max:64},{n:"iconUrl",k:"string",max:2048,f:"url"}]}},{n:"displayTag",k:"string",max:8},{n:"avatarUrl",k:"string",o:1,max:2048,f:"url"},{n:"boost",k:"object",o:1,fs:[{n:"multipliers",k:"array",max:8,it:{n:"",k:"object",fs:[{n:"currencyId",k:"string",max:64},{n:"currencySlug",k:"string",max:32},{n:"multiplierBp",k:"int",lo:1e4,hi:1e6}]}},{n:"expiresInDays",k:"int",o:1,lo:1,hi:7}]}]),ae=a("gem.pause",[{n:"paused",k:"boolean"}]),se=a("gem.prefs",[{n:"reducedMotion",k:"boolean"},{n:"muted",k:"boolean"},{n:"showFrameStats",k:"boolean",o:1},{n:"locale",k:"string",max:35,f:"bcp47"}]),ie=a("gem.cohorts",[{n:"cohorts",k:"array",max:8,it:{n:"",k:"object",fs:[{n:"experimentId",k:"string",max:36},{n:"variantKey",k:"string",max:32}]}}]),de=a("gem.viewport",[{n:"insets",k:"object",fs:[{n:"top",k:"int",lo:0,hi:4096},{n:"right",k:"int",lo:0,hi:4096},{n:"bottom",k:"int",lo:0,hi:4096},{n:"left",k:"int",lo:0,hi:4096}]}]),le=a("gem.deviceSettings",[{n:"settings",k:"json",o:1}]),me=a("gem.willTerminate",[{n:"reason",k:"enum",v:["grant_expiring","session_ended","navigating","kill_switch"]},{n:"graceMs",k:"int",lo:0,hi:6e4}]),ce=a("gem.roomEvent",[{n:"event",k:"enum",v:["updated","match_started","match_ready","match_failed","version_stale"]},{n:"roomId",k:"string",max:64},{n:"matchId",k:"string",o:1,max:64},{n:"version",k:"int",o:1,lo:0,hi:2147483647},{n:"reason",k:"string",o:1,max:64},{n:"platform",k:"enum",o:1,v:["universal","mobile"]}]),ue=a("gem.socketState",[{n:"connected",k:"boolean"},{n:"reason",k:"enum",o:1,v:["connecting","dropped","watchdog","terminal"]}]),ge=a("gem.seatedEvent",[{n:"roomId",k:"string",max:64}]),pe=a("gem.autoStartFailedEvent",[{n:"roomId",k:"string",max:64},{n:"code",k:"string",max:64}]),ye=a("gem.signalEvent",[{n:"event",k:"enum",v:["hello","offer","answer","ice","peerJoined","peerLeft","migration","matchEnded","error"]},{n:"matchId",k:"string",max:64},{n:"data",k:"json"}]),fe=a("gem.dedicatedEvent",[{n:"event",k:"enum",v:["answer","error","matchEnded"]},{n:"matchId",k:"string",max:64},{n:"sdp",k:"string",o:1,max:10240},{n:"sessionId",k:"string",o:1,max:64},{n:"code",k:"string",o:1,max:64},{n:"message",k:"string",o:1,max:256},{n:"reason",k:"string",o:1,max:64}]),he=a("gem.partyResult",[{n:"requestId",k:"string",max:64},{n:"partyId",k:"string",o:1,max:64}]),ke=a("gem.clusterTarget",[{n:"clusterTargetId",k:"string",max:64},{n:"clusterTargetIds",k:"array",o:1,max:3,it:{n:"",k:"string",max:64}}]),ve=a("gem.devtools",[{n:"action",k:"enum",v:["open","close","toggle"]}]),xe=a("gem.screenshot",[{n:"maxWidth",k:"int",lo:1,hi:7680},{n:"maxHeight",k:"int",lo:1,hi:4320}]),we=a("gem.screenshot.denied",[{n:"reason",k:"enum",v:["not_wired","no_source","unsupported","unreadable","tainted","too_large","busy","declined","failed"]},{n:"retryable",k:"boolean"}]),be=a("gem.requestContext",[]),Se=a("gem.gameContext",[{n:"context",k:"json"}]),Re=a("gem.signal",[{n:"signal",k:"enum",v:["join","offer","answer","ice","migrationAck","hostUnreachable"]},{n:"matchId",k:"string",max:64},{n:"data",k:"json"}]),Ge=a("gem.dedicatedOffer",[{n:"matchId",k:"string",max:64},{n:"sdp",k:"string",max:10240},{n:"intent",k:"enum",v:["initial","ice_restart","full_reconnect"]}]),Oe=a("gem.partyRequest",[{n:"requestId",k:"string",max:64}]),Te=a("gem.ready",[]),Pe=a("gem.progress",[{n:"loaded",k:"int",lo:0,hi:1099511627776},{n:"total",k:"int",lo:0,hi:1099511627776}]),Ee=a("gem.requestToken",[{n:"requestId",k:"string",max:64},{n:"reason",k:"enum",v:["initial","expiring","rejected"]}]),Ce=a("gem.requestLocalServer",[{n:"requestId",k:"string",max:64},{n:"gameRoomId",k:"string",max:64}]),Ie=a("gem.localServer",[{n:"requestId",k:"string",max:64},{n:"serverId",k:"string",o:1,max:128}]),qe=a("gem.localServer.denied",[{n:"requestId",k:"string",max:64},{n:"retryable",k:"boolean"},{n:"reason",k:"enum",v:["refused","unavailable"]}]),Le=a("gem.exit",[{n:"reason",k:"string",o:1,max:64}]),_e=a("gem.openExternal",[{n:"url",k:"string",max:2048,f:"url"}]),je=a("gem.requestFullscreen",[{n:"enabled",k:"boolean"}]),Ae=a("gem.audioState",[{n:"muted",k:"boolean"}]),De=a("gem.rewardCue",[{n:"currencySlug",k:"string",max:32},{n:"expected",k:"int",o:1,lo:1,hi:1e9},{n:"origin",k:"object",o:1,fs:[{n:"x",k:"int",lo:0,hi:16384},{n:"y",k:"int",lo:0,hi:16384}]}]),Me=a("gem.frameStats",[{n:"fps",k:"int",lo:0,hi:1e3},{n:"frameTimeP95Ms",k:"int",lo:0,hi:1e5}]),Fe=a("gem.error",[{n:"code",k:"enum",v:["version_mismatch","handshake_timeout","handshake_duplicate","invalid_message","rate_limited","token_unavailable","unsupported","unsupported_capability","internal"]},{n:"message",k:"string",o:1,max:256}]),$e=a("gem.requestPurchase",[{n:"requestId",k:"string",max:64},{n:"purchaseKind",k:"enum",v:["item","recipe"]},{n:"targetId",k:"string",max:64},{n:"currencySlug",k:"string",max:32},{n:"quantity",k:"int",o:1,lo:1,hi:10},{n:"catalogId",k:"string",o:1,max:64}]),He=a("gem.purchaseResult",[{n:"requestId",k:"string",max:64},{n:"outcome",k:"enum",v:["ok","declined","unavailable"]},{n:"purchaseId",k:"string",o:1,max:64}]),Ue=a("gem.deviceSettings.put",[{n:"requestId",k:"string",max:64},{n:"settings",k:"json"}]),We=a("gem.deviceSettings.result",[{n:"requestId",k:"string",max:64},{n:"outcome",k:"enum",v:["stored","too_large","unavailable"]}]),Ne=a("gem.requestAd",[{n:"requestId",k:"string",max:64},{n:"placement",k:"string",max:32},{n:"format",k:"enum",v:["interstitial","rewarded"]}]),Ve=a("gem.adResult",[{n:"requestId",k:"string",max:64},{n:"outcome",k:"enum",v:["shown","no_ad","unavailable"]}]),Be=a("gem.requestSignIn",[{n:"requestId",k:"string",max:64}]),ze=a("gem.signInResult",[{n:"requestId",k:"string",max:64},{n:"outcome",k:"enum",v:["signed_in","declined","unavailable"]}]),w=R({"gem.handshake":ee,"gem.handshake.accept":te,"gem.token":ne,"gem.token.denied":re,"gem.player":oe,"gem.pause":ae,"gem.prefs":se,"gem.cohorts":ie,"gem.viewport":de,"gem.deviceSettings":le,"gem.willTerminate":me,"gem.roomEvent":ce,"gem.socketState":ue,"gem.seatedEvent":ge,"gem.autoStartFailedEvent":pe,"gem.signalEvent":ye,"gem.dedicatedEvent":fe,"gem.partyResult":he,"gem.clusterTarget":ke,"gem.devtools":ve,"gem.screenshot":xe,"gem.screenshot.denied":we,"gem.requestContext":be,"gem.gameContext":Se,"gem.signal":Re,"gem.dedicatedOffer":Ge,"gem.partyRequest":Oe,"gem.ready":Te,"gem.progress":Pe,"gem.requestToken":Ee,"gem.requestLocalServer":Ce,"gem.localServer":Ie,"gem.localServer.denied":qe,"gem.exit":Le,"gem.openExternal":_e,"gem.requestFullscreen":je,"gem.audioState":Ae,"gem.rewardCue":De,"gem.frameStats":Me,"gem.error":Fe,"gem.requestPurchase":$e,"gem.purchaseResult":He,"gem.deviceSettings.put":Ue,"gem.deviceSettings.result":We,"gem.requestAd":Ne,"gem.adResult":Ve,"gem.requestSignIn":Be,"gem.signInResult":ze});var G=class{#e;constructor(e){this.#e=e,Object.freeze(this);}toString(){return "[gem: use gem.text.toPlain()]"}toJSON(){return this.toString()}get[Symbol.toStringTag](){return "PlayerText"}static unwrap(e){return e.#e}};function O(n){return new G(n)}var T={now:()=>Date.now(),setTimeout:(n,e)=>setTimeout(n,e),clearTimeout:n=>clearTimeout(n)},h=class{constructor(e=T){this.clock=e;}clock;tokens=new Map;lastRefill=new Map;allow(e){let t=j[e];if(t===void 0)return false;let r=this.clock.now(),i=this.lastRefill.get(e)??r,s=this.tokens.get(e)??t,d=Math.max(0,r-i),o=Math.min(t,s+d*t/6e4);return o<1?(this.tokens.set(e,o),this.lastRefill.set(e,r),false):(this.tokens.set(e,o-1),this.lastRefill.set(e,r),true)}};function P(n,e){return n.toLowerCase()===e.toLowerCase()}function F(n){let e=n.toLowerCase();return e==="localhost"||e.endsWith(".localhost")||e==="[::1]"||e==="::1"?true:/^127(\.\d{1,3}){3}$/.test(e)}function $(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:F(t.hostname)&&F(r.hostname)}function H(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}function U(n){return Math.min(16384,Math.max(0,Math.round(Number.isFinite(n)?n:0)))}function W(n,e){return Math.min(e,Math.max(0,Math.round(Number.isFinite(n)?n:0)))}function Ke(n){let e=n.untrusted,t=O(e.displayName),r=e.displayTag||e.displayHandle,i=r?O(r):void 0,s=n.discriminator||n.displayTag,d=s&&/^[0-9]{1,8}$/.test(s)?s:void 0,o=n.avatarIconUrl||n.avatarUrl,m={displayName:t,displayHandle:i??t,badges:(n.badges??[]).map(c=>({itemId:c.itemId,iconUrl:c.iconUrl}))};n.playerId&&(m.playerId=n.playerId),d&&(m.discriminator=d),i&&(m.displayTag=i),o&&(m.avatarIconUrl=m.avatarUrl=o);let u=n.boost,g=(u?.multipliers??[]).map(c=>({currencyId:c.currencyId,currencySlug:c.currencySlug,multiplier:c.multiplierBp/1e4})),p=g.some(c=>c.multiplier>1);return m.boost=p&&u?.expiresInDays?{active:p,multipliers:g,expiresInDays:u.expiresInDays}:{active:p,multipliers:g},m}var Ye=1e4,k=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??T,this.inbound=new h(this.clock),this.outbound=new h(this.clock);}options;state="waiting";port=null;version=null;peerCapabilities=[];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}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(o=>P(o,e.origin))||$(e.origin,this.options.selfOrigin)))return this.refuse(e,`embedder '${e.origin}' is not in allowedEmbedders`),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=w["gem.handshake"]?.(e.data);if(r)return this.refuse(e,`malformed handshake: ${r}`),false;let i=e.data;if(!P(i.embedder,e.origin))return this.refuse(e,`handshake claims embedder '${i.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=H(f,i.versions);return d===null?(s.onmessage=null,s.postMessage({gem:l,type:"gem.error",code:"version_mismatch",message:`frame supports v${f.min}..v${f.max}`}),s.close(),this.transition("refused"),this.options.onError?.("version_mismatch"),false):(this.port=s,this.version=d,s.onmessage=o=>this.receive(o.data,o.ports??[]),s.start?.(),this.peerCapabilities=i.capabilities??[],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=Ye){return this.state!=="waiting"?Promise.resolve(this.state):new Promise(t=>{let r=s=>{this.clock.clearTimeout(i),t(s);},i=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.state!=="connected"||!this.parentSupports("audioState")?false:(this.send({gem:l,type:"gem.audioState",muted:e}),true)}cueReward(e){if(this.state!=="connected"||!this.parentSupports("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:U(e.origin.x),y:U(e.origin.y)}),this.send(t),true}reportFrameStats(e){return this.state!=="connected"||!this.parentSupports("frameStats")?false:(this.send({gem:l,type:"gem.frameStats",fps:W(e.fps,1e3),frameTimeP95Ms:W(e.frameTimeP95Ms,1e5)}),true)}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,i,s,d){return this.send({gem:l,type:"gem.requestPurchase",requestId:e,purchaseKind:t,targetId:r,currencySlug:i,...s===void 0?{}:{quantity:s},...d===void 0?{}:{catalogId:d}})}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})}requestSignIn(e){return this.send({gem:l,type:"gem.requestSignIn",requestId: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(x)){this.options.onDropped?.(e,t);return}this.fail(e,t);}dropUnknownType(e){this.inbound.allow(x)&&this.options.onDropped?.("unsupported",`ignored unknown message type '${e}'`);}refuse(e,t){e.ports?.[0]?.close?.(),this.inbound.allow(x)&&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}});}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=w[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||N(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 i=w[r];if(!i)return this.dropUnknownType(r),false;if(!this.inbound.allow(r))return this.fail("rate_limited",`parent exceeded the limit for ${r}`),false;let s=A(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=i(e);if(d)return this.fail("invalid_message",`${r}: ${d}`),false;let o=e;if(o.v!==this.version)return this.fail("invalid_message",`${r}: expected v ${String(this.version)}`),false;switch(r){case "gem.token":this.options.onToken?.(o);break;case "gem.pause":this.options.onPause?.(o);break;case "gem.prefs":this.options.onPrefs?.(o);break;case "gem.cohorts":this.options.onCohorts?.(o);break;case "gem.viewport":this.options.onViewport?.(o);break;case "gem.willTerminate":this.options.onWillTerminate?.(o);break;case "gem.devtools":this.options.onDevtools?.(o.action);break;case "gem.requestContext":this.options.onRequestContext?.();break;case "gem.screenshot":{let m=t[0];if(!m){this.options.onError?.("invalid_message","gem.screenshot transferred no MessagePort");break}let u={maxWidth:o.maxWidth,maxHeight:o.maxHeight};if(!this.options.onScreenshot){m.close(),this.screenshotDenied("not_wired",false);break}return N(t.slice(1)),this.options.onScreenshot(u,m,(g,p)=>this.screenshotDenied(g,p)),true}case "gem.token.denied":this.options.onTokenDenied?.(o);break;case "gem.localServer":this.options.onLocalServer?.(o);break;case "gem.localServer.denied":this.options.onLocalServerDenied?.(o);break;case "gem.player":{this.options.onPlayer?.(Ke(o));break}case "gem.roomEvent":this.options.onRoomEvent?.(o);break;case "gem.seatedEvent":this.options.onSeatedEvent?.(o);break;case "gem.autoStartFailedEvent":this.options.onAutoStartFailedEvent?.(o);break;case "gem.socketState":this.options.onSocketState?.(o);break;case "gem.signalEvent":this.options.onSignalEvent?.(o);break;case "gem.dedicatedEvent":this.options.onDedicatedEvent?.(o);break;case "gem.clusterTarget":this.options.onClusterTarget?.(o);break;case "gem.partyResult":this.options.onPartyResult?.(o);break;case "gem.purchaseResult":this.options.onPurchaseResult?.(o);break;case "gem.deviceSettings":this.options.onDeviceSettings?.(o);break;case "gem.deviceSettings.result":this.options.onDeviceSettingsResult?.(o);break;case "gem.adResult":this.options.onAdResult?.(o);break;case "gem.signInResult":this.options.onSignInResult?.(o);break;case "gem.error":this.options.onError?.(o.code,o.message);break;default: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 N(n){for(let e of n)try{e?.close?.();}catch{}}I();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 k({...n,expectedSource:n.expectedSource??window.parent}),t=r=>{let i=e.handleWindowMessage({data:r.data,origin:r.origin,source:r.source,ports:r.ports});return i&&window.removeEventListener("message",t),i};return window.addEventListener("message",t),q(window,t),e}var V={connect:Xe,GemFrame:k,PROTOCOL:l,SUPPORTED_VERSIONS:f};window.GemWebSdkBridge=V;var lt=V;return lt;})();