@indiegems/gem-web-sdk 22.0.0 → 23.0.1

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/dist/sdk.d.ts CHANGED
@@ -1086,6 +1086,7 @@ declare class CharactersApi {
1086
1086
  private readonly scopes;
1087
1087
  constructor(api: GameApi$1, saves?: SavesOptions | undefined, identity?: (() => string | null) | undefined, resolveCurrencyId?: ((slugOrId: string) => Promise<string | undefined>) | undefined);
1088
1088
  private readonly scope;
1089
+ refreshHeld(): void;
1089
1090
  list(signal?: AbortSignal): Promise<readonly Character[]>;
1090
1091
  get(id: string, signal?: AbortSignal): Promise<Character>;
1091
1092
  create(options: CreateCharacterOptions): Promise<Character>;
@@ -1416,8 +1417,13 @@ declare class FriendChallengeError extends GemApiError {
1416
1417
  readonly configVersion?: number;
1417
1418
  });
1418
1419
  }
1420
+ interface PlayInviteRequest {
1421
+ readonly params?: Readonly<Record<string, string>>;
1422
+ }
1419
1423
  interface FriendsApiDependencies {
1420
1424
  readonly challenge?: (request: FriendChallengeRequest) => Promise<FriendChallengeOutcome>;
1425
+ readonly inviteToPlay?: (request?: PlayInviteRequest) => Promise<boolean>;
1426
+ readonly setInviteParams?: (params: Readonly<Record<string, string>> | null) => boolean;
1421
1427
  readonly launchedChallengeId?: string;
1422
1428
  }
1423
1429
  declare class FriendsApi {
@@ -1425,6 +1431,8 @@ declare class FriendsApi {
1425
1431
  constructor(api: GameApi$1, dependencies?: FriendsApiDependencies);
1426
1432
  list(options?: ListFriendsOptions): Promise<FriendsPage>;
1427
1433
  challenge(request: FriendChallengeRequest): Promise<FriendChallengeOutcome>;
1434
+ inviteToPlay(request?: PlayInviteRequest): Promise<boolean>;
1435
+ setInviteParams(params: Readonly<Record<string, string>> | null): boolean;
1428
1436
  inbox(options?: ListFriendChallengesOptions): Promise<FriendChallengesPage>;
1429
1437
  launchedChallenge(options?: {
1430
1438
  readonly signal?: AbortSignal;
@@ -2208,6 +2216,10 @@ interface GemCohorts$1 {
2208
2216
  variantKey: string;
2209
2217
  }[];
2210
2218
  }
2219
+ interface GemInventoryChanged {
2220
+ readonly gem: typeof PROTOCOL;
2221
+ readonly type: "gem.inventoryChanged";
2222
+ }
2211
2223
  interface GemViewport$1 {
2212
2224
  readonly gem: typeof PROTOCOL;
2213
2225
  readonly type: "gem.viewport";
@@ -2445,6 +2457,29 @@ interface GemFriendChallengeResult {
2445
2457
  readonly retryAfterMs?: number;
2446
2458
  readonly detail?: string;
2447
2459
  }
2460
+ interface GemRequestPlayInvite {
2461
+ readonly gem: typeof PROTOCOL;
2462
+ readonly type: "gem.requestPlayInvite";
2463
+ readonly requestId: string;
2464
+ readonly params?: {
2465
+ key: string;
2466
+ value: string;
2467
+ }[];
2468
+ }
2469
+ interface GemPlayInviteResult {
2470
+ readonly gem: typeof PROTOCOL;
2471
+ readonly type: "gem.playInviteResult";
2472
+ readonly requestId: string;
2473
+ readonly shown: boolean;
2474
+ }
2475
+ interface GemInviteParams {
2476
+ readonly gem: typeof PROTOCOL;
2477
+ readonly type: "gem.inviteParams";
2478
+ readonly params?: {
2479
+ key: string;
2480
+ value: string;
2481
+ }[];
2482
+ }
2448
2483
  interface GemRequestAppLinks {
2449
2484
  readonly gem: typeof PROTOCOL;
2450
2485
  readonly type: "gem.requestAppLinks";
@@ -4809,6 +4844,7 @@ interface FramePlayer extends PlayerIdentity {
4809
4844
  readonly boost: PlayerBoost;
4810
4845
  }
4811
4846
  type GemArcadeAsk = Omit<GemRequestAppLinks, "gem"> | Omit<GemRequestOpenApp, "gem"> | Omit<GemRequestOpenGame, "gem"> | Omit<GemRequestSimilarGames, "gem"> | Omit<GemRequestStoreOffers, "gem"> | Omit<GemRequestStorePurchase, "gem"> | Omit<GemRequestStoreOfferSheet, "gem">;
4847
+ type GemFriendsWindowAsk = Omit<GemRequestPlayInvite, "gem"> | Omit<GemInviteParams, "gem">;
4812
4848
  type GemArcadeAnswer = GemAppLinksResult | GemOpenAppResult | GemOpenGameResult | GemSimilarGamesResult | GemStoreOffersResult | GemStorePurchaseResult | GemStorePurchaseSettled | GemStoreOfferSheetResult;
4813
4849
  interface FrameCallbacks {
4814
4850
  onToken?(msg: GemToken): void;
@@ -4818,6 +4854,7 @@ interface FrameCallbacks {
4818
4854
  onPrefs?(msg: GemPrefs$1): void;
4819
4855
  onCohorts?(msg: GemCohorts$1): void;
4820
4856
  onEarnAllowanceChanged?(): void;
4857
+ onInventoryChanged?(msg: GemInventoryChanged): void;
4821
4858
  onViewport?(msg: GemViewport$1): void;
4822
4859
  onWillTerminate?(msg: GemWillTerminate): void;
4823
4860
  onDevtools?(action: "open" | "close" | "toggle"): void;
@@ -4851,6 +4888,7 @@ interface FrameCallbacks {
4851
4888
  onSignInResult?(msg: GemSignInResult): void;
4852
4889
  onFriendChallengeResult?(msg: GemFriendChallengeResult): void;
4853
4890
  onArcadeAnswer?(msg: GemArcadeAnswer): void;
4891
+ onPlayInviteResult?(msg: GemPlayInviteResult): void;
4854
4892
  onError?(code: GemErrorCode, message?: string): void;
4855
4893
  onDropped?(code: GemErrorCode, message?: string): void;
4856
4894
  onStateChange?(state: FrameState): void;
@@ -4931,7 +4969,7 @@ declare class GemFrame {
4931
4969
  readyCalled(): boolean;
4932
4970
  requestSignIn(requestId: string): boolean;
4933
4971
  requestFriendChallenge(requestId: string, playerId: string, template: string, params?: Readonly<Record<string, string | number>>): boolean;
4934
- requestArcade(msg: GemArcadeAsk): boolean;
4972
+ requestArcade(msg: GemArcadeAsk | GemFriendsWindowAsk): boolean;
4935
4973
  close(): void;
4936
4974
  private transition;
4937
4975
  private refuseMalformed;
@@ -5392,4 +5430,4 @@ interface ExitAnalytics {
5392
5430
  }
5393
5431
  declare function leaveAndExit(rooms: ExitRooms, bridge: ExitBridge | null, reason?: string, analytics?: ExitAnalytics): Promise<void>;
5394
5432
  declare function createGem(options?: GemOptions): Gem;
5395
- 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$1 as 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 Base64String, type BootMark, type BootTimeline, type BrandingApi, type BrandingAsset, type BrandingAssetOptions, type BrandingCurrency, type BrandingImageOptions, type BrandingList, type BrandingLookup, type BrandingTheme, type BrandingVariant, type BroadcastOptions, type BytesResponse, CONDITIONAL_HEADERS, type Challenge, type ChallengeWindow, ChallengesApi, type ClientOptions, type Clock, type ConditionalRequestHeaders, 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$1 as 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 GameApi, 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, type GemErrorReason, 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 GemMatchServer, type GemMatchServerModule, type GemOptions, type GemPlayer, type GemPreferredRoute, type GemPrefs, type GemRecommendedSettings, type GemReservedArea, GemSaveError, type GemServer, type GemServerBundle, type GemServerFactory, type GemServerHost, type GemServerHostProfile, type GemServerIdentity, type GemServerLifecycle, type GemServerOptions, type GemServerProfile, type GemTerminationNotice, GemUnframedError, type GemViewport, type GetLeaderboardOptions, type GraphicsApi, type HostTokenSource, type HostTokenSourceOptions, type JoinWelcome, type Leaderboard, type LeaderboardEntry, type LeaderboardPeriod, LeaderboardsApi, type ListChallengesOptions, type ListFriendChallengesOptions, type ListFriendsOptions, MAX_PERIODS_BACK, type MatchBackfillState, type MatchConnectOptions, type MatchConnection, type MatchHosting, type MatchHostingMode, type MatchPlayerReport, type MatchPlayerReportResult, 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$1 as PlayerBadge, type PlayerBoost, type PlayerBoostMultiplier, type PlayerIdentity, type PlayerProfile, type PlayerScope, PlayerText, type PreferredRouteOptions, type ProfileCallOptions, type ProfileShowcaseEntry$1 as 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 RequestOptions, type RewardCue, type RewardPresentation, type RewardedStatus, type RoomArgValue, type SavePage, type SaveRecord, type SendOptions$1 as SendOptions, type ServerApi, type ServerBundleHost, 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 TokenGrant, type Transport, type TransportAdvert, type TransportKind, TransportRefusal, type TransportRequest, type TransportResponse, UNRELIABLE_CHANNEL_LABEL, type VersionedGetOptions, type VersionedResponse, type VibrationApi, type WalletVisibleOptions, type WornAvatar3d$1 as WornAvatar3d, asPlayerText, createBootTimeline, createGem, createGemServer, createHostTokenSource, createMatchServer, defineServer, experimentSelection, leaveAndExit, mapIdentity, markOnResolve, platformIconUrl, presentJoinCredential, readTemplateTransports, readTransportAdvert, reportOnResolve, systemClock, text, toBase64, webTransportAvailable };
5433
+ 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$1 as 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 Base64String, type BootMark, type BootTimeline, type BrandingApi, type BrandingAsset, type BrandingAssetOptions, type BrandingCurrency, type BrandingImageOptions, type BrandingList, type BrandingLookup, type BrandingTheme, type BrandingVariant, type BroadcastOptions, type BytesResponse, CONDITIONAL_HEADERS, type Challenge, type ChallengeWindow, ChallengesApi, type ClientOptions, type Clock, type ConditionalRequestHeaders, 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$1 as 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 GameApi, 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, type GemErrorReason, 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 GemMatchServer, type GemMatchServerModule, type GemOptions, type GemPlayer, type GemPreferredRoute, type GemPrefs, type GemRecommendedSettings, type GemReservedArea, GemSaveError, type GemServer, type GemServerBundle, type GemServerFactory, type GemServerHost, type GemServerHostProfile, type GemServerIdentity, type GemServerLifecycle, type GemServerOptions, type GemServerProfile, type GemTerminationNotice, GemUnframedError, type GemViewport, type GetLeaderboardOptions, type GraphicsApi, type HostTokenSource, type HostTokenSourceOptions, type JoinWelcome, type Leaderboard, type LeaderboardEntry, type LeaderboardPeriod, LeaderboardsApi, type ListChallengesOptions, type ListFriendChallengesOptions, type ListFriendsOptions, MAX_PERIODS_BACK, type MatchBackfillState, type MatchConnectOptions, type MatchConnection, type MatchHosting, type MatchHostingMode, type MatchPlayerReport, type MatchPlayerReportResult, 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 PlayInviteRequest, type PlayerBadge$1 as PlayerBadge, type PlayerBoost, type PlayerBoostMultiplier, type PlayerIdentity, type PlayerProfile, type PlayerScope, PlayerText, type PreferredRouteOptions, type ProfileCallOptions, type ProfileShowcaseEntry$1 as 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 RequestOptions, type RewardCue, type RewardPresentation, type RewardedStatus, type RoomArgValue, type SavePage, type SaveRecord, type SendOptions$1 as SendOptions, type ServerApi, type ServerBundleHost, 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 TokenGrant, type Transport, type TransportAdvert, type TransportKind, TransportRefusal, type TransportRequest, type TransportResponse, UNRELIABLE_CHANNEL_LABEL, type VersionedGetOptions, type VersionedResponse, type VibrationApi, type WalletVisibleOptions, type WornAvatar3d$1 as WornAvatar3d, asPlayerText, createBootTimeline, createGem, createGemServer, createHostTokenSource, createMatchServer, defineServer, experimentSelection, leaveAndExit, mapIdentity, markOnResolve, platformIconUrl, presentJoinCredential, readTemplateTransports, readTransportAdvert, reportOnResolve, systemClock, text, toBase64, webTransportAvailable };
@@ -1,6 +1,6 @@
1
1
  # The function surface — API reference
2
2
 
3
- Generated from `@indiegems/gem-web-sdk/function` v22.0.0, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
3
+ Generated from `@indiegems/gem-web-sdk/function` v23.0.1, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
4
4
 
5
5
  `@indiegems/gem-web-sdk/function` exports exactly the symbols on this page and nothing else.
6
6
 
@@ -2039,8 +2039,9 @@ Throw away what is cached, so the next [InventoryApi.snapshot](#inventoryapi-sna
2039
2039
  asks.
2040
2040
 
2041
2041
  For when something you did not do changed the inventory — a purchase on
2042
- another device, a grant from a server. The SDK already drops the cache
2043
- itself after any change it made.
2042
+ another device, a grant from a server — and nothing told you. The SDK
2043
+ already drops the cache itself after any change it made, and on an
2044
+ Arcade's hint that this game's inventory changed on the server.
2044
2045
 
2045
2046
  <a id="inventoryapi-onchanged"></a>
2046
2047
 
@@ -2053,12 +2054,17 @@ onChanged(listener: () => void): () => void
2053
2054
  Run something whenever this inventory changes, and get back a function that
2054
2055
  stops listening.
2055
2056
 
2056
- ⚠️ LOCAL CHANGES ONLY — this fires for changes THIS game made through this
2057
- SDK. It does NOT fire when an inventory changes anywhere else: another
2058
- device, a game server, an admin tool, or a gift from another player. Do not
2059
- build "keep the bag live" on it; use it to react to your own writes, and
2060
- call [InventoryApi.refresh](#inventoryapi-refresh) when you have reason to think something
2061
- else moved.
2057
+ Fires for every change THIS game made through this SDK, and — on an Arcade
2058
+ that relays it — for any change to this game's inventory on the server: a
2059
+ grant from your function or server, a purchase, a gift accepted, a support
2060
+ grant, another device. It is a cue to re-read, not a receipt: it carries
2061
+ nothing, so call [InventoryApi.snapshot](#inventoryapi-snapshot) for what changed. After your
2062
+ own function's grant, show the function's answer and let this redraw.
2063
+
2064
+ An older Arcade sends no hint, and there it fires for your own writes
2065
+ only. Keep a fallback that does not depend on it: refresh on
2066
+ `visibilitychange` to `visible` and after any action that could involve
2067
+ another player. Do not poll.
2062
2068
 
2063
2069
  | Parameter | Type |
2064
2070
  | --- | --- |
@@ -5030,6 +5036,31 @@ readonly configVersion?: number
5030
5036
  On `template_not_on_channel`, when a config version is promoted to that
5031
5037
  channel: the version the template is missing from.
5032
5038
 
5039
+ <a id="playinviterequest"></a>
5040
+
5041
+ ## PlayInviteRequest
5042
+
5043
+ ```ts
5044
+ interface PlayInviteRequest
5045
+ ```
5046
+
5047
+ What `gem.friends.inviteToPlay` takes.
5048
+
5049
+ <a id="playinviterequest-params"></a>
5050
+
5051
+ ## PlayInviteRequest.params
5052
+
5053
+ ```ts
5054
+ readonly params?: Readonly<Record<string, string>>
5055
+ ```
5056
+
5057
+ Your own launch parameters for what the Arcade's link and invites open —
5058
+ `{ room: joinCode }` for a room joined by code — exactly as they should
5059
+ reach your game, on `gem.share.request`'s rules: at most 16, keys a letter
5060
+ then up to 63 letters, digits, `_` or `-`, string values of at most 512
5061
+ characters. For this one opening, they replace what
5062
+ `gem.friends.setInviteParams` declared. Omit it to use that declaration.
5063
+
5033
5064
  <a id="friendsapi"></a>
5034
5065
 
5035
5066
  ## FriendsApi
@@ -5144,6 +5175,95 @@ challengeButton.onclick = async () => {
5144
5175
  };
5145
5176
  ```
5146
5177
 
5178
+ <a id="friendsapi-invitetoplay"></a>
5179
+
5180
+ ## FriendsApi.inviteToPlay
5181
+
5182
+ ```ts
5183
+ inviteToPlay(request?: PlayInviteRequest): Promise<boolean>
5184
+ ```
5185
+
5186
+ Ask the Arcade to open ITS invite sheet, so the player can invite friends
5187
+ to come and play this game with them.
5188
+
5189
+ The Arcade lists the player's friends in its own chrome and sends an
5190
+ invite only when the player presses Invite there. A friend who accepts is
5191
+ opened into this game by the Arcade, and their quick-join seats them in
5192
+ the player's room when there is a seat: your game makes no call for it,
5193
+ and reads them as a room member who shares the player's `groupId`. Your
5194
+ game names nobody and writes no text.
5195
+
5196
+ An Arcade that does not offer the sheet answers `false` at once, and asks
5197
+ nothing. Hide the button on `gem.frame.parentSupports('playInvites')`
5198
+ rather than letting a player press one that cannot work.
5199
+
5200
+ ⚠️ **Call it ONLY from a player's press**, never on a timer or as a screen
5201
+ opens. The Arcade answers an ask with no press behind it `false`, and
5202
+ shows nothing.
5203
+
5204
+ RESOLVES `true` when the Arcade opened its sheet, and `false` when it did
5205
+ not: outside the Arcade, without `playInvites`, with another sheet
5206
+ already open, without a press, or when no answer arrived. **That is all it
5207
+ says** — never whom the player invited, how many, or whether any invite
5208
+ was sent — so never gate a reward on it. Never rejects.
5209
+
5210
+ Calls made while an ask is open share its answer.
5211
+
5212
+ **The window's share link and its invites are one system.** Pass
5213
+ `params` — your own launch parameters, `{ room: joinCode }` for a room
5214
+ joined by code — and a friend who accepts and anyone who opens the link
5215
+ arrive with them, on `gem.share.request`'s rules. Omitted, the window uses
5216
+ what [FriendsApi.setInviteParams](#friendsapi-setinviteparams) declared. A param those rules
5217
+ refuse is said on the console and nothing is asked: the call resolves
5218
+ `false`.
5219
+
5220
+ | Parameter | Type |
5221
+ | --- | --- |
5222
+ | `request` | `PlayInviteRequest` |
5223
+
5224
+ ```ts
5225
+ inviteButton.onclick = async () => {
5226
+ const shown = await gem.friends.inviteToPlay({ params: { room: joinCode } });
5227
+ if (!shown) showJoinCode(); // the Arcade's sheet did not open: your own fallback
5228
+ };
5229
+ ```
5230
+
5231
+ <a id="friendsapi-setinviteparams"></a>
5232
+
5233
+ ## FriendsApi.setInviteParams
5234
+
5235
+ ```ts
5236
+ setInviteParams(params: Readonly<Record<string, string>> | null): boolean
5237
+ ```
5238
+
5239
+ Say what the Arcade's Friends window opens when the PLAYER opens it from
5240
+ the Arcade's own menu over your game: your launch parameters, carried by
5241
+ its share link and its friend invites alike, on `gem.share.request`'s
5242
+ rules. Pass `null` to clear.
5243
+
5244
+ Call it when the player enters a room joined by code —
5245
+ `setInviteParams({ room: joinCode })` — and `setInviteParams(null)` when
5246
+ they leave it, so the window never invites anyone into a room that is
5247
+ gone. The latest call stands until the next; the SDK holds it and says it
5248
+ again after a reconnect. An explicit `inviteToPlay({ params })` wins for
5249
+ that one opening. Nothing comes back, and nothing changes on screen.
5250
+
5251
+ | Parameter | Type |
5252
+ | --- | --- |
5253
+ | `params` | `Readonly<Record<string, string>> \| null` |
5254
+
5255
+ **Returns.** whether the declaration reached the Arcade now. `false` outside
5256
+ the Arcade, without `playInvites`, before the bridge is up (it is sent on
5257
+ connect) and for params the share rules refuse, which are said on the
5258
+ console; the last declaration then stands.
5259
+
5260
+ ```ts
5261
+ // On entering a room joined by code:
5262
+ gem.friends.setInviteParams({ room: joinCode });
5263
+ // ...and on leaving it:
5264
+ gem.friends.setInviteParams(null);
5265
+ ```
5266
+
5147
5267
  <a id="friendsapi-inbox"></a>
5148
5268
 
5149
5269
  ## FriendsApi.inbox
@@ -1,6 +1,6 @@
1
1
  # The browser surface — API reference
2
2
 
3
- Generated from `@indiegems/gem-web-sdk/sdk` v22.0.0, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
3
+ Generated from `@indiegems/gem-web-sdk/sdk` v23.0.1, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
4
4
 
5
5
  `@indiegems/gem-web-sdk/sdk` is the one import a game writes, wherever its code runs. `@indiegems/gem-web-sdk/game` exports exactly the symbols on this page and nothing else, for a build that wants only this half.
6
6
 
@@ -907,8 +907,9 @@ Throw away what is cached, so the next [InventoryApi.snapshot](#inventoryapi-sna
907
907
  asks.
908
908
 
909
909
  For when something you did not do changed the inventory — a purchase on
910
- another device, a grant from a server. The SDK already drops the cache
911
- itself after any change it made.
910
+ another device, a grant from a server — and nothing told you. The SDK
911
+ already drops the cache itself after any change it made, and on an
912
+ Arcade's hint that this game's inventory changed on the server.
912
913
 
913
914
  <a id="inventoryapi-onchanged"></a>
914
915
 
@@ -921,12 +922,17 @@ onChanged(listener: () => void): () => void
921
922
  Run something whenever this inventory changes, and get back a function that
922
923
  stops listening.
923
924
 
924
- ⚠️ LOCAL CHANGES ONLY — this fires for changes THIS game made through this
925
- SDK. It does NOT fire when an inventory changes anywhere else: another
926
- device, a game server, an admin tool, or a gift from another player. Do not
927
- build "keep the bag live" on it; use it to react to your own writes, and
928
- call [InventoryApi.refresh](#inventoryapi-refresh) when you have reason to think something
929
- else moved.
925
+ Fires for every change THIS game made through this SDK, and — on an Arcade
926
+ that relays it — for any change to this game's inventory on the server: a
927
+ grant from your function or server, a purchase, a gift accepted, a support
928
+ grant, another device. It is a cue to re-read, not a receipt: it carries
929
+ nothing, so call [InventoryApi.snapshot](#inventoryapi-snapshot) for what changed. After your
930
+ own function's grant, show the function's answer and let this redraw.
931
+
932
+ An older Arcade sends no hint, and there it fires for your own writes
933
+ only. Keep a fallback that does not depend on it: refresh on
934
+ `visibilitychange` to `visible` and after any action that could involve
935
+ another player. Do not poll.
930
936
 
931
937
  | Parameter | Type |
932
938
  | --- | --- |
@@ -8528,6 +8534,31 @@ readonly configVersion?: number
8528
8534
  On `template_not_on_channel`, when a config version is promoted to that
8529
8535
  channel: the version the template is missing from.
8530
8536
 
8537
+ <a id="playinviterequest"></a>
8538
+
8539
+ ## PlayInviteRequest
8540
+
8541
+ ```ts
8542
+ interface PlayInviteRequest
8543
+ ```
8544
+
8545
+ What `gem.friends.inviteToPlay` takes.
8546
+
8547
+ <a id="playinviterequest-params"></a>
8548
+
8549
+ ## PlayInviteRequest.params
8550
+
8551
+ ```ts
8552
+ readonly params?: Readonly<Record<string, string>>
8553
+ ```
8554
+
8555
+ Your own launch parameters for what the Arcade's link and invites open —
8556
+ `{ room: joinCode }` for a room joined by code — exactly as they should
8557
+ reach your game, on `gem.share.request`'s rules: at most 16, keys a letter
8558
+ then up to 63 letters, digits, `_` or `-`, string values of at most 512
8559
+ characters. For this one opening, they replace what
8560
+ `gem.friends.setInviteParams` declared. Omit it to use that declaration.
8561
+
8531
8562
  <a id="friendsapi"></a>
8532
8563
 
8533
8564
  ## FriendsApi
@@ -8642,6 +8673,95 @@ challengeButton.onclick = async () => {
8642
8673
  };
8643
8674
  ```
8644
8675
 
8676
+ <a id="friendsapi-invitetoplay"></a>
8677
+
8678
+ ## FriendsApi.inviteToPlay
8679
+
8680
+ ```ts
8681
+ inviteToPlay(request?: PlayInviteRequest): Promise<boolean>
8682
+ ```
8683
+
8684
+ Ask the Arcade to open ITS invite sheet, so the player can invite friends
8685
+ to come and play this game with them.
8686
+
8687
+ The Arcade lists the player's friends in its own chrome and sends an
8688
+ invite only when the player presses Invite there. A friend who accepts is
8689
+ opened into this game by the Arcade, and their quick-join seats them in
8690
+ the player's room when there is a seat: your game makes no call for it,
8691
+ and reads them as a room member who shares the player's `groupId`. Your
8692
+ game names nobody and writes no text.
8693
+
8694
+ An Arcade that does not offer the sheet answers `false` at once, and asks
8695
+ nothing. Hide the button on `gem.frame.parentSupports('playInvites')`
8696
+ rather than letting a player press one that cannot work.
8697
+
8698
+ ⚠️ **Call it ONLY from a player's press**, never on a timer or as a screen
8699
+ opens. The Arcade answers an ask with no press behind it `false`, and
8700
+ shows nothing.
8701
+
8702
+ RESOLVES `true` when the Arcade opened its sheet, and `false` when it did
8703
+ not: outside the Arcade, without `playInvites`, with another sheet
8704
+ already open, without a press, or when no answer arrived. **That is all it
8705
+ says** — never whom the player invited, how many, or whether any invite
8706
+ was sent — so never gate a reward on it. Never rejects.
8707
+
8708
+ Calls made while an ask is open share its answer.
8709
+
8710
+ **The window's share link and its invites are one system.** Pass
8711
+ `params` — your own launch parameters, `{ room: joinCode }` for a room
8712
+ joined by code — and a friend who accepts and anyone who opens the link
8713
+ arrive with them, on `gem.share.request`'s rules. Omitted, the window uses
8714
+ what [FriendsApi.setInviteParams](#friendsapi-setinviteparams) declared. A param those rules
8715
+ refuse is said on the console and nothing is asked: the call resolves
8716
+ `false`.
8717
+
8718
+ | Parameter | Type |
8719
+ | --- | --- |
8720
+ | `request` | `PlayInviteRequest` |
8721
+
8722
+ ```ts
8723
+ inviteButton.onclick = async () => {
8724
+ const shown = await gem.friends.inviteToPlay({ params: { room: joinCode } });
8725
+ if (!shown) showJoinCode(); // the Arcade's sheet did not open: your own fallback
8726
+ };
8727
+ ```
8728
+
8729
+ <a id="friendsapi-setinviteparams"></a>
8730
+
8731
+ ## FriendsApi.setInviteParams
8732
+
8733
+ ```ts
8734
+ setInviteParams(params: Readonly<Record<string, string>> | null): boolean
8735
+ ```
8736
+
8737
+ Say what the Arcade's Friends window opens when the PLAYER opens it from
8738
+ the Arcade's own menu over your game: your launch parameters, carried by
8739
+ its share link and its friend invites alike, on `gem.share.request`'s
8740
+ rules. Pass `null` to clear.
8741
+
8742
+ Call it when the player enters a room joined by code —
8743
+ `setInviteParams({ room: joinCode })` — and `setInviteParams(null)` when
8744
+ they leave it, so the window never invites anyone into a room that is
8745
+ gone. The latest call stands until the next; the SDK holds it and says it
8746
+ again after a reconnect. An explicit `inviteToPlay({ params })` wins for
8747
+ that one opening. Nothing comes back, and nothing changes on screen.
8748
+
8749
+ | Parameter | Type |
8750
+ | --- | --- |
8751
+ | `params` | `Readonly<Record<string, string>> \| null` |
8752
+
8753
+ **Returns.** whether the declaration reached the Arcade now. `false` outside
8754
+ the Arcade, without `playInvites`, before the bridge is up (it is sent on
8755
+ connect) and for params the share rules refuse, which are said on the
8756
+ console; the last declaration then stands.
8757
+
8758
+ ```ts
8759
+ // On entering a room joined by code:
8760
+ gem.friends.setInviteParams({ room: joinCode });
8761
+ // ...and on leaving it:
8762
+ gem.friends.setInviteParams(null);
8763
+ ```
8764
+
8645
8765
  <a id="friendsapi-inbox"></a>
8646
8766
 
8647
8767
  ## FriendsApi.inbox
@@ -9075,6 +9195,12 @@ The call is made once. It is never repeated for you, because your function
9075
9195
  may have granted or written something: see [GemFunctionError.retryable](#gemfunctionerror-retryable)
9076
9196
  for whether repeating it could help.
9077
9197
 
9198
+ The answer is the receipt: when this resolves, what your function says it
9199
+ granted has been written. A game shows it at once and re-reads the
9200
+ inventory in the background (`gem.me.inventory.refresh()`, then
9201
+ `snapshot()`, or on `gem.me.inventory.onChanged`); never hold the player on
9202
+ a loop that re-reads until the grant shows.
9203
+
9078
9204
  ```js
9079
9205
  const result = await gem.functions.invoke({ v: 2, runId, finishMs });
9080
9206
  const { accepted, why } = result.json();
@@ -12015,10 +12141,12 @@ readonly friends: FriendsApi
12015
12141
  ```
12016
12142
 
12017
12143
  The signed-in player's accepted friends — display identity only,
12018
- read-only, paginated — and the one ask that reaches past them:
12144
+ read-only, paginated — and the asks that reach past them:
12019
12145
  [FriendsApi.challenge](#friendsapi-challenge), which asks the Arcade to send a friend a
12020
- challenge after the player confirms it in the Arcade's own sheet. The
12021
- receiving side reads the challenges this player holds in this game:
12146
+ challenge after the player confirms it in the Arcade's own sheet, and
12147
+ [FriendsApi.inviteToPlay](#friendsapi-invitetoplay), which asks the Arcade to open its own
12148
+ invite-to-play sheet. The receiving side reads the challenges this player
12149
+ holds in this game:
12022
12150
  [FriendsApi.launchedChallenge](#friendsapi-launchedchallenge) for the one this frame was launched
12023
12151
  with, [FriendsApi.inbox](#friendsapi-inbox) for all of them, and
12024
12152
  [FriendsApi.markAnswered](#friendsapi-markanswered) once one has been played.
@@ -20102,7 +20230,7 @@ readonly playWith: PlayWithOutcome | null
20102
20230
 
20103
20231
  What the last [RoomManager.quickJoin](#roommanager-quickjoin) did when the Arcade opened
20104
20232
  your game to play with someone — a friend whose Join the player pressed,
20105
- or their party's leader. Read-only.
20233
+ a friend's invite, or their party's leader. Read-only.
20106
20234
 
20107
20235
  - `'joined'` — the player was seated in that person's room, as a member
20108
20236
  sharing their `groupId`.
@@ -1,6 +1,6 @@
1
1
  # The server surface — API reference
2
2
 
3
- Generated from `@indiegems/gem-web-sdk/sdk` v22.0.0, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
3
+ Generated from `@indiegems/gem-web-sdk/sdk` v23.0.1, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
4
4
 
5
5
  `@indiegems/gem-web-sdk/sdk` is the one import a game writes, wherever its code runs. `@indiegems/gem-web-sdk/server` exports exactly the symbols on this page and nothing else, for a build that wants only this half.
6
6
 
@@ -1785,6 +1785,12 @@ The call is made once. It is never repeated for you, because your function
1785
1785
  may have granted or written something: see [GemFunctionError.retryable](#gemfunctionerror-retryable)
1786
1786
  for whether repeating it could help.
1787
1787
 
1788
+ The answer is the receipt: when this resolves, what your function says it
1789
+ granted has been written. A game shows it at once and re-reads the
1790
+ inventory in the background (`gem.me.inventory.refresh()`, then
1791
+ `snapshot()`, or on `gem.me.inventory.onChanged`); never hold the player on
1792
+ a loop that re-reads until the grant shows.
1793
+
1788
1794
  ```js
1789
1795
  const result = await gem.functions.invoke({ v: 2, runId, finishMs });
1790
1796
  const { accepted, why } = result.json();