@indiegems/gem-web-sdk 15.3.2 → 16.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.
@@ -1,6 +1,6 @@
1
1
  # The browser surface — API reference
2
2
 
3
- Generated from `@indiegems/gem-web-sdk/sdk` v15.3.2, 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` v16.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.
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
 
@@ -3787,6 +3787,725 @@ key.
3787
3787
  **Throws.** TypeError for an empty key or player id, or a list holding something
3788
3788
  other than strings; RangeError for a count or list size outside 1 to 2048.
3789
3789
 
3790
+ <a id="appstore"></a>
3791
+
3792
+ ## AppStore
3793
+
3794
+ ```ts
3795
+ type AppStore = "app_store" | "google_play"
3796
+ ```
3797
+
3798
+ Which app store a listing is in, so a game can draw the matching badge.
3799
+
3800
+ <a id="applisting"></a>
3801
+
3802
+ ## AppListing
3803
+
3804
+ ```ts
3805
+ interface AppListing
3806
+ ```
3807
+
3808
+ A store listing the arcade can open from here.
3809
+
3810
+ <a id="applisting-store"></a>
3811
+
3812
+ ## AppListing.store
3813
+
3814
+ ```ts
3815
+ readonly store: AppStore
3816
+ ```
3817
+
3818
+ Which store it is in. Never a URL: the arcade builds the link.
3819
+
3820
+ <a id="applinksoutcome"></a>
3821
+
3822
+ ## AppLinksOutcome
3823
+
3824
+ ```ts
3825
+ interface AppLinksOutcome
3826
+ ```
3827
+
3828
+ What [ArcadeApi.appLinks](#arcadeapi-applinks) resolves with. `arcade` and `game` are each
3829
+ present only when [ArcadeApi.openApp](#arcadeapi-openapp) with that target would open a
3830
+ listing here; show the matching button only then.
3831
+
3832
+ <a id="applinksoutcome-arcade"></a>
3833
+
3834
+ ## AppLinksOutcome.arcade
3835
+
3836
+ ```ts
3837
+ readonly arcade?: AppListing
3838
+ ```
3839
+
3840
+ The Gem Arcade app's listing. Absent inside the Gem Arcade app itself.
3841
+
3842
+ <a id="applinksoutcome-game"></a>
3843
+
3844
+ ## AppLinksOutcome.game
3845
+
3846
+ ```ts
3847
+ readonly game?: AppListing
3848
+ ```
3849
+
3850
+ This game's own app's listing, when it has one for this platform.
3851
+
3852
+ <a id="applinksoutcome-outcome"></a>
3853
+
3854
+ ## AppLinksOutcome.outcome
3855
+
3856
+ ```ts
3857
+ readonly outcome: ArcadeOutcomeKind
3858
+ ```
3859
+
3860
+ What happened: `ok`, `declined` or `unavailable`. Branch on this.
3861
+
3862
+ <a id="applinksoutcome-reason"></a>
3863
+
3864
+ ## AppLinksOutcome.reason
3865
+
3866
+ ```ts
3867
+ readonly reason?: string
3868
+ ```
3869
+
3870
+ Why, as a machine code — `busy`, `cancelled`, `not_found`, `pending`,
3871
+ `store_off`, `sign_in_required` and more. OPEN-ENDED: the arcade may send a
3872
+ code this SDK has never heard of, so keep a `default` arm and never show a
3873
+ code to a player. Absent when there is nothing to add.
3874
+
3875
+ Three are the SDK's own, answered without asking the arcade:
3876
+ `unsupported` (the arcade here does not offer this), `invalid_argument`
3877
+ (the SDK refused what you passed) and `busy` (another ask of the same kind
3878
+ is still open). `error` means no reliable answer arrived — the ask never
3879
+ left, the wait ran out, the bridge closed or the arcade had none. For
3880
+ `gem.store.purchase` that makes the outcome UNKNOWN, not a refusal: the
3881
+ player may have paid.
3882
+
3883
+ <a id="gamecard"></a>
3884
+
3885
+ ## GameCard
3886
+
3887
+ ```ts
3888
+ interface GameCard
3889
+ ```
3890
+
3891
+ One game, as an Arcade home tile shows it.
3892
+
3893
+ ⚠️ `name`, `tagline`, `shortDescription` and `tags` are **another
3894
+ developer's text**, so they arrive as [PlayerText](#playertext): convert with
3895
+ `text.toPlain()` and render them as text, never as markup. The media URLs are
3896
+ the platform's; your page's CSP must allow its media host for `img-src` and
3897
+ `media-src` (see `docs/arcade-and-store.md`).
3898
+
3899
+ <a id="gamecard-gameid"></a>
3900
+
3901
+ ## GameCard.gameId
3902
+
3903
+ ```ts
3904
+ readonly gameId: string
3905
+ ```
3906
+
3907
+ The game's id: what [ArcadeApi.openGame](#arcadeapi-opengame) takes.
3908
+
3909
+ <a id="gamecard-slug"></a>
3910
+
3911
+ ## GameCard.slug
3912
+
3913
+ ```ts
3914
+ readonly slug?: string
3915
+ ```
3916
+
3917
+ The game's web address, when it has one.
3918
+
3919
+ <a id="gamecard-name"></a>
3920
+
3921
+ ## GameCard.name
3922
+
3923
+ ```ts
3924
+ readonly name: PlayerText
3925
+ ```
3926
+
3927
+ The game's public name. Another developer's text.
3928
+
3929
+ <a id="gamecard-tagline"></a>
3930
+
3931
+ ## GameCard.tagline
3932
+
3933
+ ```ts
3934
+ readonly tagline: PlayerText
3935
+ ```
3936
+
3937
+ One line under the name. Another developer's text; may be empty.
3938
+
3939
+ <a id="gamecard-shortdescription"></a>
3940
+
3941
+ ## GameCard.shortDescription
3942
+
3943
+ ```ts
3944
+ readonly shortDescription: PlayerText
3945
+ ```
3946
+
3947
+ A sentence or two. Another developer's text; may be empty.
3948
+
3949
+ <a id="gamecard-tags"></a>
3950
+
3951
+ ## GameCard.tags
3952
+
3953
+ ```ts
3954
+ readonly tags: readonly PlayerText[]
3955
+ ```
3956
+
3957
+ The game's store tags. Another developer's text.
3958
+
3959
+ <a id="gamecard-iconurl"></a>
3960
+
3961
+ ## GameCard.iconUrl
3962
+
3963
+ ```ts
3964
+ readonly iconUrl: string
3965
+ ```
3966
+
3967
+ The game's icon.
3968
+
3969
+ <a id="gamecard-capsulelandscapeurl"></a>
3970
+
3971
+ ## GameCard.capsuleLandscapeUrl
3972
+
3973
+ ```ts
3974
+ readonly capsuleLandscapeUrl: string
3975
+ ```
3976
+
3977
+ The landscape tile art.
3978
+
3979
+ <a id="gamecard-capsuleportraiturl"></a>
3980
+
3981
+ ## GameCard.capsulePortraitUrl
3982
+
3983
+ ```ts
3984
+ readonly capsulePortraitUrl: string
3985
+ ```
3986
+
3987
+ The portrait tile art.
3988
+
3989
+ <a id="gamecard-previewvideourl"></a>
3990
+
3991
+ ## GameCard.previewVideoUrl
3992
+
3993
+ ```ts
3994
+ readonly previewVideoUrl?: string
3995
+ ```
3996
+
3997
+ The tile's hover clip. Absent when the game has none, and whenever the
3998
+ arcade judges a clip unwelcome: reduced motion, data saver, a phone.
3999
+
4000
+ <a id="gamecard-previewposterurl"></a>
4001
+
4002
+ ## GameCard.previewPosterUrl
4003
+
4004
+ ```ts
4005
+ readonly previewPosterUrl?: string
4006
+ ```
4007
+
4008
+ The still shown before, and instead of, the clip.
4009
+
4010
+ <a id="similargamesoutcome"></a>
4011
+
4012
+ ## SimilarGamesOutcome
4013
+
4014
+ ```ts
4015
+ interface SimilarGamesOutcome
4016
+ ```
4017
+
4018
+ What [ArcadeApi.similarGames](#arcadeapi-similargames) resolves with.
4019
+
4020
+ <a id="similargamesoutcome-games"></a>
4021
+
4022
+ ## SimilarGamesOutcome.games
4023
+
4024
+ ```ts
4025
+ readonly games: readonly GameCard[]
4026
+ ```
4027
+
4028
+ Up to `limit` games, best first. Empty unless `ok` — and an `ok` may be empty too.
4029
+
4030
+ <a id="similargamesoutcome-outcome"></a>
4031
+
4032
+ ## SimilarGamesOutcome.outcome
4033
+
4034
+ ```ts
4035
+ readonly outcome: ArcadeOutcomeKind
4036
+ ```
4037
+
4038
+ What happened: `ok`, `declined` or `unavailable`. Branch on this.
4039
+
4040
+ <a id="similargamesoutcome-reason"></a>
4041
+
4042
+ ## SimilarGamesOutcome.reason
4043
+
4044
+ ```ts
4045
+ readonly reason?: string
4046
+ ```
4047
+
4048
+ Why, as a machine code — `busy`, `cancelled`, `not_found`, `pending`,
4049
+ `store_off`, `sign_in_required` and more. OPEN-ENDED: the arcade may send a
4050
+ code this SDK has never heard of, so keep a `default` arm and never show a
4051
+ code to a player. Absent when there is nothing to add.
4052
+
4053
+ Three are the SDK's own, answered without asking the arcade:
4054
+ `unsupported` (the arcade here does not offer this), `invalid_argument`
4055
+ (the SDK refused what you passed) and `busy` (another ask of the same kind
4056
+ is still open). `error` means no reliable answer arrived — the ask never
4057
+ left, the wait ran out, the bridge closed or the arcade had none. For
4058
+ `gem.store.purchase` that makes the outcome UNKNOWN, not a refusal: the
4059
+ player may have paid.
4060
+
4061
+ <a id="arcadeavailability"></a>
4062
+
4063
+ ## ArcadeAvailability
4064
+
4065
+ ```ts
4066
+ interface ArcadeAvailability
4067
+ ```
4068
+
4069
+ Which arcade features answer here, read synchronously. Decide from these
4070
+ whether to draw a "Get the app" button or a "More games" section at all.
4071
+
4072
+ <a id="arcadeavailability-applinks"></a>
4073
+
4074
+ ## ArcadeAvailability.appLinks
4075
+
4076
+ ```ts
4077
+ readonly appLinks: boolean
4078
+ ```
4079
+
4080
+ [ArcadeApi.appLinks](#arcadeapi-applinks) and [ArcadeApi.openApp](#arcadeapi-openapp) reach the arcade.
4081
+
4082
+ <a id="arcadeavailability-opengame"></a>
4083
+
4084
+ ## ArcadeAvailability.openGame
4085
+
4086
+ ```ts
4087
+ readonly openGame: boolean
4088
+ ```
4089
+
4090
+ [ArcadeApi.openGame](#arcadeapi-opengame) and [ArcadeApi.similarGames](#arcadeapi-similargames) reach the arcade.
4091
+
4092
+ <a id="arcadeapi"></a>
4093
+
4094
+ ## ArcadeApi
4095
+
4096
+ ```ts
4097
+ interface ArcadeApi
4098
+ ```
4099
+
4100
+ The arcade-features surface. `gem.arcade` is one of these.
4101
+
4102
+ <a id="arcadeapi-available"></a>
4103
+
4104
+ ## ArcadeApi.available
4105
+
4106
+ ```ts
4107
+ readonly available: ArcadeAvailability
4108
+ ```
4109
+
4110
+ Which of these features the arcade answers here, synchronously. False
4111
+ before the bridge is up and wherever the arcade does not offer one — the
4112
+ single-game app, for instance, opens no other game.
4113
+
4114
+ <a id="arcadeapi-applinks"></a>
4115
+
4116
+ ## ArcadeApi.appLinks
4117
+
4118
+ ```ts
4119
+ appLinks(): Promise<AppLinksOutcome>
4120
+ ```
4121
+
4122
+ Which app-store listings the arcade can open from here: the Gem Arcade
4123
+ app's and this game's own. A read: call it whenever, and show a button
4124
+ for each listing present.
4125
+
4126
+ **Returns.** Always resolves; never rejects.
4127
+
4128
+ <a id="arcadeapi-openapp"></a>
4129
+
4130
+ ## ArcadeApi.openApp
4131
+
4132
+ ```ts
4133
+ openApp(target: "arcade" | "game"): Promise<ArcadeOutcome>
4134
+ ```
4135
+
4136
+ Open a store listing: the Gem Arcade app's (`'arcade'`) or this game's own
4137
+ (`'game'`). **Call it from the player's press handler** — the arcade
4138
+ refuses an ask no person pressed for, `declined` / `busy`.
4139
+
4140
+ `ok` means it opened, in a new tab or the store app, or (`reason:
4141
+ 'handed_off'`) the arcade put up its own QR sheet. The answer comes at
4142
+ that moment, not when the player closes the sheet, so carry on either
4143
+ way; while the sheet is up, another acting call is `declined` / `busy`.
4144
+
4145
+ | Parameter | Type |
4146
+ | --- | --- |
4147
+ | `target` | `"arcade" \| "game"` |
4148
+
4149
+ **Returns.** Always resolves; never rejects.
4150
+
4151
+ <a id="arcadeapi-opengame"></a>
4152
+
4153
+ ## ArcadeApi.openGame
4154
+
4155
+ ```ts
4156
+ openGame(ref: string): Promise<ArcadeOutcome>
4157
+ ```
4158
+
4159
+ Open another game in place of this one, by id or web address. **Call it
4160
+ from the player's press handler.**
4161
+
4162
+ ⚠️ On `ok` your game is about to be closed: `onWillTerminate` follows with
4163
+ the ordinary save grace (250 ms). Save before you call this, not after.
4164
+ `declined` / `same_game` names this game; `unavailable` / `not_found` is a
4165
+ game the player cannot open here.
4166
+
4167
+ | Parameter | Type |
4168
+ | --- | --- |
4169
+ | `ref` | `string` |
4170
+
4171
+ **Returns.** Always resolves; never rejects.
4172
+
4173
+ <a id="arcadeapi-similargames"></a>
4174
+
4175
+ ## ArcadeApi.similarGames
4176
+
4177
+ ```ts
4178
+ similarGames(options?: { limit?: number }): Promise<SimilarGamesOutcome>
4179
+ ```
4180
+
4181
+ Games like this one, as Arcade home tiles: up to `limit` (1 to 24, default
4182
+ 12), best first. Hide the section when `games` is empty.
4183
+
4184
+ | Parameter | Type |
4185
+ | --- | --- |
4186
+ | `options` | `{ limit?: number }` |
4187
+
4188
+ **Returns.** Always resolves; never rejects.
4189
+
4190
+ <a id="arcadeoutcomekind"></a>
4191
+
4192
+ ## ArcadeOutcomeKind
4193
+
4194
+ ```ts
4195
+ type ArcadeOutcomeKind = "ok" | "declined" | "unavailable"
4196
+ ```
4197
+
4198
+ What the arcade did with an ask, the complete vocabulary: `ok`, `declined`
4199
+ or `unavailable`. Why is in `reason`, which is open-ended.
4200
+
4201
+ <a id="arcadeoutcome"></a>
4202
+
4203
+ ## ArcadeOutcome
4204
+
4205
+ ```ts
4206
+ interface ArcadeOutcome
4207
+ ```
4208
+
4209
+ The answer every `gem.arcade` and `gem.store` call resolves with, before
4210
+ anything specific to the call.
4211
+
4212
+ <a id="arcadeoutcome-outcome"></a>
4213
+
4214
+ ## ArcadeOutcome.outcome
4215
+
4216
+ ```ts
4217
+ readonly outcome: ArcadeOutcomeKind
4218
+ ```
4219
+
4220
+ What happened: `ok`, `declined` or `unavailable`. Branch on this.
4221
+
4222
+ <a id="arcadeoutcome-reason"></a>
4223
+
4224
+ ## ArcadeOutcome.reason
4225
+
4226
+ ```ts
4227
+ readonly reason?: string
4228
+ ```
4229
+
4230
+ Why, as a machine code — `busy`, `cancelled`, `not_found`, `pending`,
4231
+ `store_off`, `sign_in_required` and more. OPEN-ENDED: the arcade may send a
4232
+ code this SDK has never heard of, so keep a `default` arm and never show a
4233
+ code to a player. Absent when there is nothing to add.
4234
+
4235
+ Three are the SDK's own, answered without asking the arcade:
4236
+ `unsupported` (the arcade here does not offer this), `invalid_argument`
4237
+ (the SDK refused what you passed) and `busy` (another ask of the same kind
4238
+ is still open). `error` means no reliable answer arrived — the ask never
4239
+ left, the wait ran out, the bridge closed or the arcade had none. For
4240
+ `gem.store.purchase` that makes the outcome UNKNOWN, not a refusal: the
4241
+ player may have paid.
4242
+
4243
+ <a id="arcadeoffer"></a>
4244
+
4245
+ ## ArcadeOffer
4246
+
4247
+ ```ts
4248
+ interface ArcadeOffer
4249
+ ```
4250
+
4251
+ One SKU the Arcade Store sells to this player, here, right now.
4252
+
4253
+ Show `priceDisplay` **exactly as given**: it is the payment rail's own
4254
+ formatted price in the player's currency. Never parse it, compare it or
4255
+ compute a discount from it. There is no numeric price, no balance and no
4256
+ availability flag — the arcade's sheet explains anything that stops a
4257
+ purchase.
4258
+
4259
+ <a id="arcadeoffer-skuid"></a>
4260
+
4261
+ ## ArcadeOffer.skuId
4262
+
4263
+ ```ts
4264
+ readonly skuId: string
4265
+ ```
4266
+
4267
+ The SKU's id: what [StoreApi.purchase](#storeapi-purchase) takes.
4268
+
4269
+ <a id="arcadeoffer-kind"></a>
4270
+
4271
+ ## ArcadeOffer.kind
4272
+
4273
+ ```ts
4274
+ readonly kind: "gem_pack" | "boost" | "pass" | "bundle"
4275
+ ```
4276
+
4277
+ What sort of thing it is.
4278
+
4279
+ <a id="arcadeoffer-name"></a>
4280
+
4281
+ ## ArcadeOffer.name
4282
+
4283
+ ```ts
4284
+ readonly name: string
4285
+ ```
4286
+
4287
+ The store's own name for it, localized as the store shows it.
4288
+
4289
+ <a id="arcadeoffer-description"></a>
4290
+
4291
+ ## ArcadeOffer.description
4292
+
4293
+ ```ts
4294
+ readonly description: string
4295
+ ```
4296
+
4297
+ What the player gets, in the store's words. May be empty.
4298
+
4299
+ <a id="arcadeoffer-imageurl"></a>
4300
+
4301
+ ## ArcadeOffer.imageUrl
4302
+
4303
+ ```ts
4304
+ readonly imageUrl?: string
4305
+ ```
4306
+
4307
+ The SKU's art, when it has any.
4308
+
4309
+ <a id="arcadeoffer-pricedisplay"></a>
4310
+
4311
+ ## ArcadeOffer.priceDisplay
4312
+
4313
+ ```ts
4314
+ readonly priceDisplay: string
4315
+ ```
4316
+
4317
+ The price, formatted by the payment rail. Show it as given.
4318
+
4319
+ <a id="arcadeoffer-grant"></a>
4320
+
4321
+ ## ArcadeOffer.grant
4322
+
4323
+ ```ts
4324
+ readonly grant?: { currency: string; amount: number }
4325
+ ```
4326
+
4327
+ For a Gem pack: the platform currency and the amount it grants.
4328
+
4329
+ <a id="arcadeoffer-grant-currency"></a>
4330
+
4331
+ ## ArcadeOffer.grant.currency
4332
+
4333
+ ```ts
4334
+ readonly currency: string
4335
+ ```
4336
+
4337
+ The platform currency's exact slug, e.g. `GEMS`.
4338
+
4339
+ <a id="arcadeoffer-grant-amount"></a>
4340
+
4341
+ ## ArcadeOffer.grant.amount
4342
+
4343
+ ```ts
4344
+ readonly amount: number
4345
+ ```
4346
+
4347
+ How much of it the pack grants.
4348
+
4349
+ <a id="storeoffersoutcome"></a>
4350
+
4351
+ ## StoreOffersOutcome
4352
+
4353
+ ```ts
4354
+ interface StoreOffersOutcome
4355
+ ```
4356
+
4357
+ What [StoreApi.offers](#storeapi-offers) resolves with.
4358
+
4359
+ <a id="storeoffersoutcome-outcome"></a>
4360
+
4361
+ ## StoreOffersOutcome.outcome
4362
+
4363
+ ```ts
4364
+ readonly outcome: ArcadeOutcomeKind
4365
+ ```
4366
+
4367
+ What happened: `ok`, `declined` or `unavailable`. Branch on this.
4368
+
4369
+ <a id="storeoffersoutcome-reason"></a>
4370
+
4371
+ ## StoreOffersOutcome.reason
4372
+
4373
+ ```ts
4374
+ readonly reason?: string
4375
+ ```
4376
+
4377
+ Why, as a machine code — `busy`, `cancelled`, `not_found`, `pending`,
4378
+ `store_off`, `sign_in_required` and more. OPEN-ENDED: the arcade may send a
4379
+ code this SDK has never heard of, so keep a `default` arm and never show a
4380
+ code to a player. Absent when there is nothing to add.
4381
+
4382
+ Three are the SDK's own, answered without asking the arcade:
4383
+ `unsupported` (the arcade here does not offer this), `invalid_argument`
4384
+ (the SDK refused what you passed) and `busy` (another ask of the same kind
4385
+ is still open). `error` means no reliable answer arrived — the ask never
4386
+ left, the wait ran out, the bridge closed or the arcade had none. For
4387
+ `gem.store.purchase` that makes the outcome UNKNOWN, not a refusal: the
4388
+ player may have paid.
4389
+
4390
+ <a id="storeoffersoutcome-offers"></a>
4391
+
4392
+ ## StoreOffersOutcome.offers
4393
+
4394
+ ```ts
4395
+ readonly offers: readonly ArcadeOffer[]
4396
+ ```
4397
+
4398
+ What the store sells here, in its own order. Empty unless `ok`.
4399
+
4400
+ <a id="storesettlement"></a>
4401
+
4402
+ ## StoreSettlement
4403
+
4404
+ ```ts
4405
+ interface StoreSettlement
4406
+ ```
4407
+
4408
+ A purchase that answered `ok` / `pending` has settled.
4409
+
4410
+ <a id="storesettlement-skuid"></a>
4411
+
4412
+ ## StoreSettlement.skuId
4413
+
4414
+ ```ts
4415
+ readonly skuId: string
4416
+ ```
4417
+
4418
+ The SKU it was for. Re-read balances and inventory through `gem.me`.
4419
+
4420
+ <a id="storeapi"></a>
4421
+
4422
+ ## StoreApi
4423
+
4424
+ ```ts
4425
+ interface StoreApi
4426
+ ```
4427
+
4428
+ **Real money.** The Arcade Store's own Gem packs, Boosts, passes and bundles,
4429
+ bought with the player's money through the arcade's own purchase sheet.
4430
+ `gem.store` is one of these. To spend Gems or Coins on your game's own items,
4431
+ use `gem.purchases`.
4432
+
4433
+ <a id="storeapi-available"></a>
4434
+
4435
+ ## StoreApi.available
4436
+
4437
+ ```ts
4438
+ readonly available: boolean
4439
+ ```
4440
+
4441
+ Whether the Arcade Store answers here, synchronously. Draw your own "Get
4442
+ Gems" button only when it is true.
4443
+
4444
+ <a id="storeapi-offers"></a>
4445
+
4446
+ ## StoreApi.offers
4447
+
4448
+ ```ts
4449
+ offers(): Promise<StoreOffersOutcome>
4450
+ ```
4451
+
4452
+ What the store sells this player here: names, art and the rail's own
4453
+ prices. `unavailable` / `sign_in_required` for a guest (offer
4454
+ `gem.account.requestSignIn`), `unavailable` / `store_off` where the store
4455
+ is withheld. Re-read on resume: what is on sale can change.
4456
+
4457
+ **Returns.** Always resolves; never rejects.
4458
+
4459
+ <a id="storeapi-purchase"></a>
4460
+
4461
+ ## StoreApi.purchase
4462
+
4463
+ ```ts
4464
+ purchase(skuId: string): Promise<ArcadeOutcome>
4465
+ ```
4466
+
4467
+ Ask the arcade to open its store's purchase sheet for one SKU from
4468
+ [StoreApi.offers](#storeapi-offers). **Call it from the player's press handler** — the
4469
+ arcade refuses an ask no person pressed for, `declined` / `busy`.
4470
+
4471
+ - `ok` — the player paid. Re-read balances and inventory through `gem.me`;
4472
+ nothing here carries an amount. With `reason: 'pending'`, the provider
4473
+ has not settled yet: [StoreApi.onSettled](#storeapi-onsettled) hears when it does.
4474
+ - `declined` — nothing was bought: `cancelled` (the player said no) or
4475
+ `busy`. Return to your screen silently, and do not ask again unprompted.
4476
+ - `unavailable` with `store_off`, `sign_in_required`, `not_found`,
4477
+ `unsupported`, `invalid_argument` or a payment provider's failure code —
4478
+ nothing was bought.
4479
+ - `unavailable` / `error` — **the outcome is unknown, and the player may
4480
+ have paid.** It is what you get when the bridge closes while the sheet
4481
+ is open, or the arcade has no reliable answer. Never tell the player
4482
+ nothing was bought: re-read balances and inventory through `gem.me`,
4483
+ and keep listening with [StoreApi.onSettled](#storeapi-onsettled).
4484
+
4485
+ NO TIMEOUT: it waits for as long as the arcade is connected, because a
4486
+ payment takes as long as it takes.
4487
+
4488
+ | Parameter | Type |
4489
+ | --- | --- |
4490
+ | `skuId` | `string` |
4491
+
4492
+ **Returns.** Always resolves; never rejects.
4493
+
4494
+ <a id="storeapi-onsettled"></a>
4495
+
4496
+ ## StoreApi.onSettled
4497
+
4498
+ ```ts
4499
+ onSettled(listener: (settlement: StoreSettlement) => void): () => void
4500
+ ```
4501
+
4502
+ Hear when a purchase that answered `ok` / `pending` settles, while your
4503
+ game is running. Returns a function that stops listening.
4504
+
4505
+ | Parameter | Type |
4506
+ | --- | --- |
4507
+ | `listener` | `(settlement: StoreSettlement) => void` |
4508
+
3790
4509
  <a id="avatar3dprice"></a>
3791
4510
 
3792
4511
  ## Avatar3dPrice
@@ -9751,8 +10470,10 @@ synchronously wherever you render.
9751
10470
  readonly purchases: PurchaseApi
9752
10471
  ```
9753
10472
 
9754
- Buy one of YOUR OWN items or recipes with platform currency, on the
9755
- player's behalf.
10473
+ **Gems and Coins, not real money.** Buy one of YOUR OWN items or recipes
10474
+ with platform currency, on the player's behalf. To sell the Arcade Store's
10475
+ own Gem packs, Boosts and passes for the player's money, use
10476
+ [Gem.store](#gem-store).
9756
10477
 
9757
10478
  This is the platform-owned path: the request crosses the bridge, the parent
9758
10479
  always renders the platform purchase sheet in trusted chrome, and the
@@ -9893,6 +10614,44 @@ shareButton.onclick = () => {
9893
10614
 
9894
10615
  **Guides.** [getting-started](../getting-started.md)
9895
10616
 
10617
+ <a id="gem-arcade"></a>
10618
+
10619
+ ## Gem.arcade
10620
+
10621
+ ```ts
10622
+ readonly arcade: ArcadeApi
10623
+ ```
10624
+
10625
+ The Gem Arcade's own features, asked for from your game: link out to the
10626
+ Gem Arcade app or your game's own app, open another game, and list games
10627
+ like yours as home tiles.
10628
+
10629
+ The game asks; the arcade decides. Nothing you send is a URL, and nothing
10630
+ rejects: every call resolves `{ outcome, reason, … }`. Check
10631
+ [ArcadeApi.available](#arcadeapi-available) before drawing a button, and call `openApp`
10632
+ and `openGame` from the player's press handler.
10633
+
10634
+ **Guides.** [arcade-and-store](../arcade-and-store.md)
10635
+
10636
+ <a id="gem-store"></a>
10637
+
10638
+ ## Gem.store
10639
+
10640
+ ```ts
10641
+ readonly store: StoreApi
10642
+ ```
10643
+
10644
+ **Real money.** The Arcade Store's own Gem packs, Boosts, passes and
10645
+ bundles, sold for the player's money through the arcade's own purchase
10646
+ sheet. To spend Gems or Coins on your game's own items, use
10647
+ [Gem.purchases](#gem-purchases).
10648
+
10649
+ List what the store sells here with `offers()`, show each `priceDisplay`
10650
+ exactly as given, and call `purchase(skuId)` from the player's press. After
10651
+ `ok`, re-read balances through [Gem.me](#gem-me). Nothing rejects.
10652
+
10653
+ **Guides.** [arcade-and-store](../arcade-and-store.md)
10654
+
9896
10655
  <a id="gem-avatarpickeravailable"></a>
9897
10656
 
9898
10657
  ## Gem.avatarPickerAvailable