@indiegems/gem-web-sdk 7.9.1 → 8.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 +30 -0
- package/README.md +1 -0
- package/dist/function.d.ts +26 -1
- package/dist/game.d.ts +32 -1
- 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 +1 -1
- package/dist/index.d.ts +12 -3
- package/dist/sdk.d.ts +32 -1
- package/docs/api/api-reference-game.md +424 -8
- package/docs/api/api-reference-server.md +1 -1
- package/docs/api/reference.json +441 -5
- package/docs/changelog.md +30 -0
- package/docs/friends.md +86 -11
- package/docs/getting-started.md +10 -6
- package/docs/manifest.json +21 -16
- package/docs/saving-player-progress.md +41 -0
- package/docs/server-bundles.md +2 -2
- package/docs/serverless-functions-js.md +3 -2
- package/docs/serverless-functions.md +53 -7
- package/docs/vibration.md +141 -0
- package/docs/what-a-game-must-do.md +12 -0
- package/package.json +1 -1
- package/schema/bridge.v1.json +60 -0
- package/schema/capabilities.public.json +9 -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` v8.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
|
|
|
@@ -4935,6 +4935,30 @@ arcade that handles share.
|
|
|
4935
4935
|
up, for an arcade that does not handle share, and past this frame's own
|
|
4936
4936
|
limit of six a minute.
|
|
4937
4937
|
|
|
4938
|
+
## GemFrame.requestVibrate
|
|
4939
|
+
|
|
4940
|
+
[GemFrame.requestVibrate](https://gemarcade.com/developer/api/game#gemframe-requestvibrate)
|
|
4941
|
+
|
|
4942
|
+
```ts
|
|
4943
|
+
requestVibrate(pattern: readonly number[]): boolean
|
|
4944
|
+
```
|
|
4945
|
+
|
|
4946
|
+
Ask the arcade to play a vibration pattern where this frame has no
|
|
4947
|
+
`navigator.vibrate` of its own. Nothing comes back.
|
|
4948
|
+
|
|
4949
|
+
Prefer `gem.vibration.vibrate`, which calls `navigator.vibrate` itself
|
|
4950
|
+
where it exists, normalizes the pattern and caps its total length. This one
|
|
4951
|
+
checks only the message's bounds, sends only while connected, and only to
|
|
4952
|
+
an arcade that handles vibration.
|
|
4953
|
+
|
|
4954
|
+
| Parameter | Type |
|
|
4955
|
+
| --- | --- |
|
|
4956
|
+
| `pattern` | `readonly number[]` |
|
|
4957
|
+
|
|
4958
|
+
**Returns.** whether the message left the frame — `false` before the bridge is
|
|
4959
|
+
up, for an arcade that does not handle vibration, and past this frame's
|
|
4960
|
+
own limit of 600 a minute.
|
|
4961
|
+
|
|
4938
4962
|
## GemFrame.reportFrameStats
|
|
4939
4963
|
|
|
4940
4964
|
[GemFrame.reportFrameStats](https://gemarcade.com/developer/api/game#gemframe-reportframestats)
|
|
@@ -5121,7 +5145,9 @@ readonly limit?: number
|
|
|
5121
5145
|
```
|
|
5122
5146
|
|
|
5123
5147
|
Friends per page — default 50, at most 200. A player holds at most 1000
|
|
5124
|
-
friends, so five max-size pages is the whole list.
|
|
5148
|
+
friends, so five max-size pages is the whole list. A larger value is
|
|
5149
|
+
clamped to 200; a value that is not a non-negative integer is refused with
|
|
5150
|
+
`invalid`.
|
|
5125
5151
|
|
|
5126
5152
|
## ListFriendsOptions.cursor
|
|
5127
5153
|
|
|
@@ -5144,6 +5170,181 @@ readonly signal?: AbortSignal
|
|
|
5144
5170
|
|
|
5145
5171
|
Abort the read.
|
|
5146
5172
|
|
|
5173
|
+
## FriendChallenge
|
|
5174
|
+
|
|
5175
|
+
[FriendChallenge](https://gemarcade.com/developer/api/game#friendchallenge)
|
|
5176
|
+
|
|
5177
|
+
```ts
|
|
5178
|
+
interface FriendChallenge
|
|
5179
|
+
```
|
|
5180
|
+
|
|
5181
|
+
One friend challenge this player received, in THIS game on THIS channel.
|
|
5182
|
+
|
|
5183
|
+
What the platform holds, not what the card said: there is no rendered line,
|
|
5184
|
+
because your game renders its own copy from [FriendChallenge.template](https://gemarcade.com/developer/api/game#friendchallenge-template)
|
|
5185
|
+
and [FriendChallenge.params](https://gemarcade.com/developer/api/game#friendchallenge-params). Who sent it is
|
|
5186
|
+
[FriendChallenge.from](https://gemarcade.com/developer/api/game#friendchallenge-from), resolved by the platform from its own records.
|
|
5187
|
+
|
|
5188
|
+
## FriendChallenge.id
|
|
5189
|
+
|
|
5190
|
+
[FriendChallenge.id](https://gemarcade.com/developer/api/game#friendchallenge-id)
|
|
5191
|
+
|
|
5192
|
+
```ts
|
|
5193
|
+
readonly id: string
|
|
5194
|
+
```
|
|
5195
|
+
|
|
5196
|
+
The challenge's id — the value the Arcade puts in the `gemChallenge`
|
|
5197
|
+
launch key, and what [FriendsApi.markAnswered](https://gemarcade.com/developer/api/game#friendsapi-markanswered) takes. Opaque: compare
|
|
5198
|
+
it, store it, never parse it.
|
|
5199
|
+
|
|
5200
|
+
## FriendChallenge.from
|
|
5201
|
+
|
|
5202
|
+
[FriendChallenge.from](https://gemarcade.com/developer/api/game#friendchallenge-from)
|
|
5203
|
+
|
|
5204
|
+
```ts
|
|
5205
|
+
readonly from: Friend
|
|
5206
|
+
```
|
|
5207
|
+
|
|
5208
|
+
Who sent it, with the same display identity a [Friend](https://gemarcade.com/developer/api/game#friend) row carries.
|
|
5209
|
+
|
|
5210
|
+
The ONLY name to show. Never read a name out of
|
|
5211
|
+
[FriendChallenge.params](https://gemarcade.com/developer/api/game#friendchallenge-params): a name in a param is one nobody checked.
|
|
5212
|
+
|
|
5213
|
+
## FriendChallenge.template
|
|
5214
|
+
|
|
5215
|
+
[FriendChallenge.template](https://gemarcade.com/developer/api/game#friendchallenge-template)
|
|
5216
|
+
|
|
5217
|
+
```ts
|
|
5218
|
+
readonly template: string
|
|
5219
|
+
```
|
|
5220
|
+
|
|
5221
|
+
The `friend_challenge_templates[].key` it was sent with — which of your
|
|
5222
|
+
templates, so your game knows what was asked.
|
|
5223
|
+
|
|
5224
|
+
## FriendChallenge.params
|
|
5225
|
+
|
|
5226
|
+
[FriendChallenge.params](https://gemarcade.com/developer/api/game#friendchallenge-params)
|
|
5227
|
+
|
|
5228
|
+
```ts
|
|
5229
|
+
readonly params: Readonly<Record<string, string | number>>
|
|
5230
|
+
```
|
|
5231
|
+
|
|
5232
|
+
The params exactly as sent: integers as numbers, date, enum and code
|
|
5233
|
+
params as strings. The template constrained them when the challenge was
|
|
5234
|
+
sent, but the config may have changed since, so check each one against
|
|
5235
|
+
what your game expects before it does anything — as you would a launch
|
|
5236
|
+
key.
|
|
5237
|
+
|
|
5238
|
+
## FriendChallenge.createdAt
|
|
5239
|
+
|
|
5240
|
+
[FriendChallenge.createdAt](https://gemarcade.com/developer/api/game#friendchallenge-createdat)
|
|
5241
|
+
|
|
5242
|
+
```ts
|
|
5243
|
+
readonly createdAt: number
|
|
5244
|
+
```
|
|
5245
|
+
|
|
5246
|
+
When it was sent, in Unix seconds.
|
|
5247
|
+
|
|
5248
|
+
## FriendChallenge.openedAt
|
|
5249
|
+
|
|
5250
|
+
[FriendChallenge.openedAt](https://gemarcade.com/developer/api/game#friendchallenge-openedat)
|
|
5251
|
+
|
|
5252
|
+
```ts
|
|
5253
|
+
readonly openedAt?: number
|
|
5254
|
+
```
|
|
5255
|
+
|
|
5256
|
+
When the player pressed Play on it in the Arcade, in Unix seconds. Absent
|
|
5257
|
+
until they have.
|
|
5258
|
+
|
|
5259
|
+
## FriendChallenge.answeredAt
|
|
5260
|
+
|
|
5261
|
+
[FriendChallenge.answeredAt](https://gemarcade.com/developer/api/game#friendchallenge-answeredat)
|
|
5262
|
+
|
|
5263
|
+
```ts
|
|
5264
|
+
readonly answeredAt?: number
|
|
5265
|
+
```
|
|
5266
|
+
|
|
5267
|
+
When a game marked it answered with [FriendsApi.markAnswered](https://gemarcade.com/developer/api/game#friendsapi-markanswered), in
|
|
5268
|
+
Unix seconds. Absent until one has — so present on a relaunch of a
|
|
5269
|
+
challenge already played, which is how a replay is told from a first
|
|
5270
|
+
attempt.
|
|
5271
|
+
|
|
5272
|
+
## FriendChallengesPage
|
|
5273
|
+
|
|
5274
|
+
[FriendChallengesPage](https://gemarcade.com/developer/api/game#friendchallengespage)
|
|
5275
|
+
|
|
5276
|
+
```ts
|
|
5277
|
+
interface FriendChallengesPage
|
|
5278
|
+
```
|
|
5279
|
+
|
|
5280
|
+
One page of the friend challenges this player holds in this game.
|
|
5281
|
+
|
|
5282
|
+
## FriendChallengesPage.challenges
|
|
5283
|
+
|
|
5284
|
+
[FriendChallengesPage.challenges](https://gemarcade.com/developer/api/game#friendchallengespage-challenges)
|
|
5285
|
+
|
|
5286
|
+
```ts
|
|
5287
|
+
readonly challenges: readonly FriendChallenge[]
|
|
5288
|
+
```
|
|
5289
|
+
|
|
5290
|
+
The page's challenges, newest first, answered ones last.
|
|
5291
|
+
|
|
5292
|
+
## FriendChallengesPage.nextCursor
|
|
5293
|
+
|
|
5294
|
+
[FriendChallengesPage.nextCursor](https://gemarcade.com/developer/api/game#friendchallengespage-nextcursor)
|
|
5295
|
+
|
|
5296
|
+
```ts
|
|
5297
|
+
readonly nextCursor?: string
|
|
5298
|
+
```
|
|
5299
|
+
|
|
5300
|
+
Present exactly when another page exists — pass it back as
|
|
5301
|
+
[ListFriendChallengesOptions.cursor](https://gemarcade.com/developer/api/game#listfriendchallengesoptions-cursor) to continue. Opaque: mint
|
|
5302
|
+
nothing, store nothing, compare nothing.
|
|
5303
|
+
|
|
5304
|
+
## ListFriendChallengesOptions
|
|
5305
|
+
|
|
5306
|
+
[ListFriendChallengesOptions](https://gemarcade.com/developer/api/game#listfriendchallengesoptions)
|
|
5307
|
+
|
|
5308
|
+
```ts
|
|
5309
|
+
interface ListFriendChallengesOptions
|
|
5310
|
+
```
|
|
5311
|
+
|
|
5312
|
+
What [FriendsApi.inbox](https://gemarcade.com/developer/api/game#friendsapi-inbox) takes.
|
|
5313
|
+
|
|
5314
|
+
## ListFriendChallengesOptions.limit
|
|
5315
|
+
|
|
5316
|
+
[ListFriendChallengesOptions.limit](https://gemarcade.com/developer/api/game#listfriendchallengesoptions-limit)
|
|
5317
|
+
|
|
5318
|
+
```ts
|
|
5319
|
+
readonly limit?: number
|
|
5320
|
+
```
|
|
5321
|
+
|
|
5322
|
+
Challenges per page — default 50, at most 200. The platform keeps at most
|
|
5323
|
+
200 per player, so one max-size page is the whole inbox. A larger value is
|
|
5324
|
+
clamped to 200; a value that is not a non-negative integer is refused with
|
|
5325
|
+
`invalid`.
|
|
5326
|
+
|
|
5327
|
+
## ListFriendChallengesOptions.cursor
|
|
5328
|
+
|
|
5329
|
+
[ListFriendChallengesOptions.cursor](https://gemarcade.com/developer/api/game#listfriendchallengesoptions-cursor)
|
|
5330
|
+
|
|
5331
|
+
```ts
|
|
5332
|
+
readonly cursor?: string
|
|
5333
|
+
```
|
|
5334
|
+
|
|
5335
|
+
The previous page's [FriendChallengesPage.nextCursor](https://gemarcade.com/developer/api/game#friendchallengespage-nextcursor), verbatim. A
|
|
5336
|
+
cursor the platform did not mint is refused with `invalid`.
|
|
5337
|
+
|
|
5338
|
+
## ListFriendChallengesOptions.signal
|
|
5339
|
+
|
|
5340
|
+
[ListFriendChallengesOptions.signal](https://gemarcade.com/developer/api/game#listfriendchallengesoptions-signal)
|
|
5341
|
+
|
|
5342
|
+
```ts
|
|
5343
|
+
readonly signal?: AbortSignal
|
|
5344
|
+
```
|
|
5345
|
+
|
|
5346
|
+
Abort the read.
|
|
5347
|
+
|
|
5147
5348
|
## FriendChallengeRequest
|
|
5148
5349
|
|
|
5149
5350
|
[FriendChallengeRequest](https://gemarcade.com/developer/api/game#friendchallengerequest)
|
|
@@ -5423,15 +5624,18 @@ channel: the version the template is missing from.
|
|
|
5423
5624
|
class FriendsApi
|
|
5424
5625
|
```
|
|
5425
5626
|
|
|
5426
|
-
Reading the signed-in player's accepted friends,
|
|
5427
|
-
|
|
5627
|
+
Reading the signed-in player's accepted friends, asking the Arcade to send
|
|
5628
|
+
one of them a friend challenge, and reading the friend challenges this
|
|
5629
|
+
player received in this game.
|
|
5428
5630
|
|
|
5429
5631
|
Reached as `gem.friends`. Display identity only, and every accepted friend
|
|
5430
5632
|
appears whether or not they have played this game — an invite-a-friend flow
|
|
5431
5633
|
needs exactly the ones who have not. The graph itself — requests, accepts,
|
|
5432
5634
|
blocks — is managed on the Arcade, not here. So is a friend challenge's
|
|
5433
5635
|
send: [FriendsApi.challenge](https://gemarcade.com/developer/api/game#friendsapi-challenge) asks, and the Arcade confirms with the
|
|
5434
|
-
player and sends.
|
|
5636
|
+
player and sends. The receiving side is [FriendsApi.launchedChallenge](https://gemarcade.com/developer/api/game#friendsapi-launchedchallenge)
|
|
5637
|
+
(the challenge this frame was launched with), [FriendsApi.inbox](https://gemarcade.com/developer/api/game#friendsapi-inbox) and
|
|
5638
|
+
[FriendsApi.markAnswered](https://gemarcade.com/developer/api/game#friendsapi-markanswered).
|
|
5435
5639
|
|
|
5436
5640
|
```js
|
|
5437
5641
|
let page = await gem.friends.list();
|
|
@@ -5460,7 +5664,8 @@ have played this one.
|
|
|
5460
5664
|
| --- | --- |
|
|
5461
5665
|
| `options` | `ListFriendsOptions` |
|
|
5462
5666
|
|
|
5463
|
-
**Throws.** `invalid` when the cursor is not one a previous page minted
|
|
5667
|
+
**Throws.** `invalid` when the cursor is not one a previous page minted or
|
|
5668
|
+
`limit` is not a non-negative integer,
|
|
5464
5669
|
`forbidden` in a context with no player — this is a player surface, and
|
|
5465
5670
|
a game server has no friend list.
|
|
5466
5671
|
|
|
@@ -5520,6 +5725,123 @@ challengeButton.onclick = async () => {
|
|
|
5520
5725
|
};
|
|
5521
5726
|
```
|
|
5522
5727
|
|
|
5728
|
+
## FriendsApi.inbox
|
|
5729
|
+
|
|
5730
|
+
[FriendsApi.inbox](https://gemarcade.com/developer/api/game#friendsapi-inbox)
|
|
5731
|
+
|
|
5732
|
+
```ts
|
|
5733
|
+
inbox(options?: ListFriendChallengesOptions): Promise<FriendChallengesPage>
|
|
5734
|
+
```
|
|
5735
|
+
|
|
5736
|
+
Read one page of the friend challenges this player holds in THIS game on
|
|
5737
|
+
THIS channel — in every state. Answered challenges are INCLUDED, and sort
|
|
5738
|
+
after the rest; within each part, newest first.
|
|
5739
|
+
|
|
5740
|
+
Pass the result's `nextCursor` back as `cursor` until it stops arriving.
|
|
5741
|
+
A guest holds no challenges, so a guest's page is empty rather than a
|
|
5742
|
+
refusal — build the screen for the empty state, not around an error.
|
|
5743
|
+
|
|
5744
|
+
For the one challenge this frame was launched with, use
|
|
5745
|
+
[FriendsApi.launchedChallenge](https://gemarcade.com/developer/api/game#friendsapi-launchedchallenge) rather than searching this list.
|
|
5746
|
+
|
|
5747
|
+
| Parameter | Type |
|
|
5748
|
+
| --- | --- |
|
|
5749
|
+
| `options` | `ListFriendChallengesOptions` |
|
|
5750
|
+
|
|
5751
|
+
**Throws.** `invalid` when the cursor is not one a previous page minted or
|
|
5752
|
+
`limit` is not a non-negative integer,
|
|
5753
|
+
`forbidden` in a context with no player of this game — a game server,
|
|
5754
|
+
or a token that is not a game-scoped player token.
|
|
5755
|
+
|
|
5756
|
+
```ts
|
|
5757
|
+
const page = await gem.friends.inbox();
|
|
5758
|
+
for (const c of page.challenges) {
|
|
5759
|
+
if (c.template !== 'beat_code_jar') continue;
|
|
5760
|
+
renderChallengeRow(c.from, c.params, c.answeredAt !== undefined);
|
|
5761
|
+
}
|
|
5762
|
+
```
|
|
5763
|
+
|
|
5764
|
+
## FriendsApi.launchedChallenge
|
|
5765
|
+
|
|
5766
|
+
[FriendsApi.launchedChallenge](https://gemarcade.com/developer/api/game#friendsapi-launchedchallenge)
|
|
5767
|
+
|
|
5768
|
+
```ts
|
|
5769
|
+
launchedChallenge(options?: { signal?: AbortSignal }): Promise<FriendChallenge | null>
|
|
5770
|
+
```
|
|
5771
|
+
|
|
5772
|
+
The friend challenge this frame was launched with, or `null`.
|
|
5773
|
+
|
|
5774
|
+
When a player opens a friend challenge in the Arcade, the Arcade launches
|
|
5775
|
+
your game with the challenge's params as launch keys plus its own
|
|
5776
|
+
`gemChallenge` key. This reads that key — never parse it yourself — and
|
|
5777
|
+
looks the challenge up, so you get the sender from the platform's records
|
|
5778
|
+
and the params as they were sent.
|
|
5779
|
+
|
|
5780
|
+
The key is read ONCE, when `createGem` runs, so cleaning your URL with
|
|
5781
|
+
`history.replaceState` afterwards changes nothing here.
|
|
5782
|
+
|
|
5783
|
+
RESOLVES `null`, never rejects, for every launch that is not this
|
|
5784
|
+
player's challenge in this game: no `gemChallenge` key, a value that is
|
|
5785
|
+
not a challenge id, a challenge that is not this player's (a link
|
|
5786
|
+
someone shared), one from another game or channel, and every guest
|
|
5787
|
+
launch. Treat `null` as an ordinary launch.
|
|
5788
|
+
|
|
5789
|
+
A RELAUNCH REPLAYS. Pressing Play again in the Arcade relaunches the
|
|
5790
|
+
same challenge, so the same one comes back; it carries
|
|
5791
|
+
[FriendChallenge.answeredAt](https://gemarcade.com/developer/api/game#friendchallenge-answeredat) once a game has called
|
|
5792
|
+
[FriendsApi.markAnswered](https://gemarcade.com/developer/api/game#friendsapi-markanswered), which is how a replay is told from a
|
|
5793
|
+
first attempt. Asks the platform on every call, so `answeredAt` is
|
|
5794
|
+
current.
|
|
5795
|
+
|
|
5796
|
+
| Parameter | Type |
|
|
5797
|
+
| --- | --- |
|
|
5798
|
+
| `options` | `{ signal?: AbortSignal }` |
|
|
5799
|
+
|
|
5800
|
+
**Throws.** What any platform read throws: `forbidden` in a context with no
|
|
5801
|
+
player of this game, `unavailable` and `rate_limited` when the platform
|
|
5802
|
+
cannot answer now — and `not_found` for a 404 that is NOT the platform's
|
|
5803
|
+
uniform challenge answer (no `inbox_item_not_found` code), which is a
|
|
5804
|
+
platform that does not serve this read rather than an ordinary launch.
|
|
5805
|
+
|
|
5806
|
+
```ts
|
|
5807
|
+
const challenge = await gem.friends.launchedChallenge();
|
|
5808
|
+
if (challenge?.template === 'beat_code_jar') {
|
|
5809
|
+
// Check every param before it does anything: the config may have changed since.
|
|
5810
|
+
const jar = challenge.params.jar;
|
|
5811
|
+
if (typeof jar === 'string' && /^[A-Z0-9]{7}$/.test(jar)) {
|
|
5812
|
+
startJar(jar, { from: challenge.from, replay: challenge.answeredAt !== undefined });
|
|
5813
|
+
}
|
|
5814
|
+
}
|
|
5815
|
+
```
|
|
5816
|
+
|
|
5817
|
+
## FriendsApi.markAnswered
|
|
5818
|
+
|
|
5819
|
+
[FriendsApi.markAnswered](https://gemarcade.com/developer/api/game#friendsapi-markanswered)
|
|
5820
|
+
|
|
5821
|
+
```ts
|
|
5822
|
+
markAnswered(id: string): Promise<void>
|
|
5823
|
+
```
|
|
5824
|
+
|
|
5825
|
+
Mark one of this player's friend challenges answered — the player has
|
|
5826
|
+
played it. Call it when your game has finished the attempt the challenge
|
|
5827
|
+
asked for, win or lose.
|
|
5828
|
+
|
|
5829
|
+
Idempotent: a second call changes nothing, and a challenge keeps the
|
|
5830
|
+
first time it was answered. The sender is told nothing — there is no read
|
|
5831
|
+
receipt — so this is your game's own record, which
|
|
5832
|
+
[FriendChallenge.answeredAt](https://gemarcade.com/developer/api/game#friendchallenge-answeredat) reads back.
|
|
5833
|
+
|
|
5834
|
+
| Parameter | Type | Description |
|
|
5835
|
+
| --- | --- | --- |
|
|
5836
|
+
| `id` | `string` | A [FriendChallenge.id](https://gemarcade.com/developer/api/game#friendchallenge-id), from
|
|
5837
|
+
[FriendsApi.launchedChallenge](https://gemarcade.com/developer/api/game#friendsapi-launchedchallenge) or [FriendsApi.inbox](https://gemarcade.com/developer/api/game#friendsapi-inbox). |
|
|
5838
|
+
|
|
5839
|
+
**Throws.** `not_found` when no challenge of this player's in this game and
|
|
5840
|
+
channel has that id — one answer for unknown and someone else's;
|
|
5841
|
+
`invalid` when `id` cannot be a challenge id at all, before anything is
|
|
5842
|
+
sent; `forbidden` in a context with no player of this game;
|
|
5843
|
+
`rate_limited` past the platform's per-player budget.
|
|
5844
|
+
|
|
5523
5845
|
## FunctionInvokeOptions
|
|
5524
5846
|
|
|
5525
5847
|
[FunctionInvokeOptions](https://gemarcade.com/developer/api/game#functioninvokeoptions)
|
|
@@ -7405,6 +7727,40 @@ shareButton.onclick = () => {
|
|
|
7405
7727
|
|
|
7406
7728
|
**Guides.** [getting-started](https://gemarcade.com/developer/docs/getting-started)
|
|
7407
7729
|
|
|
7730
|
+
## Gem.vibration
|
|
7731
|
+
|
|
7732
|
+
[Gem.vibration](https://gemarcade.com/developer/api/game#gem-vibration)
|
|
7733
|
+
|
|
7734
|
+
```ts
|
|
7735
|
+
readonly vibration: VibrationApi
|
|
7736
|
+
```
|
|
7737
|
+
|
|
7738
|
+
Vibrate the player's device — call this instead of `navigator.vibrate`,
|
|
7739
|
+
which does nothing on any iPhone. It takes the same pattern and returns the
|
|
7740
|
+
same boolean, calls `navigator.vibrate` itself where that works, and asks
|
|
7741
|
+
the arcade to vibrate where it does not.
|
|
7742
|
+
|
|
7743
|
+
Read [VibrationApi.available](https://gemarcade.com/developer/api/game#vibrationapi-available) live, after `awaitBridge()`, to decide
|
|
7744
|
+
whether to show your game's vibration toggle — on an iPhone it is `false`
|
|
7745
|
+
until the bridge connects — and check that toggle before every call:
|
|
7746
|
+
|
|
7747
|
+
```js
|
|
7748
|
+
await gem.awaitBridge();
|
|
7749
|
+
vibrationRow.hidden = !gem.vibration.available;
|
|
7750
|
+
|
|
7751
|
+
function onHit() {
|
|
7752
|
+
if (settings.vibration) gem.vibration.vibrate(30);
|
|
7753
|
+
}
|
|
7754
|
+
```
|
|
7755
|
+
|
|
7756
|
+
- **Never call `navigator.vibrate`**, guarded or not, and never fall back
|
|
7757
|
+
to it: this already does.
|
|
7758
|
+
- **Nothing vibrates before the player's first tap** in your game; the
|
|
7759
|
+
call returns `false` until then.
|
|
7760
|
+
- **Stop on pause** with `gem.vibration.vibrate(0)`.
|
|
7761
|
+
|
|
7762
|
+
**Guides.** [vibration](https://gemarcade.com/developer/docs/vibration)
|
|
7763
|
+
|
|
7408
7764
|
## Gem.analytics
|
|
7409
7765
|
|
|
7410
7766
|
[Gem.analytics](https://gemarcade.com/developer/api/game#gem-analytics)
|
|
@@ -7499,12 +7855,17 @@ readonly friends: FriendsApi
|
|
|
7499
7855
|
The signed-in player's accepted friends — display identity only,
|
|
7500
7856
|
read-only, paginated — and the one ask that reaches past them:
|
|
7501
7857
|
[FriendsApi.challenge](https://gemarcade.com/developer/api/game#friendsapi-challenge), which asks the Arcade to send a friend a
|
|
7502
|
-
challenge after the player confirms it in the Arcade's own sheet.
|
|
7858
|
+
challenge after the player confirms it in the Arcade's own sheet. The
|
|
7859
|
+
receiving side reads the challenges this player holds in this game:
|
|
7860
|
+
[FriendsApi.launchedChallenge](https://gemarcade.com/developer/api/game#friendsapi-launchedchallenge) for the one this frame was launched
|
|
7861
|
+
with, [FriendsApi.inbox](https://gemarcade.com/developer/api/game#friendsapi-inbox) for all of them, and
|
|
7862
|
+
[FriendsApi.markAnswered](https://gemarcade.com/developer/api/game#friendsapi-markanswered) once one has been played.
|
|
7503
7863
|
|
|
7504
7864
|
Every accepted friend appears whether or not they have played this game;
|
|
7505
7865
|
an invite-a-friend flow needs exactly the ones who have not. The graph
|
|
7506
7866
|
itself — requests, accepts, blocks, presence — stays on the Arcade: there
|
|
7507
|
-
is nothing here to mutate
|
|
7867
|
+
is nothing here to mutate but a challenge's own answered mark, and nothing
|
|
7868
|
+
that says who is online.
|
|
7508
7869
|
|
|
7509
7870
|
A player surface only. In a context with no player — a game server — the
|
|
7510
7871
|
platform refuses the read; a server has no friend list.
|
|
@@ -11247,6 +11608,61 @@ A unit test that constructs the SDK in a simulated DOM has to give its
|
|
|
11247
11608
|
window a parent of its own, because a simulated top-level window is exactly
|
|
11248
11609
|
what this refuses.
|
|
11249
11610
|
|
|
11611
|
+
## VibrationApi
|
|
11612
|
+
|
|
11613
|
+
[VibrationApi](https://gemarcade.com/developer/api/game#vibrationapi)
|
|
11614
|
+
|
|
11615
|
+
```ts
|
|
11616
|
+
interface VibrationApi
|
|
11617
|
+
```
|
|
11618
|
+
|
|
11619
|
+
`gem.vibration` — vibrate the player's device, on every platform that can.
|
|
11620
|
+
Call it instead of `navigator.vibrate`, which does nothing on any iPhone.
|
|
11621
|
+
|
|
11622
|
+
## VibrationApi.available
|
|
11623
|
+
|
|
11624
|
+
[VibrationApi.available](https://gemarcade.com/developer/api/game#vibrationapi-available)
|
|
11625
|
+
|
|
11626
|
+
```ts
|
|
11627
|
+
readonly available: boolean
|
|
11628
|
+
```
|
|
11629
|
+
|
|
11630
|
+
Whether this device can vibrate for your game: decide from this whether to
|
|
11631
|
+
show your game's vibration toggle. Read it live, every time — after
|
|
11632
|
+
`awaitBridge()`, and again when your settings screen opens — never once at
|
|
11633
|
+
boot: on an iPhone it is `false` until the bridge connects.
|
|
11634
|
+
|
|
11635
|
+
`false` on a desktop with a mouse, in iOS Safari, in Firefox, before the
|
|
11636
|
+
bridge is up where vibration goes through the arcade, and after the
|
|
11637
|
+
session ends there.
|
|
11638
|
+
|
|
11639
|
+
## VibrationApi.vibrate
|
|
11640
|
+
|
|
11641
|
+
[VibrationApi.vibrate](https://gemarcade.com/developer/api/game#vibrationapi-vibrate)
|
|
11642
|
+
|
|
11643
|
+
```ts
|
|
11644
|
+
vibrate(pattern: number | readonly number[]): boolean
|
|
11645
|
+
```
|
|
11646
|
+
|
|
11647
|
+
Vibrate: takes what `navigator.vibrate` takes and returns what it returns.
|
|
11648
|
+
`pattern` is a duration in milliseconds, or an array of alternating
|
|
11649
|
+
vibration and pause durations, starting with a vibration. `0` or `[]`
|
|
11650
|
+
stops a pattern that is still playing, and every call replaces it.
|
|
11651
|
+
|
|
11652
|
+
The pattern is capped at 99 entries of at most 10 000 ms each, and at
|
|
11653
|
+
10 000 ms in all: a longer one is cut short, not refused.
|
|
11654
|
+
|
|
11655
|
+
Check your game's own vibration toggle before every call. Returns `false`,
|
|
11656
|
+
and vibrates nothing, when [VibrationApi.available](https://gemarcade.com/developer/api/game#vibrationapi-available) is false, before
|
|
11657
|
+
the player's first tap or key press in your game, for a pattern with a
|
|
11658
|
+
negative or non-finite entry, and past 600 calls a minute; each of the last
|
|
11659
|
+
three says so once a session through your `log`. `true` means the pattern
|
|
11660
|
+
was accepted, never that a motor moved.
|
|
11661
|
+
|
|
11662
|
+
| Parameter | Type |
|
|
11663
|
+
| --- | --- |
|
|
11664
|
+
| `pattern` | `number \| readonly number[]` |
|
|
11665
|
+
|
|
11250
11666
|
## LeaderboardPeriod.id
|
|
11251
11667
|
|
|
11252
11668
|
[LeaderboardPeriod.id](https://gemarcade.com/developer/api/game#leaderboardperiod-id)
|
|
@@ -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` v8.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
|
|