@indiegems/gem-web-sdk 23.2.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 server surface — API reference
2
2
 
3
- Generated from `@indiegems/gem-web-sdk/sdk` v23.2.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/server` exports exactly the symbols on this page and nothing else, for a build that wants only this half.
6
6
 
@@ -1469,6 +1469,125 @@ only when your studio corrects a running period; clients may hold the old
1469
1469
  content for up to an hour afterwards, and the hash is how a verifier tells
1470
1470
  them apart.
1471
1471
 
1472
+ <a id="platformgrantsource"></a>
1473
+
1474
+ ## PlatformGrantSource
1475
+
1476
+ ```ts
1477
+ type PlatformGrantSource = { source: "pass"; pass: string; amount: number } | { source: "boost"; amount: number }
1478
+ ```
1479
+
1480
+ Where the part of a payout above its base comes from.
1481
+
1482
+ <a id="platformgrantpreview"></a>
1483
+
1484
+ ## PlatformGrantPreview
1485
+
1486
+ ```ts
1487
+ interface PlatformGrantPreview
1488
+ ```
1489
+
1490
+ One platform payout — Coins, today — as the preview expects it or a receipt
1491
+ reports it, in one shape, so "you will earn" and "you earned" render with one
1492
+ component.
1493
+
1494
+ <a id="platformgrantpreview-currencyslug"></a>
1495
+
1496
+ ## PlatformGrantPreview.currencySlug
1497
+
1498
+ ```ts
1499
+ readonly currencySlug?: string
1500
+ ```
1501
+
1502
+ The currency's slug, e.g. `ARCADE_TICKETS`. Absent when unknown.
1503
+
1504
+ <a id="platformgrantpreview-currencyid"></a>
1505
+
1506
+ ## PlatformGrantPreview.currencyId
1507
+
1508
+ ```ts
1509
+ readonly currencyId?: string
1510
+ ```
1511
+
1512
+ The currency's id, when it is known.
1513
+
1514
+ <a id="platformgrantpreview-base"></a>
1515
+
1516
+ ## PlatformGrantPreview.base
1517
+
1518
+ ```ts
1519
+ readonly base: number
1520
+ ```
1521
+
1522
+ What a player with no pass and no Boost gets.
1523
+
1524
+ <a id="platformgrantpreview-total"></a>
1525
+
1526
+ ## PlatformGrantPreview.total
1527
+
1528
+ ```ts
1529
+ readonly total: number
1530
+ ```
1531
+
1532
+ What this player gets: `base` plus `breakdown`.
1533
+
1534
+ <a id="platformgrantpreview-breakdown"></a>
1535
+
1536
+ ## PlatformGrantPreview.breakdown
1537
+
1538
+ ```ts
1539
+ readonly breakdown: readonly PlatformGrantSource[]
1540
+ ```
1541
+
1542
+ The part above `base`, and what it is from. Empty when `total` is `base`.
1543
+
1544
+ <a id="platformgrantpreview-ifcomplete"></a>
1545
+
1546
+ ## PlatformGrantPreview.ifComplete
1547
+
1548
+ ```ts
1549
+ readonly ifComplete?: true
1550
+ ```
1551
+
1552
+ `true` for an `on_complete` payout in a preview: it pays only if this
1553
+ claim completes the progression. Absent otherwise, and on a receipt.
1554
+
1555
+ <a id="earningsapi"></a>
1556
+
1557
+ ## EarningsApi
1558
+
1559
+ ```ts
1560
+ interface EarningsApi
1561
+ ```
1562
+
1563
+ `gem.earnings`: what a payout was, in the shape `gem.gameConfig.preview`
1564
+ says it would be.
1565
+
1566
+ <a id="earningsapi-fromreceipt"></a>
1567
+
1568
+ ## EarningsApi.fromReceipt
1569
+
1570
+ ```ts
1571
+ fromReceipt(change: unknown): Promise<PlatformGrantPreview | null>
1572
+ ```
1573
+
1574
+ Turn one `platform_grant` change from an order's receipt into a
1575
+ [PlatformGrantPreview](#platformgrantpreview): `base` is what a player with no pass and no
1576
+ Boost would have got under the same limits, `total` what this player got,
1577
+ and `breakdown` the pass's or the Boost's part, even when a limit trimmed
1578
+ the payout. Draw "you earned" with the component that drew "you will
1579
+ earn". Resolves `null` for any other kind of change.
1580
+
1581
+ **This and `preview` are the only way to show a platform payout.** Never
1582
+ multiply by `gem.player.boost`, and never copy a config amount into your
1583
+ game.
1584
+
1585
+ | Parameter | Type |
1586
+ | --- | --- |
1587
+ | `change` | `unknown` |
1588
+
1589
+ **Returns.** Always resolves; never rejects.
1590
+
1472
1591
  <a id="functioninvokeoptions"></a>
1473
1592
 
1474
1593
  ## FunctionInvokeOptions
@@ -1814,6 +1933,67 @@ await gem.functions.invoke({ claim: 'daily' }, { cueId });
1814
1933
  own `Err`. `TransportRefusal` for an input that is neither bytes nor
1815
1934
  JSON, before anything is sent. `AuthError` if the token cannot be renewed.
1816
1935
 
1936
+ <a id="gamepass"></a>
1937
+
1938
+ ## GamePass
1939
+
1940
+ ```ts
1941
+ interface GamePass
1942
+ ```
1943
+
1944
+ One pass games may see, and whether this player holds it. Listed whether they
1945
+ hold it or not, and this is everything a game learns about it.
1946
+
1947
+ <a id="gamepass-pass"></a>
1948
+
1949
+ ## GamePass.pass
1950
+
1951
+ ```ts
1952
+ readonly pass: string
1953
+ ```
1954
+
1955
+ The pass's offering slug, such as `vip`. Stable and not localized: key on this.
1956
+
1957
+ <a id="gamepass-held"></a>
1958
+
1959
+ ## GamePass.held
1960
+
1961
+ ```ts
1962
+ readonly held: boolean
1963
+ ```
1964
+
1965
+ Whether the player holds it right now.
1966
+
1967
+ <a id="gamepass-daysleft"></a>
1968
+
1969
+ ## GamePass.daysLeft
1970
+
1971
+ ```ts
1972
+ readonly daysLeft: number
1973
+ ```
1974
+
1975
+ Whole days the player keeps it, rounded up so a pass with any time left
1976
+ reads at least `1`, and **capped at 7**: `7` means "7 or more", and is
1977
+ also what a pass held with no end reads. `0` when it is not held. Show
1978
+ `7` as "7+ days left", never as an exact end.
1979
+
1980
+ <a id="gamepass-endsat"></a>
1981
+
1982
+ ## GamePass.endsAt
1983
+
1984
+ ```ts
1985
+ readonly endsAt: string | null
1986
+ ```
1987
+
1988
+ **Deprecated.** Use [GamePass.daysLeft](#gamepass-daysleft). An exact instant is a value two
1989
+ games could match to link one player's identities, so the platform will
1990
+ stop sending it; it reads `null` then. See
1991
+ [the deprecation policy](../deprecation-policy.md).
1992
+
1993
+ When the player stops holding it, RFC 3339 in UTC, grace and any queued
1994
+ period included. `null` when it is not held, and when it is held with no
1995
+ end, so read [GamePass.held](#gamepass-held) first: `null` alone never means ended.
1996
+
1817
1997
  <a id="clock"></a>
1818
1998
 
1819
1999
  ## Clock
@@ -2449,6 +2629,21 @@ player, and that is not an error — fall back to something of your own.
2449
2629
  [GemMatchServer.profile](#gemmatchserver-profile) is the version you usually want: same
2450
2630
  information, with the name typed as [PlayerText](#playertext).
2451
2631
 
2632
+ <a id="gemserverhostread"></a>
2633
+
2634
+ ## GemServerHostRead
2635
+
2636
+ ```ts
2637
+ interface GemServerHostRead
2638
+ ```
2639
+
2640
+ What the platform half answered to a player read it made for this match:
2641
+ the HTTP status and the decoded JSON body, untouched.
2642
+
2643
+ The runtime adds only the allocation's proof, which never enters the bundle
2644
+ process; the SDK reads the body and turns a refusal into a `GemApiError`, so
2645
+ a runtime never has to know what the route's answer means.
2646
+
2452
2647
  <a id="sendoptions"></a>
2453
2648
 
2454
2649
  ## SendOptions
@@ -2756,6 +2951,82 @@ gameId(): string
2756
2951
 
2757
2952
  The game this server is running — taken from its credential.
2758
2953
 
2954
+ <a id="matchboostmultiplier"></a>
2955
+
2956
+ ## MatchBoostMultiplier
2957
+
2958
+ ```ts
2959
+ interface MatchBoostMultiplier
2960
+ ```
2961
+
2962
+ One platform currency's Boost, as a dedicated server reads it.
2963
+
2964
+ <a id="matchboostmultiplier-currencyslug"></a>
2965
+
2966
+ ## MatchBoostMultiplier.currencySlug
2967
+
2968
+ ```ts
2969
+ readonly currencySlug: string
2970
+ ```
2971
+
2972
+ The currency's slug, e.g. `GEMS` or `ARCADE_TICKETS`.
2973
+
2974
+ <a id="matchboostmultiplier-multiplier"></a>
2975
+
2976
+ ## MatchBoostMultiplier.multiplier
2977
+
2978
+ ```ts
2979
+ readonly multiplier: number
2980
+ ```
2981
+
2982
+ How much faster the player earns it right now: `2` is 2x, `1` is not boosted.
2983
+
2984
+ <a id="matchplayerboost"></a>
2985
+
2986
+ ## MatchPlayerBoost
2987
+
2988
+ ```ts
2989
+ interface MatchPlayerBoost
2990
+ ```
2991
+
2992
+ A player's Boost, as a dedicated server reads it — **for display only**,
2993
+ exactly as `gem.player.boost` is in the browser.
2994
+
2995
+ ⚠️ **Show it; never gate on it.** Nothing a player can do, reach or win may
2996
+ depend on whether they are boosted. To gate on something a player paid for,
2997
+ gate on a pass: `gem.match.playerPasses`.
2998
+
2999
+ <a id="matchplayerboost-active"></a>
3000
+
3001
+ ## MatchPlayerBoost.active
3002
+
3003
+ ```ts
3004
+ readonly active: boolean
3005
+ ```
3006
+
3007
+ Whether any currency earns faster than 1x right now.
3008
+
3009
+ <a id="matchplayerboost-multipliers"></a>
3010
+
3011
+ ## MatchPlayerBoost.multipliers
3012
+
3013
+ ```ts
3014
+ readonly multipliers: readonly MatchBoostMultiplier[]
3015
+ ```
3016
+
3017
+ One entry per boostable platform currency, boosted or not.
3018
+
3019
+ <a id="matchplayerboost-expiresindays"></a>
3020
+
3021
+ ## MatchPlayerBoost.expiresInDays
3022
+
3023
+ ```ts
3024
+ readonly expiresInDays?: number
3025
+ ```
3026
+
3027
+ Whole days until the soonest boosted currency drops back to 1x, rounded up
3028
+ and **capped at 7** (`7` means "7 or more"). Absent when nothing is boosted.
3029
+
2759
3030
  <a id="playertext"></a>
2760
3031
 
2761
3032
  ## PlayerText
@@ -3205,7 +3476,7 @@ See [ServerApi](#serverapi).
3205
3476
  ## GemServer.match
3206
3477
 
3207
3478
  ```ts
3208
- readonly match: { end: null; setBackfill: null; reportPlayers: null }
3479
+ readonly match: { end: null; setBackfill: null; reportPlayers: null; playerPasses: null; playerBoost: null }
3209
3480
  ```
3210
3481
 
3211
3482
  Ending the match.
@@ -3311,6 +3582,77 @@ leave(playerId) {
3311
3582
  }
3312
3583
  ```
3313
3584
 
3585
+ <a id="gemserver-match-playerpasses"></a>
3586
+
3587
+ ## GemServer.match.playerPasses
3588
+
3589
+ ```ts
3590
+ playerPasses(playerId: string, signal?: AbortSignal): Promise<readonly GamePass[]>
3591
+ ```
3592
+
3593
+ Which game-visible passes a player in this match holds, in the shape
3594
+ `gem.me.passes.list()` gives in the browser: one entry per pass the
3595
+ platform marked visible to games, held or not, with `held` and
3596
+ `daysLeft`.
3597
+
3598
+ **This is what to gate on** — a VIP door, a VIP-only mode. `held` is
3599
+ exactly what a `requires: holds_pass` requirement on the same slug
3600
+ decides. Read it when the player joins and again when you need it; it is
3601
+ not pushed.
3602
+
3603
+ | Parameter | Type | Description |
3604
+ | --- | --- | --- |
3605
+ | `playerId` | `string` | A player in THIS match. Anyone else is refused
3606
+ `not_found` (`player_not_in_match`) and nothing about them is read. |
3607
+ | `signal` | `AbortSignal` | Not used — the platform half bounds its own request. |
3608
+
3609
+ **Throws.** When the platform image running this server predates the hook, or
3610
+ on a listen host (a player's browser hosting a P2P match), which holds no
3611
+ allocation proof. A `GemApiError` when the platform refuses, including
3612
+ `forbidden` (`client_permission_denied`) until the platform grants game
3613
+ servers the pass read.
3614
+
3615
+ ```js
3616
+ const vip = (await gem.match.playerPasses(playerId)).find((p) => p.pass === 'vip');
3617
+ if (vip?.held) openVipLounge(playerId);
3618
+ ```
3619
+
3620
+ <a id="gemserver-match-playerboost"></a>
3621
+
3622
+ ## GemServer.match.playerBoost
3623
+
3624
+ ```ts
3625
+ playerBoost(playerId: string, signal?: AbortSignal): Promise<MatchPlayerBoost>
3626
+ ```
3627
+
3628
+ A player's Boost, **for display only** — "2x Coins" on a results screen.
3629
+ Never gate content, difficulty, matchmaking or power on it; gate on a pass
3630
+ with `playerPasses`.
3631
+
3632
+ | Parameter | Type | Description |
3633
+ | --- | --- | --- |
3634
+ | `playerId` | `string` | A player in THIS match. |
3635
+ | `signal` | `AbortSignal` | Not used — the platform half bounds its own request. |
3636
+
3637
+ **Throws.** As `playerPasses` does.
3638
+
3639
+ <a id="gemserver-earnings"></a>
3640
+
3641
+ ## GemServer.earnings
3642
+
3643
+ ```ts
3644
+ readonly earnings: EarningsApi
3645
+ ```
3646
+
3647
+ What a platform payout was: `earnings.fromReceipt(change)` turns a
3648
+ `platform_grant` change from a receipt into the shape the browser's payout
3649
+ preview gives — `base`, `total`, and the pass's or the Boost's part — to
3650
+ send to the player whose screen draws it.
3651
+
3652
+ A server has no read of the platform's currencies, so the answer carries
3653
+ `currencyId` and no `currencySlug`; the browser's `gem.earnings` fills the
3654
+ slug in.
3655
+
3314
3656
  <a id="gemserver-analytics"></a>
3315
3657
 
3316
3658
  ## GemServer.analytics
@@ -3872,6 +4214,47 @@ Resolves with what the platform half did: `ok`, `already_ended` (this
3872
4214
  match was already over, or you asked twice), `refused` (the allocation was
3873
4215
  not ready yet) or `failed` (the platform could not be reached).
3874
4216
 
4217
+ <a id="gemserverhost-passes"></a>
4218
+
4219
+ ## GemServerHost.passes
4220
+
4221
+ ```ts
4222
+ passes(playerId: string): Promise<GemServerHostRead>
4223
+ ```
4224
+
4225
+ Ask the platform half which game-visible passes a player in this match
4226
+ holds: the match pass read, made with the allocation's own proof.
4227
+
4228
+ MAY BE ABSENT on older platform images, exactly as `endMatch` may, and a
4229
+ listen host never has it. `gem.match.playerPasses(playerId)` is this call;
4230
+ you rarely call it yourself.
4231
+
4232
+ Resolves with what the platform answered — see [GemServerHostRead](#gemserverhostread)
4233
+ — and rejects only when the platform half could not be asked at all.
4234
+
4235
+ | Parameter | Type |
4236
+ | --- | --- |
4237
+ | `playerId` | `string` |
4238
+
4239
+ <a id="gemserverhost-boost"></a>
4240
+
4241
+ ## GemServerHost.boost
4242
+
4243
+ ```ts
4244
+ boost(playerId: string): Promise<GemServerHostRead>
4245
+ ```
4246
+
4247
+ Ask the platform half for a player's Boost, for display: the match boost
4248
+ read, made with the allocation's own proof.
4249
+
4250
+ MAY BE ABSENT on older platform images and on a listen host.
4251
+ `gem.match.playerBoost(playerId)` is this call; you rarely call it
4252
+ yourself. Resolves and rejects as [GemServerHost.passes](#gemserverhost-passes) does.
4253
+
4254
+ | Parameter | Type |
4255
+ | --- | --- |
4256
+ | `playerId` | `string` |
4257
+
3875
4258
  <a id="gemserverhost-log"></a>
3876
4259
 
3877
4260
  ## GemServerHost.log
@@ -3904,6 +4287,26 @@ Like [GemServerHost.log](#gemserverhost-log), marked as a warning.
3904
4287
  | --- | --- |
3905
4288
  | `message` | `string` |
3906
4289
 
4290
+ <a id="gemserverhostread-status"></a>
4291
+
4292
+ ## GemServerHostRead.status
4293
+
4294
+ ```ts
4295
+ readonly status: number
4296
+ ```
4297
+
4298
+ The HTTP status the platform answered with.
4299
+
4300
+ <a id="gemserverhostread-body"></a>
4301
+
4302
+ ## GemServerHostRead.body
4303
+
4304
+ ```ts
4305
+ readonly body: unknown
4306
+ ```
4307
+
4308
+ The decoded JSON body, or `null` when there was none.
4309
+
3907
4310
  <a id="hosttokensourceoptions-clock"></a>
3908
4311
 
3909
4312
  ## HostTokenSourceOptions.clock
@@ -4299,7 +4702,7 @@ See [ServerApi](#serverapi).
4299
4702
  ## GemMatchServer.match
4300
4703
 
4301
4704
  ```ts
4302
- readonly match: { end: null; setBackfill: null; reportPlayers: null }
4705
+ readonly match: { end: null; setBackfill: null; reportPlayers: null; playerPasses: null; playerBoost: null }
4303
4706
  ```
4304
4707
 
4305
4708
  Ending the match.
@@ -4405,6 +4808,77 @@ leave(playerId) {
4405
4808
  }
4406
4809
  ```
4407
4810
 
4811
+ <a id="gemmatchserver-match-playerpasses"></a>
4812
+
4813
+ ## GemMatchServer.match.playerPasses
4814
+
4815
+ ```ts
4816
+ playerPasses(playerId: string, signal?: AbortSignal): Promise<readonly GamePass[]>
4817
+ ```
4818
+
4819
+ Which game-visible passes a player in this match holds, in the shape
4820
+ `gem.me.passes.list()` gives in the browser: one entry per pass the
4821
+ platform marked visible to games, held or not, with `held` and
4822
+ `daysLeft`.
4823
+
4824
+ **This is what to gate on** — a VIP door, a VIP-only mode. `held` is
4825
+ exactly what a `requires: holds_pass` requirement on the same slug
4826
+ decides. Read it when the player joins and again when you need it; it is
4827
+ not pushed.
4828
+
4829
+ | Parameter | Type | Description |
4830
+ | --- | --- | --- |
4831
+ | `playerId` | `string` | A player in THIS match. Anyone else is refused
4832
+ `not_found` (`player_not_in_match`) and nothing about them is read. |
4833
+ | `signal` | `AbortSignal` | Not used — the platform half bounds its own request. |
4834
+
4835
+ **Throws.** When the platform image running this server predates the hook, or
4836
+ on a listen host (a player's browser hosting a P2P match), which holds no
4837
+ allocation proof. A `GemApiError` when the platform refuses, including
4838
+ `forbidden` (`client_permission_denied`) until the platform grants game
4839
+ servers the pass read.
4840
+
4841
+ ```js
4842
+ const vip = (await gem.match.playerPasses(playerId)).find((p) => p.pass === 'vip');
4843
+ if (vip?.held) openVipLounge(playerId);
4844
+ ```
4845
+
4846
+ <a id="gemmatchserver-match-playerboost"></a>
4847
+
4848
+ ## GemMatchServer.match.playerBoost
4849
+
4850
+ ```ts
4851
+ playerBoost(playerId: string, signal?: AbortSignal): Promise<MatchPlayerBoost>
4852
+ ```
4853
+
4854
+ A player's Boost, **for display only** — "2x Coins" on a results screen.
4855
+ Never gate content, difficulty, matchmaking or power on it; gate on a pass
4856
+ with `playerPasses`.
4857
+
4858
+ | Parameter | Type | Description |
4859
+ | --- | --- | --- |
4860
+ | `playerId` | `string` | A player in THIS match. |
4861
+ | `signal` | `AbortSignal` | Not used — the platform half bounds its own request. |
4862
+
4863
+ **Throws.** As `playerPasses` does.
4864
+
4865
+ <a id="gemmatchserver-earnings"></a>
4866
+
4867
+ ## GemMatchServer.earnings
4868
+
4869
+ ```ts
4870
+ readonly earnings: EarningsApi
4871
+ ```
4872
+
4873
+ What a platform payout was: `earnings.fromReceipt(change)` turns a
4874
+ `platform_grant` change from a receipt into the shape the browser's payout
4875
+ preview gives — `base`, `total`, and the pass's or the Boost's part — to
4876
+ send to the player whose screen draws it.
4877
+
4878
+ A server has no read of the platform's currencies, so the answer carries
4879
+ `currencyId` and no `currencySlug`; the browser's `gem.earnings` fills the
4880
+ slug in.
4881
+
4408
4882
  <a id="gemmatchserver-analytics"></a>
4409
4883
 
4410
4884
  ## GemMatchServer.analytics