@indiegems/gem-web-sdk 8.0.0 → 9.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.
- package/CHANGELOG.md +23 -0
- package/README.md +1 -0
- package/dist/function.d.ts +1 -1
- package/dist/game.d.ts +14 -2
- package/dist/gem-web-sdk.bridge.js +1 -1
- package/dist/gem-web-sdk.esm.js +2 -2
- package/dist/gem-web-sdk.function.js +2 -2
- package/dist/gem-web-sdk.game.js +2 -2
- package/dist/gem-web-sdk.min.js +2 -2
- package/dist/gem-web-sdk.sdk.js +2 -2
- package/dist/gem-web-sdk.server.js +2 -2
- package/dist/index.d.ts +12 -3
- package/dist/sdk.d.ts +14 -2
- package/dist/server.d.ts +1 -1
- package/docs/achievements.md +72 -5
- package/docs/api/api-reference-game.md +329 -39
- package/docs/api/api-reference-server.md +6 -2
- package/docs/api/reference.json +241 -21
- package/docs/changelog.md +23 -0
- package/docs/cross-promotion.md +87 -31
- package/docs/getting-started.md +3 -2
- package/docs/manifest.json +25 -20
- package/docs/match-session.md +1 -1
- package/docs/rewarded-ads.md +464 -0
- package/docs/room-shapes.md +54 -76
- package/docs/rooms-and-matches.md +2 -3
- package/docs/server-bundles.md +2 -2
- package/docs/serverless-functions.md +42 -32
- package/docs/what-a-game-must-do.md +132 -5
- package/package.json +1 -1
- package/schema/bridge.v1.json +72 -7
- package/schema/capabilities.public.json +6 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The browser surface — API reference
|
|
2
2
|
|
|
3
|
-
Generated from `@indiegems/gem-web-sdk/sdk`
|
|
3
|
+
Generated from `@indiegems/gem-web-sdk/sdk` v9.0.0. Every symbol below links to its page on the Gem Arcade developer site.
|
|
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
|
|
|
@@ -247,6 +247,47 @@ check that a funnel you declared names events you are actually sending.
|
|
|
247
247
|
|
|
248
248
|
Absent when your game declares none.
|
|
249
249
|
|
|
250
|
+
## GameConfig.rewarded_placements
|
|
251
|
+
|
|
252
|
+
[GameConfig.rewarded_placements](https://gemarcade.com/developer/api/game#gameconfig-rewarded_placements)
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
rewarded_placements?: SnapshotRewardedPlacement[]
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Your rewarded placements — what pressing a rewarded button grants. An
|
|
259
|
+
array, one row per placement, each naming itself in `placement`, with its
|
|
260
|
+
`grants`, the caps the platform enforces on it (`max_per_day`,
|
|
261
|
+
`cooldown_seconds`, `max_held`) and what happens where no ad serves
|
|
262
|
+
(`without_ads`).
|
|
263
|
+
|
|
264
|
+
Read it to LABEL your button — "+1 Revive" — never to decide a reward. A
|
|
265
|
+
grant is an `item_grant`, with a `quantity` of the item its
|
|
266
|
+
`item_definition_id` names, or a `currency_grant`, with an `amount` of the
|
|
267
|
+
currency its `currency_id` names; the word on the button is that
|
|
268
|
+
definition's `display_name`, from [GameConfig.item](https://gemarcade.com/developer/api/game#gameconfig-item) or
|
|
269
|
+
[GameConfig.currency](https://gemarcade.com/developer/api/game#gameconfig-currency):
|
|
270
|
+
|
|
271
|
+
```js
|
|
272
|
+
const row = config?.rewarded_placements?.find((p) => p.placement === 'classic_revive');
|
|
273
|
+
const grant = row?.grants[0];
|
|
274
|
+
const label =
|
|
275
|
+
grant?.type === 'item_grant'
|
|
276
|
+
? `+${grant.quantity} ${config.item(grant.item_definition_id)?.display_name ?? ''}`
|
|
277
|
+
: grant?.type === 'currency_grant'
|
|
278
|
+
? `+${grant.amount} ${config.currency(grant.currency_id)?.display_name ?? ''}`
|
|
279
|
+
: undefined;
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Whether an ask grants anything is the platform's decision, made against
|
|
283
|
+
this config server-side; the grant lands on your game's inventory, and
|
|
284
|
+
re-reading `gem.me.inventory` is the only way to learn that it did. Whether
|
|
285
|
+
the button could pay right now is [AdsApi.rewardedStatus](https://gemarcade.com/developer/api/game#adsapi-rewardedstatus).
|
|
286
|
+
|
|
287
|
+
Absent when your game declares none.
|
|
288
|
+
|
|
289
|
+
**Guides.** [cross-promotion](https://gemarcade.com/developer/docs/cross-promotion)
|
|
290
|
+
|
|
250
291
|
## GameConfig.version
|
|
251
292
|
|
|
252
293
|
[GameConfig.version](https://gemarcade.com/developer/api/game#gameconfig-version)
|
|
@@ -2862,14 +2903,16 @@ Which kind of break this is.
|
|
|
2862
2903
|
|
|
2863
2904
|
`interstitial` is a panel the player dismisses and nothing follows from.
|
|
2864
2905
|
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
against its own record, never
|
|
2870
|
-
your game's inventory for this player, written by the platform,
|
|
2871
|
-
`gem.me.inventory` after a `rewarded` ask settles rather than
|
|
2872
|
-
signal on this pair; there will not be one.
|
|
2906
|
+
`rewarded` is a button the player pressed for a reward — a revive, an extra
|
|
2907
|
+
attempt — that your game config declares for the placement in
|
|
2908
|
+
`rewarded_placements`. It is served where this arcade serves it, and answered
|
|
2909
|
+
`no_ad` where it does not. ⚠️ The outcome grants nothing: the platform grants
|
|
2910
|
+
the reward, against its own record, never your game reading `shown`. It
|
|
2911
|
+
arrives on your game's inventory for this player, written by the platform,
|
|
2912
|
+
so re-read `gem.me.inventory` after a `rewarded` ask settles rather than
|
|
2913
|
+
waiting for a signal on this pair; there will not be one.
|
|
2914
|
+
|
|
2915
|
+
**Guides.** [rewarded-ads](https://gemarcade.com/developer/docs/rewarded-ads)
|
|
2873
2916
|
|
|
2874
2917
|
## AdRequest
|
|
2875
2918
|
|
|
@@ -2893,14 +2936,17 @@ Your own name for the break — `level-complete`, `between-rounds`.
|
|
|
2893
2936
|
|
|
2894
2937
|
**1 to 32 characters of `a-z`, `0-9`, `-` and `_`.** Lowercase, no spaces,
|
|
2895
2938
|
no accents: `'Boss Fight'` is not a placement, `'boss-fight'` is. The
|
|
2896
|
-
grammar is the platform's own, and
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2939
|
+
grammar is the platform's own, and the SDK enforces it so a name that does
|
|
2940
|
+
not fit is refused at your keyboard rather than in the field. A placement
|
|
2941
|
+
outside it is answered `no_ad` and reported to your `onError` handler.
|
|
2942
|
+
|
|
2943
|
+
For `rewarded`, it names the reward your game config declares in
|
|
2944
|
+
`rewarded_placements`: the platform matches it against that config, and a
|
|
2945
|
+
placement the config does not declare is answered `no_ad`. For
|
|
2946
|
+
`interstitial`, the platform matches it against nothing; there it is for
|
|
2947
|
+
your own telemetry, so two break points in your game can be told apart.
|
|
2948
|
+
Either way it is never shown to a player and **never sent to an ad
|
|
2949
|
+
network**.
|
|
2904
2950
|
|
|
2905
2951
|
## AdRequest.format
|
|
2906
2952
|
|
|
@@ -2926,7 +2972,8 @@ fourth.
|
|
|
2926
2972
|
- `shown` — a panel was painted and has now closed. Resume. **It grants
|
|
2927
2973
|
nothing.**
|
|
2928
2974
|
- `no_ad` — nothing was painted. Carry on exactly as if you had not asked.
|
|
2929
|
-
This is the common answer.
|
|
2975
|
+
This is the common answer. After a `rewarded` ask the reward may still
|
|
2976
|
+
have landed, with no ad, so re-read your inventory either way.
|
|
2930
2977
|
- `unavailable` — the arcade could not render just now. Not a softer no; read
|
|
2931
2978
|
it exactly as you read `no_ad`.
|
|
2932
2979
|
|
|
@@ -2934,6 +2981,11 @@ No reason is given for a `no_ad`, and one will never be added: a reason would
|
|
|
2934
2981
|
tell your game something about the player — an age, a consent state, a
|
|
2935
2982
|
subscription — that game code is deliberately not told.
|
|
2936
2983
|
|
|
2984
|
+
The one thing you can learn is about **your own economy**, and not from this
|
|
2985
|
+
answer: [AdsApi.rewardedStatus](https://gemarcade.com/developer/api/game#adsapi-rewardedstatus) reports your own declared rewarded caps
|
|
2986
|
+
as the platform holds them (a platform-wide per-placement maximum, where one
|
|
2987
|
+
is set, can lower a cap). It never reports anything about the player.
|
|
2988
|
+
|
|
2937
2989
|
## AdOutcome
|
|
2938
2990
|
|
|
2939
2991
|
[AdOutcome](https://gemarcade.com/developer/api/game#adoutcome)
|
|
@@ -2989,7 +3041,9 @@ The arcade pauses your game while a panel is up and resumes it when this
|
|
|
2989
3041
|
settles, so you do not need to pause anything yourself.
|
|
2990
3042
|
|
|
2991
3043
|
⚠️ `shown` grants nothing. Never hand out a reward, an unlock or a currency
|
|
2992
|
-
on the strength of it.
|
|
3044
|
+
on the strength of it. A `rewarded` placement's reward is granted by the
|
|
3045
|
+
platform into your game's inventory; re-read `gem.me.inventory` once this
|
|
3046
|
+
settles, whatever it settled as.
|
|
2993
3047
|
|
|
2994
3048
|
| Parameter | Type | Description |
|
|
2995
3049
|
| --- | --- | --- |
|
|
@@ -3007,8 +3061,160 @@ const { outcome } = await gem.ads.requestAd({
|
|
|
3007
3061
|
startNextLevel();
|
|
3008
3062
|
```
|
|
3009
3063
|
|
|
3064
|
+
## AdsApi.rewardedStatus
|
|
3065
|
+
|
|
3066
|
+
[AdsApi.rewardedStatus](https://gemarcade.com/developer/api/game#adsapi-rewardedstatus)
|
|
3067
|
+
|
|
3068
|
+
```ts
|
|
3069
|
+
rewardedStatus(placement: string): Promise<RewardedStatus>
|
|
3070
|
+
```
|
|
3071
|
+
|
|
3072
|
+
Whether a rewarded placement could pay right now, so you can decide whether
|
|
3073
|
+
to draw its button. **It never says whether an ad will play.**
|
|
3074
|
+
|
|
3075
|
+
The answer comes from your own `rewarded_placements` config — its daily
|
|
3076
|
+
cap, cooldown and `max_held` — applied to this player's use of it, as the
|
|
3077
|
+
platform holds them. Nothing in it describes the player. `grantable: true`
|
|
3078
|
+
means the platform would grant if an ad is watched or, where no ad serves,
|
|
3079
|
+
under the placement's `without_ads: grant`; a player can still press the
|
|
3080
|
+
button and get `no_ad`, for reasons your game is not told.
|
|
3081
|
+
|
|
3082
|
+
NOTHING REJECTS, like everything else on `gem.ads`. Without a play token,
|
|
3083
|
+
when the read fails or takes longer than ten seconds, or for a `placement`
|
|
3084
|
+
outside the grammar [AdRequest.placement](https://gemarcade.com/developer/api/game#adrequest-placement) documents, it resolves not
|
|
3085
|
+
declared and not grantable, with no `resetsAt`, and the reason goes to your
|
|
3086
|
+
`onError` handler.
|
|
3087
|
+
|
|
3088
|
+
It is a read of the platform, so call it when you draw the button — on a
|
|
3089
|
+
results or death screen — not every frame. Calls for one placement that
|
|
3090
|
+
overlap share one request. Draw the rest of the screen first rather than
|
|
3091
|
+
holding it on this answer.
|
|
3092
|
+
|
|
3093
|
+
⚠️ It grants nothing and reserves nothing. The reward is granted by the
|
|
3094
|
+
platform when the player asks with `requestAd`; re-read `gem.me.inventory`
|
|
3095
|
+
after that ask settles, whatever it settled as.
|
|
3096
|
+
|
|
3097
|
+
| Parameter | Type | Description |
|
|
3098
|
+
| --- | --- | --- |
|
|
3099
|
+
| `placement` | `string` | A placement your `rewarded_placements` config declares. |
|
|
3100
|
+
|
|
3101
|
+
**Returns.** The placement's state. Always resolves; never rejects.
|
|
3102
|
+
|
|
3103
|
+
```ts
|
|
3104
|
+
const status = await gem.ads.rewardedStatus('classic_revive');
|
|
3105
|
+
reviveButton.disabled = !status.grantable;
|
|
3106
|
+
if (status.nextEligibleAt !== undefined) {
|
|
3107
|
+
reviveButton.title = `Back at ${new Date(status.nextEligibleAt).toLocaleTimeString()}`;
|
|
3108
|
+
}
|
|
3109
|
+
```
|
|
3110
|
+
|
|
3010
3111
|
**Guides.** [cross-promotion](https://gemarcade.com/developer/docs/cross-promotion)
|
|
3011
3112
|
|
|
3113
|
+
## RewardedStatus
|
|
3114
|
+
|
|
3115
|
+
[RewardedStatus](https://gemarcade.com/developer/api/game#rewardedstatus)
|
|
3116
|
+
|
|
3117
|
+
```ts
|
|
3118
|
+
interface RewardedStatus
|
|
3119
|
+
```
|
|
3120
|
+
|
|
3121
|
+
What [AdsApi.rewardedStatus](https://gemarcade.com/developer/api/game#adsapi-rewardedstatus) answers: the state of one rewarded
|
|
3122
|
+
placement for this player, from your own declared caps.
|
|
3123
|
+
|
|
3124
|
+
Every figure comes from **your** `rewarded_placements` config — `max_per_day`,
|
|
3125
|
+
`cooldown_seconds`, `max_held` — applied to this player's use of it, as the
|
|
3126
|
+
platform holds them. The platform can hold a placement's daily cap below what
|
|
3127
|
+
you declared, never above it. Nothing here describes the player.
|
|
3128
|
+
|
|
3129
|
+
⚠️ **It never says whether an ad will play.** Whether one does depends on
|
|
3130
|
+
things your game is deliberately not told. A player can see your button,
|
|
3131
|
+
press it, and get `no_ad`: read that `no_ad` like any other, and never guess
|
|
3132
|
+
a reason.
|
|
3133
|
+
|
|
3134
|
+
## RewardedStatus.declared
|
|
3135
|
+
|
|
3136
|
+
[RewardedStatus.declared](https://gemarcade.com/developer/api/game#rewardedstatus-declared)
|
|
3137
|
+
|
|
3138
|
+
```ts
|
|
3139
|
+
readonly declared: boolean
|
|
3140
|
+
```
|
|
3141
|
+
|
|
3142
|
+
Whether this channel's published config declares the placement.
|
|
3143
|
+
|
|
3144
|
+
`false` for a placement your config does not name, a config that is not
|
|
3145
|
+
promoted to the channel being played, and every answer the platform did not
|
|
3146
|
+
give (see [RewardedStatus.resetsAt](https://gemarcade.com/developer/api/game#rewardedstatus-resetsat)).
|
|
3147
|
+
|
|
3148
|
+
## RewardedStatus.grantable
|
|
3149
|
+
|
|
3150
|
+
[RewardedStatus.grantable](https://gemarcade.com/developer/api/game#rewardedstatus-grantable)
|
|
3151
|
+
|
|
3152
|
+
```ts
|
|
3153
|
+
readonly grantable: boolean
|
|
3154
|
+
```
|
|
3155
|
+
|
|
3156
|
+
Whether pressing your button could pay right now: the platform would grant
|
|
3157
|
+
the reward if an ad is watched or, where no ad serves, under the
|
|
3158
|
+
placement's `without_ads: grant`.
|
|
3159
|
+
|
|
3160
|
+
**Not a promise that an ad will play, and not a promise of a reward.** It
|
|
3161
|
+
is `false` whenever a cap is spent, a cooldown is running, the player holds
|
|
3162
|
+
`max_held`, rewarded is off on this channel, or the arcade running your
|
|
3163
|
+
game does not take ad requests at all.
|
|
3164
|
+
|
|
3165
|
+
## RewardedStatus.remainingToday
|
|
3166
|
+
|
|
3167
|
+
[RewardedStatus.remainingToday](https://gemarcade.com/developer/api/game#rewardedstatus-remainingtoday)
|
|
3168
|
+
|
|
3169
|
+
```ts
|
|
3170
|
+
readonly remainingToday?: number
|
|
3171
|
+
```
|
|
3172
|
+
|
|
3173
|
+
Grants left today under the placement's daily cap, a non-negative integer.
|
|
3174
|
+
|
|
3175
|
+
ABSENT — no key, never a sentinel — when the placement has no daily cap,
|
|
3176
|
+
and on any answer where `declared` is `false`.
|
|
3177
|
+
|
|
3178
|
+
## RewardedStatus.nextEligibleAt
|
|
3179
|
+
|
|
3180
|
+
[RewardedStatus.nextEligibleAt](https://gemarcade.com/developer/api/game#rewardedstatus-nexteligibleat)
|
|
3181
|
+
|
|
3182
|
+
```ts
|
|
3183
|
+
readonly nextEligibleAt?: number
|
|
3184
|
+
```
|
|
3185
|
+
|
|
3186
|
+
When the placement's cooldown ends, in epoch milliseconds — render it with
|
|
3187
|
+
`new Date(nextEligibleAt)`.
|
|
3188
|
+
|
|
3189
|
+
ABSENT when no cooldown is running.
|
|
3190
|
+
|
|
3191
|
+
## RewardedStatus.heldLimitReached
|
|
3192
|
+
|
|
3193
|
+
[RewardedStatus.heldLimitReached](https://gemarcade.com/developer/api/game#rewardedstatus-heldlimitreached)
|
|
3194
|
+
|
|
3195
|
+
```ts
|
|
3196
|
+
readonly heldLimitReached: boolean
|
|
3197
|
+
```
|
|
3198
|
+
|
|
3199
|
+
Whether the player already holds the placement's `max_held` of the item it
|
|
3200
|
+
grants. Spend one first.
|
|
3201
|
+
|
|
3202
|
+
## RewardedStatus.resetsAt
|
|
3203
|
+
|
|
3204
|
+
[RewardedStatus.resetsAt](https://gemarcade.com/developer/api/game#rewardedstatus-resetsat)
|
|
3205
|
+
|
|
3206
|
+
```ts
|
|
3207
|
+
readonly resetsAt?: number
|
|
3208
|
+
```
|
|
3209
|
+
|
|
3210
|
+
When the daily count resets — the next 00:00 UTC — in epoch milliseconds.
|
|
3211
|
+
Take it from here rather than computing midnight in game code.
|
|
3212
|
+
|
|
3213
|
+
ABSENT when the platform gave no answer: no play token yet, a read that
|
|
3214
|
+
failed or took longer than ten seconds, or a platform that does not serve
|
|
3215
|
+
this read. Then the rest of the status reads not declared and not
|
|
3216
|
+
grantable, and the reason went to your `onError` handler.
|
|
3217
|
+
|
|
3012
3218
|
## AnalyticsValue
|
|
3013
3219
|
|
|
3014
3220
|
[AnalyticsValue](https://gemarcade.com/developer/api/game#analyticsvalue)
|
|
@@ -4863,6 +5069,29 @@ sends only while connected, and only to an arcade that draws a wallet.
|
|
|
4863
5069
|
**Returns.** whether it entered the send path — `false` before the bridge is
|
|
4864
5070
|
up, and `false` for an arcade with no wallet to move.
|
|
4865
5071
|
|
|
5072
|
+
## GemFrame.showPortraitBorders
|
|
5073
|
+
|
|
5074
|
+
[GemFrame.showPortraitBorders](https://gemarcade.com/developer/api/game#gemframe-showportraitborders)
|
|
5075
|
+
|
|
5076
|
+
```ts
|
|
5077
|
+
showPortraitBorders(name: string | null): boolean
|
|
5078
|
+
```
|
|
5079
|
+
|
|
5080
|
+
Tell the arcade which of your store page's portrait borders to paint beside
|
|
5081
|
+
your game, or `null` for none.
|
|
5082
|
+
|
|
5083
|
+
Prefer `gem.showPortraitBorders`, which holds your choice until the bridge
|
|
5084
|
+
is up and paces a burst of changes for you. This one sends every call it
|
|
5085
|
+
accepts, only while connected, and only to an arcade that paints borders.
|
|
5086
|
+
|
|
5087
|
+
| Parameter | Type |
|
|
5088
|
+
| --- | --- |
|
|
5089
|
+
| `name` | `string \| null` |
|
|
5090
|
+
|
|
5091
|
+
**Returns.** whether the message left the frame — `false` for a string that is
|
|
5092
|
+
not a border name (with a console warning), before the bridge is up, for
|
|
5093
|
+
an arcade that paints no borders, and past this frame's own limit.
|
|
5094
|
+
|
|
4866
5095
|
## GemFrame.setWalletVisible
|
|
4867
5096
|
|
|
4868
5097
|
[GemFrame.setWalletVisible](https://gemarcade.com/developer/api/game#gemframe-setwalletvisible)
|
|
@@ -5091,8 +5320,9 @@ draw your own placeholder rather than a broken image. Pass it through
|
|
|
5091
5320
|
readonly badges: readonly PlayerBadge[]
|
|
5092
5321
|
```
|
|
5093
5322
|
|
|
5094
|
-
The player's equipped badges,
|
|
5095
|
-
|
|
5323
|
+
The player's equipped badges, at most two, in the order the player
|
|
5324
|
+
arranged them. Always a list — empty when they wear none, or when their
|
|
5325
|
+
identity is withheld — so draw what is there and key on `itemId`.
|
|
5096
5326
|
|
|
5097
5327
|
## FriendsPage
|
|
5098
5328
|
|
|
@@ -5930,7 +6160,7 @@ The answer parsed as JSON.
|
|
|
5930
6160
|
[FunctionFailure](https://gemarcade.com/developer/api/game#functionfailure)
|
|
5931
6161
|
|
|
5932
6162
|
```ts
|
|
5933
|
-
type FunctionFailure = "trap" | "memory_exceeded" | "cpu_budget_exceeded" | "host_call_limit"
|
|
6163
|
+
type FunctionFailure = "trap" | "memory_exceeded" | "cpu_budget_exceeded" | "host_call_limit" | "output_too_large" | "argument_too_large"
|
|
5934
6164
|
```
|
|
5935
6165
|
|
|
5936
6166
|
Why a call that reached your function did not finish — carried on
|
|
@@ -5941,6 +6171,10 @@ Why a call that reached your function did not finish — carried on
|
|
|
5941
6171
|
- `memory_exceeded` — past the memory limit.
|
|
5942
6172
|
- `cpu_budget_exceeded` — past the CPU budget.
|
|
5943
6173
|
- `host_call_limit` — more platform API calls than one invocation may make.
|
|
6174
|
+
- `output_too_large` — your function's result was over the 1 MiB output cap.
|
|
6175
|
+
- `argument_too_large` — a value your function handed to a platform call
|
|
6176
|
+
(`log`, `call-api`, `download-link` or `upload-link`) was over the 16 MiB
|
|
6177
|
+
per-call limit.
|
|
5944
6178
|
|
|
5945
6179
|
## GemFunctionError
|
|
5946
6180
|
|
|
@@ -6158,8 +6392,9 @@ const { accepted, why } = result.json();
|
|
|
6158
6392
|
ARCADE_EMBEDDERS: readonly string[]
|
|
6159
6393
|
```
|
|
6160
6394
|
|
|
6161
|
-
The origins the
|
|
6162
|
-
without naming them: the website,
|
|
6395
|
+
The origins the platform embeds a game from, which every game accepts
|
|
6396
|
+
without naming them: the Gem Arcade website, the Meme Games website, and
|
|
6397
|
+
the Gem Arcade app.
|
|
6163
6398
|
|
|
6164
6399
|
You do not pass these. They are always allowed, and
|
|
6165
6400
|
[GemOptions.allowedEmbedders](https://gemarcade.com/developer/api/game#gemoptions-allowedembedders) adds to them rather than replacing them.
|
|
@@ -6188,7 +6423,7 @@ readonly allowedEmbedders?: readonly string[]
|
|
|
6188
6423
|
Extra origins allowed to embed your game, **added to** the ones the Gem
|
|
6189
6424
|
Arcade uses. Most games leave this out.
|
|
6190
6425
|
|
|
6191
|
-
The
|
|
6426
|
+
The platform's websites and the Gem Arcade app are always allowed — see
|
|
6192
6427
|
[ARCADE_EMBEDDERS](https://gemarcade.com/developer/api/game#arcade_embedders) — so do not list them. Set this only when a site
|
|
6193
6428
|
of your own embeds your game.
|
|
6194
6429
|
|
|
@@ -6883,8 +7118,9 @@ draw your own placeholder rather than a broken image. Pass it through
|
|
|
6883
7118
|
readonly badges: readonly PlayerBadge[]
|
|
6884
7119
|
```
|
|
6885
7120
|
|
|
6886
|
-
The player's equipped badges,
|
|
6887
|
-
|
|
7121
|
+
The player's equipped badges, at most two, in the order the player
|
|
7122
|
+
arranged them. Always a list — empty when they wear none, or when their
|
|
7123
|
+
identity is withheld — so draw what is there and key on `itemId`.
|
|
6888
7124
|
|
|
6889
7125
|
## GemPrefs
|
|
6890
7126
|
|
|
@@ -7664,7 +7900,10 @@ resumes it when the promise settles, so you do not pause anything yourself.
|
|
|
7664
7900
|
⚠️ `shown` **grants nothing.** It is not a receipt and not an entitlement,
|
|
7665
7901
|
and a reward must never be handed out on the strength of it.
|
|
7666
7902
|
|
|
7667
|
-
You are told no reason for a no, and there is nothing to infer from one
|
|
7903
|
+
You are told no reason for a no, and there is nothing to infer from one
|
|
7904
|
+
about the player. What you can read is your own economy:
|
|
7905
|
+
`rewardedStatus(placement)` says whether a rewarded placement could pay
|
|
7906
|
+
right now under your own declared caps — never whether an ad will play.
|
|
7668
7907
|
|
|
7669
7908
|
**Guides.** [cross-promotion](https://gemarcade.com/developer/docs/cross-promotion)
|
|
7670
7909
|
|
|
@@ -8059,6 +8298,51 @@ arcade just said is not sent.
|
|
|
8059
8298
|
| --- | --- |
|
|
8060
8299
|
| `muted` | `boolean` |
|
|
8061
8300
|
|
|
8301
|
+
## Gem.showPortraitBorders
|
|
8302
|
+
|
|
8303
|
+
[Gem.showPortraitBorders](https://gemarcade.com/developer/api/game#gem-showportraitborders)
|
|
8304
|
+
|
|
8305
|
+
```ts
|
|
8306
|
+
showPortraitBorders(name: string | null): void
|
|
8307
|
+
```
|
|
8308
|
+
|
|
8309
|
+
Choose which of your store page's **portrait borders** the arcade paints on
|
|
8310
|
+
either side of your game, or `null` for none.
|
|
8311
|
+
|
|
8312
|
+
On a desktop browser, the arcade's desktop app or a television, the arcade
|
|
8313
|
+
shows a portrait-only game as a centred portrait column. With borders
|
|
8314
|
+
declared on your store page (`media.portrait_borders`), it paints one of
|
|
8315
|
+
those images beside the column instead of its own bars. Call this at
|
|
8316
|
+
start-up and on every theme change, with the border that goes with what is
|
|
8317
|
+
on screen:
|
|
8318
|
+
|
|
8319
|
+
```js
|
|
8320
|
+
const BORDERS = new Set(['meadow', 'alpine']); // the names your store page declares
|
|
8321
|
+
|
|
8322
|
+
function applyTheme(id) {
|
|
8323
|
+
document.body.dataset.theme = id;
|
|
8324
|
+
gem.showPortraitBorders(BORDERS.has(id) ? id : null); // null: a theme with no art
|
|
8325
|
+
}
|
|
8326
|
+
```
|
|
8327
|
+
|
|
8328
|
+
Until your first call the arcade shows the page's first border. Whether
|
|
8329
|
+
your game is letterboxed at all is decided by your store page's
|
|
8330
|
+
`orientations`, never by this call, so call it unconditionally: before the
|
|
8331
|
+
connection exists your choice is held and sent when it connects, a burst of
|
|
8332
|
+
changes (a picker previewing on hover) reaches the arcade as its final
|
|
8333
|
+
value, and an arcade that paints no borders is simply not told. The arcade
|
|
8334
|
+
owns the change itself — when and how the image swaps — and sends no
|
|
8335
|
+
acknowledgement.
|
|
8336
|
+
|
|
8337
|
+
A name is 1 to 40 characters of `a-z`, `0-9`, `_` and `-`, starting with a
|
|
8338
|
+
letter or digit — the store page's own rule. Anything else is refused with
|
|
8339
|
+
a console warning and never sent; a valid name your page does not declare
|
|
8340
|
+
is ignored by the arcade, which keeps the image it is showing.
|
|
8341
|
+
|
|
8342
|
+
| Parameter | Type |
|
|
8343
|
+
| --- | --- |
|
|
8344
|
+
| `name` | `string \| null` |
|
|
8345
|
+
|
|
8062
8346
|
## Gem.cueReward
|
|
8063
8347
|
|
|
8064
8348
|
[Gem.cueReward](https://gemarcade.com/developer/api/game#gem-cuereward)
|
|
@@ -9159,7 +9443,8 @@ interface PlayerBadge
|
|
|
9159
9443
|
One badge a player has equipped — an icon the platform shows beside their
|
|
9160
9444
|
name.
|
|
9161
9445
|
|
|
9162
|
-
|
|
9446
|
+
A player wears at most two, in the order they arranged them. Each is an icon
|
|
9447
|
+
they own — an achievement in any game may have awarded it.
|
|
9163
9448
|
|
|
9164
9449
|
## PlayerBadge.itemId
|
|
9165
9450
|
|
|
@@ -9283,8 +9568,9 @@ draw your own placeholder rather than a broken image. Pass it through
|
|
|
9283
9568
|
readonly badges: readonly PlayerBadge[]
|
|
9284
9569
|
```
|
|
9285
9570
|
|
|
9286
|
-
The player's equipped badges,
|
|
9287
|
-
|
|
9571
|
+
The player's equipped badges, at most two, in the order the player
|
|
9572
|
+
arranged them. Always a list — empty when they wear none, or when their
|
|
9573
|
+
identity is withheld — so draw what is there and key on `itemId`.
|
|
9288
9574
|
|
|
9289
9575
|
## mapIdentity
|
|
9290
9576
|
|
|
@@ -11831,8 +12117,9 @@ draw your own placeholder rather than a broken image. Pass it through
|
|
|
11831
12117
|
readonly badges: readonly PlayerBadge[]
|
|
11832
12118
|
```
|
|
11833
12119
|
|
|
11834
|
-
The player's equipped badges,
|
|
11835
|
-
|
|
12120
|
+
The player's equipped badges, at most two, in the order the player
|
|
12121
|
+
arranged them. Always a list — empty when they wear none, or when their
|
|
12122
|
+
identity is withheld — so draw what is there and key on `itemId`.
|
|
11836
12123
|
|
|
11837
12124
|
## LeaderboardEntry.rank
|
|
11838
12125
|
|
|
@@ -13272,8 +13559,9 @@ draw your own placeholder rather than a broken image. Pass it through
|
|
|
13272
13559
|
readonly badges: readonly PlayerBadge[]
|
|
13273
13560
|
```
|
|
13274
13561
|
|
|
13275
|
-
The player's equipped badges,
|
|
13276
|
-
|
|
13562
|
+
The player's equipped badges, at most two, in the order the player
|
|
13563
|
+
arranged them. Always a list — empty when they wear none, or when their
|
|
13564
|
+
identity is withheld — so draw what is there and key on `itemId`.
|
|
13277
13565
|
|
|
13278
13566
|
## PlayerProfile.playerId
|
|
13279
13567
|
|
|
@@ -15306,8 +15594,9 @@ draw your own placeholder rather than a broken image. Pass it through
|
|
|
15306
15594
|
readonly badges: readonly PlayerBadge[]
|
|
15307
15595
|
```
|
|
15308
15596
|
|
|
15309
|
-
The player's equipped badges,
|
|
15310
|
-
|
|
15597
|
+
The player's equipped badges, at most two, in the order the player
|
|
15598
|
+
arranged them. Always a list — empty when they wear none, or when their
|
|
15599
|
+
identity is withheld — so draw what is there and key on `itemId`.
|
|
15311
15600
|
|
|
15312
15601
|
## RoomMember.playerId
|
|
15313
15602
|
|
|
@@ -16070,8 +16359,9 @@ draw your own placeholder rather than a broken image. Pass it through
|
|
|
16070
16359
|
readonly badges: readonly PlayerBadge[]
|
|
16071
16360
|
```
|
|
16072
16361
|
|
|
16073
|
-
The player's equipped badges,
|
|
16074
|
-
|
|
16362
|
+
The player's equipped badges, at most two, in the order the player
|
|
16363
|
+
arranged them. Always a list — empty when they wear none, or when their
|
|
16364
|
+
identity is withheld — so draw what is there and key on `itemId`.
|
|
16075
16365
|
|
|
16076
16366
|
## ShowcaseFriendEntry.playerId
|
|
16077
16367
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The server surface — API reference
|
|
2
2
|
|
|
3
|
-
Generated from `@indiegems/gem-web-sdk/sdk`
|
|
3
|
+
Generated from `@indiegems/gem-web-sdk/sdk` v9.0.0. Every symbol below links to its page on the Gem Arcade developer site.
|
|
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
|
|
|
@@ -1535,7 +1535,7 @@ The answer parsed as JSON.
|
|
|
1535
1535
|
[FunctionFailure](https://gemarcade.com/developer/api/server#functionfailure)
|
|
1536
1536
|
|
|
1537
1537
|
```ts
|
|
1538
|
-
type FunctionFailure = "trap" | "memory_exceeded" | "cpu_budget_exceeded" | "host_call_limit"
|
|
1538
|
+
type FunctionFailure = "trap" | "memory_exceeded" | "cpu_budget_exceeded" | "host_call_limit" | "output_too_large" | "argument_too_large"
|
|
1539
1539
|
```
|
|
1540
1540
|
|
|
1541
1541
|
Why a call that reached your function did not finish — carried on
|
|
@@ -1546,6 +1546,10 @@ Why a call that reached your function did not finish — carried on
|
|
|
1546
1546
|
- `memory_exceeded` — past the memory limit.
|
|
1547
1547
|
- `cpu_budget_exceeded` — past the CPU budget.
|
|
1548
1548
|
- `host_call_limit` — more platform API calls than one invocation may make.
|
|
1549
|
+
- `output_too_large` — your function's result was over the 1 MiB output cap.
|
|
1550
|
+
- `argument_too_large` — a value your function handed to a platform call
|
|
1551
|
+
(`log`, `call-api`, `download-link` or `upload-link`) was over the 16 MiB
|
|
1552
|
+
per-call limit.
|
|
1549
1553
|
|
|
1550
1554
|
## GemFunctionError
|
|
1551
1555
|
|