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