@diffenderfer-games/hub 2.0.0-next.4 → 2.0.0-next.6
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 +54 -11
- package/README.md +3 -6
- package/dist/auto.d.ts +5 -5
- package/dist/auto.js +2 -2
- package/dist/avatar-pixi.d.ts +147 -0
- package/dist/avatar-pixi.d.ts.map +1 -0
- package/dist/avatar-pixi.js +280 -0
- package/dist/avatar-pixi.js.map +1 -0
- package/dist/avatar-svg.d.ts +4 -0
- package/dist/avatar-svg.js +5 -0
- package/dist/avatar-three.d.ts +69 -0
- package/dist/avatar-three.d.ts.map +1 -0
- package/dist/avatar-three.js +49 -0
- package/dist/avatar-three.js.map +1 -0
- package/dist/avatar.d.ts +7 -0
- package/dist/avatar.js +487 -0
- package/dist/avatar.js.map +1 -0
- package/dist/daily.d.ts +2 -2
- package/dist/doctor/cli.mjs +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +2 -2
- package/dist/input.d.ts +2 -2
- package/dist/shared/animator.d.ts +104 -0
- package/dist/shared/animator.d.ts.map +1 -0
- package/dist/shared/art.js +1804 -0
- package/dist/shared/art.js.map +1 -0
- package/dist/shared/atlas.d.ts +134 -0
- package/dist/shared/atlas.d.ts.map +1 -0
- package/dist/shared/avatar.d.ts +117 -0
- package/dist/shared/avatar.d.ts.map +1 -0
- package/dist/shared/bridge.js +13 -5
- package/dist/shared/bridge.js.map +1 -1
- package/dist/shared/client-version.gen.js +1 -1
- package/dist/shared/daily.d.ts +129 -18
- package/dist/shared/daily.d.ts.map +1 -1
- package/dist/shared/daily.js +120 -26
- package/dist/shared/daily.js.map +1 -1
- package/dist/shared/defineProperty.js +39 -0
- package/dist/shared/describe.d.ts +32 -0
- package/dist/shared/describe.d.ts.map +1 -0
- package/dist/shared/describe.js +101 -0
- package/dist/shared/describe.js.map +1 -0
- package/dist/shared/globals.js +1 -39
- package/dist/shared/globals.js.map +1 -1
- package/dist/shared/index.d.ts +537 -17
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/input.d.ts +31 -13
- package/dist/shared/input.d.ts.map +1 -1
- package/dist/shared/input.js +40 -2
- package/dist/shared/input.js.map +1 -1
- package/dist/shared/json-guards.js +48 -0
- package/dist/shared/json-guards.js.map +1 -0
- package/dist/shared/live-canvas.js +62 -0
- package/dist/shared/live-canvas.js.map +1 -0
- package/dist/shared/mp.js +1 -1
- package/dist/shared/overlays.js +800 -0
- package/dist/shared/overlays.js.map +1 -0
- package/dist/shared/page-stack.js +2 -1
- package/dist/shared/page-stack.js.map +1 -1
- package/dist/shared/pose-key.js +249 -0
- package/dist/shared/pose-key.js.map +1 -0
- package/dist/shared/race.js +1 -1
- package/dist/shared/rooms.js +1 -1
- package/dist/shared/scene.d.ts +90 -0
- package/dist/shared/scene.d.ts.map +1 -0
- package/dist/shared/social.d.ts +55 -4
- package/dist/shared/social.d.ts.map +1 -1
- package/dist/shared/src.js +2217 -199
- package/dist/shared/src.js.map +1 -1
- package/dist/shared/svg-markup.js +1860 -0
- package/dist/shared/svg-markup.js.map +1 -0
- package/dist/shared/svg.js +27 -0
- package/dist/shared/svg.js.map +1 -0
- package/dist/shared/types.d.ts +166 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/social.d.ts +2 -2
- package/dist/social.js +2 -2
- package/dist/turns.d.ts +39 -0
- package/dist/turns.d.ts.map +1 -0
- package/dist/turns.js +117 -0
- package/dist/turns.js.map +1 -0
- package/package.json +33 -3
- package/src/avatar/adapters/pixi-avatar.ts +73 -0
- package/src/avatar/adapters/pixi-crowd.ts +302 -0
- package/src/avatar/adapters/pixi-types.ts +84 -0
- package/src/avatar/adapters/three.ts +126 -0
- package/src/avatar/animator/animator.ts +285 -0
- package/src/avatar/animator/reactions.ts +44 -0
- package/src/avatar/animator/schedule.ts +73 -0
- package/src/avatar/art/beard.ts +49 -0
- package/src/avatar/art/glasses.ts +9 -0
- package/src/avatar/art/hair.ts +254 -0
- package/src/avatar/art/headwear.ts +75 -0
- package/src/avatar/art/index.ts +21 -0
- package/src/avatar/art/shape.ts +68 -0
- package/src/avatar/art-store.ts +36 -0
- package/src/avatar/atlas.ts +236 -0
- package/src/avatar/catalog-view.ts +14 -0
- package/src/avatar/colour.ts +109 -0
- package/src/avatar/describe.ts +76 -0
- package/src/avatar/face.ts +187 -0
- package/src/avatar/geom.ts +168 -0
- package/src/avatar/layout.ts +47 -0
- package/src/avatar/look-like.ts +52 -0
- package/src/avatar/outputs/bitmap.ts +75 -0
- package/src/avatar/outputs/canvas-paint.ts +177 -0
- package/src/avatar/outputs/canvas.ts +62 -0
- package/src/avatar/outputs/custom-element.ts +140 -0
- package/src/avatar/outputs/element.ts +58 -0
- package/src/avatar/outputs/live-canvas.ts +57 -0
- package/src/avatar/outputs/overlay-svg.ts +22 -0
- package/src/avatar/outputs/pose-key.ts +30 -0
- package/src/avatar/outputs/svg-markup.ts +113 -0
- package/src/avatar/outputs/svg.ts +41 -0
- package/src/avatar/overlays.ts +128 -0
- package/src/avatar/render/body.ts +116 -0
- package/src/avatar/render/colours.ts +81 -0
- package/src/avatar/render/compose.ts +258 -0
- package/src/avatar/render/context.ts +117 -0
- package/src/avatar/render/eyes.ts +78 -0
- package/src/avatar/render/eyewear.ts +56 -0
- package/src/avatar/render/frame.ts +60 -0
- package/src/avatar/render/head.ts +81 -0
- package/src/avatar/render/mouth.ts +86 -0
- package/src/avatar/render/props.ts +91 -0
- package/src/avatar/render/types.ts +84 -0
- package/src/avatar/scene.ts +119 -0
- package/src/avatar-pixi.ts +20 -0
- package/src/avatar-svg.ts +21 -0
- package/src/avatar-three.ts +18 -0
- package/src/avatar.ts +62 -0
- package/src/core/avatar/avatar-cache.ts +95 -0
- package/src/core/avatar/avatar-ref.ts +34 -0
- package/src/core/avatar/avatar-types.ts +43 -0
- package/src/core/avatar/hub-avatar.ts +308 -0
- package/src/core/connection.ts +9 -0
- package/src/core/errors.ts +15 -2
- package/src/core/hub-progress.ts +269 -202
- package/src/core/hub.ts +174 -6
- package/src/core/offline/cloud-saves.ts +62 -0
- package/src/core/offline/hub-kinds/avatar-kind.ts +42 -0
- package/src/core/offline/hub-kinds/index.ts +14 -3
- package/src/core/offline/hub-kinds/progress-kinds.ts +21 -4
- package/src/core/offline/hub-kinds/saved-kind.ts +93 -0
- package/src/core/offline/local-store.ts +46 -1
- package/src/core/page-account.ts +121 -0
- package/src/core/rest/routes.gen.ts +31 -1
- package/src/core/resume/hub-resume.ts +39 -5
- package/src/core/resume/resume-types.ts +2 -2
- package/src/core/saved/daily-saves.ts +196 -0
- package/src/core/saved/daily-seed.ts +16 -0
- package/src/core/saved/hub-saved.ts +221 -0
- package/src/core/saved/local-saved.ts +122 -0
- package/src/core/saved/saved-list.ts +129 -0
- package/src/core/saved/saved-open.ts +104 -0
- package/src/core/saved/saved-order.ts +49 -0
- package/src/core/saved/saved-types.ts +24 -0
- package/src/core/turns/hub-turns.ts +140 -0
- package/src/core/turns/turn-game.ts +388 -0
- package/src/core/version/client-version.gen.ts +2 -2
- package/src/daily/daily-system.ts +112 -13
- package/src/daily/page-daily.ts +2 -2
- package/src/daily/types.ts +46 -9
- package/src/doctor/hub-version-fetch.ts +43 -43
- package/src/index.ts +11 -1
- package/src/input/input-system.ts +10 -1
- package/src/input/navigator.ts +11 -0
- package/src/input.ts +1 -0
- package/src/overlay/overlay.ts +25 -1
- package/src/realtime/runtime-api.ts +14 -3
- package/src/social.ts +1 -0
- package/src/turns-kit/check-rules.ts +182 -0
- package/src/turns.ts +13 -0
package/dist/shared/index.d.ts
CHANGED
|
@@ -1,11 +1,129 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { b as avatar_d_exports } from "./avatar.js";
|
|
2
|
+
import { M as SavedOpened, S as SavedEntry, s as DailySystem, w as SavedListOptions, y as GamePayload } from "./daily.js";
|
|
2
3
|
import { O as InputSystem, n as getUiStack } from "./input.js";
|
|
3
4
|
import { o as multiplayerForwarder } from "./mp.js";
|
|
4
5
|
import { f as raceForwarder } from "./race.js";
|
|
5
6
|
import { n as roomsForwarder } from "./rooms.js";
|
|
6
|
-
import { Q as
|
|
7
|
-
import {
|
|
7
|
+
import { Q as OpenDesignerOptions, X as AvatarRef, Y as AvatarChange, Z as DesignerResult, it as socialForwarder, nt as notifyForwarder, rt as presenceForwarder } from "./social.js";
|
|
8
|
+
import { AvatarLook } from "@diffenderfer-games/hub-contract/avatar";
|
|
9
|
+
import { Board, Board as Board$1, CreateTurnGame, ErrorCode, GameInfo, GameLeaderboards, GameRecords, HubVersion, Inventory, Inventory as Inventory$1, Json, Json as Json$1, LeaderboardEntry, Metrics, Metrics as Metrics$1, MyAvatar, OpenTurnGame, OpenTurnGame as OpenTurnGame$1, PublicEndpoints, RejectReason, ResumeSlot, ResumeSummary, SavedCounts, SessionUser, SortDir, SortDir as SortDir$1, Stats, Stats as Stats$1, TurnChatLine, TurnChatLine as TurnChatLine$1, TurnDeadline, TurnDeadline as TurnDeadline$1, TurnGameView, TurnGameView as TurnGameView$1, TurnSummary } from "@diffenderfer-games/hub-contract";
|
|
8
10
|
import { CallReturn, ClientData } from "@ayepi/core/client";
|
|
11
|
+
//#region src/core/page-account.d.ts
|
|
12
|
+
/** The signed-in player as the page heard it. */
|
|
13
|
+
interface PageUser {
|
|
14
|
+
readonly id: number;
|
|
15
|
+
/** Their look code when the source carried it, else `null`. */
|
|
16
|
+
readonly look: string | null;
|
|
17
|
+
}
|
|
18
|
+
/** Where the news came from: an account event, or a socket hello (a time to catch up on what was missed). */
|
|
19
|
+
type AccountSource = 'account' | 'session';
|
|
20
|
+
/** Hears every report of who is signed in. */
|
|
21
|
+
type AccountListener = (user: PageUser | null, source: AccountSource) => void;
|
|
22
|
+
/** The page's account, as last heard. */
|
|
23
|
+
declare class PageAccount {
|
|
24
|
+
/** `undefined` until something said; `null` when signed out. */
|
|
25
|
+
private heard;
|
|
26
|
+
private readonly listeners;
|
|
27
|
+
private isListening;
|
|
28
|
+
constructor();
|
|
29
|
+
/** The signed-in player, `null` when signed out, `undefined` before anything said. */
|
|
30
|
+
get user(): PageUser | null | undefined;
|
|
31
|
+
/** Record who is signed in (this client's own sign-in or sign-out) and tell the listeners. */
|
|
32
|
+
note(user: PageUser | null, source?: AccountSource): void;
|
|
33
|
+
/** Hear every report; returns the unsubscribe function. */
|
|
34
|
+
on(listener: AccountListener): () => void;
|
|
35
|
+
/** Listen to the window events (at once in a page; made before a window existed, on first use). */
|
|
36
|
+
private listen;
|
|
37
|
+
private onEvent;
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region src/core/avatar/avatar-ref.d.ts
|
|
41
|
+
/** Anything that carries a player's look: a seat, a `PlayerLite`, a racer, a ticket user. */
|
|
42
|
+
interface CarriesLook {
|
|
43
|
+
readonly look?: string;
|
|
44
|
+
readonly userId?: number;
|
|
45
|
+
readonly id?: number;
|
|
46
|
+
readonly uid?: number;
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/core/avatar/hub-avatar.d.ts
|
|
50
|
+
/** What `hub.avatar` needs from its client. */
|
|
51
|
+
interface AvatarHost {
|
|
52
|
+
/** The signed-in user's id, or `null` (`hub.userId()`). */
|
|
53
|
+
readonly currentUserId: () => number | null;
|
|
54
|
+
/** Hear every report of who is signed in (the page's account). */
|
|
55
|
+
readonly onAccount: (listener: AccountListener) => () => void;
|
|
56
|
+
/** `GET /avatar/me`; rejects when offline. */
|
|
57
|
+
readonly fetchMine: () => Promise<MyAvatar>;
|
|
58
|
+
/** `POST /avatar/batch`. */
|
|
59
|
+
readonly fetchCodes: (ids: readonly number[]) => Promise<Record<string, string>>;
|
|
60
|
+
/** Queue a save of your look (sent now when online, replayed later when not). */
|
|
61
|
+
readonly queueSave: (code: string, savedAt: number) => Promise<void>;
|
|
62
|
+
}
|
|
63
|
+
/** The renderer module `load()` resolves with. */
|
|
64
|
+
type AvatarModule = typeof avatar_d_exports;
|
|
65
|
+
type ChangeListener = (change: AvatarChange) => void;
|
|
66
|
+
/** `hub.avatar`. */
|
|
67
|
+
declare class HubAvatar {
|
|
68
|
+
private readonly host;
|
|
69
|
+
private readonly cache;
|
|
70
|
+
private readonly listeners;
|
|
71
|
+
private pending;
|
|
72
|
+
private flushQueued;
|
|
73
|
+
private detachRuntime;
|
|
74
|
+
/** The account the last report named. */
|
|
75
|
+
private lastUserId;
|
|
76
|
+
/** The code of your look the page was last given (`mine`, `mineSync`, `change`). */
|
|
77
|
+
private mineShown;
|
|
78
|
+
/** Players this page asked about or was handed (re-checked on each socket hello). */
|
|
79
|
+
private readonly seen;
|
|
80
|
+
constructor(host: AvatarHost);
|
|
81
|
+
/**
|
|
82
|
+
* Your look (your default if you never designed one). Works offline from
|
|
83
|
+
* the device cache. Before your account exists (a new guest's is made just
|
|
84
|
+
* after the game starts) it resolves at once with a default look, and
|
|
85
|
+
* `change` brings yours when the account is there.
|
|
86
|
+
*/
|
|
87
|
+
mine(): Promise<AvatarRef>;
|
|
88
|
+
/** Your cached look, or your default; `null` only while nobody is signed in. */
|
|
89
|
+
mineSync(): AvatarRef | null;
|
|
90
|
+
/** Any player's look: from the cache, else batched with other requests in the same tick. */
|
|
91
|
+
of(userId: number): Promise<AvatarRef>;
|
|
92
|
+
/** Many players' looks at once. */
|
|
93
|
+
many(userIds: readonly number[]): Promise<Map<number, AvatarRef>>;
|
|
94
|
+
/** The look a payload already carries (a `RoomSeat`, `PlayerLite`, racer or ticket user). No request. */
|
|
95
|
+
from(carrier: CarriesLook): AvatarRef;
|
|
96
|
+
/** A seeded default for bots, previews and local pass-and-play seats: `bot('local:2')`. */
|
|
97
|
+
bot(seed: string | number): AvatarRef;
|
|
98
|
+
/** Save your look (designer code paths; queued offline, latest wins). */
|
|
99
|
+
save(look: AvatarLook): Promise<AvatarRef>;
|
|
100
|
+
/**
|
|
101
|
+
* Hear about look changes (yours, friends', your room's, and yours when
|
|
102
|
+
* your account appears). Returns the unsubscribe function. Wait for this
|
|
103
|
+
* rather than polling `mine()`.
|
|
104
|
+
*/
|
|
105
|
+
on(_event: 'change', listener: ChangeListener): () => void;
|
|
106
|
+
/** Open "Make your avatar" over the game; resolves when it closes. */
|
|
107
|
+
openDesigner(options?: OpenDesignerOptions): Promise<DesignerResult>;
|
|
108
|
+
/** Loads the renderer and its art; resolves when rendering is synchronous. */
|
|
109
|
+
load(): Promise<AvatarModule>;
|
|
110
|
+
/** Remember the ref the page was given for your look. */
|
|
111
|
+
private showMine;
|
|
112
|
+
/** Cache your look; `change` fires when it differs from the one the page last had. */
|
|
113
|
+
private noteMine;
|
|
114
|
+
/** Someone said who is signed in: fetch your look when the account is new or its look isn't the cached one. */
|
|
115
|
+
private onAccount;
|
|
116
|
+
private refreshMine;
|
|
117
|
+
/** The socket (re)connected: a change sent while it was down never arrived, so ask again. */
|
|
118
|
+
private recheckSeen;
|
|
119
|
+
private emit;
|
|
120
|
+
private attachRuntime;
|
|
121
|
+
private scheduleFlush;
|
|
122
|
+
private flush;
|
|
123
|
+
/** Players' codes, in batches; offline or failing, the missing ones are left out (they get their default). */
|
|
124
|
+
private fetchCodes;
|
|
125
|
+
}
|
|
126
|
+
//#endregion
|
|
9
127
|
//#region src/core/storage/key-value.d.ts
|
|
10
128
|
/**
|
|
11
129
|
* The string store behind the offline cache and queues: `localStorage` when
|
|
@@ -25,10 +143,6 @@ interface KeyValueStore {
|
|
|
25
143
|
keys(): string[];
|
|
26
144
|
}
|
|
27
145
|
//#endregion
|
|
28
|
-
//#region src/core/game-data.d.ts
|
|
29
|
-
/** Anything a game may store as JSON: an object (interfaces included), an array, text, a number, a boolean or `null`. */
|
|
30
|
-
type GamePayload = object | string | number | boolean | null;
|
|
31
|
-
//#endregion
|
|
32
146
|
//#region src/core/rest/endpoint-types.d.ts
|
|
33
147
|
/** The name of a public REST endpoint (`getCurrentUser`, `writeSave`, ...). */
|
|
34
148
|
type EndpointName = keyof PublicEndpoints;
|
|
@@ -256,6 +370,16 @@ declare class LocalStore {
|
|
|
256
370
|
putSave(slot: string, saveData: Json, label: string | null): number;
|
|
257
371
|
/** Forget a save. */
|
|
258
372
|
deleteSave(slot: string): void;
|
|
373
|
+
/**
|
|
374
|
+
* The hub's `updatedAt` for `slot` as the current user last saw it (`null`:
|
|
375
|
+
* the slot was empty), or `undefined` when this device doesn't know.
|
|
376
|
+
*/
|
|
377
|
+
cloudSave(slot: string): number | null | undefined;
|
|
378
|
+
/** Note the hub's copy of `slot` (just read or written) for the current user: its `updatedAt`, or `null` when empty. */
|
|
379
|
+
rememberCloudSave(slot: string, updatedAt: number | null): void;
|
|
380
|
+
/** Cache a slot as read from the hub (forgetting it when the hub has none), and note the hub's copy. */
|
|
381
|
+
cacheCloudSave(slot: string, save: Save | null): void;
|
|
382
|
+
private readCloudSaves;
|
|
259
383
|
/** This game's cached stats. */
|
|
260
384
|
getStats(): Stats;
|
|
261
385
|
/** Apply one stat update and return the stat's new value. */
|
|
@@ -278,7 +402,12 @@ declare class LocalStore {
|
|
|
278
402
|
setEvents(events: readonly BufferedEvent[]): void;
|
|
279
403
|
/** Buffer one event (capped; heartbeats are dropped first). */
|
|
280
404
|
bufferEvent(type: string): void;
|
|
281
|
-
/**
|
|
405
|
+
/**
|
|
406
|
+
* Fan a `/me/snapshot` reply out across every game's cache keys. It lists
|
|
407
|
+
* every save slot of every game the player has played, so each game's
|
|
408
|
+
* slots on the hub become known (and this game's are all empty when it
|
|
409
|
+
* isn't listed).
|
|
410
|
+
*/
|
|
282
411
|
hydrate(snapshot: SnapshotResponse): void;
|
|
283
412
|
}
|
|
284
413
|
//#endregion
|
|
@@ -585,6 +714,43 @@ declare class LocalResumeStore {
|
|
|
585
714
|
all(): Map<string, LocalResume>;
|
|
586
715
|
}
|
|
587
716
|
//#endregion
|
|
717
|
+
//#region src/core/saved/local-saved.d.ts
|
|
718
|
+
/** A daily challenge as this device last saw it. */
|
|
719
|
+
interface LocalDaily {
|
|
720
|
+
readonly id: string;
|
|
721
|
+
readonly game: string;
|
|
722
|
+
readonly day: string;
|
|
723
|
+
readonly seed: number;
|
|
724
|
+
/** `active` in progress; `finished` (won) or `discarded`, kept until the hub has it. */
|
|
725
|
+
readonly status: 'active' | 'finished' | 'discarded';
|
|
726
|
+
readonly userId: number | null;
|
|
727
|
+
/** When it last changed here, epoch ms. */
|
|
728
|
+
readonly at: number;
|
|
729
|
+
readonly label: string;
|
|
730
|
+
readonly fraction: number | null;
|
|
731
|
+
readonly title: string | null;
|
|
732
|
+
readonly version: number;
|
|
733
|
+
readonly gameTitle: string;
|
|
734
|
+
/** The state the game last saved, `null` before its first save. */
|
|
735
|
+
readonly state: Json;
|
|
736
|
+
readonly isSynced: boolean;
|
|
737
|
+
}
|
|
738
|
+
/** The device copies of daily challenges. */
|
|
739
|
+
declare class LocalDailyStore {
|
|
740
|
+
private readonly store;
|
|
741
|
+
constructor(store: KeyValueStore);
|
|
742
|
+
/** The copy of `game`'s `day`, or `null`. */
|
|
743
|
+
read(game: string, day: string): LocalDaily | null;
|
|
744
|
+
/** Store a copy; answers whether it stuck (a full storage refuses a large state). */
|
|
745
|
+
write(copy: LocalDaily): boolean;
|
|
746
|
+
/** Forget a copy. */
|
|
747
|
+
remove(game: string, day: string): void;
|
|
748
|
+
/** The hub has the change made at `at` (and calls the instance `id`): mark it synced; a closed copy is forgotten. */
|
|
749
|
+
markSynced(game: string, day: string, at: number, id?: string): void;
|
|
750
|
+
/** Every copy of `userId`'s, any game. */
|
|
751
|
+
all(userId: number | null): LocalDaily[];
|
|
752
|
+
}
|
|
753
|
+
//#endregion
|
|
588
754
|
//#region src/core/connection.d.ts
|
|
589
755
|
/** A queued op the hub refused during a sync (or that kept failing): dropped, with the reason. */
|
|
590
756
|
interface SyncConflict {
|
|
@@ -619,6 +785,8 @@ declare class HubConnection {
|
|
|
619
785
|
protected readonly outbox: Outbox;
|
|
620
786
|
/** The device copies of every game's resume slot (`hub.resume`). */
|
|
621
787
|
protected readonly resumeStore: LocalResumeStore;
|
|
788
|
+
/** The device copies of daily challenges in progress (every game's). */
|
|
789
|
+
protected readonly dailyStore: LocalDailyStore;
|
|
622
790
|
private readonly offlineMode;
|
|
623
791
|
private isReachable;
|
|
624
792
|
private runningSync;
|
|
@@ -717,6 +885,16 @@ interface ProfileUpdate<TData extends GamePayload = Json> {
|
|
|
717
885
|
}
|
|
718
886
|
/** Accounts, profile, saves, stats and leaderboards. */
|
|
719
887
|
declare class HubProgress extends HubConnection {
|
|
888
|
+
/** Who the page is signed in as, as the hub's events and this client's sign-ins tell it. */
|
|
889
|
+
protected readonly account: PageAccount;
|
|
890
|
+
/**
|
|
891
|
+
* Your user id, or `null` when nobody is signed in (also before an offline
|
|
892
|
+
* first visit has an account). Synchronous, and it follows the account as
|
|
893
|
+
* the hub changes it (a new guest's account made by the menu, sign-in,
|
|
894
|
+
* sign-out) with no `hub.me()` needed. Compare it with a seat's `userId`
|
|
895
|
+
* to find yours.
|
|
896
|
+
*/
|
|
897
|
+
userId(): number | null;
|
|
720
898
|
/** The current user (or `null`) and the games they have a profile in. */
|
|
721
899
|
me(): Promise<MeResponse>;
|
|
722
900
|
/**
|
|
@@ -740,6 +918,11 @@ declare class HubProgress extends HubConnection {
|
|
|
740
918
|
ok: true;
|
|
741
919
|
}>;
|
|
742
920
|
private signInLocally;
|
|
921
|
+
/** Remember who the hub signed in, so the cache's notes about the hub's copies are read for the right player. */
|
|
922
|
+
private signedIn;
|
|
923
|
+
/** The cache and the page (`hub.userId()`, `hub.avatar`) learn who is signed in. */
|
|
924
|
+
private remember;
|
|
925
|
+
private signedOut;
|
|
743
926
|
/** This game's profile for the current user, or `profile: null`. `TData` is the game's own data type. */
|
|
744
927
|
getProfile<TData = Json>(): Promise<{
|
|
745
928
|
profile: Profile<TData> | null;
|
|
@@ -752,10 +935,18 @@ declare class HubProgress extends HubConnection {
|
|
|
752
935
|
listSaves(): Promise<{
|
|
753
936
|
saves: SaveMeta[];
|
|
754
937
|
}>;
|
|
755
|
-
/**
|
|
938
|
+
/**
|
|
939
|
+
* One slot's contents, or `save: null` when the slot is empty. `TData` is
|
|
940
|
+
* the game's own save type. Offline it answers from the device's copy, but
|
|
941
|
+
* only when the device knows the hub's copy of the slot; otherwise (a fresh
|
|
942
|
+
* device or cleared browser) it rejects with a {@link HubError} whose
|
|
943
|
+
* `code` is `save_unknown` (`isOffline` is `true`), never a false "empty".
|
|
944
|
+
*/
|
|
756
945
|
getSave<TData = Json>(slot: string): Promise<{
|
|
757
946
|
save: Save<TData> | null;
|
|
758
947
|
}>;
|
|
948
|
+
/** The device's copy of `slot`, when it can be trusted offline (see {@link getSave}). */
|
|
949
|
+
private offlineSave;
|
|
759
950
|
/** Create or overwrite a save slot. `saveData` is any JSON up to 64 KB. */
|
|
760
951
|
putSave<TData extends GamePayload = Json>(slot: string, saveData: TData, label?: string): Promise<{
|
|
761
952
|
ok: true;
|
|
@@ -971,8 +1162,8 @@ interface ResumeEntry {
|
|
|
971
1162
|
/** Saved on this device and not yet sent to the hub (offline, or the tab closed first). */
|
|
972
1163
|
readonly isLocalOnly: boolean;
|
|
973
1164
|
}
|
|
974
|
-
/** Why a save was ignored: the page is in a race
|
|
975
|
-
type ResumeBlocker = 'race' | 'daily' | 'room';
|
|
1165
|
+
/** Why a save was ignored: the page is in a race or an online room. (`'daily'` is no longer returned: a save during a daily goes to the day.) */
|
|
1166
|
+
type ResumeBlocker = 'race' | 'daily' | 'room' | 'turns';
|
|
976
1167
|
//#endregion
|
|
977
1168
|
//#region src/core/resume/hub-resume.d.ts
|
|
978
1169
|
/** How long saves must be quiet before the latest is sent, ms. */
|
|
@@ -990,6 +1181,8 @@ interface ResumeHost {
|
|
|
990
1181
|
gameTitle(): string;
|
|
991
1182
|
/** Why saving is off right now, or `null`. */
|
|
992
1183
|
blocker(): ResumeBlocker | null;
|
|
1184
|
+
/** The page's daily challenge while one is being played (saves go to the day instead of the run), else `null`. */
|
|
1185
|
+
daily?(): DailyRoute | null;
|
|
993
1186
|
/** Perform a resume op: at once when online with nothing waiting, else queued. */
|
|
994
1187
|
send(payload: ResumePayload): Promise<void>;
|
|
995
1188
|
/** This game's run on the hub, or `undefined` when the hub can't be reached. */
|
|
@@ -998,6 +1191,12 @@ interface ResumeHost {
|
|
|
998
1191
|
fetchList(): Promise<ResumeSummary[] | undefined>;
|
|
999
1192
|
/** Clear another game's run on the hub (the home page's discard); throws offline. */
|
|
1000
1193
|
clearOther(slug: string): Promise<void>;
|
|
1194
|
+
/** The run changed here (saved or cleared): `hub.saved` listeners hear it. */
|
|
1195
|
+
onChange?(): void;
|
|
1196
|
+
}
|
|
1197
|
+
/** Where a save goes during a daily challenge (`hub.daily`). */
|
|
1198
|
+
interface DailyRoute {
|
|
1199
|
+
save(input: ResumeSaveInput<GamePayload>): boolean;
|
|
1001
1200
|
}
|
|
1002
1201
|
/** `hub.resume`. */
|
|
1003
1202
|
declare class HubResume {
|
|
@@ -1018,14 +1217,17 @@ declare class HubResume {
|
|
|
1018
1217
|
/**
|
|
1019
1218
|
* Save the run (the latest save wins). Stored on the device at once; sent
|
|
1020
1219
|
* after {@link RESUME_DEBOUNCE_MS} of quiet, or when the page is hidden.
|
|
1021
|
-
* Returns `false` (and saves nothing) in a race
|
|
1022
|
-
*
|
|
1220
|
+
* Returns `false` (and saves nothing) in a race or an online room; during
|
|
1221
|
+
* a daily challenge the save goes to the day (`hub.daily.save`). Throws a
|
|
1222
|
+
* `HubError` 413 over 512 KB, 400 without a label.
|
|
1023
1223
|
*/
|
|
1024
1224
|
save<TState extends GamePayload>(run: ResumeSaveInput<TState>): boolean;
|
|
1025
1225
|
/** Send a waiting save now (the page does this itself when hidden or closed). */
|
|
1026
1226
|
flush(): Promise<void>;
|
|
1027
1227
|
/** Clear the run: call it when the run ends (won, lost or quit). Works offline. */
|
|
1028
1228
|
clear(): Promise<void>;
|
|
1229
|
+
/** Delete the game's saved run (never the day being played). */
|
|
1230
|
+
private clearRun;
|
|
1029
1231
|
/** The saved run with its progress and time, or `null`. The newer of the device's copy and the hub's wins. */
|
|
1030
1232
|
get<TState = GamePayload>(options?: ResumeLoadOptions): Promise<ResumeRun<TState> | null>;
|
|
1031
1233
|
/** The saved state, or `null` (see {@link get} for the version rule). */
|
|
@@ -1042,6 +1244,282 @@ declare class HubResume {
|
|
|
1042
1244
|
private listenToPage;
|
|
1043
1245
|
}
|
|
1044
1246
|
//#endregion
|
|
1247
|
+
//#region src/core/saved/saved-list.d.ts
|
|
1248
|
+
/** What the device holds, for one player. */
|
|
1249
|
+
interface DeviceCopies {
|
|
1250
|
+
/** Run copies by slug (`hub.resume`). */
|
|
1251
|
+
readonly runs: ReadonlyMap<string, LocalResume>;
|
|
1252
|
+
/** Daily copies (`hub.daily`), any game. */
|
|
1253
|
+
readonly dailies: readonly LocalDaily[];
|
|
1254
|
+
}
|
|
1255
|
+
//#endregion
|
|
1256
|
+
//#region src/core/saved/hub-saved.d.ts
|
|
1257
|
+
/** How long changes must be quiet before `on('change')` listeners hear the new list, ms. */
|
|
1258
|
+
declare const SAVED_CHANGE_QUIET_MS = 300;
|
|
1259
|
+
/** What `hub.saved` needs from its client. */
|
|
1260
|
+
interface SavedHost {
|
|
1261
|
+
/** This game's slug; `null` on the home page. */
|
|
1262
|
+
readonly slug: string | null;
|
|
1263
|
+
/** The hub's list (one game, or all), or `undefined` when it can't be reached. */
|
|
1264
|
+
fetchList(game: string | null): Promise<readonly SavedEntry[] | undefined>;
|
|
1265
|
+
/** What this device holds for the signed-in player. */
|
|
1266
|
+
deviceCopies(): DeviceCopies;
|
|
1267
|
+
/** Discard a daily or run (works offline where it can). */
|
|
1268
|
+
discard(entry: SavedEntry): Promise<void>;
|
|
1269
|
+
/** Go to a URL (`location.assign`). */
|
|
1270
|
+
navigate(url: string): void;
|
|
1271
|
+
}
|
|
1272
|
+
/** A change listener: this game's games in progress. */
|
|
1273
|
+
type SavedChangeListener = (games: SavedEntry[]) => void;
|
|
1274
|
+
/** An `onOpen` handler: switch to this instance without a reload. */
|
|
1275
|
+
type SavedOpenHandler = (instance: SavedEntry) => void | Promise<void>;
|
|
1276
|
+
/** The detail of {@link SAVED_OPEN_EVENT}. */
|
|
1277
|
+
interface SavedOpenDetail {
|
|
1278
|
+
readonly entry: SavedEntry;
|
|
1279
|
+
}
|
|
1280
|
+
/** `hub.saved`. */
|
|
1281
|
+
declare class HubSaved {
|
|
1282
|
+
private readonly host;
|
|
1283
|
+
/** Each handler with the kinds it takes (every kind when `undefined`). */
|
|
1284
|
+
private readonly openHandlers;
|
|
1285
|
+
private readonly changeListeners;
|
|
1286
|
+
private isListeningForOpen;
|
|
1287
|
+
private isListeningForChange;
|
|
1288
|
+
private changeTimer;
|
|
1289
|
+
constructor(host: SavedHost);
|
|
1290
|
+
/**
|
|
1291
|
+
* The instance this page was opened for (`?hub_open=<id>&hub_kind=<kind>`,
|
|
1292
|
+
* taken out of the address bar), or `null`. Synchronous: read it before
|
|
1293
|
+
* routing or drawing a title screen.
|
|
1294
|
+
*/
|
|
1295
|
+
get opened(): SavedOpened | null;
|
|
1296
|
+
/** This game's games in progress: online games waiting on the player first, then the newest. Works offline. */
|
|
1297
|
+
list(options?: SavedListOptions): Promise<SavedEntry[]>;
|
|
1298
|
+
/** Every game's games in progress (the home page and the menu). Online, plus this device's copies. */
|
|
1299
|
+
listAll(): Promise<SavedEntry[]>;
|
|
1300
|
+
/** The badge counts across every game. */
|
|
1301
|
+
counts(): Promise<SavedCounts>;
|
|
1302
|
+
/**
|
|
1303
|
+
* Switch to an instance of THIS game when the player picks it from the
|
|
1304
|
+
* hub menu, without a reload. Without a handler the page reloads with
|
|
1305
|
+
* `?hub_open=<id>`. With `{ kinds }` the handler takes only those kinds;
|
|
1306
|
+
* the others still reload the page (with `?hub_resume=1` or `?daily=` for
|
|
1307
|
+
* a saved run or a daily). Returns a function that removes the handler.
|
|
1308
|
+
*/
|
|
1309
|
+
onOpen(handler: SavedOpenHandler, options?: SavedListOptions): () => void;
|
|
1310
|
+
/** Open an instance: in this game through `onOpen` (or a reload), in another game by going there. */
|
|
1311
|
+
open(id: string): Promise<void>;
|
|
1312
|
+
/** Open an entry already in hand (the hub's lists). */
|
|
1313
|
+
openEntry(entry: SavedEntry): void;
|
|
1314
|
+
/**
|
|
1315
|
+
* Discard a daily challenge or a saved run (the caller asks first; the
|
|
1316
|
+
* hub's own lists ask for themselves). Online games are left with
|
|
1317
|
+
* `hub.turns`, never discarded.
|
|
1318
|
+
*/
|
|
1319
|
+
discard(id: string): Promise<void>;
|
|
1320
|
+
/** Hear when this game's list changes; returns a function that stops listening. */
|
|
1321
|
+
on(_eventName: 'change', listener: SavedChangeListener): () => void;
|
|
1322
|
+
/** Something of this game's changed (a save here, an event from the hub): tell the listeners, once per quiet spell. */
|
|
1323
|
+
changed(): void;
|
|
1324
|
+
private listenForOpen;
|
|
1325
|
+
private listenForChange;
|
|
1326
|
+
}
|
|
1327
|
+
//#endregion
|
|
1328
|
+
//#region src/core/turns/turn-game.d.ts
|
|
1329
|
+
/** The window event the social runtime fires for each `ev:turn`. */
|
|
1330
|
+
declare const TURN_EVENT = "hub:turn";
|
|
1331
|
+
/** The runtime's live connection (re)opened: anything sent while it was down is fetched again. */
|
|
1332
|
+
declare const TURN_RESYNC_EVENT = "hub:turn-resync";
|
|
1333
|
+
/** The window event the social runtime fires for each `ev:turn.chat`. */
|
|
1334
|
+
declare const TURN_CHAT_EVENT = "hub:turn-chat";
|
|
1335
|
+
/** How often a page without the live runtime looks for moves, ms. */
|
|
1336
|
+
declare const TURN_POLL_MS = 20000;
|
|
1337
|
+
/** A game's end: the winning seats, and optionally places and scores by seat. */
|
|
1338
|
+
type TurnOutcome = NonNullable<TurnGameView['outcome']>;
|
|
1339
|
+
/** One move as this seat saw it. */
|
|
1340
|
+
interface TurnMoveEvent<View, Ev> {
|
|
1341
|
+
readonly seq: number;
|
|
1342
|
+
readonly seat: number;
|
|
1343
|
+
/** The view after the move (for a replayed move, the view now). */
|
|
1344
|
+
readonly view: View;
|
|
1345
|
+
readonly events: readonly Ev[];
|
|
1346
|
+
}
|
|
1347
|
+
/** What a game's listeners hear. */
|
|
1348
|
+
interface TurnGameEvents<View, Ev> {
|
|
1349
|
+
move: TurnMoveEvent<View, Ev>;
|
|
1350
|
+
turn: TurnSummary;
|
|
1351
|
+
ended: {
|
|
1352
|
+
readonly outcome: TurnOutcome | null;
|
|
1353
|
+
readonly view: View;
|
|
1354
|
+
};
|
|
1355
|
+
chat: TurnChatLine;
|
|
1356
|
+
}
|
|
1357
|
+
/** What a game needs from its client: the REST calls, by name. */
|
|
1358
|
+
interface TurnGameHost {
|
|
1359
|
+
get(id: string): Promise<TurnGameView>;
|
|
1360
|
+
start(id: string): Promise<TurnGameView>;
|
|
1361
|
+
move(id: string, seq: number, move: Json): Promise<{
|
|
1362
|
+
game: TurnGameView;
|
|
1363
|
+
events: Json[];
|
|
1364
|
+
}>;
|
|
1365
|
+
history(id: string, since: number): Promise<{
|
|
1366
|
+
seq: number;
|
|
1367
|
+
seat: number;
|
|
1368
|
+
events: Json[];
|
|
1369
|
+
}[]>;
|
|
1370
|
+
leave(id: string): Promise<void>;
|
|
1371
|
+
nudge(id: string): Promise<void>;
|
|
1372
|
+
setNotify(id: string, mode: 'on' | 'off'): Promise<void>;
|
|
1373
|
+
rematch(id: string): Promise<TurnGameView>;
|
|
1374
|
+
invite(id: string, userIds: readonly number[]): Promise<TurnGameView>;
|
|
1375
|
+
share(id: string, share: {
|
|
1376
|
+
readonly link?: boolean;
|
|
1377
|
+
readonly public?: boolean;
|
|
1378
|
+
}): Promise<TurnGameView>;
|
|
1379
|
+
autoPlay(id: string): Promise<TurnGameView>;
|
|
1380
|
+
chat(id: string, send: {
|
|
1381
|
+
readonly text?: string;
|
|
1382
|
+
readonly quick?: string;
|
|
1383
|
+
}): Promise<TurnChatLine>;
|
|
1384
|
+
/** The page has a game open (saves of a run are off while it does). */
|
|
1385
|
+
opened(game: object): void;
|
|
1386
|
+
closed(game: object): void;
|
|
1387
|
+
/** Whether the live runtime is on the page (else the game polls). */
|
|
1388
|
+
isLive(): boolean;
|
|
1389
|
+
}
|
|
1390
|
+
type Listener<Payload> = (payload: Payload) => void;
|
|
1391
|
+
/** One online game. `View`, `Move` and `Ev` (its events) are the game's own JSON types from its rules. */
|
|
1392
|
+
declare class TurnGame<View = GamePayload, Move extends GamePayload = GamePayload, Ev = GamePayload> {
|
|
1393
|
+
readonly id: string;
|
|
1394
|
+
private state;
|
|
1395
|
+
private readonly host;
|
|
1396
|
+
private readonly listeners;
|
|
1397
|
+
private readonly stopListening;
|
|
1398
|
+
private isClosed;
|
|
1399
|
+
private catchingUp;
|
|
1400
|
+
/** The move count this page's own move in flight will make (its live echo is not another player's move). */
|
|
1401
|
+
private ownSeq;
|
|
1402
|
+
constructor(host: TurnGameHost, initial: TurnGameView);
|
|
1403
|
+
/** Whose move it is, the seats and the deadline. */
|
|
1404
|
+
get summary(): TurnSummary;
|
|
1405
|
+
/** This seat's view, from the game's rules (`null` before the game starts). */
|
|
1406
|
+
get view(): View;
|
|
1407
|
+
/** This player's seat, or `null` (they left). */
|
|
1408
|
+
get mySeat(): number | null;
|
|
1409
|
+
/** The end, once the game is over. */
|
|
1410
|
+
get outcome(): TurnOutcome | null;
|
|
1411
|
+
/** The last chat lines, oldest first. */
|
|
1412
|
+
get chat(): readonly TurnChatLine[];
|
|
1413
|
+
/** `on`: friends may type (moderated); `quick`: quick-chat and emotes only; `off`. */
|
|
1414
|
+
get chatMode(): TurnGameView['chatMode'];
|
|
1415
|
+
/** The link others can take a seat with (the creator's, while seats are open), else `null`. */
|
|
1416
|
+
get link(): string | null;
|
|
1417
|
+
/** Creator: start the game (empty seats go to the computer when the game allows). */
|
|
1418
|
+
start(): Promise<void>;
|
|
1419
|
+
/**
|
|
1420
|
+
* Make a move. Rejects with a `HubError`: 403 `not_your_turn`, 409
|
|
1421
|
+
* `stale` (the game moved on: the view is refreshed first), 422 `illegal`
|
|
1422
|
+
* with the rules' own code in `rule`.
|
|
1423
|
+
*/
|
|
1424
|
+
move(move: Move): Promise<{
|
|
1425
|
+
seq: number;
|
|
1426
|
+
view: View;
|
|
1427
|
+
events: Ev[];
|
|
1428
|
+
}>;
|
|
1429
|
+
/** The moves after `sinceSeq`, with their events as this seat may see them ("what happened while you were away"). */
|
|
1430
|
+
history(sinceSeq: number): Promise<{
|
|
1431
|
+
seq: number;
|
|
1432
|
+
seat: number;
|
|
1433
|
+
events: Ev[];
|
|
1434
|
+
}[]>;
|
|
1435
|
+
/** Leave: the computer plays the seat (or, without bots, the others win). The player can't come back. */
|
|
1436
|
+
leave(): Promise<void>;
|
|
1437
|
+
/** Remind whoever must move (once a day). */
|
|
1438
|
+
nudge(): Promise<void>;
|
|
1439
|
+
/** This game's "your turn" alerts. */
|
|
1440
|
+
setNotify(mode: 'on' | 'off'): Promise<void>;
|
|
1441
|
+
/** A finished game: a new one with the same friends (they get an invite). */
|
|
1442
|
+
rematch(): Promise<TurnGame<View, Move, Ev>>;
|
|
1443
|
+
/** Creator, before the start: add an invite link (`link: true`, then read `link`) or list the open seats for anyone (`public`). */
|
|
1444
|
+
share(share: {
|
|
1445
|
+
readonly link?: boolean;
|
|
1446
|
+
readonly public?: boolean;
|
|
1447
|
+
}): Promise<void>;
|
|
1448
|
+
/** Invite friends to free seats (before the start). */
|
|
1449
|
+
invite(userIds: readonly number[]): Promise<void>;
|
|
1450
|
+
/** The turn's deadline passed (or its player is suspended): let the computer play it. */
|
|
1451
|
+
letComputerPlay(): Promise<void>;
|
|
1452
|
+
/** Say something: `{ text }` between friends (moderated), `{ quick }` (a quick-chat phrase id) with anyone. */
|
|
1453
|
+
say(send: {
|
|
1454
|
+
readonly text?: string;
|
|
1455
|
+
readonly quick?: string;
|
|
1456
|
+
}): Promise<TurnChatLine>;
|
|
1457
|
+
/** Fetch the game again, and replay moves missed since the last one this page saw. */
|
|
1458
|
+
refresh(): Promise<void>;
|
|
1459
|
+
/** Hear moves, turn changes, the end and chat; returns a function that stops listening. */
|
|
1460
|
+
on<K extends keyof TurnGameEvents<View, Ev>>(eventName: K, listener: Listener<TurnGameEvents<View, Ev>[K]>): () => void;
|
|
1461
|
+
/** Stop live updates for this page (the game itself goes on). */
|
|
1462
|
+
close(): void;
|
|
1463
|
+
/** Take a fresh answer from the hub; fire `turn` and `ended` when they changed. */
|
|
1464
|
+
private update;
|
|
1465
|
+
private emit;
|
|
1466
|
+
/** A live `hub:turn` for this game: a move (or a missed run of them), or another change. */
|
|
1467
|
+
private onLive;
|
|
1468
|
+
/** Replay what was missed (one catch-up at a time). */
|
|
1469
|
+
private catchUp;
|
|
1470
|
+
private listen;
|
|
1471
|
+
}
|
|
1472
|
+
//#endregion
|
|
1473
|
+
//#region src/core/turns/hub-turns.d.ts
|
|
1474
|
+
/** The query parameter an invite link carries (`/<slug>/?hub_turn_link=<key>`); the client strips it. */
|
|
1475
|
+
declare const TURN_LINK_PARAM = "hub_turn_link";
|
|
1476
|
+
/** How to make a game. */
|
|
1477
|
+
interface TurnCreateOptions {
|
|
1478
|
+
readonly mode?: string;
|
|
1479
|
+
/** The game's own setup choices (at most 2 KB of JSON). */
|
|
1480
|
+
readonly options?: GamePayload;
|
|
1481
|
+
/** Friends to invite (their seats are held). */
|
|
1482
|
+
readonly invite?: readonly number[];
|
|
1483
|
+
/** Make a link others can take a seat with (`game.link`). */
|
|
1484
|
+
readonly link?: boolean;
|
|
1485
|
+
/** List the open seats in Play online for anyone to take. */
|
|
1486
|
+
readonly public?: boolean;
|
|
1487
|
+
/** Seats in all (within `game.turns.players`). */
|
|
1488
|
+
readonly seats?: number;
|
|
1489
|
+
/** Let the computer fill seats nobody took (default true, when the game has bots). */
|
|
1490
|
+
readonly bots?: boolean;
|
|
1491
|
+
/** How long a turn may wait before the others may let the computer play it (default none). */
|
|
1492
|
+
readonly deadline?: TurnDeadline;
|
|
1493
|
+
/** Start by itself once every seat is taken (the creator needn't come back). */
|
|
1494
|
+
readonly autoStart?: boolean;
|
|
1495
|
+
}
|
|
1496
|
+
/** What `hub.turns` needs from its client. */
|
|
1497
|
+
interface TurnsHost extends TurnGameHost {
|
|
1498
|
+
readonly slug: string | null;
|
|
1499
|
+
create(body: CreateTurnGame): ReturnType<TurnGameHost['get']>;
|
|
1500
|
+
join(id: string): ReturnType<TurnGameHost['get']>;
|
|
1501
|
+
joinByLink(key: string): ReturnType<TurnGameHost['get']>;
|
|
1502
|
+
listOpen(game: string | null): Promise<OpenTurnGame[]>;
|
|
1503
|
+
list(): Promise<SavedEntry[]>;
|
|
1504
|
+
}
|
|
1505
|
+
/** `hub.turns`. */
|
|
1506
|
+
declare class HubTurns {
|
|
1507
|
+
private readonly host;
|
|
1508
|
+
constructor(host: TurnsHost);
|
|
1509
|
+
/** The invite link key this page was opened with (`?hub_turn_link=`), taken out of the address bar; `null` when none. Synchronous. */
|
|
1510
|
+
get link(): string | null;
|
|
1511
|
+
/** Make a game in this page's game (its lobby): the player takes the first seat. */
|
|
1512
|
+
create<View = GamePayload, Move extends GamePayload = GamePayload, Event = GamePayload>(options?: TurnCreateOptions): Promise<TurnGame<View, Move, Event>>;
|
|
1513
|
+
/** Take a seat: by the game's id (an invite, an open seat) or by an invite link's key. */
|
|
1514
|
+
join<View = GamePayload, Move extends GamePayload = GamePayload, Event = GamePayload>(idOrLinkKey: string): Promise<TurnGame<View, Move, Event>>;
|
|
1515
|
+
/** Open a game the player sits in (from `hub.saved.opened`, the Continue list, an invite). */
|
|
1516
|
+
open<View = GamePayload, Move extends GamePayload = GamePayload, Event = GamePayload>(id: string): Promise<TurnGame<View, Move, Event>>;
|
|
1517
|
+
/** This game's online games the player sits in (the same rows as `hub.saved.list({ kinds: ['turns'] })`). */
|
|
1518
|
+
list(): Promise<SavedEntry[]>;
|
|
1519
|
+
/** Open-seat games of this game anyone may join (none across a block). */
|
|
1520
|
+
openLobbies(): Promise<OpenTurnGame[]>;
|
|
1521
|
+
}
|
|
1522
|
+
//#endregion
|
|
1045
1523
|
//#region src/core/version/hub-version.d.ts
|
|
1046
1524
|
/** How a hub regards a client version. */
|
|
1047
1525
|
type ClientSupport =
|
|
@@ -1060,6 +1538,12 @@ declare class Hub extends HubEconomy {
|
|
|
1060
1538
|
/** This client's package version (sent as `x-hub-client`). */
|
|
1061
1539
|
readonly clientVersion: string;
|
|
1062
1540
|
private resumeApi;
|
|
1541
|
+
private avatarApi;
|
|
1542
|
+
private savedApi;
|
|
1543
|
+
private dailySavesApi;
|
|
1544
|
+
private turnsApi;
|
|
1545
|
+
/** The online games open on this page (a run isn't saved while one is). */
|
|
1546
|
+
private readonly openTurnGames;
|
|
1063
1547
|
/**
|
|
1064
1548
|
* The hub's version and the client versions it supports (`GET /_api/version`),
|
|
1065
1549
|
* read once per page. `null` for a hub from before versioning.
|
|
@@ -1101,9 +1585,35 @@ declare class Hub extends HubEconomy {
|
|
|
1101
1585
|
* pick it up again (docs: "Resume saved games"). Needs `game.resumable: true`.
|
|
1102
1586
|
*/
|
|
1103
1587
|
get resume(): HubResume;
|
|
1588
|
+
/**
|
|
1589
|
+
* Players' avatars: `hub.avatar.mine()`, `of(userId)`, `from(seat)`,
|
|
1590
|
+
* `bot(seed)`, `on('change')`, `openDesigner()` and `load()` for the renderer
|
|
1591
|
+
* (docs: "Avatars"). No art or renderer until `load()`.
|
|
1592
|
+
*/
|
|
1593
|
+
get avatar(): HubAvatar;
|
|
1594
|
+
/**
|
|
1595
|
+
* Every game the player has in progress, of every kind: `hub.saved.list()`
|
|
1596
|
+
* for this game's "Continue" list, `opened` and `onOpen` to open the one
|
|
1597
|
+
* the player picked (docs: "Saved games").
|
|
1598
|
+
*/
|
|
1599
|
+
get saved(): HubSaved;
|
|
1600
|
+
/**
|
|
1601
|
+
* Online games played over minutes or days, run by the hub from the
|
|
1602
|
+
* game's rules module (`game.turns`): `hub.turns.create`, `join`, `open`
|
|
1603
|
+
* (docs/multiplayer.md "Turn games").
|
|
1604
|
+
*/
|
|
1605
|
+
get turns(): HubTurns;
|
|
1606
|
+
/** What `hub.turns` needs from this client: its REST calls. */
|
|
1607
|
+
private turnsHost;
|
|
1608
|
+
/** What `hub.saved` needs from this client. */
|
|
1609
|
+
private savedHost;
|
|
1610
|
+
/** Discard a daily or run: this game's run through `hub.resume` (works offline), others on the hub. */
|
|
1611
|
+
private discardSaved;
|
|
1104
1612
|
/** What `hub.resume` needs from this client. */
|
|
1105
1613
|
private resumeHost;
|
|
1106
|
-
/**
|
|
1614
|
+
/** This game's daily saves (device copies and their sends). */
|
|
1615
|
+
private dailySaves;
|
|
1616
|
+
/** What the daily system needs from this client: its REST calls, the device copies and window events. */
|
|
1107
1617
|
private dailyHost;
|
|
1108
1618
|
}
|
|
1109
1619
|
/** A ready-to-use client, with the slug and API base detected from the page. */
|
|
@@ -1119,12 +1629,18 @@ declare function createHub(options?: HubOptions): Hub;
|
|
|
1119
1629
|
declare const UNSUPPORTED_BY_HUB = "unsupported_by_hub";
|
|
1120
1630
|
/** The code the social runtime gives a call it could not send (no connection). */
|
|
1121
1631
|
declare const OFFLINE_CODE = "offline";
|
|
1632
|
+
/**
|
|
1633
|
+
* The code `getSave` rejects with when the hub can't be reached and this
|
|
1634
|
+
* device has no copy of the slot it can trust (a fresh device or cleared
|
|
1635
|
+
* browser): the slot may well hold a save, so it is not reported empty.
|
|
1636
|
+
*/
|
|
1637
|
+
declare const SAVE_UNKNOWN_CODE = "save_unknown";
|
|
1122
1638
|
/**
|
|
1123
1639
|
* A machine-readable error code: one of the contract's public codes
|
|
1124
1640
|
* (`content_rejected`, `rate_limited`, `suspended`, `claim_required`, ...),
|
|
1125
1641
|
* {@link UNSUPPORTED_BY_HUB}, or a code a newer hub added.
|
|
1126
1642
|
*/
|
|
1127
|
-
type HubErrorCode = ErrorCode | typeof UNSUPPORTED_BY_HUB | typeof OFFLINE_CODE | (string & Record<never, never>);
|
|
1643
|
+
type HubErrorCode = ErrorCode | typeof UNSUPPORTED_BY_HUB | typeof OFFLINE_CODE | typeof SAVE_UNKNOWN_CODE | (string & Record<never, never>);
|
|
1128
1644
|
/** The machine-readable extras the hub attaches to an error body. */
|
|
1129
1645
|
interface HubErrorDetails {
|
|
1130
1646
|
/** A stable error code, for code to branch on. */
|
|
@@ -1137,6 +1653,8 @@ interface HubErrorDetails {
|
|
|
1137
1653
|
readonly retryAfterMs?: number | undefined;
|
|
1138
1654
|
/** When a suspension or mute ends (epoch ms). */
|
|
1139
1655
|
readonly until?: number | undefined;
|
|
1656
|
+
/** An online game's rules refused a move (`illegal`): the rules' own short code. */
|
|
1657
|
+
readonly rule?: string | undefined;
|
|
1140
1658
|
}
|
|
1141
1659
|
/**
|
|
1142
1660
|
* Thrown by every hub call that fails. `status` is the HTTP status when the
|
|
@@ -1157,6 +1675,8 @@ declare class HubError extends Error {
|
|
|
1157
1675
|
readonly retryAfterMs: number | undefined;
|
|
1158
1676
|
/** When a suspension or mute ends (epoch ms). */
|
|
1159
1677
|
readonly until: number | undefined;
|
|
1678
|
+
/** An online game's rules refused a move (`code` is `illegal`): the rules' own short code, such as `cell_taken`. */
|
|
1679
|
+
readonly rule: string | undefined;
|
|
1160
1680
|
/** An error with a player-safe `message`, the HTTP `status` (if any) and the body's extras. */
|
|
1161
1681
|
constructor(message: string, status?: number, details?: HubErrorDetails);
|
|
1162
1682
|
/** `true` when the failure was a network or transport error, not an HTTP status. */
|
|
@@ -1179,7 +1699,7 @@ declare class ContentRejectedError extends HubError {
|
|
|
1179
1699
|
//#endregion
|
|
1180
1700
|
//#region src/core/version/client-version.gen.d.ts
|
|
1181
1701
|
/** This client's package version, sent as `x-hub-client` on REST calls and `client` in `hello`. */
|
|
1182
|
-
declare const HUB_CLIENT_VERSION = "2.0.0-next.
|
|
1702
|
+
declare const HUB_CLIENT_VERSION = "2.0.0-next.6";
|
|
1183
1703
|
//#endregion
|
|
1184
|
-
export {
|
|
1704
|
+
export { OfflineApi as $, SavedChangeListener as A, MeResponse as At, ResumeRun as B, SubmitScoreResult as Bt, TURN_RESYNC_EVENT as C, HubOptions as Ct, TurnOutcome as D, Json$1 as Dt, TurnMoveEvent as E, InventorySnapshot as Et, RESUME_MAX_STATE_BYTES as F, SaveMeta as Ft, TradeId as G, AvatarHost as Gt, HubMenuControl as H, EndpointFields as Ht, ResumeBlocker as I, SnapshotResponse as It, AuthResponse as J, CarriesLook as Jt, TradeListOptions as K, AvatarModule as Kt, ResumeEntry as L, SortDir$1 as Lt, SavedOpenHandler as M, Profile as Mt, HubResume as N, ProfileSummary as Nt, HubSaved as O, LeaderboardEntry as Ot, RESUME_DEBOUNCE_MS as P, Save as Pt, SyncResult as Q, ResumeLoadOptions as R, Stats$1 as Rt, TURN_POLL_MS as S, GlobalAnalytics as St, TurnGameEvents as T, Inventory$1 as Tt, GrantBundle as U, EndpointName as Ut, ResumeSaveInput as V, User as Vt, TradeBundle as W, EndpointReply as Wt, StatResult as X, ProfileUpdate as Y, SyncConflict as Z, HubTurns as _, BoardWithTop as _t, HUB_CLIENT_VERSION as a, OUTBOX_MAX_CHARS as at, TURN_CHAT_EVENT as b, GameLeaderboards as bt, HubErrorCode as c, OfflineKindDefinition as ct, SAVE_UNKNOWN_CODE as d, ProfilePatch as dt, OUTBOX_FULL_CODE as et, UNSUPPORTED_BY_HUB as f, QueueOp as ft, ClientSupport as g, Board$1 as gt, hub as h, BufferedEvent as ht, TurnGameView$1 as i, OfflineOp as it, SavedOpenDetail as j, Metrics$1 as jt, SAVED_CHANGE_QUIET_MS as k, LeaderboardResult as kt, HubErrorDetails as l, ReplayContext as lt, createHub as m, QueuedScoreOptions as mt, TurnChatLine$1 as n, OfflineEventName as nt, ContentRejectedError as o, OUTBOX_MAX_ENTRIES as ot, Hub as p, QueueOpInput as pt, TradeNoteOptions as q, HubAvatar as qt, TurnDeadline$1 as r, OfflineListener as rt, HubError as s, OfflineHandler as st, OpenTurnGame$1 as t, OfflineEventDetails as tt, OfflineError as u, CLIENT_VERSION_HEADER as ut, TURN_LINK_PARAM as v, GameAnalytics as vt, TurnGame as w, HubStatus as wt, TURN_EVENT as x, GameRecords as xt, TurnCreateOptions as y, GameInfo$1 as yt, ResumeProgress as z, SubmitScoreOptions as zt };
|
|
1185
1705
|
//# sourceMappingURL=index.d.ts.map
|