@indiegems/gem-web-sdk 23.1.3 → 23.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/dist/game.d.ts +13 -2
- package/dist/gem-web-sdk.bridge.js +2 -2
- package/dist/gem-web-sdk.conformance.js +2 -2
- package/dist/gem-web-sdk.esm.js +2 -2
- package/dist/gem-web-sdk.function.js +3 -3
- package/dist/gem-web-sdk.game.js +3 -3
- package/dist/gem-web-sdk.min.js +3 -3
- package/dist/gem-web-sdk.sdk.js +3 -3
- package/dist/gem-web-sdk.server.js +2 -2
- package/dist/index.d.ts +3 -1
- package/dist/sdk.d.ts +13 -2
- package/docs/analytics.md +40 -0
- package/docs/api/api-reference-function.md +3 -2
- package/docs/api/api-reference-game.md +157 -7
- package/docs/api/api-reference-server.md +1 -1
- package/docs/api/reference.json +147 -7
- package/docs/arcade-and-store.md +4 -2
- package/docs/changelog.md +30 -0
- package/docs/getting-started.md +1 -1
- package/docs/manifest.json +16 -16
- package/docs/player-sign-in.md +51 -3
- package/docs/rewarded-ads.md +113 -8
- package/docs/server-bundles.md +2 -2
- package/docs/what-a-game-must-do.md +7 -4
- package/package.json +1 -1
- package/schema/bridge.v1.json +41 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The browser surface — API reference
|
|
2
2
|
|
|
3
|
-
Generated from `@indiegems/gem-web-sdk/sdk` v23.
|
|
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.
|
|
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
|
|
|
@@ -284,6 +284,12 @@ this config server-side; the grant lands on your game's inventory, and
|
|
|
284
284
|
re-reading `gem.me.inventory` is the only way to learn that it did. Whether
|
|
285
285
|
the button could pay right now is [AdsApi.rewardedStatus](#adsapi-rewardedstatus).
|
|
286
286
|
|
|
287
|
+
A row may also carry `platform_prices`, the Coin and Gem prices that unlock
|
|
288
|
+
it beside the ad, and `ad: false` when only a price does (`ad` is absent
|
|
289
|
+
otherwise, which means the ad unlocks it). Both are what you declared, not
|
|
290
|
+
what is offered now: label the button from `rewardedStatus`'s
|
|
291
|
+
`adGrantable` and `options`, which say what this platform serves.
|
|
292
|
+
|
|
287
293
|
Absent when your game declares none.
|
|
288
294
|
|
|
289
295
|
**Guides.** [rewarded-ads](../rewarded-ads.md)
|
|
@@ -3117,6 +3123,7 @@ fourth.
|
|
|
3117
3123
|
- `declined` — the player closed the prompt, or the arcade chose not to show
|
|
3118
3124
|
one. Return to the game silently.
|
|
3119
3125
|
- `unavailable` — the arcade could not offer sign-in, or never answered.
|
|
3126
|
+
[AccountApi.signInAvailable](#accountapi-signinavailable) says so before you draw the button.
|
|
3120
3127
|
|
|
3121
3128
|
No reason is given for a `declined`, and one will never be added: why a
|
|
3122
3129
|
sign-in did not happen is a fact about the player's account, and the arcade
|
|
@@ -3156,6 +3163,59 @@ interface AccountApi
|
|
|
3156
3163
|
|
|
3157
3164
|
The account surface. `gem.account` is one of these.
|
|
3158
3165
|
|
|
3166
|
+
<a id="accountapi-signinavailable"></a>
|
|
3167
|
+
|
|
3168
|
+
## AccountApi.signInAvailable
|
|
3169
|
+
|
|
3170
|
+
```ts
|
|
3171
|
+
readonly signInAvailable: boolean
|
|
3172
|
+
```
|
|
3173
|
+
|
|
3174
|
+
Whether [AccountApi.requestSignIn](#accountapi-requestsignin) can show this player a sign-in
|
|
3175
|
+
here. Read it before you draw a "Sign in to claim" button, and hide the
|
|
3176
|
+
offer when it is `false`.
|
|
3177
|
+
|
|
3178
|
+
- `true` — a guest the arcade can offer sign-up to. An ask may still
|
|
3179
|
+
answer `declined` at a busy moment.
|
|
3180
|
+
- `false` — an ask would show nothing. The player is already signed in
|
|
3181
|
+
(it answers `signed_in` at once; every player in a current Gem Arcade
|
|
3182
|
+
app build, v3.33.174 and later, is), or there is no Arcade sign-in here
|
|
3183
|
+
(it answers `unavailable`). Also `false` until the player is known.
|
|
3184
|
+
|
|
3185
|
+
On an arcade older than this signal it reads `true` for every player, a
|
|
3186
|
+
full account included, as before it existed. So gate a sign-up gift on it
|
|
3187
|
+
and on the guest test you use today; see docs/player-sign-in.md.
|
|
3188
|
+
[AccountApi.onSignInAvailableChange](#accountapi-onsigninavailablechange) tells you when it changes.
|
|
3189
|
+
|
|
3190
|
+
```ts
|
|
3191
|
+
const draw = (available: boolean) => {
|
|
3192
|
+
signInButton.hidden = !available;
|
|
3193
|
+
};
|
|
3194
|
+
draw(gem.account.signInAvailable);
|
|
3195
|
+
gem.account.onSignInAvailableChange(draw);
|
|
3196
|
+
```
|
|
3197
|
+
|
|
3198
|
+
**Guides.** [player-sign-in](../player-sign-in.md)
|
|
3199
|
+
|
|
3200
|
+
<a id="accountapi-onsigninavailablechange"></a>
|
|
3201
|
+
|
|
3202
|
+
## AccountApi.onSignInAvailableChange
|
|
3203
|
+
|
|
3204
|
+
```ts
|
|
3205
|
+
onSignInAvailableChange(listener: (available: boolean) => void): () => void
|
|
3206
|
+
```
|
|
3207
|
+
|
|
3208
|
+
Runs `listener` whenever [AccountApi.signInAvailable](#accountapi-signinavailable) changes: when
|
|
3209
|
+
the player arrives, when the arcade changes its answer (a guest who signs
|
|
3210
|
+
up), and when the connection closes. Not on a re-sent player with the same
|
|
3211
|
+
answer.
|
|
3212
|
+
|
|
3213
|
+
| Parameter | Type |
|
|
3214
|
+
| --- | --- |
|
|
3215
|
+
| `listener` | `(available: boolean) => void` |
|
|
3216
|
+
|
|
3217
|
+
**Returns.** A function that stops the listener.
|
|
3218
|
+
|
|
3159
3219
|
<a id="accountapi-requestsignin"></a>
|
|
3160
3220
|
|
|
3161
3221
|
## AccountApi.requestSignIn
|
|
@@ -3419,6 +3479,13 @@ means the platform would grant if an ad is watched or, where no ad serves,
|
|
|
3419
3479
|
under the placement's `without_ads: grant`; a player can still press the
|
|
3420
3480
|
button and get `no_ad`, for reasons your game is not told.
|
|
3421
3481
|
|
|
3482
|
+
A placement your config also prices in Coins or Gems (`platform_prices`)
|
|
3483
|
+
carries those prices in `options`, where the platform lets players pay for
|
|
3484
|
+
one, and `adGrantable` says whether the ad itself could pay. Label your
|
|
3485
|
+
button from both: name the ad only when `adGrantable` is `true`, and each
|
|
3486
|
+
price in `options`. The Arcade then shows the player those choices when
|
|
3487
|
+
they press, and the press answers and is re-read exactly as an ad's is.
|
|
3488
|
+
|
|
3422
3489
|
NOTHING REJECTS, like everything else on `gem.ads`. Without a play token,
|
|
3423
3490
|
when the read fails or takes longer than ten seconds, or for a `placement`
|
|
3424
3491
|
outside the grammar [AdRequest.placement](#adrequest-placement) documents, it resolves not
|
|
@@ -3450,6 +3517,52 @@ if (status.nextEligibleAt !== undefined) {
|
|
|
3450
3517
|
|
|
3451
3518
|
**Guides.** [rewarded-ads](../rewarded-ads.md)
|
|
3452
3519
|
|
|
3520
|
+
<a id="rewardedoption"></a>
|
|
3521
|
+
|
|
3522
|
+
## RewardedOption
|
|
3523
|
+
|
|
3524
|
+
```ts
|
|
3525
|
+
interface RewardedOption
|
|
3526
|
+
```
|
|
3527
|
+
|
|
3528
|
+
One price that also unlocks a rewarded placement, in
|
|
3529
|
+
[RewardedStatus.options](#rewardedstatus-options): what your config's `platform_prices` set for
|
|
3530
|
+
it, as the platform serves it. Label your button from it ("5 Gems").
|
|
3531
|
+
|
|
3532
|
+
It says nothing about the player: not their balance, and not whether they
|
|
3533
|
+
can afford it. The Arcade shows them that when they press.
|
|
3534
|
+
|
|
3535
|
+
<a id="rewardedoption-kind"></a>
|
|
3536
|
+
|
|
3537
|
+
## RewardedOption.kind
|
|
3538
|
+
|
|
3539
|
+
```ts
|
|
3540
|
+
readonly kind: "coins" | "gems"
|
|
3541
|
+
```
|
|
3542
|
+
|
|
3543
|
+
Which platform currency: `coins` (Coins, `ARCADE_TICKETS`) or `gems`
|
|
3544
|
+
(Gems, `GEMS`).
|
|
3545
|
+
|
|
3546
|
+
<a id="rewardedoption-currencyid"></a>
|
|
3547
|
+
|
|
3548
|
+
## RewardedOption.currencyId
|
|
3549
|
+
|
|
3550
|
+
```ts
|
|
3551
|
+
readonly currencyId: string
|
|
3552
|
+
```
|
|
3553
|
+
|
|
3554
|
+
The platform currency's id, as your config's `platform_prices` resolved it.
|
|
3555
|
+
|
|
3556
|
+
<a id="rewardedoption-price"></a>
|
|
3557
|
+
|
|
3558
|
+
## RewardedOption.price
|
|
3559
|
+
|
|
3560
|
+
```ts
|
|
3561
|
+
readonly price: number
|
|
3562
|
+
```
|
|
3563
|
+
|
|
3564
|
+
The price, a positive whole number of the currency.
|
|
3565
|
+
|
|
3453
3566
|
<a id="rewardedstatus"></a>
|
|
3454
3567
|
|
|
3455
3568
|
## RewardedStatus
|
|
@@ -3495,12 +3608,48 @@ readonly grantable: boolean
|
|
|
3495
3608
|
|
|
3496
3609
|
Whether pressing your button could pay right now: the platform would grant
|
|
3497
3610
|
the reward if an ad is watched or, where no ad serves, under the
|
|
3498
|
-
placement's `without_ads: grant
|
|
3611
|
+
placement's `without_ads: grant` — or, where [RewardedStatus.options](#rewardedstatus-options)
|
|
3612
|
+
is present, if the player pays one of its prices.
|
|
3613
|
+
|
|
3614
|
+
**Not a promise that an ad will play, and not a promise of a reward.** For
|
|
3615
|
+
the ad, it is `false` whenever a cap is spent, a cooldown is running, the
|
|
3616
|
+
player holds `max_held`, rewarded is off on this channel, or the arcade
|
|
3617
|
+
running your game does not take ad requests at all. The cap, the cooldown
|
|
3618
|
+
and `max_held` limit the ad only: a placement with `options` stays
|
|
3619
|
+
grantable through them, because the player can still pay. It never says
|
|
3620
|
+
whether the player can afford a price.
|
|
3621
|
+
|
|
3622
|
+
<a id="rewardedstatus-adgrantable"></a>
|
|
3623
|
+
|
|
3624
|
+
## RewardedStatus.adGrantable
|
|
3625
|
+
|
|
3626
|
+
```ts
|
|
3627
|
+
readonly adGrantable: boolean
|
|
3628
|
+
```
|
|
3629
|
+
|
|
3630
|
+
Whether the AD could pay right now: [RewardedStatus.grantable](#rewardedstatus-grantable) for
|
|
3631
|
+
the ad alone, leaving out the prices. Name the ad on your button only when
|
|
3632
|
+
this is `true`.
|
|
3633
|
+
|
|
3634
|
+
The same as `grantable` for a placement with no `options`. `false` for a
|
|
3635
|
+
placement whose config switches the ad off (`ad: false`) where the
|
|
3636
|
+
platform lets players pay for it, and on every answer where `grantable` is.
|
|
3637
|
+
|
|
3638
|
+
<a id="rewardedstatus-options"></a>
|
|
3639
|
+
|
|
3640
|
+
## RewardedStatus.options
|
|
3641
|
+
|
|
3642
|
+
```ts
|
|
3643
|
+
readonly options?: readonly RewardedOption[]
|
|
3644
|
+
```
|
|
3645
|
+
|
|
3646
|
+
The Coin and Gem prices that also unlock the placement, from your config's
|
|
3647
|
+
`platform_prices`, at most one per currency.
|
|
3499
3648
|
|
|
3500
|
-
|
|
3501
|
-
is `false
|
|
3502
|
-
|
|
3503
|
-
|
|
3649
|
+
ABSENT — no key — for a placement with no prices, on any answer where
|
|
3650
|
+
`declared` is `false`, and wherever the platform does not yet let players
|
|
3651
|
+
pay for a placement: there your prices are not offered and the placement
|
|
3652
|
+
unlocks by its ad alone. Nothing here says what the player holds.
|
|
3504
3653
|
|
|
3505
3654
|
<a id="rewardedstatus-remainingtoday"></a>
|
|
3506
3655
|
|
|
@@ -3903,7 +4052,8 @@ dimension for it on the events you want to break down, with the arms as its
|
|
|
3903
4052
|
values, named after the experiment, and pass the selection there yourself:
|
|
3904
4053
|
`gem.analytics.track('tutorial_finished', { tutorial_length: tutorial })`.
|
|
3905
4054
|
Never the platform's `variant` field, which belongs to store-page
|
|
3906
|
-
experiments.
|
|
4055
|
+
experiments. For the platform's results to show the test, also declare it
|
|
4056
|
+
under `analytics_tests` in your game config (see docs/analytics.md).
|
|
3907
4057
|
|
|
3908
4058
|
WAITS FOR THE PLAYER. The id arrives with the first play token, so a call
|
|
3909
4059
|
during boot waits for it, and rejects as [Gem.awaitIdentity](#gem-awaitidentity) does
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The server surface — API reference
|
|
2
2
|
|
|
3
|
-
Generated from `@indiegems/gem-web-sdk/sdk` v23.
|
|
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.
|
|
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
|
|
package/docs/api/reference.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schema_version": 2,
|
|
3
3
|
"source": {
|
|
4
4
|
"repo": "IndieGems/gem-web-sdk",
|
|
5
|
-
"version": "23.
|
|
5
|
+
"version": "23.3.0"
|
|
6
6
|
},
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -397,7 +397,7 @@
|
|
|
397
397
|
"group": "config",
|
|
398
398
|
"signature": "rewarded_placements?: SnapshotRewardedPlacement[]",
|
|
399
399
|
"documented": true,
|
|
400
|
-
"summary": "Your rewarded placements — what pressing a rewarded button grants. An\narray, one row per placement, each naming itself in `placement`, with its\n`grants`, the caps the platform enforces on it (`max_per_day`,\n`cooldown_seconds`, `max_held`) and what happens where no ad serves\n(`without_ads`, which is `nothing` when the config leaves it out).\n\nRead it to LABEL your button — \"+1 Revive\" — never to decide a reward. A\ngrant is an `item_grant`, with a `quantity` of the item its\n`item_definition_id` names, or a `currency_grant`, with an `amount` of the\ncurrency its `currency_id` names; the word on the button is that\ndefinition's `display_name`, from [GameConfig.item](api-reference-game.md#gameconfig-item) or\n[GameConfig.currency](api-reference-game.md#gameconfig-currency):\n\n```js\nconst row = config?.rewarded_placements?.find((p) => p.placement === 'classic_revive');\nconst grant = row?.grants[0];\nconst label =\n grant?.type === 'item_grant'\n ? `+${grant.quantity} ${config.item(grant.item_definition_id)?.display_name ?? ''}`\n : grant?.type === 'currency_grant'\n ? `+${grant.amount} ${config.currency(grant.currency_id)?.display_name ?? ''}`\n : undefined;\n```\n\nWhether an ask grants anything is the platform's decision, made against\nthis config server-side; the grant lands on your game's inventory, and\nre-reading `gem.me.inventory` is the only way to learn that it did. Whether\nthe button could pay right now is [AdsApi.rewardedStatus](api-reference-game.md#adsapi-rewardedstatus).\n\nAbsent when your game declares none.",
|
|
400
|
+
"summary": "Your rewarded placements — what pressing a rewarded button grants. An\narray, one row per placement, each naming itself in `placement`, with its\n`grants`, the caps the platform enforces on it (`max_per_day`,\n`cooldown_seconds`, `max_held`) and what happens where no ad serves\n(`without_ads`, which is `nothing` when the config leaves it out).\n\nRead it to LABEL your button — \"+1 Revive\" — never to decide a reward. A\ngrant is an `item_grant`, with a `quantity` of the item its\n`item_definition_id` names, or a `currency_grant`, with an `amount` of the\ncurrency its `currency_id` names; the word on the button is that\ndefinition's `display_name`, from [GameConfig.item](api-reference-game.md#gameconfig-item) or\n[GameConfig.currency](api-reference-game.md#gameconfig-currency):\n\n```js\nconst row = config?.rewarded_placements?.find((p) => p.placement === 'classic_revive');\nconst grant = row?.grants[0];\nconst label =\n grant?.type === 'item_grant'\n ? `+${grant.quantity} ${config.item(grant.item_definition_id)?.display_name ?? ''}`\n : grant?.type === 'currency_grant'\n ? `+${grant.amount} ${config.currency(grant.currency_id)?.display_name ?? ''}`\n : undefined;\n```\n\nWhether an ask grants anything is the platform's decision, made against\nthis config server-side; the grant lands on your game's inventory, and\nre-reading `gem.me.inventory` is the only way to learn that it did. Whether\nthe button could pay right now is [AdsApi.rewardedStatus](api-reference-game.md#adsapi-rewardedstatus).\n\nA row may also carry `platform_prices`, the Coin and Gem prices that unlock\nit beside the ad, and `ad: false` when only a price does (`ad` is absent\notherwise, which means the ad unlocks it). Both are what you declared, not\nwhat is offered now: label the button from `rewardedStatus`'s\n`adGrantable` and `options`, which say what this platform serves.\n\nAbsent when your game declares none.",
|
|
401
401
|
"deprecated": null,
|
|
402
402
|
"params": [],
|
|
403
403
|
"returns": null,
|
|
@@ -3929,7 +3929,7 @@
|
|
|
3929
3929
|
"group": "account",
|
|
3930
3930
|
"signature": "type SignInOutcomeKind = \"signed_in\" | \"declined\" | \"unavailable\"",
|
|
3931
3931
|
"documented": true,
|
|
3932
|
-
"summary": "The complete vocabulary of answers. Three values, and there will not be a\nfourth.\n\n- `signed_in` — the player is signed in, and [Gem.identity](api-reference-game.md#gem-identity),\n [Gem.player](api-reference-game.md#gem-player) and [Gem.me](api-reference-game.md#gem-me) already answer for their account.\n Re-read anything you loaded before asking. Also the answer for a player who\n was signed in all along.\n- `declined` — the player closed the prompt, or the arcade chose not to show\n one. Return to the game silently.\n- `unavailable` — the arcade could not offer sign-in, or never answered.\n\nNo reason is given for a `declined`, and one will never be added: why a\nsign-in did not happen is a fact about the player's account, and the arcade\nis the one that explains those.",
|
|
3932
|
+
"summary": "The complete vocabulary of answers. Three values, and there will not be a\nfourth.\n\n- `signed_in` — the player is signed in, and [Gem.identity](api-reference-game.md#gem-identity),\n [Gem.player](api-reference-game.md#gem-player) and [Gem.me](api-reference-game.md#gem-me) already answer for their account.\n Re-read anything you loaded before asking. Also the answer for a player who\n was signed in all along.\n- `declined` — the player closed the prompt, or the arcade chose not to show\n one. Return to the game silently.\n- `unavailable` — the arcade could not offer sign-in, or never answered.\n [AccountApi.signInAvailable](api-reference-game.md#accountapi-signinavailable) says so before you draw the button.\n\nNo reason is given for a `declined`, and one will never be added: why a\nsign-in did not happen is a fact about the player's account, and the arcade\nis the one that explains those.",
|
|
3933
3933
|
"deprecated": null,
|
|
3934
3934
|
"params": [],
|
|
3935
3935
|
"returns": null,
|
|
@@ -3986,6 +3986,50 @@
|
|
|
3986
3986
|
"defaultValue": null,
|
|
3987
3987
|
"guides": []
|
|
3988
3988
|
},
|
|
3989
|
+
{
|
|
3990
|
+
"id": "AccountApi.signInAvailable",
|
|
3991
|
+
"name": "signInAvailable",
|
|
3992
|
+
"anchor": "accountapi-signinavailable",
|
|
3993
|
+
"group": "account",
|
|
3994
|
+
"signature": "readonly signInAvailable: boolean",
|
|
3995
|
+
"documented": true,
|
|
3996
|
+
"summary": "Whether [AccountApi.requestSignIn](api-reference-game.md#accountapi-requestsignin) can show this player a sign-in\nhere. Read it before you draw a \"Sign in to claim\" button, and hide the\noffer when it is `false`.\n\n- `true` — a guest the arcade can offer sign-up to. An ask may still\n answer `declined` at a busy moment.\n- `false` — an ask would show nothing. The player is already signed in\n (it answers `signed_in` at once; every player in a current Gem Arcade\n app build, v3.33.174 and later, is), or there is no Arcade sign-in here\n (it answers `unavailable`). Also `false` until the player is known.\n\nOn an arcade older than this signal it reads `true` for every player, a\nfull account included, as before it existed. So gate a sign-up gift on it\nand on the guest test you use today; see docs/player-sign-in.md.\n[AccountApi.onSignInAvailableChange](api-reference-game.md#accountapi-onsigninavailablechange) tells you when it changes.",
|
|
3997
|
+
"deprecated": null,
|
|
3998
|
+
"params": [],
|
|
3999
|
+
"returns": null,
|
|
4000
|
+
"throws": null,
|
|
4001
|
+
"example": "```ts\nconst draw = (available: boolean) => {\n signInButton.hidden = !available;\n};\ndraw(gem.account.signInAvailable);\ngem.account.onSignInAvailableChange(draw);\n```",
|
|
4002
|
+
"defaultValue": null,
|
|
4003
|
+
"guides": [
|
|
4004
|
+
{
|
|
4005
|
+
"slug": "player-sign-in",
|
|
4006
|
+
"anchor": null
|
|
4007
|
+
}
|
|
4008
|
+
]
|
|
4009
|
+
},
|
|
4010
|
+
{
|
|
4011
|
+
"id": "AccountApi.onSignInAvailableChange",
|
|
4012
|
+
"name": "onSignInAvailableChange",
|
|
4013
|
+
"anchor": "accountapi-onsigninavailablechange",
|
|
4014
|
+
"group": "account",
|
|
4015
|
+
"signature": "onSignInAvailableChange(listener: (available: boolean) => void): () => void",
|
|
4016
|
+
"documented": true,
|
|
4017
|
+
"summary": "Runs `listener` whenever [AccountApi.signInAvailable](api-reference-game.md#accountapi-signinavailable) changes: when\nthe player arrives, when the arcade changes its answer (a guest who signs\nup), and when the connection closes. Not on a re-sent player with the same\nanswer.",
|
|
4018
|
+
"deprecated": null,
|
|
4019
|
+
"params": [
|
|
4020
|
+
{
|
|
4021
|
+
"name": "listener",
|
|
4022
|
+
"type": "(available: boolean) => void",
|
|
4023
|
+
"optional": false,
|
|
4024
|
+
"summary": null
|
|
4025
|
+
}
|
|
4026
|
+
],
|
|
4027
|
+
"returns": "A function that stops the listener.",
|
|
4028
|
+
"throws": null,
|
|
4029
|
+
"example": null,
|
|
4030
|
+
"defaultValue": null,
|
|
4031
|
+
"guides": []
|
|
4032
|
+
},
|
|
3989
4033
|
{
|
|
3990
4034
|
"id": "AccountApi.requestSignIn",
|
|
3991
4035
|
"name": "requestSignIn",
|
|
@@ -4170,7 +4214,7 @@
|
|
|
4170
4214
|
"group": "ads",
|
|
4171
4215
|
"signature": "rewardedStatus(placement: string): Promise<RewardedStatus>",
|
|
4172
4216
|
"documented": true,
|
|
4173
|
-
"summary": "Whether a rewarded placement could pay right now, so you can decide whether\nto draw its button. **It never says whether an ad will play.**\n\nThe answer comes from your own `rewarded_placements` config — its daily\ncap, cooldown and `max_held` — applied to this player's use of it, as the\nplatform holds them. Nothing in it describes the player. `grantable: true`\nmeans the platform would grant if an ad is watched or, where no ad serves,\nunder the placement's `without_ads: grant`; a player can still press the\nbutton and get `no_ad`, for reasons your game is not told.\n\nNOTHING REJECTS, like everything else on `gem.ads`. Without a play token,\nwhen the read fails or takes longer than ten seconds, or for a `placement`\noutside the grammar [AdRequest.placement](api-reference-game.md#adrequest-placement) documents, it resolves not\ndeclared and not grantable, with no `resetsAt`, and the reason goes to your\n`onError` handler.\n\nIt is a read of the platform, so call it when you draw the button — on a\nresults or death screen — not every frame. Calls for one placement that\noverlap share one request. Draw the rest of the screen first rather than\nholding it on this answer.\n\n⚠️ It grants nothing and reserves nothing. The reward is granted by the\nplatform when the player asks with `requestAd`; re-read `gem.me.inventory`\nafter that ask settles, whatever it settled as.",
|
|
4217
|
+
"summary": "Whether a rewarded placement could pay right now, so you can decide whether\nto draw its button. **It never says whether an ad will play.**\n\nThe answer comes from your own `rewarded_placements` config — its daily\ncap, cooldown and `max_held` — applied to this player's use of it, as the\nplatform holds them. Nothing in it describes the player. `grantable: true`\nmeans the platform would grant if an ad is watched or, where no ad serves,\nunder the placement's `without_ads: grant`; a player can still press the\nbutton and get `no_ad`, for reasons your game is not told.\n\nA placement your config also prices in Coins or Gems (`platform_prices`)\ncarries those prices in `options`, where the platform lets players pay for\none, and `adGrantable` says whether the ad itself could pay. Label your\nbutton from both: name the ad only when `adGrantable` is `true`, and each\nprice in `options`. The Arcade then shows the player those choices when\nthey press, and the press answers and is re-read exactly as an ad's is.\n\nNOTHING REJECTS, like everything else on `gem.ads`. Without a play token,\nwhen the read fails or takes longer than ten seconds, or for a `placement`\noutside the grammar [AdRequest.placement](api-reference-game.md#adrequest-placement) documents, it resolves not\ndeclared and not grantable, with no `resetsAt`, and the reason goes to your\n`onError` handler.\n\nIt is a read of the platform, so call it when you draw the button — on a\nresults or death screen — not every frame. Calls for one placement that\noverlap share one request. Draw the rest of the screen first rather than\nholding it on this answer.\n\n⚠️ It grants nothing and reserves nothing. The reward is granted by the\nplatform when the player asks with `requestAd`; re-read `gem.me.inventory`\nafter that ask settles, whatever it settled as.",
|
|
4174
4218
|
"deprecated": null,
|
|
4175
4219
|
"params": [
|
|
4176
4220
|
{
|
|
@@ -4191,6 +4235,70 @@
|
|
|
4191
4235
|
}
|
|
4192
4236
|
]
|
|
4193
4237
|
},
|
|
4238
|
+
{
|
|
4239
|
+
"id": "RewardedOption",
|
|
4240
|
+
"name": "RewardedOption",
|
|
4241
|
+
"anchor": "rewardedoption",
|
|
4242
|
+
"group": "ads",
|
|
4243
|
+
"signature": "interface RewardedOption",
|
|
4244
|
+
"documented": true,
|
|
4245
|
+
"summary": "One price that also unlocks a rewarded placement, in\n[RewardedStatus.options](api-reference-game.md#rewardedstatus-options): what your config's `platform_prices` set for\nit, as the platform serves it. Label your button from it (\"5 Gems\").\n\nIt says nothing about the player: not their balance, and not whether they\ncan afford it. The Arcade shows them that when they press.",
|
|
4246
|
+
"deprecated": null,
|
|
4247
|
+
"params": [],
|
|
4248
|
+
"returns": null,
|
|
4249
|
+
"throws": null,
|
|
4250
|
+
"example": null,
|
|
4251
|
+
"defaultValue": null,
|
|
4252
|
+
"guides": []
|
|
4253
|
+
},
|
|
4254
|
+
{
|
|
4255
|
+
"id": "RewardedOption.kind",
|
|
4256
|
+
"name": "kind",
|
|
4257
|
+
"anchor": "rewardedoption-kind",
|
|
4258
|
+
"group": "ads",
|
|
4259
|
+
"signature": "readonly kind: \"coins\" | \"gems\"",
|
|
4260
|
+
"documented": true,
|
|
4261
|
+
"summary": "Which platform currency: `coins` (Coins, `ARCADE_TICKETS`) or `gems`\n(Gems, `GEMS`).",
|
|
4262
|
+
"deprecated": null,
|
|
4263
|
+
"params": [],
|
|
4264
|
+
"returns": null,
|
|
4265
|
+
"throws": null,
|
|
4266
|
+
"example": null,
|
|
4267
|
+
"defaultValue": null,
|
|
4268
|
+
"guides": []
|
|
4269
|
+
},
|
|
4270
|
+
{
|
|
4271
|
+
"id": "RewardedOption.currencyId",
|
|
4272
|
+
"name": "currencyId",
|
|
4273
|
+
"anchor": "rewardedoption-currencyid",
|
|
4274
|
+
"group": "ads",
|
|
4275
|
+
"signature": "readonly currencyId: string",
|
|
4276
|
+
"documented": true,
|
|
4277
|
+
"summary": "The platform currency's id, as your config's `platform_prices` resolved it.",
|
|
4278
|
+
"deprecated": null,
|
|
4279
|
+
"params": [],
|
|
4280
|
+
"returns": null,
|
|
4281
|
+
"throws": null,
|
|
4282
|
+
"example": null,
|
|
4283
|
+
"defaultValue": null,
|
|
4284
|
+
"guides": []
|
|
4285
|
+
},
|
|
4286
|
+
{
|
|
4287
|
+
"id": "RewardedOption.price",
|
|
4288
|
+
"name": "price",
|
|
4289
|
+
"anchor": "rewardedoption-price",
|
|
4290
|
+
"group": "ads",
|
|
4291
|
+
"signature": "readonly price: number",
|
|
4292
|
+
"documented": true,
|
|
4293
|
+
"summary": "The price, a positive whole number of the currency.",
|
|
4294
|
+
"deprecated": null,
|
|
4295
|
+
"params": [],
|
|
4296
|
+
"returns": null,
|
|
4297
|
+
"throws": null,
|
|
4298
|
+
"example": null,
|
|
4299
|
+
"defaultValue": null,
|
|
4300
|
+
"guides": []
|
|
4301
|
+
},
|
|
4194
4302
|
{
|
|
4195
4303
|
"id": "RewardedStatus",
|
|
4196
4304
|
"name": "RewardedStatus",
|
|
@@ -4230,7 +4338,39 @@
|
|
|
4230
4338
|
"group": "ads",
|
|
4231
4339
|
"signature": "readonly grantable: boolean",
|
|
4232
4340
|
"documented": true,
|
|
4233
|
-
"summary": "Whether pressing your button could pay right now: the platform would grant\nthe reward if an ad is watched or, where no ad serves, under the\nplacement's `without_ads: grant
|
|
4341
|
+
"summary": "Whether pressing your button could pay right now: the platform would grant\nthe reward if an ad is watched or, where no ad serves, under the\nplacement's `without_ads: grant` — or, where [RewardedStatus.options](api-reference-game.md#rewardedstatus-options)\nis present, if the player pays one of its prices.\n\n**Not a promise that an ad will play, and not a promise of a reward.** For\nthe ad, it is `false` whenever a cap is spent, a cooldown is running, the\nplayer holds `max_held`, rewarded is off on this channel, or the arcade\nrunning your game does not take ad requests at all. The cap, the cooldown\nand `max_held` limit the ad only: a placement with `options` stays\ngrantable through them, because the player can still pay. It never says\nwhether the player can afford a price.",
|
|
4342
|
+
"deprecated": null,
|
|
4343
|
+
"params": [],
|
|
4344
|
+
"returns": null,
|
|
4345
|
+
"throws": null,
|
|
4346
|
+
"example": null,
|
|
4347
|
+
"defaultValue": null,
|
|
4348
|
+
"guides": []
|
|
4349
|
+
},
|
|
4350
|
+
{
|
|
4351
|
+
"id": "RewardedStatus.adGrantable",
|
|
4352
|
+
"name": "adGrantable",
|
|
4353
|
+
"anchor": "rewardedstatus-adgrantable",
|
|
4354
|
+
"group": "ads",
|
|
4355
|
+
"signature": "readonly adGrantable: boolean",
|
|
4356
|
+
"documented": true,
|
|
4357
|
+
"summary": "Whether the AD could pay right now: [RewardedStatus.grantable](api-reference-game.md#rewardedstatus-grantable) for\nthe ad alone, leaving out the prices. Name the ad on your button only when\nthis is `true`.\n\nThe same as `grantable` for a placement with no `options`. `false` for a\nplacement whose config switches the ad off (`ad: false`) where the\nplatform lets players pay for it, and on every answer where `grantable` is.",
|
|
4358
|
+
"deprecated": null,
|
|
4359
|
+
"params": [],
|
|
4360
|
+
"returns": null,
|
|
4361
|
+
"throws": null,
|
|
4362
|
+
"example": null,
|
|
4363
|
+
"defaultValue": null,
|
|
4364
|
+
"guides": []
|
|
4365
|
+
},
|
|
4366
|
+
{
|
|
4367
|
+
"id": "RewardedStatus.options",
|
|
4368
|
+
"name": "options",
|
|
4369
|
+
"anchor": "rewardedstatus-options",
|
|
4370
|
+
"group": "ads",
|
|
4371
|
+
"signature": "readonly options?: readonly RewardedOption[]",
|
|
4372
|
+
"documented": true,
|
|
4373
|
+
"summary": "The Coin and Gem prices that also unlock the placement, from your config's\n`platform_prices`, at most one per currency.\n\nABSENT — no key — for a placement with no prices, on any answer where\n`declared` is `false`, and wherever the platform does not yet let players\npay for a placement: there your prices are not offered and the placement\nunlocks by its ad alone. Nothing here says what the player holds.",
|
|
4234
4374
|
"deprecated": null,
|
|
4235
4375
|
"params": [],
|
|
4236
4376
|
"returns": null,
|
|
@@ -4639,7 +4779,7 @@
|
|
|
4639
4779
|
"group": "analytics",
|
|
4640
4780
|
"signature": "experiment(key: string, count: number): Promise<number>",
|
|
4641
4781
|
"documented": true,
|
|
4642
|
-
"summary": "Which arm of one of your experiments this player gets — the same answer on\nevery call, every refresh and every device. Use it wherever you would have\npicked an arm with `Math.random()`, which deals a player a new arm on each\nvisit and makes the test unreadable.\n\nPass a COUNT and get an index, `0` to `count - 1`; pass a LIST of strings\nand get one of them. A string listed twice is twice as likely.\n\n```js\nconst tutorial = await gem.analytics.experiment('tutorial_length', ['short', 'long']);\nconst layout = await gem.analytics.experiment('shop_layout', 3); // 0, 1 or 2\n```\n\nThe selection is a hash of the key and the signed-in player's id — FNV-1a\n32-bit over `\"<key>:<playerId>\"`, then MurmurHash3's 32-bit finalizer, mod\nthe arm count; see\n[experimentSelection](api-reference-game.md#experimentselection), which computes the same answer for an id you\nhold. Hashing the key in is what keeps your experiments independent: the\nplayers in one experiment's first arm are not the same players in every\nother experiment's first arm.\n\n⚠️ **Keep the key and the arms fixed for the life of the experiment.** A new\ncount or list re-deals every player. To start over on purpose, use a new\nkey.\n\n⚠️ **NOTHING IS RECORDED FOR YOU.** The selection is not sent anywhere, and\nthe SDK does not add it to your events. To analyse an experiment, declare a\ndimension for it on the events you want to break down, with the arms as its\nvalues, named after the experiment, and pass the selection there yourself:\n`gem.analytics.track('tutorial_finished', { tutorial_length: tutorial })`.\nNever the platform's `variant` field, which belongs to store-page\nexperiments.\n\nWAITS FOR THE PLAYER. The id arrives with the first play token, so a call\nduring boot waits for it, and rejects as [Gem.awaitIdentity](api-reference-game.md#gem-awaitidentity) does\nwhen none arrives — outside the Arcade, the Gem Editor or the dev host.\nThere is no random fallback: catch the rejection and play your control arm.\nA guest is selected by their guest id, which is stable for as long as their\nguest account lasts; once they sign in to an account they are that\naccount's player, and its selection applies.\n\nIn a serverless function it selects for the player who invoked it, with\nno wait, and rejects when a game server invoked it.\n\nWorks with analytics turned off: it reads no setting and sends nothing.",
|
|
4782
|
+
"summary": "Which arm of one of your experiments this player gets — the same answer on\nevery call, every refresh and every device. Use it wherever you would have\npicked an arm with `Math.random()`, which deals a player a new arm on each\nvisit and makes the test unreadable.\n\nPass a COUNT and get an index, `0` to `count - 1`; pass a LIST of strings\nand get one of them. A string listed twice is twice as likely.\n\n```js\nconst tutorial = await gem.analytics.experiment('tutorial_length', ['short', 'long']);\nconst layout = await gem.analytics.experiment('shop_layout', 3); // 0, 1 or 2\n```\n\nThe selection is a hash of the key and the signed-in player's id — FNV-1a\n32-bit over `\"<key>:<playerId>\"`, then MurmurHash3's 32-bit finalizer, mod\nthe arm count; see\n[experimentSelection](api-reference-game.md#experimentselection), which computes the same answer for an id you\nhold. Hashing the key in is what keeps your experiments independent: the\nplayers in one experiment's first arm are not the same players in every\nother experiment's first arm.\n\n⚠️ **Keep the key and the arms fixed for the life of the experiment.** A new\ncount or list re-deals every player. To start over on purpose, use a new\nkey.\n\n⚠️ **NOTHING IS RECORDED FOR YOU.** The selection is not sent anywhere, and\nthe SDK does not add it to your events. To analyse an experiment, declare a\ndimension for it on the events you want to break down, with the arms as its\nvalues, named after the experiment, and pass the selection there yourself:\n`gem.analytics.track('tutorial_finished', { tutorial_length: tutorial })`.\nNever the platform's `variant` field, which belongs to store-page\nexperiments. For the platform's results to show the test, also declare it\nunder `analytics_tests` in your game config (see docs/analytics.md).\n\nWAITS FOR THE PLAYER. The id arrives with the first play token, so a call\nduring boot waits for it, and rejects as [Gem.awaitIdentity](api-reference-game.md#gem-awaitidentity) does\nwhen none arrives — outside the Arcade, the Gem Editor or the dev host.\nThere is no random fallback: catch the rejection and play your control arm.\nA guest is selected by their guest id, which is stable for as long as their\nguest account lasts; once they sign in to an account they are that\naccount's player, and its selection applies.\n\nIn a serverless function it selects for the player who invoked it, with\nno wait, and rejects when a game server invoked it.\n\nWorks with analytics turned off: it reads no setting and sends nothing.",
|
|
4643
4783
|
"deprecated": null,
|
|
4644
4784
|
"params": [
|
|
4645
4785
|
{
|
|
@@ -30922,7 +31062,7 @@
|
|
|
30922
31062
|
"group": "analytics",
|
|
30923
31063
|
"signature": "experiment(key: string, count: number): Promise<number>",
|
|
30924
31064
|
"documented": true,
|
|
30925
|
-
"summary": "Which arm of one of your experiments this player gets — the same answer on\nevery call, every refresh and every device. Use it wherever you would have\npicked an arm with `Math.random()`, which deals a player a new arm on each\nvisit and makes the test unreadable.\n\nPass a COUNT and get an index, `0` to `count - 1`; pass a LIST of strings\nand get one of them. A string listed twice is twice as likely.\n\n```js\nconst tutorial = await gem.analytics.experiment('tutorial_length', ['short', 'long']);\nconst layout = await gem.analytics.experiment('shop_layout', 3); // 0, 1 or 2\n```\n\nThe selection is a hash of the key and the signed-in player's id — FNV-1a\n32-bit over `\"<key>:<playerId>\"`, then MurmurHash3's 32-bit finalizer, mod\nthe arm count; see\n`experimentSelection`, which computes the same answer for an id you\nhold. Hashing the key in is what keeps your experiments independent: the\nplayers in one experiment's first arm are not the same players in every\nother experiment's first arm.\n\n⚠️ **Keep the key and the arms fixed for the life of the experiment.** A new\ncount or list re-deals every player. To start over on purpose, use a new\nkey.\n\n⚠️ **NOTHING IS RECORDED FOR YOU.** The selection is not sent anywhere, and\nthe SDK does not add it to your events. To analyse an experiment, declare a\ndimension for it on the events you want to break down, with the arms as its\nvalues, named after the experiment, and pass the selection there yourself:\n`gem.analytics.track('tutorial_finished', { tutorial_length: tutorial })`.\nNever the platform's `variant` field, which belongs to store-page\nexperiments.\n\nWAITS FOR THE PLAYER. The id arrives with the first play token, so a call\nduring boot waits for it, and rejects as `Gem.awaitIdentity` does\nwhen none arrives — outside the Arcade, the Gem Editor or the dev host.\nThere is no random fallback: catch the rejection and play your control arm.\nA guest is selected by their guest id, which is stable for as long as their\nguest account lasts; once they sign in to an account they are that\naccount's player, and its selection applies.\n\nIn a serverless function it selects for the player who invoked it, with\nno wait, and rejects when a game server invoked it.\n\nWorks with analytics turned off: it reads no setting and sends nothing.",
|
|
31065
|
+
"summary": "Which arm of one of your experiments this player gets — the same answer on\nevery call, every refresh and every device. Use it wherever you would have\npicked an arm with `Math.random()`, which deals a player a new arm on each\nvisit and makes the test unreadable.\n\nPass a COUNT and get an index, `0` to `count - 1`; pass a LIST of strings\nand get one of them. A string listed twice is twice as likely.\n\n```js\nconst tutorial = await gem.analytics.experiment('tutorial_length', ['short', 'long']);\nconst layout = await gem.analytics.experiment('shop_layout', 3); // 0, 1 or 2\n```\n\nThe selection is a hash of the key and the signed-in player's id — FNV-1a\n32-bit over `\"<key>:<playerId>\"`, then MurmurHash3's 32-bit finalizer, mod\nthe arm count; see\n`experimentSelection`, which computes the same answer for an id you\nhold. Hashing the key in is what keeps your experiments independent: the\nplayers in one experiment's first arm are not the same players in every\nother experiment's first arm.\n\n⚠️ **Keep the key and the arms fixed for the life of the experiment.** A new\ncount or list re-deals every player. To start over on purpose, use a new\nkey.\n\n⚠️ **NOTHING IS RECORDED FOR YOU.** The selection is not sent anywhere, and\nthe SDK does not add it to your events. To analyse an experiment, declare a\ndimension for it on the events you want to break down, with the arms as its\nvalues, named after the experiment, and pass the selection there yourself:\n`gem.analytics.track('tutorial_finished', { tutorial_length: tutorial })`.\nNever the platform's `variant` field, which belongs to store-page\nexperiments. For the platform's results to show the test, also declare it\nunder `analytics_tests` in your game config (see docs/analytics.md).\n\nWAITS FOR THE PLAYER. The id arrives with the first play token, so a call\nduring boot waits for it, and rejects as `Gem.awaitIdentity` does\nwhen none arrives — outside the Arcade, the Gem Editor or the dev host.\nThere is no random fallback: catch the rejection and play your control arm.\nA guest is selected by their guest id, which is stable for as long as their\nguest account lasts; once they sign in to an account they are that\naccount's player, and its selection applies.\n\nIn a serverless function it selects for the player who invoked it, with\nno wait, and rejects when a game server invoked it.\n\nWorks with analytics turned off: it reads no setting and sends nothing.",
|
|
30926
31066
|
"deprecated": null,
|
|
30927
31067
|
"params": [
|
|
30928
31068
|
{
|
package/docs/arcade-and-store.md
CHANGED
|
@@ -223,7 +223,8 @@ policy refused. Allow that host rather than a wildcard.
|
|
|
223
223
|
|
|
224
224
|
```js
|
|
225
225
|
const { outcome, reason, offers } = await gem.store.offers();
|
|
226
|
-
if (outcome === 'unavailable' && reason === 'sign_in_required'
|
|
226
|
+
if (outcome === 'unavailable' && reason === 'sign_in_required' && gem.account.signInAvailable)
|
|
227
|
+
showSignInButton(); // gem.account.requestSignIn
|
|
227
228
|
for (const offer of offers) drawOffer(offer);
|
|
228
229
|
```
|
|
229
230
|
|
|
@@ -443,7 +444,8 @@ player, and the route refuses it with `403`. The body is `{ pass, held, ends_at
|
|
|
443
444
|
or the lounge, and either way nobody got in by editing the page. Redraw the door when the function
|
|
444
445
|
says no.
|
|
445
446
|
- **A guest has no VIP and cannot buy it from here.** Their door is shut, and `offers()` answers
|
|
446
|
-
`unavailable` / `sign_in_required`, so offer `gem.account.requestSignIn` instead of the button
|
|
447
|
+
`unavailable` / `sign_in_required`, so offer `gem.account.requestSignIn` instead of the button,
|
|
448
|
+
when `gem.account.signInAvailable` says the Arcade can show them a sign-in.
|
|
447
449
|
|
|
448
450
|
### When the door moves by itself
|
|
449
451
|
|
package/docs/changelog.md
CHANGED
|
@@ -16,6 +16,36 @@ Its entries are grouped under up to five headings:
|
|
|
16
16
|
- **Rebuild**: a type changed. Recompile against the new version; code that compiles today keeps compiling unless the entry says otherwise.
|
|
17
17
|
- **New capability**: something a game can now do. Nothing changes unless you use it.
|
|
18
18
|
|
|
19
|
+
## 23.3.0
|
|
20
|
+
|
|
21
|
+
*Written from the API facts alone; no summary was generated for this release.*
|
|
22
|
+
|
|
23
|
+
Upgrading from 23.2.0. Impact: required.
|
|
24
|
+
|
|
25
|
+
### Must change
|
|
26
|
+
|
|
27
|
+
- FrameCallbacks.onPlayer changed its signature.
|
|
28
|
+
- FrameOptions.onPlayer changed its signature.
|
|
29
|
+
|
|
30
|
+
### New capability
|
|
31
|
+
|
|
32
|
+
- AccountApi.onSignInAvailableChange was added.
|
|
33
|
+
- AccountApi.signInAvailable was added.
|
|
34
|
+
- GemPlayer.signInAvailable was added.
|
|
35
|
+
- SendPlayerInput.signInAvailable was added.
|
|
36
|
+
|
|
37
|
+
## 23.2.0
|
|
38
|
+
|
|
39
|
+
*Written from the API facts alone; no summary was generated for this release.*
|
|
40
|
+
|
|
41
|
+
Upgrading from 23.1.3. Impact: none.
|
|
42
|
+
|
|
43
|
+
### New capability
|
|
44
|
+
|
|
45
|
+
- RewardedOption was added.
|
|
46
|
+
- RewardedStatus.adGrantable was added.
|
|
47
|
+
- RewardedStatus.options was added.
|
|
48
|
+
|
|
19
49
|
## 23.1.3
|
|
20
50
|
|
|
21
51
|
Upgrading from 23.1.2. Impact: none.
|
package/docs/getting-started.md
CHANGED
package/docs/manifest.json
CHANGED
|
@@ -13,13 +13,13 @@
|
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
"file": "analytics.md",
|
|
16
|
-
"sha256": "
|
|
17
|
-
"updated": "2026-11-
|
|
16
|
+
"sha256": "3f81025a763f96d0ca17f57377042a3e3890797983265cdb1721902b700aa3a6",
|
|
17
|
+
"updated": "2026-11-09T18:54:26Z"
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
"file": "arcade-and-store.md",
|
|
21
|
-
"sha256": "
|
|
22
|
-
"updated": "2026-11-
|
|
21
|
+
"sha256": "5b880e515ce0d65ffff77b97c93844dbcc14d7ab55d89edabaa54f4858376216",
|
|
22
|
+
"updated": "2026-11-09T16:45:36Z"
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
25
|
"file": "arcade-avatars.md",
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
50
|
"file": "changelog.md",
|
|
51
|
-
"sha256": "
|
|
52
|
-
"updated": "2026-11-
|
|
51
|
+
"sha256": "85e888011b15aa2e9ebb56d938b9a8165489167bcebda236cba9e4f09937044f",
|
|
52
|
+
"updated": "2026-11-10T15:57:23Z"
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
"file": "daily-challenges.md",
|
|
@@ -78,8 +78,8 @@
|
|
|
78
78
|
},
|
|
79
79
|
{
|
|
80
80
|
"file": "getting-started.md",
|
|
81
|
-
"sha256": "
|
|
82
|
-
"updated": "2026-11-
|
|
81
|
+
"sha256": "bdadeee9b46529d4ef9543a2be61cd096e6b200c20dbe2ab1b361d23139d3e64",
|
|
82
|
+
"updated": "2026-11-10T15:57:23Z"
|
|
83
83
|
},
|
|
84
84
|
{
|
|
85
85
|
"file": "graphics-route.md",
|
|
@@ -118,13 +118,13 @@
|
|
|
118
118
|
},
|
|
119
119
|
{
|
|
120
120
|
"file": "player-sign-in.md",
|
|
121
|
-
"sha256": "
|
|
122
|
-
"updated": "2026-11-
|
|
121
|
+
"sha256": "f5066f2382bac9336c697d3646843f546295686a959726e877431ec7dc2daea3",
|
|
122
|
+
"updated": "2026-11-09T18:39:56Z"
|
|
123
123
|
},
|
|
124
124
|
{
|
|
125
125
|
"file": "rewarded-ads.md",
|
|
126
|
-
"sha256": "
|
|
127
|
-
"updated": "2026-11-
|
|
126
|
+
"sha256": "36394d5faee67f3907139b1fe8c8210a6074a6eac593bc070b567625e71c6129",
|
|
127
|
+
"updated": "2026-11-09T19:34:44Z"
|
|
128
128
|
},
|
|
129
129
|
{
|
|
130
130
|
"file": "room-shapes.md",
|
|
@@ -143,8 +143,8 @@
|
|
|
143
143
|
},
|
|
144
144
|
{
|
|
145
145
|
"file": "server-bundles.md",
|
|
146
|
-
"sha256": "
|
|
147
|
-
"updated": "2026-11-
|
|
146
|
+
"sha256": "921591332e0a9fc52d36e3372af26a5ea808768e1bbd49826d765b7e4615ab53",
|
|
147
|
+
"updated": "2026-11-10T15:57:23Z"
|
|
148
148
|
},
|
|
149
149
|
{
|
|
150
150
|
"file": "serverless-functions-js.md",
|
|
@@ -168,8 +168,8 @@
|
|
|
168
168
|
},
|
|
169
169
|
{
|
|
170
170
|
"file": "what-a-game-must-do.md",
|
|
171
|
-
"sha256": "
|
|
172
|
-
"updated": "2026-11-
|
|
171
|
+
"sha256": "c5400f43a1218de0d2838d4332dce4c05afe21ff04e352d2e201ef5bb4268bed",
|
|
172
|
+
"updated": "2026-11-09T18:39:56Z"
|
|
173
173
|
}
|
|
174
174
|
]
|
|
175
175
|
}
|