@indiegems/gem-web-sdk 14.0.3 → 15.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.
- package/CHANGELOG.md +27 -0
- package/dist/function.d.ts +3 -0
- package/dist/game.d.ts +15 -1
- package/dist/gem-web-sdk.bridge.js +1 -1
- package/dist/gem-web-sdk.esm.js +1 -1
- package/dist/gem-web-sdk.function.js +3 -3
- package/dist/gem-web-sdk.game.js +3 -3
- package/dist/gem-web-sdk.min.js +3 -3
- package/dist/gem-web-sdk.sdk.js +3 -3
- package/dist/gem-web-sdk.server.js +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/sdk.d.ts +15 -1
- package/docs/analytics.md +71 -7
- package/docs/api/api-reference-function.md +67 -1
- package/docs/api/api-reference-game.md +213 -1
- package/docs/api/api-reference-server.md +1 -1
- package/docs/api/reference.json +190 -1
- package/docs/changelog.md +27 -0
- package/docs/getting-started.md +1 -1
- package/docs/manifest.json +10 -10
- package/docs/server-bundles.md +2 -2
- package/docs/what-a-game-must-do.md +64 -15
- package/package.json +1 -1
- package/schema/bridge.v1.json +45 -0
- package/schema/capabilities.public.json +8 -0
package/CHANGELOG.md
CHANGED
|
@@ -16,6 +16,33 @@ Its entries are grouped under up to five headings:
|
|
|
16
16
|
- **Rebuild**: a type changed. Recompile against the new version; code that compiles today keeps compiling unless the entry says otherwise.
|
|
17
17
|
- **New capability**: something a game can now do. Nothing changes unless you use it.
|
|
18
18
|
|
|
19
|
+
## 15.1.0
|
|
20
|
+
|
|
21
|
+
Upgrading from 15.0.0. Impact: none.
|
|
22
|
+
|
|
23
|
+
### New capability
|
|
24
|
+
|
|
25
|
+
- AnalyticsApi.experiment gives a player a stable experiment arm. Pass an experiment key and either an arm count or a list of options. It returns the same arm for that player on every call, refresh and device: an index from zero up to one less than the count, or one of the strings in the list. Games that picked an arm with a random number landed a player in a different arm on every refresh, so no test could be read. Switching to this call fixes that. Different experiment keys are independent of each other. Nothing is recorded for you. To analyse an experiment, declare a dimension on the events you choose and pass the selection yourself. The call rejects when there is no player.
|
|
26
|
+
- experimentSelection computes the same arm as AnalyticsApi.experiment from an experiment key, a player id you hold, and an arm count or list of options. Use it where the SDK is not running, such as a dedicated game server or an analytics query, to reproduce which arm a player was given.
|
|
27
|
+
|
|
28
|
+
## 15.0.0
|
|
29
|
+
|
|
30
|
+
*Written from the API facts alone; no summary was generated for this release.*
|
|
31
|
+
|
|
32
|
+
Upgrading from 14.0.3. Impact: required.
|
|
33
|
+
|
|
34
|
+
### Must change
|
|
35
|
+
|
|
36
|
+
- GemCapability changed its signature.
|
|
37
|
+
- GemHost.sendPrefs changed its signature.
|
|
38
|
+
|
|
39
|
+
### New capability
|
|
40
|
+
|
|
41
|
+
- GemAudioChannels was added.
|
|
42
|
+
- GemOptions.onAudioChannels was added.
|
|
43
|
+
- GemPrefs.music was added.
|
|
44
|
+
- GemPrefs.sounds was added.
|
|
45
|
+
|
|
19
46
|
## 14.0.3
|
|
20
47
|
|
|
21
48
|
Upgrading from 14.0.2. Impact: none.
|
package/dist/function.d.ts
CHANGED
|
@@ -128,6 +128,7 @@ interface AnalyticsApiOptions {
|
|
|
128
128
|
readonly clock: Clock;
|
|
129
129
|
readonly gameId: () => string | null;
|
|
130
130
|
readonly playerId: () => string | null;
|
|
131
|
+
readonly awaitPlayerId?: () => Promise<string>;
|
|
131
132
|
readonly options?: AnalyticsOptions;
|
|
132
133
|
readonly log?: ((message: string) => void) | null;
|
|
133
134
|
}
|
|
@@ -136,6 +137,8 @@ declare class AnalyticsApi {
|
|
|
136
137
|
constructor(options: AnalyticsApiOptions);
|
|
137
138
|
track(name: string, props?: Readonly<Record<string, AnalyticsValue>>): void;
|
|
138
139
|
setContext(props: Readonly<Record<string, AnalyticsValue>>): void;
|
|
140
|
+
experiment(key: string, count: number): Promise<number>;
|
|
141
|
+
experiment<T extends string>(key: string, options: readonly T[]): Promise<T>;
|
|
139
142
|
get environment(): Readonly<Record<string, string>>;
|
|
140
143
|
flush(options?: AnalyticsFlushOptions): Promise<AnalyticsFlushResult>;
|
|
141
144
|
trackPlatform(name: PlatformEventName, props?: Readonly<Record<string, AnalyticsValue>>): void;
|
package/dist/game.d.ts
CHANGED
|
@@ -1491,6 +1491,7 @@ interface AnalyticsApiOptions {
|
|
|
1491
1491
|
readonly clock: Clock;
|
|
1492
1492
|
readonly gameId: () => string | null;
|
|
1493
1493
|
readonly playerId: () => string | null;
|
|
1494
|
+
readonly awaitPlayerId?: () => Promise<string>;
|
|
1494
1495
|
readonly options?: AnalyticsOptions;
|
|
1495
1496
|
readonly log?: ((message: string) => void) | null;
|
|
1496
1497
|
}
|
|
@@ -1499,6 +1500,8 @@ declare class AnalyticsApi {
|
|
|
1499
1500
|
constructor(options: AnalyticsApiOptions);
|
|
1500
1501
|
track(name: string, props?: Readonly<Record<string, AnalyticsValue>>): void;
|
|
1501
1502
|
setContext(props: Readonly<Record<string, AnalyticsValue>>): void;
|
|
1503
|
+
experiment(key: string, count: number): Promise<number>;
|
|
1504
|
+
experiment<T extends string>(key: string, options: readonly T[]): Promise<T>;
|
|
1502
1505
|
get environment(): Readonly<Record<string, string>>;
|
|
1503
1506
|
flush(options?: AnalyticsFlushOptions): Promise<AnalyticsFlushResult>;
|
|
1504
1507
|
trackPlatform(name: PlatformEventName, props?: Readonly<Record<string, AnalyticsValue>>): void;
|
|
@@ -2095,6 +2098,8 @@ interface GemPrefs$1 {
|
|
|
2095
2098
|
readonly reducedMotion: boolean;
|
|
2096
2099
|
readonly muted: boolean;
|
|
2097
2100
|
readonly showFrameStats?: boolean;
|
|
2101
|
+
readonly music?: boolean;
|
|
2102
|
+
readonly sounds?: boolean;
|
|
2098
2103
|
readonly locale: string;
|
|
2099
2104
|
readonly recommended?: {
|
|
2100
2105
|
volume: number;
|
|
@@ -3110,6 +3115,8 @@ interface DeviceSettingsApi {
|
|
|
3110
3115
|
declare class GemUnframedError extends Error {
|
|
3111
3116
|
constructor();
|
|
3112
3117
|
}
|
|
3118
|
+
declare function experimentSelection(key: string, playerId: string, count: number): number;
|
|
3119
|
+
declare function experimentSelection<T extends string>(key: string, playerId: string, options: readonly T[]): T;
|
|
3113
3120
|
interface AvatarRigNode {
|
|
3114
3121
|
readonly node: string;
|
|
3115
3122
|
readonly parent: string | null;
|
|
@@ -3144,6 +3151,7 @@ interface GemOptions {
|
|
|
3144
3151
|
readonly onDeviceSettings?: (settings: DeviceSettings | null) => void;
|
|
3145
3152
|
readonly onViewport?: (viewport: GemViewport) => void;
|
|
3146
3153
|
readonly manageAudio?: boolean;
|
|
3154
|
+
readonly onAudioChannels?: (channels: GemAudioChannels) => void;
|
|
3147
3155
|
readonly selectableText?: boolean;
|
|
3148
3156
|
readonly onPause?: (paused: boolean) => void;
|
|
3149
3157
|
readonly onWillTerminate?: (notice: GemTerminationNotice) => void;
|
|
@@ -3165,9 +3173,15 @@ interface GemPrefs {
|
|
|
3165
3173
|
readonly reducedMotion: boolean;
|
|
3166
3174
|
readonly muted: boolean;
|
|
3167
3175
|
readonly showFrameStats: boolean;
|
|
3176
|
+
readonly music: boolean;
|
|
3177
|
+
readonly sounds: boolean;
|
|
3168
3178
|
readonly locale: string;
|
|
3169
3179
|
readonly recommended: GemRecommendedSettings | null;
|
|
3170
3180
|
}
|
|
3181
|
+
interface GemAudioChannels {
|
|
3182
|
+
readonly music: boolean;
|
|
3183
|
+
readonly sounds: boolean;
|
|
3184
|
+
}
|
|
3171
3185
|
interface GemRecommendedSettings {
|
|
3172
3186
|
readonly volume: number;
|
|
3173
3187
|
readonly batterySaver: boolean;
|
|
@@ -3299,4 +3313,4 @@ interface ExitAnalytics {
|
|
|
3299
3313
|
}
|
|
3300
3314
|
declare function leaveAndExit(rooms: ExitRooms, bridge: ExitBridge | null, reason?: string, analytics?: ExitAnalytics): Promise<void>;
|
|
3301
3315
|
declare function createGem(options?: GemOptions): Gem;
|
|
3302
|
-
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, AuthError, type AuthFailure, type AuthState, type Avatar3dFamily, type Avatar3dOffer, type Avatar3dPrice, type Avatar3dPurchaseRequest, type AvatarRigNode, type AvatarRigs, type Avatars3dApi, type BootMark, type BootTimeline, 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 GameConfig, type GameMenu, type GameMenuItem, type GameServerLink, type GameSettingsApi, type Gem, GemApiError, 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 GemIdentity, type GemInsets, type GemLook, type GemLookBase, type GemLookDelta, type GemLookOptions, type GemLookSpeed, type GemMatchApi, type GemMatchServerModule, type GemOptions, type GemPlayer, 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 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 MessageMeta, type MomentKind, type MomentResult, type MomentSignal, type MomentsApi, type MultiTransportSession, PLATFORM_EVENTS, 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, PlayerText, type ProfileCallOptions, type ProfileShowcaseEntry, ProfilesApi, type PurchaseApi, type PurchaseOptions, type PurchaseOutcome, PurchaseRefusal, type PurchaseRefusalCode, type PurchaseRequest, 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, type ShareRequest, 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, type VibrationApi, type WalletVisibleOptions, type WornAvatar3d, asPlayerText, createBootTimeline, createGem, leaveAndExit, mapIdentity, markOnResolve, platformIconUrl, presentJoinCredential, readTemplateTransports, readTransportAdvert, reportOnResolve, text, webTransportAvailable };
|
|
3316
|
+
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, AuthError, type AuthFailure, type AuthState, type Avatar3dFamily, type Avatar3dOffer, type Avatar3dPrice, type Avatar3dPurchaseRequest, type AvatarRigNode, type AvatarRigs, type Avatars3dApi, type BootMark, type BootTimeline, 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 GameConfig, type GameMenu, type GameMenuItem, 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 GemIdentity, type GemInsets, type GemLook, type GemLookBase, type GemLookDelta, type GemLookOptions, type GemLookSpeed, type GemMatchApi, type GemMatchServerModule, type GemOptions, type GemPlayer, 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 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 MessageMeta, type MomentKind, type MomentResult, type MomentSignal, type MomentsApi, type MultiTransportSession, PLATFORM_EVENTS, 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, PlayerText, type ProfileCallOptions, type ProfileShowcaseEntry, ProfilesApi, type PurchaseApi, type PurchaseOptions, type PurchaseOutcome, PurchaseRefusal, type PurchaseRefusalCode, type PurchaseRequest, 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, type ShareRequest, 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, 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 I="GemWebSdkHandshake";function re(){return typeof document>"u"?void 0:document.readyState}var F=()=>Date.now();function $(t={}){let e=t.win??window,n=e,r=n[I];if(r!==void 0)return r;let s=t.readyState??re,i=t.now??F,d=[],a=[],c=y=>{let u=y.data;!u||u.type!=="gem.handshake"||(d.length>=4&&(d.shift(),a.shift(),p.dropped+=1),d.push(y),a.push(i()));};e.addEventListener("message",c);let p={events:d,times:a,dropped:0,late:s()==="complete",uninstall(){e.removeEventListener("message",c);}};return n[I]=p,p}function U(t,e,n={}){let r=t[I];if(r===void 0)return null;let s=n.ttlMs??9500,i=n.now??F,d=r.events.splice(0),a=r.times?.splice(0),c=0,p=0,y=false,u=i()-s;for(let f=d.length-1;f>=0;f--){let h=a?.[f];if(h!==void 0&&h<u){p+=1;continue}if(c+=1,e(d[f])===true){y=true;break}}return r.uninstall(),{capture:r,delivered:c,stale:p,accepted:y}}var l="gem-web-bridge",v={min:1,max:1},k=65536,H=8,R=5e3,W=1024;var b=Object.create(null),S="__malformed";var q=Object.create(null),oe=Object.freeze([["gem.asyncOpponents.","asyncOpponents"],["gem.vibration.","vibration"],["gem.viewport.","reservedAreas"],["gem.moments.","moments"]]);function B(t){let e=q[t];if(e!==void 0)return e;for(let[n,r]of oe)if(t.startsWith(n))return r}function ae(t){let e=/^([a-z][a-z0-9+.-]*):\/\/([a-z0-9.-]+|\[[0-9a-f:.]+\])(:([0-9]{1,5}))?$/i.exec(t);return e===null?false:e[4]===void 0||Number(e[4])<=65535}function se(t){let e;try{e=new URL(t);}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 ie(t){return /^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i.test(t)}function le(t){return /^[a-z_]+$/.test(t)}function L(t,e,n){if(e>H)return `nesting deeper than ${H}`;if(++n.nodes>R)return `more than ${R} values`;if(n.bytes>k)return `over the ${k} byte limit`;if(t==null)return n.bytes+=4,null;let r=typeof t;if(r==="boolean")return n.bytes+=5,null;if(r==="number")return n.bytes+=8,null;if(r==="string")return n.bytes+=t.length*3+2,null;if(r!=="object")return `${r} is not plain data`;let s=t;if(n.seen.has(s))return "a repeated or cyclic object reference";if(n.seen.add(s),Array.isArray(t)){if(t.length>W)return `an array of ${t.length} entries, over the ${W} limit`;n.bytes+=2;for(let a of t){let c=L(a,e+1,n);if(c)return c}return null}let i=Object.getPrototypeOf(t);if(i!==Object.prototype&&i!==null)return "a value that is not a plain object";n.bytes+=2;let d=t;for(let a in d){if(!Object.prototype.hasOwnProperty.call(d,a))continue;if(++n.nodes>R)return `more than ${R} values`;if(n.bytes+=a.length*3+4,n.bytes>k)return `over the ${k} byte limit`;let c=L(d[a],e+1,n);if(c)return c}return null}function de(t){let e={nodes:0,bytes:0,seen:new Set},n=L(t,0,e);return n?`message contains ${n}`:e.bytes>k?`message is over the ${k} byte limit`:null}var me={origin:[ae,"not a well-formed origin"],url:[se,"not a safe absolute http(s) URL"],bcp47:[ie,"not a well-formed BCP 47 tag"],code:[le,"not a code of lower-case letters and underscores"]};function N(t,e,n){for(let r of e){let s=n===""?r.n:`${n}.${r.n}`,i=t[r.n];if(i==null){if(r.o)continue;return `${s}: required`}let d=A(i,r,s);if(d)return d}return null}function A(t,e,n){switch(e.k){case "u":return typeof t=="boolean"?null:A(t,{...e,k:typeof t=="string"?"s":"n"},n);case "s":{if(typeof t!="string")return `${n}: expected string`;if(t.length>e.max)return `${n}: exceeds ${e.max} characters`;if(e.f){let[r,s]=me[e.f];if(!r(t))return `${n}: ${s}`}return null}case "n":case "i":return typeof t!="number"||!(e.k=="i"?Number.isInteger:Number.isFinite)(t)?`${n}: expected ${e.k=="i"?"integer":"number"}`:t<e.lo||t>e.hi?`${n}: out of range ${e.lo}..${e.hi}`:null;case "b":return typeof t=="boolean"?null:`${n}: expected boolean`;case "e":{let r=e.v;return r.includes(t)?null:`${n}: not one of ${r.join("|")}`}case "o":return typeof t!="object"||t===null||Array.isArray(t)?`${n}: expected object`:N(t,e.fs,n);case "j":return typeof t!="object"||t===null||Array.isArray(t)?`${n}: expected a plain object`:null;case "a":{if(!Array.isArray(t))return `${n}: expected array`;if(t.length>e.max)return `${n}: exceeds ${e.max} items`;let r=e.it,s=`${n}[]`;for(let i of t){if(i==null){if(r.o)continue;return `${s}: required`}let d=A(i,r,s);if(d)return d}return null}default:{let r=e.k;return `${n}: unknown kind ${String(r)}`}}}var V=Object.create(null);function o(t,e,n,r){return b[t]=n,r&&(q[t]=r),V[t]=s=>{let i=de(s);if(i)return i;if(typeof s!="object"||s===null||Array.isArray(s))return "message: expected object";let d=s;return d.gem!==l?"gem: wrong protocol marker":d.type!==t?`type: expected ${t}`:N(d,e,"")}}var m={n:"requestId",k:"s",max:64};o("gem.handshake",[{n:"versions",k:"o",fs:[{n:"min",k:"i",lo:1,hi:1e3},{n:"max",k:"i",lo:1,hi:1e3}]},{n:"capabilities",k:"a",o:1,max:64,it:{n:"",k:"s",max:64}},{n:"embedder",k:"s",max:2048,f:"origin"},{n:"unbidden",k:"b",o:1}],30);o("gem.handshake.accept",[{n:"v",k:"i",lo:1,hi:1e3},{n:"capabilities",k:"a",o:1,max:64,it:{n:"",k:"s",max:64}}],5);o("gem.token",[{n:"token",k:"s",max:4096},{n:"requestId",k:"s",o:1,max:64},{n:"generation",k:"i",lo:0,hi:2147483647},{n:"apiBaseUrl",k:"s",o:1,max:512,f:"url"},{n:"playerId",k:"s",max:64},{n:"gameId",k:"s",max:64},{n:"channel",k:"e",v:["dev","test","release"]},{n:"gameVersion",k:"s",o:1,max:64},{n:"expiresAt",k:"i",lo:0,hi:4102444800},{n:"chainEndsAt",k:"i",lo:0,hi:4102444800},{n:"allowDevTools",k:"b",o:1}],30);o("gem.token.denied",[m,{n:"retryable",k:"b"},{n:"retryAfterMs",k:"i",o:1,lo:0,hi:36e5},{n:"reason",k:"e",v:["chain_exhausted","unavailable"]},{n:"correlationId",k:"s",max:64}],30);o("gem.player",[{n:"untrusted",k:"o",fs:[{n:"displayName",k:"s",max:64},{n:"displayTag",k:"s",o:1,max:80},{n:"displayHandle",k:"s",max:80}]},{n:"playerId",k:"s",o:1,max:64},{n:"discriminator",k:"s",o:1,max:8},{n:"avatarIconUrl",k:"s",o:1,max:2048,f:"url"},{n:"avatarIconId",k:"s",o:1,max:64},{n:"avatar3dId",k:"s",o:1,max:64},{n:"avatar3dModelUrl",k:"s",o:1,max:2048,f:"url"},{n:"avatar3dIconUrl",k:"s",o:1,max:2048,f:"url"},{n:"avatars3d",k:"a",o:1,max:8,it:{n:"",k:"o",fs:[{n:"family",k:"s",max:32},{n:"id",k:"s",max:64},{n:"modelUrl",k:"s",max:256,f:"url"},{n:"iconUrl",k:"s",max:256,f:"url"}]}},{n:"badges",k:"a",o:1,max:2,it:{n:"",k:"o",fs:[{n:"itemId",k:"s",max:64},{n:"iconUrl",k:"s",max:2048,f:"url"}]}},{n:"displayTag",k:"s",max:8},{n:"avatarUrl",k:"s",o:1,max:2048,f:"url"},{n:"boost",k:"o",o:1,fs:[{n:"multipliers",k:"a",max:8,it:{n:"",k:"o",fs:[{n:"currencyId",k:"s",max:64},{n:"currencySlug",k:"s",max:32},{n:"multiplierBp",k:"i",lo:1e4,hi:1e6}]}},{n:"expiresInDays",k:"i",o:1,lo:1,hi:7}]}],12);o("gem.pause",[{n:"paused",k:"b"}],120);o("gem.prefs",[{n:"reducedMotion",k:"b"},{n:"muted",k:"b"},{n:"showFrameStats",k:"b",o:1},{n:"locale",k:"s",max:35,f:"bcp47"},{n:"recommended",k:"o",o:1,fs:[{n:"volume",k:"i",lo:0,hi:100},{n:"batterySaver",k:"b"},{n:"keyboardLayout",k:"e",v:["wasd","arrows"]},{n:"gamepadConfirm",k:"e",v:["south","east"]},{n:"vibration",k:"b"},{n:"lookSensitivity",k:"i",o:1,lo:20,hi:400},{n:"gamepadLookSensitivity",k:"i",o:1,lo:20,hi:400},{n:"invertLookY",k:"b",o:1},{n:"touchMovement",k:"s",o:1,max:16,f:"code"},{n:"graphicsQuality",k:"s",o:1,max:16,f:"code"},{n:"graphicsQualityAuto",k:"b",o:1}]}],60);o("gem.cohorts",[{n:"cohorts",k:"a",max:8,it:{n:"",k:"o",fs:[{n:"experimentId",k:"s",max:36},{n:"variantKey",k:"s",max:32}]}}],12,"cohorts");o("gem.earnAllowanceChanged",[],30,"earnAllowance");o("gem.viewport",[{n:"insets",k:"o",fs:[{n:"top",k:"i",lo:0,hi:4096},{n:"right",k:"i",lo:0,hi:4096},{n:"bottom",k:"i",lo:0,hi:4096},{n:"left",k:"i",lo:0,hi:4096}]},{n:"reserved",k:"a",o:1,max:4,it:{n:"",k:"o",fs:[{n:"x",k:"i",lo:0,hi:16384},{n:"y",k:"i",lo:0,hi:16384},{n:"width",k:"i",lo:0,hi:16384},{n:"height",k:"i",lo:0,hi:16384},{n:"control",k:"o",o:1,fs:[{n:"x",k:"i",lo:0,hi:16384},{n:"y",k:"i",lo:0,hi:16384},{n:"width",k:"i",lo:0,hi:16384},{n:"height",k:"i",lo:0,hi:16384}]}]}}],60,"viewport");o("gem.deviceSettings",[{n:"settings",k:"j",o:1}],12,"deviceSettings");o("gem.willTerminate",[{n:"reason",k:"e",v:["grant_expiring","session_ended","navigating","kill_switch"]},{n:"graceMs",k:"i",lo:0,hi:6e4}],10);o("gem.roomEvent",[{n:"event",k:"e",v:["updated","match_started","match_ready","match_failed","version_stale"]},{n:"roomId",k:"s",max:64},{n:"matchId",k:"s",o:1,max:64},{n:"version",k:"i",o:1,lo:0,hi:2147483647},{n:"reason",k:"s",o:1,max:64},{n:"platform",k:"e",o:1,v:["universal","mobile"]}],120,"rooms");o("gem.socketState",[{n:"connected",k:"b"},{n:"reason",k:"e",o:1,v:["connecting","dropped","watchdog","terminal"]}],12,"socketState");o("gem.seatedEvent",[{n:"roomId",k:"s",max:64}],60,"partySeating");o("gem.autoStartFailedEvent",[{n:"roomId",k:"s",max:64},{n:"code",k:"s",max:64}],30,"autoStartFailure");o("gem.ticketEvent",[{n:"event",k:"e",v:["queued","matched","expired","cancelled","failed"]},{n:"ticketId",k:"s",max:64},{n:"partySize",k:"i",o:1,lo:1,hi:64},{n:"queuedAt",k:"i",o:1,lo:0,hi:4102444800},{n:"expiresAt",k:"i",o:1,lo:0,hi:4102444800},{n:"reason",k:"s",o:1,max:64},{n:"roomId",k:"s",o:1,max:64}],60,"ticketEvents");o("gem.signalEvent",[{n:"event",k:"e",v:["hello","offer","answer","ice","peerJoined","peerLeft","migration","matchEnded","error"]},{n:"matchId",k:"s",max:64},{n:"data",k:"j"}],1800,"p2p");o("gem.dedicatedEvent",[{n:"event",k:"e",v:["answer","error","matchEnded"]},{n:"matchId",k:"s",max:64},{n:"sdp",k:"s",o:1,max:10240},{n:"sessionId",k:"s",o:1,max:64},{n:"code",k:"s",o:1,max:64},{n:"message",k:"s",o:1,max:256},{n:"reason",k:"s",o:1,max:64}],120,"dedicated");o("gem.partyResult",[m,{n:"partyId",k:"s",o:1,max:64}],30,"parties");o("gem.clusterTarget",[{n:"clusterTargetId",k:"s",max:64},{n:"clusterTargetIds",k:"a",o:1,max:3,it:{n:"",k:"s",max:64}}],12,"clusterTarget");o("gem.devtools",[{n:"action",k:"e",v:["open","close","toggle"]}],30,"devtools");o("gem.screenshot",[{n:"maxWidth",k:"i",lo:1,hi:7680},{n:"maxHeight",k:"i",lo:1,hi:4320}],6,"screenshot");o("gem.screenshot.denied",[{n:"reason",k:"e",v:["not_wired","no_source","unsupported","unreadable","tainted","too_large","busy","declined","failed"]},{n:"retryable",k:"b"}],12,"screenshot");o("gem.requestContext",[],12,"feedbackContext");o("gem.gameContext",[{n:"context",k:"j"}],12,"feedbackContext");o("gem.signal",[{n:"signal",k:"e",v:["join","offer","answer","ice","migrationAck","hostUnreachable"]},{n:"matchId",k:"s",max:64},{n:"data",k:"j"}],1200,"p2p");o("gem.dedicatedOffer",[{n:"matchId",k:"s",max:64},{n:"sdp",k:"s",max:10240},{n:"intent",k:"e",v:["initial","ice_restart","full_reconnect"]}],60,"dedicated");o("gem.partyRequest",[m],12,"parties");o("gem.ready",[],5);o("gem.engaged",[],5,"engagement");o("gem.progress",[{n:"loaded",k:"i",lo:0,hi:1099511627776},{n:"total",k:"i",lo:0,hi:1099511627776}],600);o("gem.requestToken",[m,{n:"reason",k:"e",v:["initial","expiring","rejected"]}],12);o("gem.requestLocalServer",[m,{n:"gameRoomId",k:"s",max:64}],6,"localHost");o("gem.localServer",[m,{n:"serverId",k:"s",o:1,max:128}],30,"localHost");o("gem.localServer.denied",[m,{n:"retryable",k:"b"},{n:"reason",k:"e",v:["refused","unavailable"]}],30,"localHost");o("gem.exit",[{n:"reason",k:"s",o:1,max:64}],5);o("gem.openExternal",[{n:"url",k:"s",max:2048,f:"url"}],6);o("gem.requestFullscreen",[{n:"enabled",k:"b"}],30);o("gem.audioState",[{n:"muted",k:"b"}],120,"audioState");o("gem.rewardCue",[{n:"currencySlug",k:"s",max:32},{n:"expected",k:"i",o:1,lo:1,hi:1e9},{n:"origin",k:"o",o:1,fs:[{n:"x",k:"i",lo:0,hi:16384},{n:"y",k:"i",lo:0,hi:16384}]}],60,"rewardCue");o("gem.walletDisplay",[{n:"visible",k:"b"},{n:"currencies",k:"a",o:1,max:8,it:{n:"",k:"s",max:64}},{n:"score",k:"b",o:1}],60,"walletDisplay");o("gem.controlsDeclare",[{n:"uses",k:"o",fs:[{n:"lookSensitivity",k:"s",o:1,max:16,f:"code"},{n:"gamepadLookSensitivity",k:"s",o:1,max:16,f:"code"},{n:"invertLookY",k:"s",o:1,max:16,f:"code"},{n:"touchMovement",k:"s",o:1,max:16,f:"code"}]}],60,"controls");o("gem.menu",[{n:"settings",k:"b"},{n:"items",k:"a",o:1,max:4,it:{n:"",k:"o",fs:[{n:"id",k:"s",max:32},{n:"label",k:"s",max:40}]}}],60,"gameMenu");o("gem.menuSelect",[{n:"entry",k:"e",v:["settings","item"]},{n:"id",k:"s",o:1,max:32}],60,"gameMenu");o("gem.gemCorner",[{n:"corner",k:"e",v:["top-left","top-right","bottom-left","bottom-right"]}],12,"gemCorner");o("gem.settingsDeclare",[{n:"settings",k:"a",max:8,it:{n:"",k:"o",fs:[{n:"id",k:"s",max:40},{n:"label",k:"s",max:40},{n:"kind",k:"e",v:["toggle","slider","choice"]},{n:"value",k:"u",max:40,lo:-1e6,hi:1e6},{n:"quick",k:"b",o:1},{n:"icon",k:"s",o:1,max:16,f:"code"},{n:"min",k:"n",o:1,lo:-1e6,hi:1e6},{n:"max",k:"n",o:1,lo:-1e6,hi:1e6},{n:"step",k:"n",o:1,lo:0,hi:1e6},{n:"options",k:"a",o:1,max:4,it:{n:"",k:"o",fs:[{n:"id",k:"s",max:40},{n:"label",k:"s",max:40}]}}]}}],120,"gameSettings");o("gem.settingChange",[{n:"id",k:"s",max:40},{n:"value",k:"u",max:40,lo:-1e6,hi:1e6}],120,"gameSettings");o("gem.requestShare",[{n:"params",k:"a",max:16,it:{n:"",k:"o",fs:[{n:"key",k:"s",max:64},{n:"value",k:"s",max:512}]}}],6,"share");o("gem.requestAvatarPicker",[{n:"tab",k:"e",o:1,v:["2d","3d"]}],6,"avatarPicker");o("gem.vibrate",[{n:"pattern",k:"a",max:99,it:{n:"",k:"i",lo:0,hi:1e4}}],600,"vibration");o("gem.frameStats",[{n:"fps",k:"i",lo:0,hi:1e3},{n:"frameTimeP95Ms",k:"i",lo:0,hi:1e5},{n:"counts",k:"e",o:1,v:["pageFrames","gameDraws"]}],120,"frameStats");o("gem.portraitBorders",[{n:"name",k:"s",o:1,max:40}],60,"portraitBorders");o("gem.error",[{n:"code",k:"e",v:["version_mismatch","handshake_timeout","handshake_duplicate","invalid_message","rate_limited","token_unavailable","unsupported","unsupported_capability","internal"]},{n:"message",k:"s",o:1,max:256}],60);o("gem.requestPurchase",[m,{n:"purchaseKind",k:"e",v:["item","recipe"]},{n:"targetId",k:"s",max:64},{n:"currencySlug",k:"s",max:32},{n:"quantity",k:"i",o:1,lo:1,hi:10},{n:"catalogId",k:"s",o:1,max:64}],12,"purchases");o("gem.requestAvatar3dPurchase",[m,{n:"itemId",k:"s",max:64},{n:"currencySlug",k:"s",max:32}],12,"avatar3dPurchases");o("gem.purchaseResult",[m,{n:"outcome",k:"e",v:["ok","declined","unavailable"]},{n:"reason",k:"s",o:1,max:64,f:"code"},{n:"purchaseId",k:"s",o:1,max:64}],30,"purchases");o("gem.deviceSettings.put",[m,{n:"settings",k:"j"}],30,"deviceSettings");o("gem.deviceSettings.result",[m,{n:"outcome",k:"e",v:["stored","too_large","unavailable"]}],30,"deviceSettings");o("gem.requestAd",[m,{n:"placement",k:"s",max:32},{n:"format",k:"e",v:["interstitial","rewarded"]}],6,"ads");o("gem.adResult",[m,{n:"outcome",k:"e",v:["shown","no_ad","unavailable"]}],12,"ads");o("gem.signalMoment",[m,{n:"kind",k:"e",v:["level_end","run_end","match_end","menu_return","other_break"]},{n:"placement",k:"s",o:1,max:32}],6,"moments");o("gem.momentResult",[m,{n:"shown",k:"b"}],12,"moments");o("gem.requestSignIn",[m],6,"signIn");o("gem.signInResult",[m,{n:"outcome",k:"e",v:["signed_in","declined","unavailable"]}],12,"signIn");o("gem.requestFriendChallenge",[m,{n:"playerId",k:"s",max:64},{n:"template",k:"s",max:64},{n:"params",k:"j",o:1}],12,"friendChallenges");o("gem.friendChallengeResult",[m,{n:"outcome",k:"e",v:["accepted","cancelled","refused","unavailable","rate_limited","invalid"]},{n:"code",k:"s",o:1,max:64},{n:"param",k:"s",o:1,max:64},{n:"channel",k:"s",o:1,max:16},{n:"configVersion",k:"i",o:1,lo:0,hi:9007199254740991},{n:"retryAfterMs",k:"i",o:1,lo:0,hi:864e5},{n:"detail",k:"s",o:1,max:300}],30,"friendChallenges");var G=Object.freeze(V);b.__malformed=60;Object.freeze(b);Object.freeze(q);var ce=/^[a-z0-9][a-z0-9_-]{0,39}$/;function ue(t){return typeof t=="string"&&ce.test(t)}function z(t){if(t===null||ue(t))return t;let e=typeof t=="string"?JSON.stringify(t.length>48?`${t.slice(0,48)}\u2026`:t):`a value of type ${typeof t}`;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 M={now:()=>Date.now(),setTimeout:(t,e)=>setTimeout(t,e),clearTimeout:t=>clearTimeout(t)},x=class{constructor(e=M){this.clock=e;}clock;tokens=new Map;lastRefill=new Map;allow(e){let n=b[e];if(n===void 0)return false;let r=this.clock.now(),s=this.lastRefill.get(e)??r,i=this.tokens.get(e)??n,d=Math.max(0,r-s),a=Math.min(n,i+d*n/6e4);return a<1?(this.tokens.set(e,a),this.lastRefill.set(e,r),false):(this.tokens.set(e,a-1),this.lastRefill.set(e,r),true)}};function _(t,e){return t.toLowerCase()===e.toLowerCase()}function O(t){let e=t.toLowerCase();return e==="localhost"||e.endsWith(".localhost")||e==="[::1]"||e==="::1"?true:/^127(\.\d{1,3}){3}$/.test(e)}function Y(t,e){if(typeof e!="string"||e==="")return false;let n,r;try{n=new URL(t),r=new URL(e);}catch{return false}return n.protocol!=="http:"&&n.protocol!=="https:"||r.protocol!=="http:"&&r.protocol!=="https:"||n.username!==""||n.password!==""||n.pathname!=="/"||n.search!==""||n.hash!==""||n.port===""?false:O(n.hostname)&&O(r.hostname)}function K(t,e){if(t.min>t.max||e.min>e.max)return null;let n=Math.min(t.max,e.max),r=Math.max(t.min,e.min);return n>=r?n:null}var X="[gem: use gem.text.toPlain()]",J=new Set,Q;function ge(t){try{if(J.has(t))return;let e=globalThis.location;if(Q??=!!e?.port&&O(e.hostname??""),!Q)return;J.add(t),console.warn(`[gem] ${t} is PlayerText, turned into a string: players see ${X}. Render text.toPlain(value) (text is in @indiegems/gem-web-sdk/sdk).
|
|
1
|
+
var GemWebSdkBridgeBundle=(function(){'use strict';var I="GemWebSdkHandshake";function re(){return typeof document>"u"?void 0:document.readyState}var F=()=>Date.now();function $(t={}){let e=t.win??window,n=e,r=n[I];if(r!==void 0)return r;let s=t.readyState??re,i=t.now??F,d=[],a=[],c=y=>{let u=y.data;!u||u.type!=="gem.handshake"||(d.length>=4&&(d.shift(),a.shift(),p.dropped+=1),d.push(y),a.push(i()));};e.addEventListener("message",c);let p={events:d,times:a,dropped:0,late:s()==="complete",uninstall(){e.removeEventListener("message",c);}};return n[I]=p,p}function U(t,e,n={}){let r=t[I];if(r===void 0)return null;let s=n.ttlMs??9500,i=n.now??F,d=r.events.splice(0),a=r.times?.splice(0),c=0,p=0,y=false,u=i()-s;for(let f=d.length-1;f>=0;f--){let h=a?.[f];if(h!==void 0&&h<u){p+=1;continue}if(c+=1,e(d[f])===true){y=true;break}}return r.uninstall(),{capture:r,delivered:c,stale:p,accepted:y}}var l="gem-web-bridge",v={min:1,max:1},k=65536,H=8,R=5e3,W=1024;var b=Object.create(null),S="__malformed";var q=Object.create(null),oe=Object.freeze([["gem.asyncOpponents.","asyncOpponents"],["gem.vibration.","vibration"],["gem.viewport.","reservedAreas"],["gem.moments.","moments"],["gem.prefs.","audioChannels"]]);function B(t){let e=q[t];if(e!==void 0)return e;for(let[n,r]of oe)if(t.startsWith(n))return r}function ae(t){let e=/^([a-z][a-z0-9+.-]*):\/\/([a-z0-9.-]+|\[[0-9a-f:.]+\])(:([0-9]{1,5}))?$/i.exec(t);return e===null?false:e[4]===void 0||Number(e[4])<=65535}function se(t){let e;try{e=new URL(t);}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 ie(t){return /^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i.test(t)}function le(t){return /^[a-z_]+$/.test(t)}function L(t,e,n){if(e>H)return `nesting deeper than ${H}`;if(++n.nodes>R)return `more than ${R} values`;if(n.bytes>k)return `over the ${k} byte limit`;if(t==null)return n.bytes+=4,null;let r=typeof t;if(r==="boolean")return n.bytes+=5,null;if(r==="number")return n.bytes+=8,null;if(r==="string")return n.bytes+=t.length*3+2,null;if(r!=="object")return `${r} is not plain data`;let s=t;if(n.seen.has(s))return "a repeated or cyclic object reference";if(n.seen.add(s),Array.isArray(t)){if(t.length>W)return `an array of ${t.length} entries, over the ${W} limit`;n.bytes+=2;for(let a of t){let c=L(a,e+1,n);if(c)return c}return null}let i=Object.getPrototypeOf(t);if(i!==Object.prototype&&i!==null)return "a value that is not a plain object";n.bytes+=2;let d=t;for(let a in d){if(!Object.prototype.hasOwnProperty.call(d,a))continue;if(++n.nodes>R)return `more than ${R} values`;if(n.bytes+=a.length*3+4,n.bytes>k)return `over the ${k} byte limit`;let c=L(d[a],e+1,n);if(c)return c}return null}function de(t){let e={nodes:0,bytes:0,seen:new Set},n=L(t,0,e);return n?`message contains ${n}`:e.bytes>k?`message is over the ${k} byte limit`:null}var me={origin:[ae,"not a well-formed origin"],url:[se,"not a safe absolute http(s) URL"],bcp47:[ie,"not a well-formed BCP 47 tag"],code:[le,"not a code of lower-case letters and underscores"]};function N(t,e,n){for(let r of e){let s=n===""?r.n:`${n}.${r.n}`,i=t[r.n];if(i==null){if(r.o)continue;return `${s}: required`}let d=A(i,r,s);if(d)return d}return null}function A(t,e,n){switch(e.k){case "u":return typeof t=="boolean"?null:A(t,{...e,k:typeof t=="string"?"s":"n"},n);case "s":{if(typeof t!="string")return `${n}: expected string`;if(t.length>e.max)return `${n}: exceeds ${e.max} characters`;if(e.f){let[r,s]=me[e.f];if(!r(t))return `${n}: ${s}`}return null}case "n":case "i":return typeof t!="number"||!(e.k=="i"?Number.isInteger:Number.isFinite)(t)?`${n}: expected ${e.k=="i"?"integer":"number"}`:t<e.lo||t>e.hi?`${n}: out of range ${e.lo}..${e.hi}`:null;case "b":return typeof t=="boolean"?null:`${n}: expected boolean`;case "e":{let r=e.v;return r.includes(t)?null:`${n}: not one of ${r.join("|")}`}case "o":return typeof t!="object"||t===null||Array.isArray(t)?`${n}: expected object`:N(t,e.fs,n);case "j":return typeof t!="object"||t===null||Array.isArray(t)?`${n}: expected a plain object`:null;case "a":{if(!Array.isArray(t))return `${n}: expected array`;if(t.length>e.max)return `${n}: exceeds ${e.max} items`;let r=e.it,s=`${n}[]`;for(let i of t){if(i==null){if(r.o)continue;return `${s}: required`}let d=A(i,r,s);if(d)return d}return null}default:{let r=e.k;return `${n}: unknown kind ${String(r)}`}}}var V=Object.create(null);function o(t,e,n,r){return b[t]=n,r&&(q[t]=r),V[t]=s=>{let i=de(s);if(i)return i;if(typeof s!="object"||s===null||Array.isArray(s))return "message: expected object";let d=s;return d.gem!==l?"gem: wrong protocol marker":d.type!==t?`type: expected ${t}`:N(d,e,"")}}var m={n:"requestId",k:"s",max:64};o("gem.handshake",[{n:"versions",k:"o",fs:[{n:"min",k:"i",lo:1,hi:1e3},{n:"max",k:"i",lo:1,hi:1e3}]},{n:"capabilities",k:"a",o:1,max:64,it:{n:"",k:"s",max:64}},{n:"embedder",k:"s",max:2048,f:"origin"},{n:"unbidden",k:"b",o:1}],30);o("gem.handshake.accept",[{n:"v",k:"i",lo:1,hi:1e3},{n:"capabilities",k:"a",o:1,max:64,it:{n:"",k:"s",max:64}}],5);o("gem.token",[{n:"token",k:"s",max:4096},{n:"requestId",k:"s",o:1,max:64},{n:"generation",k:"i",lo:0,hi:2147483647},{n:"apiBaseUrl",k:"s",o:1,max:512,f:"url"},{n:"playerId",k:"s",max:64},{n:"gameId",k:"s",max:64},{n:"channel",k:"e",v:["dev","test","release"]},{n:"gameVersion",k:"s",o:1,max:64},{n:"expiresAt",k:"i",lo:0,hi:4102444800},{n:"chainEndsAt",k:"i",lo:0,hi:4102444800},{n:"allowDevTools",k:"b",o:1}],30);o("gem.token.denied",[m,{n:"retryable",k:"b"},{n:"retryAfterMs",k:"i",o:1,lo:0,hi:36e5},{n:"reason",k:"e",v:["chain_exhausted","unavailable"]},{n:"correlationId",k:"s",max:64}],30);o("gem.player",[{n:"untrusted",k:"o",fs:[{n:"displayName",k:"s",max:64},{n:"displayTag",k:"s",o:1,max:80},{n:"displayHandle",k:"s",max:80}]},{n:"playerId",k:"s",o:1,max:64},{n:"discriminator",k:"s",o:1,max:8},{n:"avatarIconUrl",k:"s",o:1,max:2048,f:"url"},{n:"avatarIconId",k:"s",o:1,max:64},{n:"avatar3dId",k:"s",o:1,max:64},{n:"avatar3dModelUrl",k:"s",o:1,max:2048,f:"url"},{n:"avatar3dIconUrl",k:"s",o:1,max:2048,f:"url"},{n:"avatars3d",k:"a",o:1,max:8,it:{n:"",k:"o",fs:[{n:"family",k:"s",max:32},{n:"id",k:"s",max:64},{n:"modelUrl",k:"s",max:256,f:"url"},{n:"iconUrl",k:"s",max:256,f:"url"}]}},{n:"badges",k:"a",o:1,max:2,it:{n:"",k:"o",fs:[{n:"itemId",k:"s",max:64},{n:"iconUrl",k:"s",max:2048,f:"url"}]}},{n:"displayTag",k:"s",max:8},{n:"avatarUrl",k:"s",o:1,max:2048,f:"url"},{n:"boost",k:"o",o:1,fs:[{n:"multipliers",k:"a",max:8,it:{n:"",k:"o",fs:[{n:"currencyId",k:"s",max:64},{n:"currencySlug",k:"s",max:32},{n:"multiplierBp",k:"i",lo:1e4,hi:1e6}]}},{n:"expiresInDays",k:"i",o:1,lo:1,hi:7}]}],12);o("gem.pause",[{n:"paused",k:"b"}],120);o("gem.prefs",[{n:"reducedMotion",k:"b"},{n:"muted",k:"b"},{n:"showFrameStats",k:"b",o:1},{n:"music",k:"b",o:1},{n:"sounds",k:"b",o:1},{n:"locale",k:"s",max:35,f:"bcp47"},{n:"recommended",k:"o",o:1,fs:[{n:"volume",k:"i",lo:0,hi:100},{n:"batterySaver",k:"b"},{n:"keyboardLayout",k:"e",v:["wasd","arrows"]},{n:"gamepadConfirm",k:"e",v:["south","east"]},{n:"vibration",k:"b"},{n:"lookSensitivity",k:"i",o:1,lo:20,hi:400},{n:"gamepadLookSensitivity",k:"i",o:1,lo:20,hi:400},{n:"invertLookY",k:"b",o:1},{n:"touchMovement",k:"s",o:1,max:16,f:"code"},{n:"graphicsQuality",k:"s",o:1,max:16,f:"code"},{n:"graphicsQualityAuto",k:"b",o:1}]}],60);o("gem.cohorts",[{n:"cohorts",k:"a",max:8,it:{n:"",k:"o",fs:[{n:"experimentId",k:"s",max:36},{n:"variantKey",k:"s",max:32}]}}],12,"cohorts");o("gem.earnAllowanceChanged",[],30,"earnAllowance");o("gem.viewport",[{n:"insets",k:"o",fs:[{n:"top",k:"i",lo:0,hi:4096},{n:"right",k:"i",lo:0,hi:4096},{n:"bottom",k:"i",lo:0,hi:4096},{n:"left",k:"i",lo:0,hi:4096}]},{n:"reserved",k:"a",o:1,max:4,it:{n:"",k:"o",fs:[{n:"x",k:"i",lo:0,hi:16384},{n:"y",k:"i",lo:0,hi:16384},{n:"width",k:"i",lo:0,hi:16384},{n:"height",k:"i",lo:0,hi:16384},{n:"control",k:"o",o:1,fs:[{n:"x",k:"i",lo:0,hi:16384},{n:"y",k:"i",lo:0,hi:16384},{n:"width",k:"i",lo:0,hi:16384},{n:"height",k:"i",lo:0,hi:16384}]}]}}],60,"viewport");o("gem.deviceSettings",[{n:"settings",k:"j",o:1}],12,"deviceSettings");o("gem.willTerminate",[{n:"reason",k:"e",v:["grant_expiring","session_ended","navigating","kill_switch"]},{n:"graceMs",k:"i",lo:0,hi:6e4}],10);o("gem.roomEvent",[{n:"event",k:"e",v:["updated","match_started","match_ready","match_failed","version_stale"]},{n:"roomId",k:"s",max:64},{n:"matchId",k:"s",o:1,max:64},{n:"version",k:"i",o:1,lo:0,hi:2147483647},{n:"reason",k:"s",o:1,max:64},{n:"platform",k:"e",o:1,v:["universal","mobile"]}],120,"rooms");o("gem.socketState",[{n:"connected",k:"b"},{n:"reason",k:"e",o:1,v:["connecting","dropped","watchdog","terminal"]}],12,"socketState");o("gem.seatedEvent",[{n:"roomId",k:"s",max:64}],60,"partySeating");o("gem.autoStartFailedEvent",[{n:"roomId",k:"s",max:64},{n:"code",k:"s",max:64}],30,"autoStartFailure");o("gem.ticketEvent",[{n:"event",k:"e",v:["queued","matched","expired","cancelled","failed"]},{n:"ticketId",k:"s",max:64},{n:"partySize",k:"i",o:1,lo:1,hi:64},{n:"queuedAt",k:"i",o:1,lo:0,hi:4102444800},{n:"expiresAt",k:"i",o:1,lo:0,hi:4102444800},{n:"reason",k:"s",o:1,max:64},{n:"roomId",k:"s",o:1,max:64}],60,"ticketEvents");o("gem.signalEvent",[{n:"event",k:"e",v:["hello","offer","answer","ice","peerJoined","peerLeft","migration","matchEnded","error"]},{n:"matchId",k:"s",max:64},{n:"data",k:"j"}],1800,"p2p");o("gem.dedicatedEvent",[{n:"event",k:"e",v:["answer","error","matchEnded"]},{n:"matchId",k:"s",max:64},{n:"sdp",k:"s",o:1,max:10240},{n:"sessionId",k:"s",o:1,max:64},{n:"code",k:"s",o:1,max:64},{n:"message",k:"s",o:1,max:256},{n:"reason",k:"s",o:1,max:64}],120,"dedicated");o("gem.partyResult",[m,{n:"partyId",k:"s",o:1,max:64}],30,"parties");o("gem.clusterTarget",[{n:"clusterTargetId",k:"s",max:64},{n:"clusterTargetIds",k:"a",o:1,max:3,it:{n:"",k:"s",max:64}}],12,"clusterTarget");o("gem.devtools",[{n:"action",k:"e",v:["open","close","toggle"]}],30,"devtools");o("gem.screenshot",[{n:"maxWidth",k:"i",lo:1,hi:7680},{n:"maxHeight",k:"i",lo:1,hi:4320}],6,"screenshot");o("gem.screenshot.denied",[{n:"reason",k:"e",v:["not_wired","no_source","unsupported","unreadable","tainted","too_large","busy","declined","failed"]},{n:"retryable",k:"b"}],12,"screenshot");o("gem.requestContext",[],12,"feedbackContext");o("gem.gameContext",[{n:"context",k:"j"}],12,"feedbackContext");o("gem.signal",[{n:"signal",k:"e",v:["join","offer","answer","ice","migrationAck","hostUnreachable"]},{n:"matchId",k:"s",max:64},{n:"data",k:"j"}],1200,"p2p");o("gem.dedicatedOffer",[{n:"matchId",k:"s",max:64},{n:"sdp",k:"s",max:10240},{n:"intent",k:"e",v:["initial","ice_restart","full_reconnect"]}],60,"dedicated");o("gem.partyRequest",[m],12,"parties");o("gem.ready",[],5);o("gem.engaged",[],5,"engagement");o("gem.progress",[{n:"loaded",k:"i",lo:0,hi:1099511627776},{n:"total",k:"i",lo:0,hi:1099511627776}],600);o("gem.requestToken",[m,{n:"reason",k:"e",v:["initial","expiring","rejected"]}],12);o("gem.requestLocalServer",[m,{n:"gameRoomId",k:"s",max:64}],6,"localHost");o("gem.localServer",[m,{n:"serverId",k:"s",o:1,max:128}],30,"localHost");o("gem.localServer.denied",[m,{n:"retryable",k:"b"},{n:"reason",k:"e",v:["refused","unavailable"]}],30,"localHost");o("gem.exit",[{n:"reason",k:"s",o:1,max:64}],5);o("gem.openExternal",[{n:"url",k:"s",max:2048,f:"url"}],6);o("gem.requestFullscreen",[{n:"enabled",k:"b"}],30);o("gem.audioState",[{n:"muted",k:"b"}],120,"audioState");o("gem.rewardCue",[{n:"currencySlug",k:"s",max:32},{n:"expected",k:"i",o:1,lo:1,hi:1e9},{n:"origin",k:"o",o:1,fs:[{n:"x",k:"i",lo:0,hi:16384},{n:"y",k:"i",lo:0,hi:16384}]}],60,"rewardCue");o("gem.walletDisplay",[{n:"visible",k:"b"},{n:"currencies",k:"a",o:1,max:8,it:{n:"",k:"s",max:64}},{n:"score",k:"b",o:1}],60,"walletDisplay");o("gem.controlsDeclare",[{n:"uses",k:"o",fs:[{n:"lookSensitivity",k:"s",o:1,max:16,f:"code"},{n:"gamepadLookSensitivity",k:"s",o:1,max:16,f:"code"},{n:"invertLookY",k:"s",o:1,max:16,f:"code"},{n:"touchMovement",k:"s",o:1,max:16,f:"code"}]}],60,"controls");o("gem.menu",[{n:"settings",k:"b"},{n:"items",k:"a",o:1,max:4,it:{n:"",k:"o",fs:[{n:"id",k:"s",max:32},{n:"label",k:"s",max:40}]}}],60,"gameMenu");o("gem.menuSelect",[{n:"entry",k:"e",v:["settings","item"]},{n:"id",k:"s",o:1,max:32}],60,"gameMenu");o("gem.gemCorner",[{n:"corner",k:"e",v:["top-left","top-right","bottom-left","bottom-right"]}],12,"gemCorner");o("gem.settingsDeclare",[{n:"settings",k:"a",max:8,it:{n:"",k:"o",fs:[{n:"id",k:"s",max:40},{n:"label",k:"s",max:40},{n:"kind",k:"e",v:["toggle","slider","choice"]},{n:"value",k:"u",max:40,lo:-1e6,hi:1e6},{n:"quick",k:"b",o:1},{n:"icon",k:"s",o:1,max:16,f:"code"},{n:"min",k:"n",o:1,lo:-1e6,hi:1e6},{n:"max",k:"n",o:1,lo:-1e6,hi:1e6},{n:"step",k:"n",o:1,lo:0,hi:1e6},{n:"options",k:"a",o:1,max:4,it:{n:"",k:"o",fs:[{n:"id",k:"s",max:40},{n:"label",k:"s",max:40}]}}]}}],120,"gameSettings");o("gem.settingChange",[{n:"id",k:"s",max:40},{n:"value",k:"u",max:40,lo:-1e6,hi:1e6}],120,"gameSettings");o("gem.requestShare",[{n:"params",k:"a",max:16,it:{n:"",k:"o",fs:[{n:"key",k:"s",max:64},{n:"value",k:"s",max:512}]}}],6,"share");o("gem.requestAvatarPicker",[{n:"tab",k:"e",o:1,v:["2d","3d"]}],6,"avatarPicker");o("gem.vibrate",[{n:"pattern",k:"a",max:99,it:{n:"",k:"i",lo:0,hi:1e4}}],600,"vibration");o("gem.frameStats",[{n:"fps",k:"i",lo:0,hi:1e3},{n:"frameTimeP95Ms",k:"i",lo:0,hi:1e5},{n:"counts",k:"e",o:1,v:["pageFrames","gameDraws"]}],120,"frameStats");o("gem.portraitBorders",[{n:"name",k:"s",o:1,max:40}],60,"portraitBorders");o("gem.error",[{n:"code",k:"e",v:["version_mismatch","handshake_timeout","handshake_duplicate","invalid_message","rate_limited","token_unavailable","unsupported","unsupported_capability","internal"]},{n:"message",k:"s",o:1,max:256}],60);o("gem.requestPurchase",[m,{n:"purchaseKind",k:"e",v:["item","recipe"]},{n:"targetId",k:"s",max:64},{n:"currencySlug",k:"s",max:32},{n:"quantity",k:"i",o:1,lo:1,hi:10},{n:"catalogId",k:"s",o:1,max:64}],12,"purchases");o("gem.requestAvatar3dPurchase",[m,{n:"itemId",k:"s",max:64},{n:"currencySlug",k:"s",max:32}],12,"avatar3dPurchases");o("gem.purchaseResult",[m,{n:"outcome",k:"e",v:["ok","declined","unavailable"]},{n:"reason",k:"s",o:1,max:64,f:"code"},{n:"purchaseId",k:"s",o:1,max:64}],30,"purchases");o("gem.deviceSettings.put",[m,{n:"settings",k:"j"}],30,"deviceSettings");o("gem.deviceSettings.result",[m,{n:"outcome",k:"e",v:["stored","too_large","unavailable"]}],30,"deviceSettings");o("gem.requestAd",[m,{n:"placement",k:"s",max:32},{n:"format",k:"e",v:["interstitial","rewarded"]}],6,"ads");o("gem.adResult",[m,{n:"outcome",k:"e",v:["shown","no_ad","unavailable"]}],12,"ads");o("gem.signalMoment",[m,{n:"kind",k:"e",v:["level_end","run_end","match_end","menu_return","other_break"]},{n:"placement",k:"s",o:1,max:32}],6,"moments");o("gem.momentResult",[m,{n:"shown",k:"b"}],12,"moments");o("gem.requestSignIn",[m],6,"signIn");o("gem.signInResult",[m,{n:"outcome",k:"e",v:["signed_in","declined","unavailable"]}],12,"signIn");o("gem.requestFriendChallenge",[m,{n:"playerId",k:"s",max:64},{n:"template",k:"s",max:64},{n:"params",k:"j",o:1}],12,"friendChallenges");o("gem.friendChallengeResult",[m,{n:"outcome",k:"e",v:["accepted","cancelled","refused","unavailable","rate_limited","invalid"]},{n:"code",k:"s",o:1,max:64},{n:"param",k:"s",o:1,max:64},{n:"channel",k:"s",o:1,max:16},{n:"configVersion",k:"i",o:1,lo:0,hi:9007199254740991},{n:"retryAfterMs",k:"i",o:1,lo:0,hi:864e5},{n:"detail",k:"s",o:1,max:300}],30,"friendChallenges");var G=Object.freeze(V);b.__malformed=60;Object.freeze(b);Object.freeze(q);var ce=/^[a-z0-9][a-z0-9_-]{0,39}$/;function ue(t){return typeof t=="string"&&ce.test(t)}function z(t){if(t===null||ue(t))return t;let e=typeof t=="string"?JSON.stringify(t.length>48?`${t.slice(0,48)}\u2026`:t):`a value of type ${typeof t}`;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 M={now:()=>Date.now(),setTimeout:(t,e)=>setTimeout(t,e),clearTimeout:t=>clearTimeout(t)},x=class{constructor(e=M){this.clock=e;}clock;tokens=new Map;lastRefill=new Map;allow(e){let n=b[e];if(n===void 0)return false;let r=this.clock.now(),s=this.lastRefill.get(e)??r,i=this.tokens.get(e)??n,d=Math.max(0,r-s),a=Math.min(n,i+d*n/6e4);return a<1?(this.tokens.set(e,a),this.lastRefill.set(e,r),false):(this.tokens.set(e,a-1),this.lastRefill.set(e,r),true)}};function _(t,e){return t.toLowerCase()===e.toLowerCase()}function O(t){let e=t.toLowerCase();return e==="localhost"||e.endsWith(".localhost")||e==="[::1]"||e==="::1"?true:/^127(\.\d{1,3}){3}$/.test(e)}function Y(t,e){if(typeof e!="string"||e==="")return false;let n,r;try{n=new URL(t),r=new URL(e);}catch{return false}return n.protocol!=="http:"&&n.protocol!=="https:"||r.protocol!=="http:"&&r.protocol!=="https:"||n.username!==""||n.password!==""||n.pathname!=="/"||n.search!==""||n.hash!==""||n.port===""?false:O(n.hostname)&&O(r.hostname)}function K(t,e){if(t.min>t.max||e.min>e.max)return null;let n=Math.min(t.max,e.max),r=Math.max(t.min,e.min);return n>=r?n:null}var X="[gem: use gem.text.toPlain()]",J=new Set,Q;function ge(t){try{if(J.has(t))return;let e=globalThis.location;if(Q??=!!e?.port&&O(e.hostname??""),!Q)return;J.add(t),console.warn(`[gem] ${t} is PlayerText, turned into a string: players see ${X}. Render text.toPlain(value) (text is in @indiegems/gem-web-sdk/sdk).
|
|
2
2
|
${new Error().stack}`);}catch{}}var D=class{#e;#n;constructor(e,n="player text"){this.#e=e,this.#n=n,Object.freeze(this);}toString(){return ge(this.#n),X}toJSON(){return this.toString()}get[Symbol.toStringTag](){return "PlayerText"}static unwrap(e){return e.#e}};function j(t,e){return new D(t,e)}function Z(t){return Math.min(16384,Math.max(0,Math.round(Number.isFinite(t)?t:0)))}function pe(t,e){if(t!==true)return {visible:false};let n=[],r=false;for(let s of Array.isArray(e)?e:[])s==="score"?r=true:typeof s=="string"&&s.length>0&&s.length<=64&&!n.includes(s)&&n.push(s);return !r&&n.length===0?{visible:true}:{visible:true,currencies:n.slice(0,8),score:r}}function ye(t){let e=[];for(let n of Array.isArray(t)?t:[]){if(e.length===4)break;if(typeof n!="object"||n===null)continue;let{id:r,label:s}=n;typeof r!="string"||r.length===0||r.length>32||typeof s!="string"||s.trim().length===0||e.some(i=>i.id===r)||e.push({id:r,label:s.trim().slice(0,40)});}return e.length===0?{settings:false}:{settings:false,items:e}}function ee(t,e){return Math.min(e,Math.max(0,Math.round(Number.isFinite(t)?t:0)))}function fe(t){let e=t.untrusted,n=j(e.displayName,"gem.player.displayName"),r=e.displayTag||e.displayHandle,s=r?j(r,"gem.player.displayTag"):void 0,i=t.discriminator||t.displayTag,d=i&&/^[0-9]{1,8}$/.test(i)?i:void 0,a=t.avatarIconUrl||t.avatarUrl,c=/^[\da-f]{8}(-[\da-f]{4}){3}-[\da-f]{12}$/i,p=t.avatarIconId,y=t.avatar3dId,u={displayName:n,displayHandle:s??n,badges:(t.badges??[]).map(g=>({itemId:g.itemId,iconUrl:g.iconUrl}))};t.playerId&&(u.playerId=t.playerId),d&&(u.discriminator=d),s&&(u.displayTag=s),a&&(u.avatarIconUrl=u.avatarUrl=a),p&&c.test(p)&&(u.avatarIconId=p),y&&c.test(y)&&(u.avatar3dId=y),t.avatar3dModelUrl&&(u.avatar3dModelUrl=t.avatar3dModelUrl),t.avatar3dIconUrl&&(u.avatar3dIconUrl=t.avatar3dIconUrl),t.avatars3d&&(u.avatars3d=t.avatars3d.filter(g=>c.test(g.id)&&/^[a-z][a-z0-9_]*$/.test(g.family)).filter((g,P,T)=>T.findIndex(E=>E.family==g.family)==P).map(({family:g,id:P,modelUrl:T,iconUrl:E})=>({family:g,id:P,modelUrl:T,iconUrl:E})));let f=t.boost,h=(f?.multipliers??[]).map(g=>({currencyId:g.currencyId,currencySlug:g.currencySlug,multiplier:g.multiplierBp/1e4})),C=h.some(g=>g.multiplier>1);return u.boost=C&&f?.expiresInDays?{active:C,multipliers:h,expiresInDays:f.expiresInDays}:{active:C,multipliers:h},u}var he=1e4,w=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??M,this.inbound=new x(this.clock),this.outbound=new x(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(a=>_(a,e.origin))||Y(e.origin,this.options.selfOrigin)))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=G["gem.handshake"]?.(e.data);if(r)return this.refuse(e,`malformed handshake: ${r}`),false;let s=e.data;if(!_(s.embedder,e.origin))return this.refuse(e,`handshake claims embedder '${s.embedder}' but arrived from '${e.origin}'`),false;let i=e.ports?.[0];if(!i)return this.refuse(e,"handshake transferred no MessagePort"),false;let d=K(v,s.versions);return d===null?(i.onmessage=null,i.postMessage({gem:l,type:"gem.error",code:"version_mismatch",message:`frame supports v${v.min}..v${v.max}`}),i.close(),this.transition("refused"),this.options.onError?.("version_mismatch"),false):(this.port=i,this.version=d,i.onmessage=a=>this.receive(a.data,a.ports??[]),i.start?.(),this.peerCapabilities=s.capabilities??[],this.unbidden=s.unbidden===true,i.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=he){return this.state!=="waiting"?Promise.resolve(this.state):new Promise(n=>{let r=i=>{this.clock.clearTimeout(s),n(i);},s=this.clock.setTimeout(()=>{let i=this.settleWaiters.indexOf(r);i>=0&&this.settleWaiters.splice(i,1),n(this.state);},e);this.settleWaiters.push(r);})}progress(e,n){this.send({gem:l,type:"gem.progress",loaded:e,total:n});}requestToken(e,n){this.send({gem:l,type:"gem.requestToken",requestId:e,reason:n});}requestLocalServer(e,n){return this.parentSupports("localHost")?(this.send({gem:l,type:"gem.requestLocalServer",requestId:e,gameRoomId:n}),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 n={gem:l,type:"gem.rewardCue",currencySlug:String(e.currencySlug).slice(0,32)};return e.expected!==void 0&&Number.isFinite(e.expected)&&e.expected>=1&&(n.expected=Math.min(1e9,Math.round(e.expected))),e.origin&&(n.origin={x:Z(e.origin.x),y:Z(e.origin.y)}),this.send(n),true}showPortraitBorders(e){let n=z(e);return n===void 0||!this.gated("portraitBorders")?false:this.send(n===null?{gem:l,type:"gem.portraitBorders"}:{gem:l,type:"gem.portraitBorders",name:n})}setWalletVisible(e,n){return this.gated("walletDisplay")?this.send({gem:l,type:"gem.walletDisplay",...pe(e,n?.only)}):false}setMenu(e){return this.gated("gameMenu")?this.send({gem:l,type:"gem.menu",...ye(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}requestShare(e){return this.gated("share")?this.send({gem:l,type:"gem.requestShare",params:e.map(({key:n,value:r})=>({key:n,value:r}))}):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:ee(e.fps,1e3),frameTimeP95Ms:ee(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,n,r){this.send({gem:l,type:"gem.signal",signal:e,matchId:n,data:r});}dedicatedOffer(e,n,r){this.send({gem:l,type:"gem.dedicatedOffer",matchId:e,sdp:n,intent:r});}requestParty(e){return this.send({gem:l,type:"gem.partyRequest",requestId:e})}requestPurchase(e,n,r,s,i,d){return this.send({gem:l,type:"gem.requestPurchase",requestId:e,purchaseKind:n,targetId:r,currencySlug:s,...i===void 0?{}:{quantity:i},...d===void 0?{}:{catalogId:d}})}requestAvatar3dPurchase(e,n,r){return this.parentSupports("avatar3dPurchases")?this.send({gem:l,type:"gem.requestAvatar3dPurchase",requestId:e,itemId:n,currencySlug:r}):false}putDeviceSettings(e,n){return this.send({gem:l,type:"gem.deviceSettings.put",requestId:e,settings:n})}requestAd(e,n,r){return this.send({gem:l,type:"gem.requestAd",requestId:e,placement:n,format:r})}signalMoment(e,n,r){return this.send({gem:l,type:"gem.signalMoment",requestId:e,kind:n,...r===void 0?{}:{placement:r}})}readyCalled(){return this.readySent||this.readyPending}requestSignIn(e){return this.send({gem:l,type:"gem.requestSignIn",requestId:e})}requestFriendChallenge(e,n,r,s){return this.send({gem:l,type:"gem.requestFriendChallenge",requestId:e,playerId:n,template:r,...s===void 0?{}:{params:s}})}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 n of this.settleWaiters.splice(0))n(e);this.options.onStateChange?.(e);}}refuseMalformed(e,n){if(!this.inbound.allow(S)){this.options.onDropped?.(e,n);return}this.fail(e,n);}dropUnknownType(e){this.inbound.allow(S)&&this.options.onDropped?.("unsupported",`ignored unknown message type '${e}'`);}refuse(e,n){e.ports?.[0]?.close?.(),this.inbound.allow(S)&&this.options.onRefused?.(n);}fail(e,n){this.options.onError?.(e,n),this.state==="connected"&&this.port&&this.send({gem:l,type:"gem.error",code:e,...n===void 0?{}:{message:n}});}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 n=e.type;if(!this.outbound.allow(n))return this.options.onError?.("rate_limited",`frame exceeded its own limit for ${n}`),false;let r=G[n]?.(e);return r?(this.options.onError?.("internal",`refusing to send malformed ${n}: ${r}`),false):(this.port.postMessage(this.version===null?e:{...e,v:this.version}),true)}receive(e,n=[]){let r=false;try{r=this.dispatchInbound(e,n);}finally{r||ne(n);}}dispatchInbound(e,n){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 s=G[r];if(!s)return this.dropUnknownType(r),false;if(!this.inbound.allow(r))return this.fail("rate_limited",`parent exceeded the limit for ${r}`),false;let i=B(r);if(i!==void 0&&!this.options.capabilities?.includes(i))return this.fail("unsupported_capability",`${r} requires the '${i}' capability, which this frame did not advertise`),false;let d=s(e);if(d)return this.fail("invalid_message",`${r}: ${d}`),false;let a=e;if(a.v!==this.version)return this.fail("invalid_message",`${r}: expected v ${String(this.version)}`),false;switch(r){case "gem.token":this.options.onToken?.(a);break;case "gem.pause":this.options.onPause?.(a);break;case "gem.menuSelect":this.options.onMenuSelect?.(a);break;case "gem.settingChange":this.options.onSettingChange?.(a);break;case "gem.prefs":this.options.onPrefs?.(a);break;case "gem.cohorts":this.options.onCohorts?.(a);break;case "gem.earnAllowanceChanged":this.options.onEarnAllowanceChanged?.();break;case "gem.viewport":this.options.onViewport?.(a);break;case "gem.willTerminate":this.options.onWillTerminate?.(a);break;case "gem.devtools":this.options.onDevtools?.(a.action);break;case "gem.requestContext":this.options.onRequestContext?.();break;case "gem.screenshot":{let c=n[0];if(!c){this.options.onError?.("invalid_message","gem.screenshot transferred no MessagePort");break}let p={maxWidth:a.maxWidth,maxHeight:a.maxHeight};if(!this.options.onScreenshot){c.close(),this.screenshotDenied("not_wired",false);break}return ne(n.slice(1)),this.options.onScreenshot(p,c,(y,u)=>this.screenshotDenied(y,u)),true}case "gem.token.denied":this.options.onTokenDenied?.(a);break;case "gem.localServer":this.options.onLocalServer?.(a);break;case "gem.localServer.denied":this.options.onLocalServerDenied?.(a);break;case "gem.player":{this.options.onPlayer?.(fe(a));break}case "gem.roomEvent":this.options.onRoomEvent?.(a);break;case "gem.seatedEvent":this.options.onSeatedEvent?.(a);break;case "gem.autoStartFailedEvent":this.options.onAutoStartFailedEvent?.(a);break;case "gem.ticketEvent":this.options.onTicketEvent?.(a);break;case "gem.socketState":this.options.onSocketState?.(a);break;case "gem.signalEvent":this.options.onSignalEvent?.(a);break;case "gem.dedicatedEvent":this.options.onDedicatedEvent?.(a);break;case "gem.clusterTarget":this.options.onClusterTarget?.(a);break;case "gem.partyResult":this.options.onPartyResult?.(a);break;case "gem.purchaseResult":this.options.onPurchaseResult?.(a);break;case "gem.deviceSettings":this.options.onDeviceSettings?.(a);break;case "gem.deviceSettings.result":this.options.onDeviceSettingsResult?.(a);break;case "gem.adResult":this.options.onAdResult?.(a);break;case "gem.momentResult":this.options.onMomentResult?.(a);break;case "gem.signInResult":this.options.onSignInResult?.(a);break;case "gem.friendChallengeResult":this.options.onFriendChallengeResult?.(a);break;case "gem.error":this.options.onError?.(a.code,a.message);break;default:this.fail("unsupported",`no frame handler for '${r}'`);}return false}screenshotDenied(e,n){this.send({gem:l,type:"gem.screenshot.denied",reason:e,retryable:n});}};function ne(t){for(let e of t)try{e?.close?.();}catch{}}$();function ke(t){if((t.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 w({...t,expectedSource:t.expectedSource??window.parent}),n=r=>{let s=e.handleWindowMessage({data:r.data,origin:r.origin,source:r.source,ports:r.ports});return s&&window.removeEventListener("message",n),s};return window.addEventListener("message",n),U(window,n),e}var te={connect:ke,GemFrame:w,PROTOCOL:l,SUPPORTED_VERSIONS:v};window.GemWebSdkBridge=te;var Yn=te;return Yn;})();
|