@indiegems/gem-web-sdk 9.1.4 → 10.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/dist/sdk.d.ts CHANGED
@@ -157,6 +157,11 @@ type AffixSelection = {
157
157
  "pool": AffixPoolRef;
158
158
  "respect_groups"?: boolean;
159
159
  };
160
+ type BackfillPolicy = "fill_existing_first" | "prefer_new_match";
161
+ type BackfillSettings = {
162
+ "enabled": boolean;
163
+ "policy"?: BackfillPolicy;
164
+ };
160
165
  type Boundary = {
161
166
  "boundary"?: string;
162
167
  "reset_time"?: string;
@@ -230,11 +235,20 @@ type LevelDefinition = {
230
235
  "rewards"?: RecipeOperation[];
231
236
  "threshold": number;
232
237
  };
238
+ type MatchmakingSettings = {
239
+ "backfill"?: null | BackfillSettings;
240
+ "cluster_stagger_seconds"?: number;
241
+ "enabled": boolean;
242
+ "fill_window_seconds"?: number;
243
+ "strategy"?: MatchmakingStrategy;
244
+ "ticket_expiry_seconds"?: number | null;
245
+ };
246
+ type MatchmakingStrategy = "fifo";
233
247
  type OrderBySpec = {
234
248
  "column": RunValueColumn;
235
249
  "direction": SortDirection;
236
250
  };
237
- type OrderSource$1 = "real_money_purchase" | "real_money_refund" | "full_game_purchase" | "full_game_refund" | "platform_purchase" | "reward" | "admin" | "system" | "promo" | "game_consume" | "play" | "recipe" | "transfer" | "platform_funded_game_inventory_purchase" | "earning_reset";
251
+ type OrderSource$1 = "real_money_purchase" | "real_money_refund" | "full_game_purchase" | "full_game_refund" | "platform_purchase" | "reward" | "admin" | "system" | "promo" | "game_consume" | "play" | "recipe" | "transfer" | "platform_funded_game_inventory_purchase" | "earning_reset" | "test_account_provision" | "developer_grant";
238
252
  type OverflowBehavior$1 = "fail" | "clamp" | "allow";
239
253
  type PityEffect = "guarantee_tier" | {
240
254
  "weight_boost": {
@@ -452,6 +466,7 @@ type SnapshotGameRoomTemplate = {
452
466
  "id": string;
453
467
  "idle_timeout_seconds"?: number | null;
454
468
  "match_type": string;
469
+ "matchmaking"?: null | MatchmakingSettings;
455
470
  "max_match_duration_seconds"?: number | null;
456
471
  "max_players": number;
457
472
  "min_players": number;
@@ -523,6 +538,7 @@ type SnapshotProgression = {
523
538
  "display_name"?: string | null;
524
539
  "icon_url"?: string | null;
525
540
  "id": string;
541
+ "localized"?: Record<string, unknown>;
526
542
  "progression_type": string;
527
543
  "slug"?: string | null;
528
544
  "sort_order": number;
@@ -560,6 +576,7 @@ type SnapshotRewardedPlacement = {
560
576
  "grants": SnapshotRewardGrant[];
561
577
  "max_held"?: number | null;
562
578
  "max_per_day"?: number | null;
579
+ "min_watch_secs"?: number | null;
563
580
  "placement": string;
564
581
  "reward_class": string;
565
582
  "without_ads": string;
@@ -1524,26 +1541,6 @@ interface ClusterTarget {
1524
1541
  readonly id: string;
1525
1542
  readonly pressure: string;
1526
1543
  }
1527
- type RoomArgScalar = string | number | boolean;
1528
- type RoomArgValue$1 = RoomArgScalar | readonly RoomArgScalar[];
1529
- type RoomArgs = Readonly<Record<string, RoomArgValue$1>>;
1530
- type RoomArgType$1 = "string" | "int" | "float" | "bool" | (string & {});
1531
- interface RoomArgEntry {
1532
- readonly name: string;
1533
- readonly type: RoomArgType$1;
1534
- readonly list: boolean;
1535
- readonly required: boolean;
1536
- readonly mutable: boolean;
1537
- readonly fixed?: RoomArgValue$1;
1538
- readonly default?: RoomArgValue$1;
1539
- readonly description?: string;
1540
- readonly allowed?: readonly RoomArgScalar[];
1541
- readonly min?: number;
1542
- readonly max?: number;
1543
- readonly minItems?: number;
1544
- readonly maxItems?: number;
1545
- readonly maxLength?: number;
1546
- }
1547
1544
  type DedicatedServerFailure = "timeout" | "aborted" | "allocation_failed" | "no_server_ready" | "start_rate_limited" | "p2p_unavailable" | "unsupported_protocol" | "credential_expired" | "credential_reused" | "join_rate_limited" | "signaling_unavailable" | "signaling_failed" | "offer_refused" | "invalid_sdp" | "media_refused" | "connection_failed" | "join_refused" | "match_ended" | "misconfigured";
1548
1545
  declare class DedicatedServerError extends Error {
1549
1546
  readonly reason: DedicatedServerFailure;
@@ -1652,6 +1649,26 @@ interface TransportAdvert {
1652
1649
  declare function readTemplateTransports(value: unknown): readonly TransportKind[] | null;
1653
1650
  declare function readTransportAdvert(settings: unknown, forMatch?: string): TransportAdvert | null;
1654
1651
  declare function webTransportAvailable(): boolean;
1652
+ type RoomArgScalar = string | number | boolean;
1653
+ type RoomArgValue$1 = RoomArgScalar | readonly RoomArgScalar[];
1654
+ type RoomArgs = Readonly<Record<string, RoomArgValue$1>>;
1655
+ type RoomArgType$1 = "string" | "int" | "float" | "bool" | (string & {});
1656
+ interface RoomArgEntry {
1657
+ readonly name: string;
1658
+ readonly type: RoomArgType$1;
1659
+ readonly list: boolean;
1660
+ readonly required: boolean;
1661
+ readonly mutable: boolean;
1662
+ readonly fixed?: RoomArgValue$1;
1663
+ readonly default?: RoomArgValue$1;
1664
+ readonly description?: string;
1665
+ readonly allowed?: readonly RoomArgScalar[];
1666
+ readonly min?: number;
1667
+ readonly max?: number;
1668
+ readonly minItems?: number;
1669
+ readonly maxItems?: number;
1670
+ readonly maxLength?: number;
1671
+ }
1655
1672
  type RoomStatus = "open" | "in_game" | "closed" | (string & {});
1656
1673
  type MatchConnectionState = "disconnected" | "connecting" | "connected" | "suspended";
1657
1674
  type MatchSessionPhase = "none" | "starting" | "ready" | "connected" | "suspended" | "ended" | (string & {});
@@ -1749,6 +1766,38 @@ interface RoomOperationError {
1749
1766
  readonly message: string;
1750
1767
  readonly retryable: boolean;
1751
1768
  }
1769
+ interface QueueForMatchOptions {
1770
+ readonly templateSlugs: readonly string[];
1771
+ readonly partyId?: string;
1772
+ readonly signal?: AbortSignal;
1773
+ }
1774
+ type MatchTicketStatus = "queued" | "matched" | "expired" | "cancelled" | "failed" | "lost" | "unavailable";
1775
+ type MatchTicketOutcome = {
1776
+ readonly status: "matched";
1777
+ readonly room: Room;
1778
+ } | {
1779
+ readonly status: "expired";
1780
+ readonly reason: string;
1781
+ } | {
1782
+ readonly status: "cancelled";
1783
+ readonly reason: string;
1784
+ } | {
1785
+ readonly status: "failed";
1786
+ readonly reason: string;
1787
+ } | {
1788
+ readonly status: "lost";
1789
+ } | {
1790
+ readonly status: "unavailable";
1791
+ };
1792
+ interface MatchTicket {
1793
+ readonly id: string;
1794
+ readonly status: MatchTicketStatus;
1795
+ readonly partySize: number;
1796
+ readonly queuedAt: number;
1797
+ readonly expiresAt: number;
1798
+ readonly outcome: Promise<MatchTicketOutcome>;
1799
+ cancel(): Promise<MatchTicketOutcome>;
1800
+ }
1752
1801
  interface CreateRoomOptions {
1753
1802
  readonly name: string;
1754
1803
  readonly maxPlayers?: number;
@@ -1891,6 +1940,7 @@ interface RoomManager {
1891
1940
  join(roomId: string, options?: JoinRoomOptions): Promise<Room>;
1892
1941
  joinByCode(code: string, options?: JoinRoomOptions): Promise<Room>;
1893
1942
  quickJoin(options: QuickJoinOptions): Promise<Room>;
1943
+ queueForMatch(options: QueueForMatchOptions): Promise<MatchTicket>;
1894
1944
  list(options?: ListRoomsOptions): Promise<RoomPage>;
1895
1945
  myRooms(signal?: AbortSignal): Promise<readonly RoomSummary[]>;
1896
1946
  leave(options?: {
@@ -1916,6 +1966,7 @@ interface RoomManager {
1916
1966
  }): Promise<void>;
1917
1967
  readonly gameId: string | null;
1918
1968
  readonly currentRoom: Room | null;
1969
+ readonly currentTicket: MatchTicket | null;
1919
1970
  readonly currentMatch: ReadyMatch | null;
1920
1971
  readonly matchConnectionState: MatchConnectionState;
1921
1972
  readonly matchSession: MatchSession;
@@ -1,6 +1,6 @@
1
1
  # The browser surface — API reference
2
2
 
3
- Generated from `@indiegems/gem-web-sdk/sdk` v9.1.4, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
3
+ Generated from `@indiegems/gem-web-sdk/sdk` v10.0.0, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
4
4
 
5
5
  `@indiegems/gem-web-sdk/sdk` is the one import a game writes, wherever its code runs. `@indiegems/gem-web-sdk/game` exports exactly the symbols on this page and nothing else, for a build that wants only this half.
6
6
 
@@ -14668,6 +14668,58 @@ session — [RoomManager.leaveAll](#roommanager-leaveall) is what clears those.
14668
14668
 
14669
14669
  **Returns.** The room joined or created.
14670
14670
 
14671
+ <a id="roommanager-queueformatch"></a>
14672
+
14673
+ ## RoomManager.queueForMatch
14674
+
14675
+ ```ts
14676
+ queueForMatch(options: QueueForMatchOptions): Promise<MatchTicket>
14677
+ ```
14678
+
14679
+ Queue for a match with other players, and get a ticket to wait on.
14680
+
14681
+ FOR A MODE THAT NEEDS A FULL LOBBY BEFORE IT STARTS. The platform holds the
14682
+ player in a queue until it has enough players for one of the templates you
14683
+ named, then makes the room, seats everyone and starts the match — nobody
14684
+ hosts and nobody presses start. For a drop-in mode, where a player should
14685
+ be in a room at once and others join around them, use
14686
+ [RoomManager.quickJoin](#roommanager-quickjoin) instead.
14687
+
14688
+ This call answers as soon as the player is queued. What happens next is on
14689
+ the ticket: await [MatchTicket.outcome](#matchticket-outcome), and when it says `matched`
14690
+ this manager is already in the room — `joined` has fired and the match
14691
+ events follow as for any other room.
14692
+
14693
+ A PLAYER MAY QUEUE FROM INSIDE A ROOM — a hub, or a social lobby they wait
14694
+ in. When the ticket is matched the manager moves to the match's room:
14695
+ `currentRoom` becomes it and `joined` fires. The seat in the room they
14696
+ queued from is kept on the platform, not given up, so when the match is
14697
+ over `join()` with that room's id puts them back in it. If the tab closes
14698
+ before they go back, the SDK leaves both rooms.
14699
+
14700
+ What it does refuse is a second thing in flight: while a ticket waits,
14701
+ `create`, `join`, `joinByCode`, `quickJoin` and another `queueForMatch`
14702
+ refuse until it ends or is cancelled.
14703
+
14704
+ CLOSING THE TAB CANCELS THE TICKET. The SDK sends the cancel as the page
14705
+ goes away, so a player who left is not matched into a lobby they will
14706
+ never arrive in.
14707
+
14708
+ | Parameter | Type | Description |
14709
+ | --- | --- | --- |
14710
+ | `options` | `QueueForMatchOptions` | The templates the player accepts. |
14711
+
14712
+ **Returns.** The ticket, still `queued` unless a lobby was waiting for exactly
14713
+ this player.
14714
+
14715
+ **Throws.** `GemApiError` when the platform refuses the ticket. Two refusals
14716
+ are worth their own branch, by [GemApiError.code](#gemapierror-code):
14717
+ `already_queued` — this player, or someone in their party, is already
14718
+ on a ticket, possibly in another tab or another game — and
14719
+ `matchmaking_unavailable`, which means matchmaking is turned off or not
14720
+ answering. Tell the player; do not loop on it, and do not quietly
14721
+ substitute `quickJoin`, which puts them in a different kind of room.
14722
+
14671
14723
  <a id="roommanager-list"></a>
14672
14724
 
14673
14725
  ## RoomManager.list
@@ -15002,6 +15054,20 @@ The room this player is in, or `null`. Kept fresh for you.
15002
15054
  Read it whenever you render the lobby rather than caching it — the manager
15003
15055
  updates it as players join, ready up and leave, and emits events as it does.
15004
15056
 
15057
+ <a id="roommanager-currentticket"></a>
15058
+
15059
+ ## RoomManager.currentTicket
15060
+
15061
+ ```ts
15062
+ readonly currentTicket: MatchTicket | null
15063
+ ```
15064
+
15065
+ The matchmaking ticket this player is waiting on, or `null`.
15066
+
15067
+ Set from the moment [RoomManager.queueForMatch](#roommanager-queueformatch) answers until the
15068
+ ticket ends — so it is `null` again by the time a matched ticket's room is
15069
+ [RoomManager.currentRoom](#roommanager-currentroom).
15070
+
15005
15071
  <a id="roommanager-currentmatch"></a>
15006
15072
 
15007
15073
  ## RoomManager.currentMatch
@@ -15212,6 +15278,220 @@ Stop polling and drop every listener.
15212
15278
  Call this when tearing your game down. It does not leave the room — use
15213
15279
  [RoomManager.leave](#roommanager-leave) or `gem.exit()` for that.
15214
15280
 
15281
+ <a id="queueformatchoptions"></a>
15282
+
15283
+ ## QueueForMatchOptions
15284
+
15285
+ ```ts
15286
+ interface QueueForMatchOptions
15287
+ ```
15288
+
15289
+ What you pass to `gem.rooms.queueForMatch(...)`.
15290
+
15291
+ NAME EVERY MODE THE PLAYER WILL ACCEPT. The ticket waits for all of them at
15292
+ once and is matched under whichever fills first, so "any mode" is one ticket
15293
+ naming several templates rather than several tickets — a player can only be
15294
+ on one.
15295
+
15296
+ ```js
15297
+ const ticket = await gem.rooms.queueForMatch({ templateSlugs: ['duel', 'brawl'] });
15298
+ ```
15299
+
15300
+ **Guides.** [rooms-and-matches](../rooms-and-matches.md)
15301
+
15302
+ <a id="queueformatchoptions-templateslugs"></a>
15303
+
15304
+ ## QueueForMatchOptions.templateSlugs
15305
+
15306
+ ```ts
15307
+ readonly templateSlugs: readonly string[]
15308
+ ```
15309
+
15310
+ The room templates this player accepts, by slug — one to eight of them.
15311
+
15312
+ EVERY ONE MUST HAVE MATCHMAKING TURNED ON in your game config. A template
15313
+ without it refuses the whole ticket rather than being skipped, so a typo
15314
+ is an error you see and not a mode nobody is ever matched into.
15315
+
15316
+ <a id="queueformatchoptions-partyid"></a>
15317
+
15318
+ ## QueueForMatchOptions.partyId
15319
+
15320
+ ```ts
15321
+ readonly partyId?: string
15322
+ ```
15323
+
15324
+ A party to queue as one unit. Normally omit it — the SDK brings the
15325
+ player's party along when they lead one, exactly as a room call does.
15326
+
15327
+ A party is seated together or not at all. If it gains or loses a member
15328
+ while it waits, the ticket ends `cancelled` with reason `party_changed`.
15329
+
15330
+ <a id="queueformatchoptions-signal"></a>
15331
+
15332
+ ## QueueForMatchOptions.signal
15333
+
15334
+ ```ts
15335
+ readonly signal?: AbortSignal
15336
+ ```
15337
+
15338
+ Cancel the request that creates the ticket.
15339
+
15340
+ Only that request. Once you hold a ticket, [MatchTicket.cancel](#matchticket-cancel) is
15341
+ what takes the player out of the queue.
15342
+
15343
+ <a id="matchticketstatus"></a>
15344
+
15345
+ ## MatchTicketStatus
15346
+
15347
+ ```ts
15348
+ type MatchTicketStatus = "queued" | "matched" | "expired" | "cancelled" | "failed" | "lost" | "unavailable"
15349
+ ```
15350
+
15351
+ Where a ticket is: `queued` while it waits, and anything else for good.
15352
+
15353
+ - `matched` — the player is seated and the match is starting.
15354
+ - `expired` — it waited too long, or stopped being kept alive.
15355
+ - `cancelled` — the player backed out, or their party changed.
15356
+ - `failed` — the platform formed a match and could not start it, repeatedly.
15357
+ - `lost` — the platform no longer has the ticket. Queue again.
15358
+ - `unavailable` — matchmaking is turned off or not answering.
15359
+
15360
+ <a id="matchticketoutcome"></a>
15361
+
15362
+ ## MatchTicketOutcome
15363
+
15364
+ ```ts
15365
+ type MatchTicketOutcome = { status: "matched"; room: Room } | { status: "expired"; reason: string } | { status: "cancelled"; reason: string } | { status: "failed"; reason: string } | { status: "lost" } | { status: "unavailable" }
15366
+ ```
15367
+
15368
+ How a ticket ended. Branch on `status`.
15369
+
15370
+ ONLY `matched` CARRIES A ROOM, and by the time you see it the SDK is already
15371
+ in that room: `gem.rooms.currentRoom` is it, `joined` has fired, and the
15372
+ match events follow as they do for any other room.
15373
+
15374
+ Every other ending leaves the player in no room and on no ticket, free to
15375
+ queue again. None of them is retried for you, and nothing falls back to
15376
+ `quickJoin` — a game that wants either does it on purpose.
15377
+
15378
+ `reason` says why, where the platform gave one: `timed_out` or
15379
+ `heartbeat_lapsed` for `expired`, `requested` or `party_changed` for
15380
+ `cancelled`, `handoff_failed` for `failed`. Treat a value you do not
15381
+ recognise as the status alone.
15382
+
15383
+ <a id="matchticket"></a>
15384
+
15385
+ ## MatchTicket
15386
+
15387
+ ```ts
15388
+ interface MatchTicket
15389
+ ```
15390
+
15391
+ A place in the matchmaking queue — what `gem.rooms.queueForMatch(...)`
15392
+ answers with.
15393
+
15394
+ You do not keep it alive; the SDK does, for as long as it waits. What you do
15395
+ with it is wait for [MatchTicket.outcome](#matchticket-outcome), and offer the player a
15396
+ button that calls [MatchTicket.cancel](#matchticket-cancel).
15397
+
15398
+ ```js
15399
+ const ticket = await gem.rooms.queueForMatch({ templateSlugs: ['duel'] });
15400
+ showSearching({ onCancel: () => ticket.cancel() });
15401
+
15402
+ const outcome = await ticket.outcome;
15403
+ if (outcome.status === 'matched') enterMatch(outcome.room);
15404
+ else backToMenu(outcome.status);
15405
+ ```
15406
+
15407
+ **Guides.** [rooms-and-matches](../rooms-and-matches.md)
15408
+
15409
+ <a id="matchticket-id"></a>
15410
+
15411
+ ## MatchTicket.id
15412
+
15413
+ ```ts
15414
+ readonly id: string
15415
+ ```
15416
+
15417
+ The ticket's id. For logs and bug reports; nothing you call takes it.
15418
+
15419
+ <a id="matchticket-status"></a>
15420
+
15421
+ ## MatchTicket.status
15422
+
15423
+ ```ts
15424
+ readonly status: MatchTicketStatus
15425
+ ```
15426
+
15427
+ Where the ticket is right now. Changes once, from `queued` to how it ended.
15428
+
15429
+ <a id="matchticket-partysize"></a>
15430
+
15431
+ ## MatchTicket.partySize
15432
+
15433
+ ```ts
15434
+ readonly partySize: number
15435
+ ```
15436
+
15437
+ How many players the ticket seats: 1, or the size of the party.
15438
+
15439
+ <a id="matchticket-queuedat"></a>
15440
+
15441
+ ## MatchTicket.queuedAt
15442
+
15443
+ ```ts
15444
+ readonly queuedAt: number
15445
+ ```
15446
+
15447
+ When the ticket joined the queue, in Unix seconds.
15448
+
15449
+ <a id="matchticket-expiresat"></a>
15450
+
15451
+ ## MatchTicket.expiresAt
15452
+
15453
+ ```ts
15454
+ readonly expiresAt: number
15455
+ ```
15456
+
15457
+ When the ticket gives up if it is still waiting, in Unix seconds. Good for
15458
+ a countdown; the platform decides the length, per template.
15459
+
15460
+ <a id="matchticket-outcome"></a>
15461
+
15462
+ ## MatchTicket.outcome
15463
+
15464
+ ```ts
15465
+ readonly outcome: Promise<MatchTicketOutcome>
15466
+ ```
15467
+
15468
+ How the ticket ends. Settles exactly once, and RESOLVES for every ending
15469
+ the platform reports — matched, expired, cancelled and the rest are
15470
+ outcomes to branch on, not errors to catch.
15471
+
15472
+ It rejects in one case only: the ticket was matched and the SDK could not
15473
+ read the room it was seated in. The player holds a seat then, so
15474
+ `gem.rooms.myRooms()` shows the room and `gem.rooms.join(id)` enters it.
15475
+
15476
+ <a id="matchticket-cancel"></a>
15477
+
15478
+ ## MatchTicket.cancel
15479
+
15480
+ ```ts
15481
+ cancel(): Promise<MatchTicketOutcome>
15482
+ ```
15483
+
15484
+ Take the player — and their party — out of the queue.
15485
+
15486
+ A CANCEL CAN LOSE THE RACE, and then the answer is `matched`. A ticket the
15487
+ platform has already seated is never undone, so read the outcome this
15488
+ returns rather than assuming: when it says `matched` the player is in a
15489
+ room, and backing out is `gem.rooms.leave()`.
15490
+
15491
+ Safe to call more than once, and after the ticket has ended.
15492
+
15493
+ **Returns.** The same promise as [MatchTicket.outcome](#matchticket-outcome).
15494
+
15215
15495
  <a id="roomstatus"></a>
15216
15496
 
15217
15497
  ## RoomStatus
@@ -1,6 +1,6 @@
1
1
  # The server surface — API reference
2
2
 
3
- Generated from `@indiegems/gem-web-sdk/sdk` v9.1.4, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
3
+ Generated from `@indiegems/gem-web-sdk/sdk` v10.0.0, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
4
4
 
5
5
  `@indiegems/gem-web-sdk/sdk` is the one import a game writes, wherever its code runs. `@indiegems/gem-web-sdk/server` exports exactly the symbols on this page and nothing else, for a build that wants only this half.
6
6