@indiegems/gem-web-sdk 23.3.0 → 24.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` v23.3.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` v24.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
 
@@ -4738,10 +4738,13 @@ The SKU's id: what [StoreApi.purchase](#storeapi-purchase) takes.
4738
4738
  ## ArcadeOffer.kind
4739
4739
 
4740
4740
  ```ts
4741
- readonly kind: "gem_pack" | "boost" | "pass" | "bundle"
4741
+ readonly kind: ArcadeOfferKind
4742
4742
  ```
4743
4743
 
4744
- What sort of thing it is.
4744
+ What sort of thing it is: `coin_pack`, `boost`, `pass` or `bundle` — or
4745
+ `gem_pack`, which is deprecated: Gems are being retired, and a pack of
4746
+ Coins is `coin_pack`. Keep a `default` arm. See
4747
+ [the deprecation policy](../deprecation-policy.md).
4745
4748
 
4746
4749
  <a id="arcadeoffer-name"></a>
4747
4750
 
@@ -4791,7 +4794,7 @@ The price, formatted by the payment rail. Show it as given.
4791
4794
  readonly grant?: { currency: string; amount: number }
4792
4795
  ```
4793
4796
 
4794
- For a Gem pack: the platform currency and the amount it grants.
4797
+ For a Coin pack: the platform currency and the amount it grants.
4795
4798
 
4796
4799
  <a id="arcadeoffer-grant-currency"></a>
4797
4800
 
@@ -4801,7 +4804,7 @@ For a Gem pack: the platform currency and the amount it grants.
4801
4804
  readonly currency: string
4802
4805
  ```
4803
4806
 
4804
- The platform currency's exact slug, e.g. `GEMS`.
4807
+ The platform currency's exact slug, e.g. `ARCADE_TICKETS` for Coins.
4805
4808
 
4806
4809
  <a id="arcadeoffer-grant-amount"></a>
4807
4810
 
@@ -4813,6 +4816,129 @@ readonly amount: number
4813
4816
 
4814
4817
  How much of it the pack grants.
4815
4818
 
4819
+ <a id="arcadeoffer-pass"></a>
4820
+
4821
+ ## ArcadeOffer.pass
4822
+
4823
+ ```ts
4824
+ readonly pass?: string
4825
+ ```
4826
+
4827
+ For a pass, or a bundle carrying one: the pass's slug, such as `vip` — the
4828
+ slug `gem.me.passes` reports and [StoreApi.showPass](#storeapi-showpass) takes. Absent
4829
+ for everything else, and on an older Arcade.
4830
+
4831
+ <a id="arcadeoffer-earnmultipliers"></a>
4832
+
4833
+ ## ArcadeOffer.earnMultipliers
4834
+
4835
+ ```ts
4836
+ readonly earnMultipliers: readonly ArcadeOfferEarnMultiplier[]
4837
+ ```
4838
+
4839
+ For an offer that makes the player earn a platform currency faster while
4840
+ they hold it: one entry per currency. Empty when it boosts nothing.
4841
+
4842
+ The platform's own figure, for `gem.gameConfig.preview` to work out what
4843
+ holding it would add. **Never multiply a reward by it yourself**: the
4844
+ preview rounds the way the platform pays.
4845
+
4846
+ <a id="arcadeofferkind"></a>
4847
+
4848
+ ## ArcadeOfferKind
4849
+
4850
+ ```ts
4851
+ type ArcadeOfferKind = "coin_pack" | "gem_pack" | "boost" | "pass" | "bundle"
4852
+ ```
4853
+
4854
+ What sort of SKU an [ArcadeOffer](#arcadeoffer) is. `gem_pack` is deprecated: Gems
4855
+ are being retired, and a pack of Coins is `coin_pack`.
4856
+
4857
+ <a id="arcadeofferearnmultiplier"></a>
4858
+
4859
+ ## ArcadeOfferEarnMultiplier
4860
+
4861
+ ```ts
4862
+ interface ArcadeOfferEarnMultiplier
4863
+ ```
4864
+
4865
+ One currency an [ArcadeOffer](#arcadeoffer) boosts while it is held.
4866
+
4867
+ <a id="arcadeofferearnmultiplier-currencyslug"></a>
4868
+
4869
+ ## ArcadeOfferEarnMultiplier.currencySlug
4870
+
4871
+ ```ts
4872
+ readonly currencySlug: string
4873
+ ```
4874
+
4875
+ The currency's slug, e.g. `ARCADE_TICKETS`.
4876
+
4877
+ <a id="arcadeofferearnmultiplier-multiplierbp"></a>
4878
+
4879
+ ## ArcadeOfferEarnMultiplier.multiplierBp
4880
+
4881
+ ```ts
4882
+ readonly multiplierBp: number
4883
+ ```
4884
+
4885
+ Basis points: `10000` is 1x, `15000` is 1.5x. An integer, so the preview
4886
+ rounds exactly as the platform does.
4887
+
4888
+ <a id="showpassoutcome"></a>
4889
+
4890
+ ## ShowPassOutcome
4891
+
4892
+ ```ts
4893
+ interface ShowPassOutcome
4894
+ ```
4895
+
4896
+ What [StoreApi.showPass](#storeapi-showpass) resolves with: an [ArcadeOutcome](#arcadeoutcome), plus
4897
+ whether a fresh read shows the pass held.
4898
+
4899
+ <a id="showpassoutcome-outcome"></a>
4900
+
4901
+ ## ShowPassOutcome.outcome
4902
+
4903
+ ```ts
4904
+ readonly outcome: ArcadeOutcomeKind
4905
+ ```
4906
+
4907
+ What happened: `ok`, `declined` or `unavailable`. Branch on this.
4908
+
4909
+ <a id="showpassoutcome-reason"></a>
4910
+
4911
+ ## ShowPassOutcome.reason
4912
+
4913
+ ```ts
4914
+ readonly reason?: string
4915
+ ```
4916
+
4917
+ Why, as a machine code — `busy`, `cancelled`, `not_found`, `pending`,
4918
+ `store_off`, `sign_in_required` and more. OPEN-ENDED: the arcade may send a
4919
+ code this SDK has never heard of, so keep a `default` arm and never show a
4920
+ code to a player. Absent when there is nothing to add.
4921
+
4922
+ Three are the SDK's own, answered without asking the arcade:
4923
+ `unsupported` (the arcade here does not offer this), `invalid_argument`
4924
+ (the SDK refused what you passed) and `busy` (another ask of the same kind
4925
+ is still open). `error` means no reliable answer arrived — the ask never
4926
+ left, the wait ran out, the bridge closed or the arcade had none. For
4927
+ `gem.store.purchase` that makes the outcome UNKNOWN, not a refusal: the
4928
+ player may have paid.
4929
+
4930
+ <a id="showpassoutcome-held"></a>
4931
+
4932
+ ## ShowPassOutcome.held
4933
+
4934
+ ```ts
4935
+ readonly held: boolean
4936
+ ```
4937
+
4938
+ Whether a fresh read of `gem.me.passes` showed the pass held once the
4939
+ sheet closed. `true` exactly when `outcome` is `ok` with no `reason`: a
4940
+ recipe the game runs next gets the pass's bonus.
4941
+
4816
4942
  <a id="storeoffersoutcome"></a>
4817
4943
 
4818
4944
  ## StoreOffersOutcome
@@ -4892,10 +5018,11 @@ The SKU it was for. Re-read balances and inventory through `gem.me`.
4892
5018
  interface StoreApi
4893
5019
  ```
4894
5020
 
4895
- **Real money.** The Arcade Store's own Gem packs, Boosts, passes and bundles,
5021
+ **Real money.** The Arcade Store's own Coin packs, Boosts, passes and bundles,
4896
5022
  bought with the player's money through the Arcade Store's own checkout.
4897
- `gem.store` is one of these. To spend Gems or Coins on your game's own items,
4898
- use `gem.purchases`.
5023
+ `gem.store` is one of these. To spend Coins on your game's own items, use
5024
+ `gem.purchases`. Only the Arcade sells Coins: a game never sells currency
5025
+ for money.
4899
5026
 
4900
5027
  <a id="storeapi-available"></a>
4901
5028
 
@@ -4906,7 +5033,7 @@ readonly available: boolean
4906
5033
  ```
4907
5034
 
4908
5035
  Whether the Arcade Store answers here, synchronously. Draw your own "Get
4909
- Gems" button only when it is true.
5036
+ Coins" button only when it is true.
4910
5037
 
4911
5038
  <a id="storeapi-showofferavailable"></a>
4912
5039
 
@@ -4930,9 +5057,10 @@ offers(): Promise<StoreOffersOutcome>
4930
5057
  ```
4931
5058
 
4932
5059
  What the store sells this player here: names, art and the rail's own
4933
- prices. `unavailable` / `sign_in_required` for a guest (offer
4934
- `gem.account.requestSignIn`), `unavailable` / `store_off` where the store
4935
- is withheld. Re-read on resume: what is on sale can change.
5060
+ prices. A guest is answered too: buying takes them through sign-up first,
5061
+ in the Arcade's own screens. `unavailable` / `store_off` where the store is
5062
+ withheld. An older Arcade answers a guest `unavailable` /
5063
+ `sign_in_required`. Re-read on resume: what is on sale can change.
4936
5064
 
4937
5065
  **Returns.** Always resolves; never rejects.
4938
5066
 
@@ -4992,7 +5120,8 @@ has left. The sheet's Buy opens the same checkout as
4992
5120
 
4993
5121
  Use it for an offer you would have to hardcode a pitch for: VIP and other
4994
5122
  passes, and bundles. Your button only needs to say what it opens. Draw a
4995
- Gem pack yourself and use `purchase` instead. Check
5123
+ Coin pack yourself and use `purchase` instead. For a pass, call
5124
+ [StoreApi.showPass](#storeapi-showpass) with its slug. Check
4996
5125
  [StoreApi.showOfferAvailable](#storeapi-showofferavailable) first, and that the SKU is in `offers`.
4997
5126
 
4998
5127
  It answers exactly as `purchase` does, with one addition: `declined` /
@@ -5013,6 +5142,66 @@ player may read a sheet and pay for as long as they like.
5013
5142
 
5014
5143
  **Returns.** Always resolves; never rejects.
5015
5144
 
5145
+ <a id="storeapi-showpass"></a>
5146
+
5147
+ ## StoreApi.showPass
5148
+
5149
+ ```ts
5150
+ showPass(slug: string): Promise<ShowPassOutcome>
5151
+ ```
5152
+
5153
+ Show a pass by its slug in the Arcade's own sheet, over your paused game.
5154
+ Pass it `upsell.pass` straight from `gem.gameConfig.preview`, never a
5155
+ literal. Sugar over [StoreApi.offers](#storeapi-offers) and [StoreApi.showOffer](#storeapi-showoffer):
5156
+ it finds the offer whose `pass` is `slug` and shows that. A guest is taken
5157
+ through sign-up first, then back to the sheet.
5158
+
5159
+ - `ok`, `held: true` — **a fresh read of `gem.me.passes` shows the pass
5160
+ held.** Run the recipe or claim now, and the pass's bonus applies.
5161
+ - `ok` / `pending`, `held: false` — the player paid, and the pass has not
5162
+ arrived yet (Ask to Buy, a slow payment). Run the recipe now, without
5163
+ the bonus: the platform holds nothing back for later.
5164
+ - `declined` — they closed the sheet. Run the recipe as it is, and don't
5165
+ ask again at this reward moment.
5166
+ - `unavailable` / `not_found` — the pass is not on sale to this player
5167
+ here, or this Arcade is too old to say which offer is a pass, and
5168
+ nothing opened. `unavailable` / `unsupported` — this Arcade draws no
5169
+ sheet. Run the recipe as it is.
5170
+ - `unavailable` / `error` — **the outcome is unknown, and the player may
5171
+ have paid.** Run the recipe; `gem.me.passes.on('changed')` hears the
5172
+ pass if it arrives.
5173
+
5174
+ NO TIMEOUT on the sheet, as with `showOffer`. After a paid `ok` it reads
5175
+ `gem.me.passes` for about ten seconds before it settles for `pending`.
5176
+
5177
+ | Parameter | Type |
5178
+ | --- | --- |
5179
+ | `slug` | `string` |
5180
+
5181
+ **Returns.** Always resolves; never rejects.
5182
+
5183
+ <a id="storeapi-passonsale"></a>
5184
+
5185
+ ## StoreApi.passOnSale
5186
+
5187
+ ```ts
5188
+ passOnSale(slug: string): Promise<boolean>
5189
+ ```
5190
+
5191
+ Whether the pass `slug` is on sale to this player here, so
5192
+ [StoreApi.showPass](#storeapi-showpass) would open it. For a screen that sells a pass
5193
+ outside a reward moment, such as a "VIP perks" panel; at a reward moment,
5194
+ `gem.gameConfig.preview`'s `upsells` already says so. `false` where the
5195
+ store is off, for a player the platform won't sell it to, after the
5196
+ player declined its sheet twice today, and on an older Arcade. A player
5197
+ who holds the pass may still read `true`: the sheet adds time.
5198
+
5199
+ | Parameter | Type |
5200
+ | --- | --- |
5201
+ | `slug` | `string` |
5202
+
5203
+ **Returns.** Always resolves; never rejects.
5204
+
5016
5205
  <a id="storeapi-onsettled"></a>
5017
5206
 
5018
5207
  ## StoreApi.onSettled
@@ -6702,6 +6891,256 @@ only when your studio corrects a running period; clients may hold the old
6702
6891
  content for up to an hour afterwards, and the hash is how a verifier tells
6703
6892
  them apart.
6704
6893
 
6894
+ <a id="previewtarget"></a>
6895
+
6896
+ ## PreviewTarget
6897
+
6898
+ ```ts
6899
+ type PreviewTarget = { recipe: string } | { progression: string; add?: number }
6900
+ ```
6901
+
6902
+ What to preview: a recipe, or a progression with the delta the game is about
6903
+ to apply. A config id, never an amount and never a pass.
6904
+
6905
+ - `{ recipe: 'open_chest' }` — the recipe's grants, its roll, its bonuses,
6906
+ and the platform payouts of any progression it adds to.
6907
+ - `{ progression: 'run_complete' }` — the progression's `on_complete`
6908
+ payouts, "if it completes".
6909
+ - `{ progression: 'puzzles_cleared', add: 3 }` — its `on_add` payouts for
6910
+ that delta, and its `on_complete` payouts if it completes.
6911
+
6912
+ Ids and slugs are both accepted, as everywhere in `gem.gameConfig`.
6913
+
6914
+ <a id="previewgrant"></a>
6915
+
6916
+ ## PreviewGrant
6917
+
6918
+ ```ts
6919
+ type PreviewGrant = { kind: "item"; itemId: string; quantity: number } | { kind: "currency"; currencyId: string; amount: number } | { kind: "roll"; lootTableId: string; count: number }
6920
+ ```
6921
+
6922
+ One thing a claim grants in your game. A roll is a count of rolls from a loot
6923
+ table, never what they land on: never show a locked roll's outcome.
6924
+
6925
+ <a id="unmetrequirement"></a>
6926
+
6927
+ ## UnmetRequirement
6928
+
6929
+ ```ts
6930
+ interface UnmetRequirement
6931
+ ```
6932
+
6933
+ One requirement a bonus has that the player does not meet: where it is, and its kind.
6934
+
6935
+ <a id="unmetrequirement-index"></a>
6936
+
6937
+ ## UnmetRequirement.index
6938
+
6939
+ ```ts
6940
+ readonly index: number
6941
+ ```
6942
+
6943
+ Its position in the bonus's `requires`.
6944
+
6945
+ <a id="unmetrequirement-kind"></a>
6946
+
6947
+ ## UnmetRequirement.kind
6948
+
6949
+ ```ts
6950
+ readonly kind: string
6951
+ ```
6952
+
6953
+ Its kind, such as `holds_pass`. Never the pass or the item it names.
6954
+
6955
+ <a id="bonuspreview"></a>
6956
+
6957
+ ## BonusPreview
6958
+
6959
+ ```ts
6960
+ interface BonusPreview
6961
+ ```
6962
+
6963
+ One `bonuses` entry, and whether this player gets it.
6964
+
6965
+ <a id="bonuspreview-id"></a>
6966
+
6967
+ ## BonusPreview.id
6968
+
6969
+ ```ts
6970
+ readonly id: string
6971
+ ```
6972
+
6973
+ The bonus's id, as you configured it.
6974
+
6975
+ <a id="bonuspreview-grants"></a>
6976
+
6977
+ ## BonusPreview.grants
6978
+
6979
+ ```ts
6980
+ readonly grants: readonly PreviewGrant[]
6981
+ ```
6982
+
6983
+ What it grants.
6984
+
6985
+ <a id="bonuspreview-eligible"></a>
6986
+
6987
+ ## BonusPreview.eligible
6988
+
6989
+ ```ts
6990
+ readonly eligible: boolean | "unknown"
6991
+ ```
6992
+
6993
+ `true` — every requirement holds now. `false` — at least one does not
6994
+ (see `unmet`). `'unknown'` — one the browser cannot see, such as owning a
6995
+ platform item; never a guess. Advisory: the run decides.
6996
+
6997
+ <a id="bonuspreview-unmet"></a>
6998
+
6999
+ ## BonusPreview.unmet
7000
+
7001
+ ```ts
7002
+ readonly unmet: readonly UnmetRequirement[]
7003
+ ```
7004
+
7005
+ The requirements that do not hold. Empty unless `eligible` is `false`.
7006
+
7007
+ <a id="passupsell"></a>
7008
+
7009
+ ## PassUpsell
7010
+
7011
+ ```ts
7012
+ interface PassUpsell
7013
+ ```
7014
+
7015
+ What holding one pass would add to a claim.
7016
+
7017
+ <a id="passupsell-pass"></a>
7018
+
7019
+ ## PassUpsell.pass
7020
+
7021
+ ```ts
7022
+ readonly pass: string
7023
+ ```
7024
+
7025
+ The pass's slug: what `gem.store.showPass` takes.
7026
+
7027
+ <a id="passupsell-name"></a>
7028
+
7029
+ ## PassUpsell.name
7030
+
7031
+ ```ts
7032
+ readonly name: string
7033
+ ```
7034
+
7035
+ The store's own name for it, localized. Show this, never your own word for it.
7036
+
7037
+ <a id="passupsell-offer"></a>
7038
+
7039
+ ## PassUpsell.offer
7040
+
7041
+ ```ts
7042
+ readonly offer: ArcadeOffer
7043
+ ```
7044
+
7045
+ The pass's offer, as `gem.store.offers` lists it.
7046
+
7047
+ <a id="passupsell-platformgrants"></a>
7048
+
7049
+ ## PassUpsell.platformGrants
7050
+
7051
+ ```ts
7052
+ readonly platformGrants: readonly { currencySlug?: string; currencyId?: string; total: number; extra: number; ifComplete?: true }[]
7053
+ ```
7054
+
7055
+ Each payout this pass would raise: the new `total`, and the `extra` over now.
7056
+
7057
+ <a id="passupsell-bonuses"></a>
7058
+
7059
+ ## PassUpsell.bonuses
7060
+
7061
+ ```ts
7062
+ readonly bonuses: readonly { id: string; grants: readonly PreviewGrant[] }[]
7063
+ ```
7064
+
7065
+ The bonuses this pass would make eligible.
7066
+
7067
+ <a id="configpreview"></a>
7068
+
7069
+ ## ConfigPreview
7070
+
7071
+ ```ts
7072
+ interface ConfigPreview
7073
+ ```
7074
+
7075
+ What [PreviewTarget](#previewtarget) would give this player now, and what each pass would add.
7076
+
7077
+ <a id="configpreview-grants"></a>
7078
+
7079
+ ## ConfigPreview.grants
7080
+
7081
+ ```ts
7082
+ readonly grants: readonly PreviewGrant[]
7083
+ ```
7084
+
7085
+ Your game's own grants: items, game currencies, rolls.
7086
+
7087
+ <a id="configpreview-platformgrants"></a>
7088
+
7089
+ ## ConfigPreview.platformGrants
7090
+
7091
+ ```ts
7092
+ readonly platformGrants: readonly PlatformGrantPreview[]
7093
+ ```
7094
+
7095
+ One per platform payout that would fire.
7096
+
7097
+ <a id="configpreview-bonuses"></a>
7098
+
7099
+ ## ConfigPreview.bonuses
7100
+
7101
+ ```ts
7102
+ readonly bonuses: readonly BonusPreview[]
7103
+ ```
7104
+
7105
+ One per `bonuses` entry, in config order.
7106
+
7107
+ <a id="configpreview-upsells"></a>
7108
+
7109
+ ## ConfigPreview.upsells
7110
+
7111
+ ```ts
7112
+ readonly upsells: readonly PassUpsell[]
7113
+ ```
7114
+
7115
+ One per pass on sale here, not held, that would change this answer. Empty
7116
+ means show no upsell: no pass would add anything, or none is on sale to
7117
+ this player (a minor, a store that is off, a pass declined twice today, or
7118
+ already held).
7119
+
7120
+ <a id="previewerror"></a>
7121
+
7122
+ ## PreviewError
7123
+
7124
+ ```ts
7125
+ class PreviewError
7126
+ ```
7127
+
7128
+ Why `gem.gameConfig.preview` could not work out an answer.
7129
+
7130
+ <a id="previewerror-code"></a>
7131
+
7132
+ ## PreviewError.code
7133
+
7134
+ ```ts
7135
+ readonly code: "unsupported" | "not_found" | "invalid_argument"
7136
+ ```
7137
+
7138
+ `not_found` — the config has no recipe or progression by that id or
7139
+ slug; `invalid_argument` — the target is not `{ recipe }` or
7140
+ `{ progression, add? }` with a positive whole `add`; `unsupported` —
7141
+ not in a browser game (a function or a server runs the recipe and reads
7142
+ the receipt).
7143
+
6705
7144
  <a id="gemlookspeed"></a>
6706
7145
 
6707
7146
  ## GemLookSpeed
@@ -7192,48 +7631,124 @@ readonly isOpen: boolean
7192
7631
 
7193
7632
  Whether the panel is on screen right now.
7194
7633
 
7195
- <a id="gamepass"></a>
7634
+ <a id="platformgrantsource"></a>
7196
7635
 
7197
- ## GamePass
7636
+ ## PlatformGrantSource
7198
7637
 
7199
7638
  ```ts
7200
- interface GamePass
7639
+ type PlatformGrantSource = { source: "pass"; pass: string; amount: number } | { source: "boost"; amount: number }
7201
7640
  ```
7202
7641
 
7203
- One pass games may see, and whether this player holds it. Listed whether they
7204
- hold it or not, and this is everything a game learns about it.
7642
+ Where the part of a payout above its base comes from.
7205
7643
 
7206
- <a id="gamepass-pass"></a>
7644
+ <a id="platformgrantpreview"></a>
7207
7645
 
7208
- ## GamePass.pass
7646
+ ## PlatformGrantPreview
7209
7647
 
7210
7648
  ```ts
7211
- readonly pass: string
7649
+ interface PlatformGrantPreview
7212
7650
  ```
7213
7651
 
7214
- The pass's offering slug, such as `vip`. Stable and not localized: key on this.
7652
+ One platform payout — Coins, today — as the preview expects it or a receipt
7653
+ reports it, in one shape, so "you will earn" and "you earned" render with one
7654
+ component.
7215
7655
 
7216
- <a id="gamepass-held"></a>
7656
+ <a id="platformgrantpreview-currencyslug"></a>
7217
7657
 
7218
- ## GamePass.held
7658
+ ## PlatformGrantPreview.currencySlug
7219
7659
 
7220
7660
  ```ts
7221
- readonly held: boolean
7661
+ readonly currencySlug?: string
7222
7662
  ```
7223
7663
 
7224
- Whether the player holds it right now.
7664
+ The currency's slug, e.g. `ARCADE_TICKETS`. Absent when unknown.
7225
7665
 
7226
- <a id="gamepass-endsat"></a>
7666
+ <a id="platformgrantpreview-currencyid"></a>
7227
7667
 
7228
- ## GamePass.endsAt
7668
+ ## PlatformGrantPreview.currencyId
7229
7669
 
7230
7670
  ```ts
7231
- readonly endsAt: string | null
7671
+ readonly currencyId?: string
7232
7672
  ```
7233
7673
 
7234
- When the player stops holding it, RFC 3339 in UTC, grace and any queued
7235
- period included. `null` when it is not held, and when it is held with no
7236
- end, so read [GamePass.held](#gamepass-held) first: `null` alone never means ended.
7674
+ The currency's id, when it is known.
7675
+
7676
+ <a id="platformgrantpreview-base"></a>
7677
+
7678
+ ## PlatformGrantPreview.base
7679
+
7680
+ ```ts
7681
+ readonly base: number
7682
+ ```
7683
+
7684
+ What a player with no pass and no Boost gets.
7685
+
7686
+ <a id="platformgrantpreview-total"></a>
7687
+
7688
+ ## PlatformGrantPreview.total
7689
+
7690
+ ```ts
7691
+ readonly total: number
7692
+ ```
7693
+
7694
+ What this player gets: `base` plus `breakdown`.
7695
+
7696
+ <a id="platformgrantpreview-breakdown"></a>
7697
+
7698
+ ## PlatformGrantPreview.breakdown
7699
+
7700
+ ```ts
7701
+ readonly breakdown: readonly PlatformGrantSource[]
7702
+ ```
7703
+
7704
+ The part above `base`, and what it is from. Empty when `total` is `base`.
7705
+
7706
+ <a id="platformgrantpreview-ifcomplete"></a>
7707
+
7708
+ ## PlatformGrantPreview.ifComplete
7709
+
7710
+ ```ts
7711
+ readonly ifComplete?: true
7712
+ ```
7713
+
7714
+ `true` for an `on_complete` payout in a preview: it pays only if this
7715
+ claim completes the progression. Absent otherwise, and on a receipt.
7716
+
7717
+ <a id="earningsapi"></a>
7718
+
7719
+ ## EarningsApi
7720
+
7721
+ ```ts
7722
+ interface EarningsApi
7723
+ ```
7724
+
7725
+ `gem.earnings`: what a payout was, in the shape `gem.gameConfig.preview`
7726
+ says it would be.
7727
+
7728
+ <a id="earningsapi-fromreceipt"></a>
7729
+
7730
+ ## EarningsApi.fromReceipt
7731
+
7732
+ ```ts
7733
+ fromReceipt(change: unknown): Promise<PlatformGrantPreview | null>
7734
+ ```
7735
+
7736
+ Turn one `platform_grant` change from an order's receipt into a
7737
+ [PlatformGrantPreview](#platformgrantpreview): `base` is what a player with no pass and no
7738
+ Boost would have got under the same limits, `total` what this player got,
7739
+ and `breakdown` the pass's or the Boost's part, even when a limit trimmed
7740
+ the payout. Draw "you earned" with the component that drew "you will
7741
+ earn". Resolves `null` for any other kind of change.
7742
+
7743
+ **This and `preview` are the only way to show a platform payout.** Never
7744
+ multiply by `gem.player.boost`, and never copy a config amount into your
7745
+ game.
7746
+
7747
+ | Parameter | Type |
7748
+ | --- | --- |
7749
+ | `change` | `unknown` |
7750
+
7751
+ **Returns.** Always resolves; never rejects.
7237
7752
 
7238
7753
  <a id="passesevent"></a>
7239
7754
 
@@ -10636,6 +11151,32 @@ when it pays. See [PlayerBoost](#playerboost).
10636
11151
 
10637
11152
  **Guides.** [platform-rules](../platform-rules.md)
10638
11153
 
11154
+ <a id="gemplayer-isguest"></a>
11155
+
11156
+ ## GemPlayer.isGuest
11157
+
11158
+ ```ts
11159
+ readonly isGuest: boolean
11160
+ ```
11161
+
11162
+ Whether the Arcade says this player is a **guest it can sign up here**.
11163
+
11164
+ `true` only when the Arcade said so. `false` for a player with a full
11165
+ account, on a surface that offers no sign-up, and when the Arcade did not
11166
+ say — an older Arcade — so `false` is never proof of an account. That
11167
+ makes it the test for a sign-up gift: offer one only while this is
11168
+ `true`, and the gift can never reach a player who already has an account.
11169
+
11170
+ It changes when a guest signs up in place: `gem.player` is pushed again,
11171
+ and `onPlayer` hears it.
11172
+
11173
+ ```js
11174
+ const gem = createGem({ onPlayer: (player) => (signUpGift.hidden = !player.isGuest) });
11175
+ ```
11176
+
11177
+ For drawing only, like everything on `gem.player`: what a sign-up earns
11178
+ is granted by your function or server, which reads the account itself.
11179
+
10639
11180
  <a id="gemplayer-playerid"></a>
10640
11181
 
10641
11182
  ## GemPlayer.playerId
@@ -11829,6 +12370,18 @@ Every other surface returns ids; this is what turns them into something a
11829
12370
  player can read. Call `load()` once during start-up, then look up
11830
12371
  synchronously wherever you render.
11831
12372
 
12373
+ <a id="gem-earnings"></a>
12374
+
12375
+ ## Gem.earnings
12376
+
12377
+ ```ts
12378
+ readonly earnings: EarningsApi
12379
+ ```
12380
+
12381
+ What a platform payout was: `gem.earnings.fromReceipt(change)` turns a
12382
+ receipt's `platform_grant` change into the shape `gem.gameConfig.preview`
12383
+ gives, so "you will earn" and "you earned" draw with one component.
12384
+
11832
12385
  <a id="gem-purchases"></a>
11833
12386
 
11834
12387
  ## Gem.purchases
@@ -15233,6 +15786,67 @@ engine's WebTransport without a datagram lane (WebKit today): that is a
15233
15786
  fact about the browser too, and one worth remembering — see
15234
15787
  [webTransportRefusal](#webtransportrefusal).
15235
15788
 
15789
+ <a id="gamepass"></a>
15790
+
15791
+ ## GamePass
15792
+
15793
+ ```ts
15794
+ interface GamePass
15795
+ ```
15796
+
15797
+ One pass games may see, and whether this player holds it. Listed whether they
15798
+ hold it or not, and this is everything a game learns about it.
15799
+
15800
+ <a id="gamepass-pass"></a>
15801
+
15802
+ ## GamePass.pass
15803
+
15804
+ ```ts
15805
+ readonly pass: string
15806
+ ```
15807
+
15808
+ The pass's offering slug, such as `vip`. Stable and not localized: key on this.
15809
+
15810
+ <a id="gamepass-held"></a>
15811
+
15812
+ ## GamePass.held
15813
+
15814
+ ```ts
15815
+ readonly held: boolean
15816
+ ```
15817
+
15818
+ Whether the player holds it right now.
15819
+
15820
+ <a id="gamepass-daysleft"></a>
15821
+
15822
+ ## GamePass.daysLeft
15823
+
15824
+ ```ts
15825
+ readonly daysLeft: number
15826
+ ```
15827
+
15828
+ Whole days the player keeps it, rounded up so a pass with any time left
15829
+ reads at least `1`, and **capped at 7**: `7` means "7 or more", and is
15830
+ also what a pass held with no end reads. `0` when it is not held. Show
15831
+ `7` as "7+ days left", never as an exact end.
15832
+
15833
+ <a id="gamepass-endsat"></a>
15834
+
15835
+ ## GamePass.endsAt
15836
+
15837
+ ```ts
15838
+ readonly endsAt: string | null
15839
+ ```
15840
+
15841
+ **Deprecated.** Use [GamePass.daysLeft](#gamepass-daysleft). An exact instant is a value two
15842
+ games could match to link one player's identities, so the platform will
15843
+ stop sending it; it reads `null` then. See
15844
+ [the deprecation policy](../deprecation-policy.md).
15845
+
15846
+ When the player stops holding it, RFC 3339 in UTC, grace and any queued
15847
+ period included. `null` when it is not held, and when it is held with no
15848
+ end, so read [GamePass.held](#gamepass-held) first: `null` alone never means ended.
15849
+
15236
15850
  <a id="platformcurrencyaccess"></a>
15237
15851
 
15238
15852
  ## PlatformCurrencyAccess
@@ -16404,6 +17018,47 @@ Resolves with what the platform half did: `ok`, `already_ended` (this
16404
17018
  match was already over, or you asked twice), `refused` (the allocation was
16405
17019
  not ready yet) or `failed` (the platform could not be reached).
16406
17020
 
17021
+ <a id="gemserverhost-passes"></a>
17022
+
17023
+ ## GemServerHost.passes
17024
+
17025
+ ```ts
17026
+ passes(playerId: string): Promise<GemServerHostRead>
17027
+ ```
17028
+
17029
+ Ask the platform half which game-visible passes a player in this match
17030
+ holds: the match pass read, made with the allocation's own proof.
17031
+
17032
+ MAY BE ABSENT on older platform images, exactly as `endMatch` may, and a
17033
+ listen host never has it. `gem.match.playerPasses(playerId)` is this call;
17034
+ you rarely call it yourself.
17035
+
17036
+ Resolves with what the platform answered — see [GemServerHostRead](#gemserverhostread)
17037
+ — and rejects only when the platform half could not be asked at all.
17038
+
17039
+ | Parameter | Type |
17040
+ | --- | --- |
17041
+ | `playerId` | `string` |
17042
+
17043
+ <a id="gemserverhost-boost"></a>
17044
+
17045
+ ## GemServerHost.boost
17046
+
17047
+ ```ts
17048
+ boost(playerId: string): Promise<GemServerHostRead>
17049
+ ```
17050
+
17051
+ Ask the platform half for a player's Boost, for display: the match boost
17052
+ read, made with the allocation's own proof.
17053
+
17054
+ MAY BE ABSENT on older platform images and on a listen host.
17055
+ `gem.match.playerBoost(playerId)` is this call; you rarely call it
17056
+ yourself. Resolves and rejects as [GemServerHost.passes](#gemserverhost-passes) does.
17057
+
17058
+ | Parameter | Type |
17059
+ | --- | --- |
17060
+ | `playerId` | `string` |
17061
+
16407
17062
  <a id="gemserverhost-log"></a>
16408
17063
 
16409
17064
  ## GemServerHost.log
@@ -16436,6 +17091,41 @@ Like [GemServerHost.log](#gemserverhost-log), marked as a warning.
16436
17091
  | --- | --- |
16437
17092
  | `message` | `string` |
16438
17093
 
17094
+ <a id="gemserverhostread"></a>
17095
+
17096
+ ## GemServerHostRead
17097
+
17098
+ ```ts
17099
+ interface GemServerHostRead
17100
+ ```
17101
+
17102
+ What the platform half answered to a player read it made for this match:
17103
+ the HTTP status and the decoded JSON body, untouched.
17104
+
17105
+ The runtime adds only the allocation's proof, which never enters the bundle
17106
+ process; the SDK reads the body and turns a refusal into a `GemApiError`, so
17107
+ a runtime never has to know what the route's answer means.
17108
+
17109
+ <a id="gemserverhostread-status"></a>
17110
+
17111
+ ## GemServerHostRead.status
17112
+
17113
+ ```ts
17114
+ readonly status: number
17115
+ ```
17116
+
17117
+ The HTTP status the platform answered with.
17118
+
17119
+ <a id="gemserverhostread-body"></a>
17120
+
17121
+ ## GemServerHostRead.body
17122
+
17123
+ ```ts
17124
+ readonly body: unknown
17125
+ ```
17126
+
17127
+ The decoded JSON body, or `null` when there was none.
17128
+
16439
17129
  <a id="gemserverbundle"></a>
16440
17130
 
16441
17131
  ## GemServerBundle