@diffenderfer-games/hub 0.0.0-stage → 2.0.0-next.1
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 +9 -0
- package/LICENSE +21 -0
- package/README.md +191 -3
- package/dist/auto.d.ts +36 -0
- package/dist/auto.d.ts.map +1 -0
- package/dist/auto.js +27 -0
- package/dist/auto.js.map +1 -0
- package/dist/daily.d.ts +2 -0
- package/dist/daily.js +1 -0
- package/dist/doctor/cli.mjs +268 -0
- package/dist/doctor/cli.mjs.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +6 -0
- package/dist/input.d.ts +2 -0
- package/dist/input.js +3 -0
- package/dist/mp.d.ts +4 -0
- package/dist/mp.js +1 -0
- package/dist/race.d.ts +4 -0
- package/dist/race.js +1 -0
- package/dist/rooms.d.ts +4 -0
- package/dist/rooms.js +1 -0
- package/dist/shared/bridge.js +209 -0
- package/dist/shared/bridge.js.map +1 -0
- package/dist/shared/client-version.gen.js +7 -0
- package/dist/shared/client-version.gen.js.map +1 -0
- package/dist/shared/daily.d.ts +123 -0
- package/dist/shared/daily.d.ts.map +1 -0
- package/dist/shared/daily.js +191 -0
- package/dist/shared/daily.js.map +1 -0
- package/dist/shared/dom.js +48 -0
- package/dist/shared/dom.js.map +1 -0
- package/dist/shared/globals.js +102 -0
- package/dist/shared/globals.js.map +1 -0
- package/dist/shared/index.d.ts +706 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/input.d.ts +730 -0
- package/dist/shared/input.d.ts.map +1 -0
- package/dist/shared/input.js +2718 -0
- package/dist/shared/input.js.map +1 -0
- package/dist/shared/latest-state.js +17 -0
- package/dist/shared/latest-state.js.map +1 -0
- package/dist/shared/mp.d.ts +9 -0
- package/dist/shared/mp.d.ts.map +1 -0
- package/dist/shared/mp.js +30 -0
- package/dist/shared/mp.js.map +1 -0
- package/dist/shared/multiplayer-types.d.ts +47 -0
- package/dist/shared/multiplayer-types.d.ts.map +1 -0
- package/dist/shared/page-stack.js +207 -0
- package/dist/shared/page-stack.js.map +1 -0
- package/dist/shared/race-types.d.ts +126 -0
- package/dist/shared/race-types.d.ts.map +1 -0
- package/dist/shared/race.d.ts +9 -0
- package/dist/shared/race.d.ts.map +1 -0
- package/dist/shared/race.js +53 -0
- package/dist/shared/race.js.map +1 -0
- package/dist/shared/room-types.d.ts +125 -0
- package/dist/shared/room-types.d.ts.map +1 -0
- package/dist/shared/rooms.d.ts +9 -0
- package/dist/shared/rooms.d.ts.map +1 -0
- package/dist/shared/rooms.js +62 -0
- package/dist/shared/rooms.js.map +1 -0
- package/dist/shared/runtime-opener.js +84 -0
- package/dist/shared/runtime-opener.js.map +1 -0
- package/dist/shared/social.d.ts +148 -0
- package/dist/shared/social.d.ts.map +1 -0
- package/dist/shared/social.js +73 -0
- package/dist/shared/social.js.map +1 -0
- package/dist/shared/src.js +2164 -0
- package/dist/shared/src.js.map +1 -0
- package/dist/shared/wire-types.d.ts +51 -0
- package/dist/shared/wire-types.d.ts.map +1 -0
- package/dist/social.d.ts +6 -0
- package/dist/social.js +3 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.js +0 -0
- package/package.json +89 -6
- package/src/auto.ts +39 -0
- package/src/core/connection.ts +299 -0
- package/src/core/errors.ts +147 -0
- package/src/core/game-data.ts +38 -0
- package/src/core/hub-economy.ts +179 -0
- package/src/core/hub-progress.ts +205 -0
- package/src/core/hub.ts +131 -0
- package/src/core/menu-control.ts +61 -0
- package/src/core/offline/events.ts +50 -0
- package/src/core/offline/favorites.ts +21 -0
- package/src/core/offline/local-store.ts +261 -0
- package/src/core/offline/queue.ts +171 -0
- package/src/core/page.ts +74 -0
- package/src/core/rest/endpoint-types.ts +22 -0
- package/src/core/rest/rest-client.ts +152 -0
- package/src/core/rest/routes.gen.ts +90 -0
- package/src/core/storage/json-guards.ts +74 -0
- package/src/core/storage/key-value.ts +66 -0
- package/src/core/ticket.ts +43 -0
- package/src/core/types.ts +134 -0
- package/src/core/version/client-version.gen.ts +3 -0
- package/src/core/version/hub-version.ts +62 -0
- package/src/core/version/semver.ts +97 -0
- package/src/daily/daily-system.ts +161 -0
- package/src/daily/page-daily.ts +36 -0
- package/src/daily/types.ts +67 -0
- package/src/daily.ts +10 -0
- package/src/doctor/checks.ts +78 -0
- package/src/doctor/cli.ts +98 -0
- package/src/doctor/hub-version-fetch.ts +43 -0
- package/src/doctor/tsconfig.json +12 -0
- package/src/globals.ts +115 -0
- package/src/index.ts +50 -0
- package/src/input/device-state.ts +146 -0
- package/src/input/edges.ts +55 -0
- package/src/input/gamepad.ts +61 -0
- package/src/input/input-events.ts +32 -0
- package/src/input/input-registry.ts +164 -0
- package/src/input/input-system.ts +393 -0
- package/src/input/legacy-controls.ts +64 -0
- package/src/input/nav-state.ts +191 -0
- package/src/input/navigator.ts +171 -0
- package/src/input/on-screen-controls.ts +101 -0
- package/src/input/page-control.ts +43 -0
- package/src/input/page-input.ts +193 -0
- package/src/input/player-remaps.ts +77 -0
- package/src/input/source-values.ts +116 -0
- package/src/input/spatial.ts +47 -0
- package/src/input/types.ts +331 -0
- package/src/input/zero-config.ts +177 -0
- package/src/input.ts +22 -0
- package/src/mp.ts +10 -0
- package/src/overlay/controls-panel.ts +163 -0
- package/src/overlay/dom.ts +46 -0
- package/src/overlay/layout-clusters.ts +162 -0
- package/src/overlay/layout-geometry.ts +136 -0
- package/src/overlay/layout.ts +203 -0
- package/src/overlay/listener-scope.ts +23 -0
- package/src/overlay/on-screen-keyboard.ts +137 -0
- package/src/overlay/overlay.ts +208 -0
- package/src/overlay/styles.ts +54 -0
- package/src/overlay/virtual-controls.ts +262 -0
- package/src/race.ts +10 -0
- package/src/realtime/bridge.ts +121 -0
- package/src/realtime/cross-bundle.ts +29 -0
- package/src/realtime/fallback-notice.ts +48 -0
- package/src/realtime/hub-link.ts +65 -0
- package/src/realtime/latest-state.ts +33 -0
- package/src/realtime/multiplayer-forwarder.ts +28 -0
- package/src/realtime/multiplayer-types.ts +52 -0
- package/src/realtime/page-runtime.ts +60 -0
- package/src/realtime/race-forwarder.ts +59 -0
- package/src/realtime/race-types.ts +132 -0
- package/src/realtime/room-types.ts +125 -0
- package/src/realtime/rooms-forwarder.ts +79 -0
- package/src/realtime/runtime-api.ts +49 -0
- package/src/realtime/runtime-opener.ts +61 -0
- package/src/realtime/social-forwarder.ts +72 -0
- package/src/realtime/social-types.ts +78 -0
- package/src/realtime/types.ts +53 -0
- package/src/realtime/wire-types.ts +72 -0
- package/src/rooms.ts +10 -0
- package/src/social.ts +18 -0
- package/src/types.ts +13 -0
- package/src/uistack/page-stack.ts +45 -0
- package/src/uistack/play-suspension.ts +82 -0
- package/src/uistack/types.ts +76 -0
- package/src/uistack/ui-stack.ts +144 -0
|
@@ -0,0 +1,706 @@
|
|
|
1
|
+
import { s as DailySystem } from "./daily.js";
|
|
2
|
+
import { n as getUiStack, w as InputSystem } from "./input.js";
|
|
3
|
+
import { o as multiplayerForwarder } from "./mp.js";
|
|
4
|
+
import { f as raceForwarder } from "./race.js";
|
|
5
|
+
import { n as roomsForwarder } from "./rooms.js";
|
|
6
|
+
import { Q as socialForwarder, X as notifyForwarder, Z as presenceForwarder } from "./social.js";
|
|
7
|
+
import { Board, Board as Board$1, ErrorCode, GameInfo, GameLeaderboards, GameRecords, HubVersion, Inventory, Json, Json as Json$1, LeaderboardEntry, Metrics, Metrics as Metrics$1, PublicEndpoints, RejectReason, SessionUser, SortDir, SortDir as SortDir$1, Stats, Stats as Stats$1 } from "@diffenderfer-games/hub-contract";
|
|
8
|
+
import { CallReturn, ClientData } from "@ayepi/core/client";
|
|
9
|
+
//#region src/core/storage/key-value.d.ts
|
|
10
|
+
/**
|
|
11
|
+
* The string store behind the offline cache and queues: `localStorage` when
|
|
12
|
+
* the page has it, else an in-memory map (privacy mode, Node, tests). Every
|
|
13
|
+
* key keeps the v1 client's name, so a page upgraded from a vendored copy
|
|
14
|
+
* still reads the queue and cache that copy wrote.
|
|
15
|
+
*/
|
|
16
|
+
/** A string key-value store with `localStorage`'s semantics. */
|
|
17
|
+
interface KeyValueStore {
|
|
18
|
+
/** The stored text, or `null`. */
|
|
19
|
+
read(key: string): string | null;
|
|
20
|
+
/** Store text; a full or blocked storage is ignored. */
|
|
21
|
+
write(key: string, text: string): void;
|
|
22
|
+
/** Forget a key. */
|
|
23
|
+
remove(key: string): void;
|
|
24
|
+
/** Every stored key. */
|
|
25
|
+
keys(): string[];
|
|
26
|
+
}
|
|
27
|
+
//#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
|
+
//#region src/core/rest/endpoint-types.d.ts
|
|
33
|
+
/** The name of a public REST endpoint (`getCurrentUser`, `writeSave`, ...). */
|
|
34
|
+
type EndpointName = keyof PublicEndpoints;
|
|
35
|
+
/** One endpoint's request fields: path params, query and body merged into one object. */
|
|
36
|
+
type EndpointFields<K extends EndpointName> = ClientData<PublicEndpoints[K]>;
|
|
37
|
+
/**
|
|
38
|
+
* An endpoint that declares several success statuses comes back from ayepi's
|
|
39
|
+
* client as `{ status, data }`; this client always hands back the body.
|
|
40
|
+
*/
|
|
41
|
+
type ReplyBody<Reply> = Reply extends {
|
|
42
|
+
readonly status: number;
|
|
43
|
+
readonly data: infer Body;
|
|
44
|
+
} ? Body : Reply;
|
|
45
|
+
/** One endpoint's success reply body. */
|
|
46
|
+
type EndpointReply<K extends EndpointName> = ReplyBody<Awaited<CallReturn<PublicEndpoints[K]>>>;
|
|
47
|
+
//#endregion
|
|
48
|
+
//#region src/core/types.d.ts
|
|
49
|
+
/** The signed-in player. Offline (a locally stored user) only `id`, `username` and `guest` are known. */
|
|
50
|
+
type User = Pick<SessionUser, 'id' | 'username'> & Partial<Omit<SessionUser, 'id' | 'username'>>;
|
|
51
|
+
/** One game the player has a profile in. */
|
|
52
|
+
interface ProfileSummary {
|
|
53
|
+
/** The game's slug. */
|
|
54
|
+
readonly game: string;
|
|
55
|
+
/** The player's display name there, or `null`. */
|
|
56
|
+
readonly displayName: string | null;
|
|
57
|
+
}
|
|
58
|
+
/** What `hub.me()` answers: the current user (or `null`) and their game profiles. */
|
|
59
|
+
interface MeResponse {
|
|
60
|
+
/** The signed-in player, or `null`. */
|
|
61
|
+
readonly user: User | null;
|
|
62
|
+
/** The games the player has a profile in. */
|
|
63
|
+
readonly profiles: ProfileSummary[];
|
|
64
|
+
}
|
|
65
|
+
/** A player's profile in one game, with the game's own data typed as `TData`. */
|
|
66
|
+
interface Profile<TData = Json> {
|
|
67
|
+
/** The game's slug. */
|
|
68
|
+
readonly game: string;
|
|
69
|
+
/** Shown to other players; `null` when never set. */
|
|
70
|
+
readonly displayName: string | null;
|
|
71
|
+
/** The game's own profile data. */
|
|
72
|
+
readonly data: TData;
|
|
73
|
+
/** Epoch ms. */
|
|
74
|
+
readonly updatedAt: number;
|
|
75
|
+
}
|
|
76
|
+
/** A save slot's metadata (no payload). */
|
|
77
|
+
interface SaveMeta {
|
|
78
|
+
/** The slot key. */
|
|
79
|
+
readonly slot: string;
|
|
80
|
+
/** The slot's label, or `null`. */
|
|
81
|
+
readonly label: string | null;
|
|
82
|
+
/** Epoch ms. */
|
|
83
|
+
readonly updatedAt: number;
|
|
84
|
+
}
|
|
85
|
+
/** A save slot with its payload typed as `TData`. */
|
|
86
|
+
interface Save<TData = Json> extends SaveMeta {
|
|
87
|
+
/** The stored JSON. */
|
|
88
|
+
readonly data: TData;
|
|
89
|
+
}
|
|
90
|
+
/** Options for `hub.submitScore()`, with the score's metadata typed as `TMeta`. */
|
|
91
|
+
interface SubmitScoreOptions<TMeta extends GamePayload = Json> {
|
|
92
|
+
/** The board's title; only used when the board key is first created. */
|
|
93
|
+
readonly title?: string;
|
|
94
|
+
/** The sort direction; only used on board creation. Default `desc`. */
|
|
95
|
+
readonly sort?: SortDir;
|
|
96
|
+
/** Any JSON stored with the entry (a character, a run seed). */
|
|
97
|
+
readonly meta?: TMeta;
|
|
98
|
+
}
|
|
99
|
+
/** What `hub.submitScore()` answers: the board, the player's best and rank (offline: rank 1). */
|
|
100
|
+
interface SubmitScoreResult {
|
|
101
|
+
/** The board. */
|
|
102
|
+
readonly board: Board;
|
|
103
|
+
/** The player's best score, or `null` when it did not count (a zero on a board that hides zeros). */
|
|
104
|
+
readonly best: number | null;
|
|
105
|
+
/** The player's rank, or `null`. */
|
|
106
|
+
readonly rank: number | null;
|
|
107
|
+
}
|
|
108
|
+
/** One board's ranked entries (`hub.getLeaderboard()`). */
|
|
109
|
+
type LeaderboardResult = EndpointReply<'getLeaderboard'>;
|
|
110
|
+
/** A board with its top entries. */
|
|
111
|
+
type BoardWithTop = EndpointReply<'listTopOfEveryLeaderboard'>['games'][number]['boards'][number];
|
|
112
|
+
/** One game's play counts, with its slug (`hub.analytics()`). */
|
|
113
|
+
type GameAnalytics = EndpointReply<'getGameAnalytics'>;
|
|
114
|
+
/** Catalog-wide play counts with a per-game breakdown (`hub.globalAnalytics()`). */
|
|
115
|
+
interface GlobalAnalytics {
|
|
116
|
+
/** Across every game. */
|
|
117
|
+
readonly global: Metrics;
|
|
118
|
+
/** Per game. */
|
|
119
|
+
readonly games: (Metrics & {
|
|
120
|
+
readonly slug: string;
|
|
121
|
+
readonly title: string;
|
|
122
|
+
})[];
|
|
123
|
+
}
|
|
124
|
+
/** A listed game (`hub.listGames()`). */
|
|
125
|
+
type GameInfo$1 = GameInfo;
|
|
126
|
+
/** What `GET /me/snapshot` answers; `hub.prefetchAll()` warms the offline cache for every game from it. */
|
|
127
|
+
type SnapshotResponse = EndpointReply<'getMyOfflineSnapshot'>;
|
|
128
|
+
/** A player's holdings in one game, as the inventory calls answer. */
|
|
129
|
+
type InventorySnapshot = EndpointReply<'getMyInventory'>;
|
|
130
|
+
/** The connection and sync status `hub.onStatus()` reports. */
|
|
131
|
+
interface HubStatus {
|
|
132
|
+
/** The hub is reachable. */
|
|
133
|
+
readonly online: boolean;
|
|
134
|
+
/** Calls are being served from the offline cache. */
|
|
135
|
+
readonly offline: boolean;
|
|
136
|
+
/** Queued writes plus buffered events waiting to sync. */
|
|
137
|
+
readonly pending: number;
|
|
138
|
+
}
|
|
139
|
+
/** How a client created with `createHub()` / `new Hub()` behaves. */
|
|
140
|
+
interface HubOptions {
|
|
141
|
+
/** The game's slug. Default: `window.__HUB__.slug`, then the first URL path segment. */
|
|
142
|
+
readonly slug?: string;
|
|
143
|
+
/** The API base. Default: `window.__HUB__.apiBase`, then `/_api`. */
|
|
144
|
+
readonly apiBase?: string;
|
|
145
|
+
/** A custom fetch (tests, non-browser code). Default: the global fetch. */
|
|
146
|
+
readonly fetch?: typeof fetch;
|
|
147
|
+
/**
|
|
148
|
+
* What to do when the hub can't be reached:
|
|
149
|
+
* - `auto` (default): try the network; on a connection failure fall back to
|
|
150
|
+
* the offline cache in `localStorage`, and sync when the hub is back;
|
|
151
|
+
* - `always`: never touch the network (develop a game without a hub);
|
|
152
|
+
* - `never`: never fall back; every call throws when the hub is unreachable.
|
|
153
|
+
*/
|
|
154
|
+
readonly offline?: 'auto' | 'always' | 'never';
|
|
155
|
+
}
|
|
156
|
+
//#endregion
|
|
157
|
+
//#region src/core/offline/events.d.ts
|
|
158
|
+
/** One buffered event. */
|
|
159
|
+
interface BufferedEvent {
|
|
160
|
+
/** The event type, as `recordGameEvent` sends it. */
|
|
161
|
+
readonly type: string;
|
|
162
|
+
/** When it happened (epoch ms). */
|
|
163
|
+
readonly ts: number;
|
|
164
|
+
}
|
|
165
|
+
//#endregion
|
|
166
|
+
//#region src/core/offline/queue.d.ts
|
|
167
|
+
/** A score submission's options as queued (the metadata already JSON). */
|
|
168
|
+
interface QueuedScoreOptions {
|
|
169
|
+
/** The board's title; only used when the board key is first created. */
|
|
170
|
+
readonly title?: string;
|
|
171
|
+
/** The sort direction; only used on board creation. Default `desc`. */
|
|
172
|
+
readonly sort?: SortDir;
|
|
173
|
+
/** Any JSON stored with the entry (a character, a run seed). */
|
|
174
|
+
readonly meta?: Json;
|
|
175
|
+
}
|
|
176
|
+
/** A profile change: either part may be left out. */
|
|
177
|
+
interface ProfilePatch {
|
|
178
|
+
/** Shown to other players; `null` clears it. */
|
|
179
|
+
displayName?: string | null;
|
|
180
|
+
/** The game's own profile data. */
|
|
181
|
+
data?: Json;
|
|
182
|
+
}
|
|
183
|
+
/** A queued op's id and when it was queued. */
|
|
184
|
+
interface QueueStamp {
|
|
185
|
+
/** Unique within this page: `<epoch ms>-<sequence>`. */
|
|
186
|
+
readonly id: string;
|
|
187
|
+
/** When it was queued (epoch ms). */
|
|
188
|
+
readonly ts: number;
|
|
189
|
+
}
|
|
190
|
+
/** A queued write, before it is stamped. */
|
|
191
|
+
type QueueOpInput = {
|
|
192
|
+
readonly kind: 'putSave';
|
|
193
|
+
readonly slot: string;
|
|
194
|
+
readonly data: Json;
|
|
195
|
+
readonly label: string | null;
|
|
196
|
+
} | {
|
|
197
|
+
readonly kind: 'deleteSave';
|
|
198
|
+
readonly slot: string;
|
|
199
|
+
} | {
|
|
200
|
+
readonly kind: 'setStat';
|
|
201
|
+
readonly key: string;
|
|
202
|
+
readonly value: number;
|
|
203
|
+
} | {
|
|
204
|
+
readonly kind: 'maxStat';
|
|
205
|
+
readonly key: string;
|
|
206
|
+
readonly value: number;
|
|
207
|
+
} | {
|
|
208
|
+
readonly kind: 'incrStat';
|
|
209
|
+
readonly key: string;
|
|
210
|
+
readonly amount: number;
|
|
211
|
+
} | {
|
|
212
|
+
readonly kind: 'submitScore';
|
|
213
|
+
readonly key: string;
|
|
214
|
+
readonly score: number;
|
|
215
|
+
readonly opts: QueuedScoreOptions;
|
|
216
|
+
} | {
|
|
217
|
+
readonly kind: 'setProfile';
|
|
218
|
+
readonly patch: ProfilePatch;
|
|
219
|
+
};
|
|
220
|
+
/** A queued write, as stored under `hub:<slug>:queue`. */
|
|
221
|
+
type QueueOp = QueueOpInput & QueueStamp;
|
|
222
|
+
//#endregion
|
|
223
|
+
//#region src/core/offline/local-store.d.ts
|
|
224
|
+
/** A board this player has a local best on. */
|
|
225
|
+
interface LocalBoard {
|
|
226
|
+
/** The board. */
|
|
227
|
+
readonly board: Board;
|
|
228
|
+
/** This player's best score. */
|
|
229
|
+
readonly best: number;
|
|
230
|
+
}
|
|
231
|
+
/** How a stat update combines with the stored value. */
|
|
232
|
+
type StatUpdateMode = 'set' | 'incr' | 'max';
|
|
233
|
+
/** One game's offline cache, queue and event buffer. */
|
|
234
|
+
declare class LocalStore {
|
|
235
|
+
private readonly prefix;
|
|
236
|
+
private readonly store;
|
|
237
|
+
private sequence;
|
|
238
|
+
/** The cache for game `slug` in `store` (default: `localStorage`, or memory without it). */
|
|
239
|
+
constructor(slug: string, store?: KeyValueStore);
|
|
240
|
+
private readStored;
|
|
241
|
+
private writeStored;
|
|
242
|
+
/** The locally known user. */
|
|
243
|
+
getUser(): User | null;
|
|
244
|
+
/** Remember the user (offline sign-in, or a snapshot). */
|
|
245
|
+
setUser(user: User): void;
|
|
246
|
+
/** Forget the user (offline sign-out). */
|
|
247
|
+
clearUser(): void;
|
|
248
|
+
/** This game's cached profile. */
|
|
249
|
+
getProfile(): Profile | null;
|
|
250
|
+
/** Store this game's profile and return it. */
|
|
251
|
+
setProfile(game: string, displayName: string | null, profileData: Json): Profile;
|
|
252
|
+
/** Every cached save's metadata, newest first. */
|
|
253
|
+
listSaves(): SaveMeta[];
|
|
254
|
+
/** One cached save, or `null`. */
|
|
255
|
+
getSave(slot: string): Save | null;
|
|
256
|
+
/** Store a save and return its `updatedAt`. */
|
|
257
|
+
putSave(slot: string, saveData: Json, label: string | null): number;
|
|
258
|
+
/** Forget a save. */
|
|
259
|
+
deleteSave(slot: string): void;
|
|
260
|
+
/** This game's cached stats. */
|
|
261
|
+
getStats(): Stats;
|
|
262
|
+
/** Apply one stat update and return the stat's new value. */
|
|
263
|
+
updateStat(key: string, amount: number, mode: StatUpdateMode): number;
|
|
264
|
+
/** The boards this player has a local best on (offline boards only know the player's own best). */
|
|
265
|
+
listBoards(): Board[];
|
|
266
|
+
/** One board's local best, or `null`. */
|
|
267
|
+
getBoard(key: string): LocalBoard | null;
|
|
268
|
+
/** Record a score locally, keeping the best one; returns the board and best. */
|
|
269
|
+
submitScore(key: string, score: number, options: QueuedScoreOptions): LocalBoard;
|
|
270
|
+
/** The queued writes, oldest first. */
|
|
271
|
+
getQueue(): QueueOp[];
|
|
272
|
+
/** Replace the queue. */
|
|
273
|
+
setQueue(queue: readonly QueueOp[]): void;
|
|
274
|
+
/** How many writes are queued. */
|
|
275
|
+
queueLength(): number;
|
|
276
|
+
/** Queue a write, collapsing it with a compatible queued one. */
|
|
277
|
+
enqueue(input: QueueOpInput): void;
|
|
278
|
+
/** The buffered analytics events, oldest first. */
|
|
279
|
+
getEvents(): BufferedEvent[];
|
|
280
|
+
/** Replace the event buffer. */
|
|
281
|
+
setEvents(events: readonly BufferedEvent[]): void;
|
|
282
|
+
/** Buffer one event (capped; heartbeats are dropped first). */
|
|
283
|
+
bufferEvent(type: string): void;
|
|
284
|
+
/** Fan a `/me/snapshot` reply out across every game's cache keys. */
|
|
285
|
+
hydrate(snapshot: SnapshotResponse): void;
|
|
286
|
+
}
|
|
287
|
+
//#endregion
|
|
288
|
+
//#region src/core/rest/rest-client.d.ts
|
|
289
|
+
/** The header that tells the hub which client version is calling. */
|
|
290
|
+
declare const CLIENT_VERSION_HEADER = "x-hub-client";
|
|
291
|
+
/** The arguments of a call: the fields, optional when the endpoint takes none that are required. */
|
|
292
|
+
type CallArguments<K extends EndpointName> = Partial<EndpointFields<K>> extends EndpointFields<K> ? [fields?: EndpointFields<K>] : [fields: EndpointFields<K>];
|
|
293
|
+
/** Typed calls to the hub's public REST API. */
|
|
294
|
+
interface RestClient {
|
|
295
|
+
/** The API's absolute base URL. */
|
|
296
|
+
readonly apiBase: string;
|
|
297
|
+
/** Call an endpoint; resolves with its reply body, rejects with a {@link HubError}. */
|
|
298
|
+
call<K extends EndpointName>(name: K, ...fieldsArgument: CallArguments<K>): Promise<EndpointReply<K>>;
|
|
299
|
+
}
|
|
300
|
+
//#endregion
|
|
301
|
+
//#region src/core/connection.d.ts
|
|
302
|
+
/** A queued write the hub refused during a sync: dropped, with the hub's message. */
|
|
303
|
+
interface SyncConflict {
|
|
304
|
+
/** The refused op. */
|
|
305
|
+
readonly op: QueueOp;
|
|
306
|
+
/** The hub's message. */
|
|
307
|
+
readonly error?: string;
|
|
308
|
+
}
|
|
309
|
+
/** What one `sync()` did. */
|
|
310
|
+
interface SyncResult {
|
|
311
|
+
/** Queued writes the hub accepted. */
|
|
312
|
+
readonly flushed: number;
|
|
313
|
+
/** Queued writes the hub refused (and that were dropped). */
|
|
314
|
+
readonly conflicts: SyncConflict[];
|
|
315
|
+
}
|
|
316
|
+
/** The game slug's path field, or a {@link HubError} when the slug is unknown. */
|
|
317
|
+
interface GameFields {
|
|
318
|
+
/** The game's slug. */
|
|
319
|
+
readonly slug: string;
|
|
320
|
+
}
|
|
321
|
+
/** The connection, offline cache and sync machinery shared by every `Hub` method. */
|
|
322
|
+
declare class HubConnection {
|
|
323
|
+
/** This client's game slug (`null` when it could not be determined). */
|
|
324
|
+
readonly slug: string | null;
|
|
325
|
+
/** The absolute API base, e.g. `https://diffenderfer.games/_api`. */
|
|
326
|
+
readonly apiBase: string;
|
|
327
|
+
/** Typed REST calls to {@link apiBase}. */
|
|
328
|
+
protected readonly rest: RestClient;
|
|
329
|
+
/** This game's offline cache, queue and event buffer. */
|
|
330
|
+
protected readonly store: LocalStore;
|
|
331
|
+
private readonly offlineMode;
|
|
332
|
+
private isReachable;
|
|
333
|
+
private isSyncing;
|
|
334
|
+
private lastPrefetchAt;
|
|
335
|
+
private readonly statusListeners;
|
|
336
|
+
/** A connection for `options` (slug and API base default to the page's). */
|
|
337
|
+
constructor(options?: HubOptions);
|
|
338
|
+
/** `true` when calls are being served from the offline cache rather than the hub. */
|
|
339
|
+
get isOffline(): boolean;
|
|
340
|
+
/** `true` while the hub is reachable. */
|
|
341
|
+
get isOnline(): boolean;
|
|
342
|
+
/** Queued writes plus buffered analytics events waiting to sync. */
|
|
343
|
+
pending(): number;
|
|
344
|
+
/** Subscribe to connection and sync status changes; returns the unsubscribe function. */
|
|
345
|
+
onStatus(listener: (status: HubStatus) => void): () => void;
|
|
346
|
+
/** Tell `onStatus` listeners and the page (`hub:status`) the current status. */
|
|
347
|
+
protected notifyStatus(): void;
|
|
348
|
+
/** Record reachability; coming back online syncs the queue and re-warms the cache. */
|
|
349
|
+
protected setReachable(isReachableNow: boolean): void;
|
|
350
|
+
/** `{ slug }` for this game's endpoints; throws when the slug is unknown. */
|
|
351
|
+
protected gameFields(): GameFields;
|
|
352
|
+
/**
|
|
353
|
+
* Run the network call, falling back to the offline answer when the hub
|
|
354
|
+
* can't be reached (per the offline mode). Real API errors (with an HTTP
|
|
355
|
+
* status) always reach the caller.
|
|
356
|
+
*/
|
|
357
|
+
protected withFallback<Reply>(networkCall: () => Promise<Reply>, offlineAnswer: () => Reply): Promise<Reply>;
|
|
358
|
+
/** Send one queued write. */
|
|
359
|
+
private sendOp;
|
|
360
|
+
/**
|
|
361
|
+
* Apply a write to the offline cache at once, then send it now (online
|
|
362
|
+
* with an empty queue) or queue it behind the others. Resolves with the
|
|
363
|
+
* local answer; a real API error on the direct path reaches the caller and
|
|
364
|
+
* is not queued.
|
|
365
|
+
*/
|
|
366
|
+
protected mutateQueued<Reply>(input: QueueOpInput, localAnswer: () => Reply): Promise<Reply>;
|
|
367
|
+
/**
|
|
368
|
+
* Replay the queue, then the buffered events, in order. Stops at the first
|
|
369
|
+
* transport failure (offline again: the rest stays queued); a write the hub
|
|
370
|
+
* refuses is dropped and reported as a conflict.
|
|
371
|
+
*/
|
|
372
|
+
sync(): Promise<SyncResult>;
|
|
373
|
+
/** Send the buffered analytics events; a refused one is dropped (telemetry never blocks). */
|
|
374
|
+
private flushEvents;
|
|
375
|
+
/**
|
|
376
|
+
* Warm the offline cache for every game the player has touched, in one
|
|
377
|
+
* request, so going offline later still shows complete progress.
|
|
378
|
+
* Throttled to once per 30 s unless `isForced`; `null` when offline or throttled.
|
|
379
|
+
*/
|
|
380
|
+
prefetchAll(isForced?: boolean): Promise<SnapshotResponse | null>;
|
|
381
|
+
}
|
|
382
|
+
//#endregion
|
|
383
|
+
//#region src/core/hub-progress.d.ts
|
|
384
|
+
/** A signed-in user, as the auth calls answer. */
|
|
385
|
+
interface AuthResponse {
|
|
386
|
+
/** The signed-in user. */
|
|
387
|
+
readonly user: User;
|
|
388
|
+
}
|
|
389
|
+
/** A stat's new value, as the stat calls answer. */
|
|
390
|
+
interface StatResult {
|
|
391
|
+
/** The stat key. */
|
|
392
|
+
readonly key: string;
|
|
393
|
+
/** Its value after the update. */
|
|
394
|
+
readonly value: number;
|
|
395
|
+
}
|
|
396
|
+
/** A profile change with the game's own data typed as `TData`. */
|
|
397
|
+
interface ProfileUpdate<TData extends GamePayload = Json> {
|
|
398
|
+
/** Shown to other players; `null` clears it. */
|
|
399
|
+
readonly displayName?: string | null;
|
|
400
|
+
/** The game's own profile data. */
|
|
401
|
+
readonly data?: TData;
|
|
402
|
+
}
|
|
403
|
+
/** Accounts, profile, saves, stats and leaderboards. */
|
|
404
|
+
declare class HubProgress extends HubConnection {
|
|
405
|
+
/** The current user (or `null`) and the games they have a profile in. */
|
|
406
|
+
me(): Promise<MeResponse>;
|
|
407
|
+
/**
|
|
408
|
+
* Make sure a session exists, creating a guest (a random name, no
|
|
409
|
+
* password) when the player isn't signed in, so progress saves without a
|
|
410
|
+
* sign-in. Idempotent. Offline, a local guest is used.
|
|
411
|
+
*/
|
|
412
|
+
ensureGuest(): Promise<AuthResponse>;
|
|
413
|
+
/**
|
|
414
|
+
* Turn the current guest into a registered account (the same identity, so
|
|
415
|
+
* all progress carries over). Rejects with 409 when already registered or
|
|
416
|
+
* the name is taken; the player should `login` instead.
|
|
417
|
+
*/
|
|
418
|
+
claim(username: string, password: string): Promise<AuthResponse>;
|
|
419
|
+
/** Create an account and sign in. (Offline: a local user is stored.) */
|
|
420
|
+
signup(username: string, password: string): Promise<AuthResponse>;
|
|
421
|
+
/** Sign in. (Offline: a local user is stored so signed-in flows work.) */
|
|
422
|
+
login(username: string, password: string): Promise<AuthResponse>;
|
|
423
|
+
/** Sign out (ends the session shared by every game). */
|
|
424
|
+
logout(): Promise<{
|
|
425
|
+
ok: true;
|
|
426
|
+
}>;
|
|
427
|
+
private signInLocally;
|
|
428
|
+
/** This game's profile for the current user, or `profile: null`. `TData` is the game's own data type. */
|
|
429
|
+
getProfile<TData = Json>(): Promise<{
|
|
430
|
+
profile: Profile<TData> | null;
|
|
431
|
+
}>;
|
|
432
|
+
/** Create or update this game's profile for the current user. */
|
|
433
|
+
setProfile<TData extends GamePayload = Json>(patch: ProfileUpdate<TData>): Promise<{
|
|
434
|
+
profile: Profile<TData>;
|
|
435
|
+
}>;
|
|
436
|
+
/** Metadata for every save slot (no payloads), newest first. */
|
|
437
|
+
listSaves(): Promise<{
|
|
438
|
+
saves: SaveMeta[];
|
|
439
|
+
}>;
|
|
440
|
+
/** One slot's contents, or `save: null` when the slot is empty. `TData` is the game's own save type. */
|
|
441
|
+
getSave<TData = Json>(slot: string): Promise<{
|
|
442
|
+
save: Save<TData> | null;
|
|
443
|
+
}>;
|
|
444
|
+
/** Create or overwrite a save slot. `saveData` is any JSON up to 64 KB. */
|
|
445
|
+
putSave<TData extends GamePayload = Json>(slot: string, saveData: TData, label?: string): Promise<{
|
|
446
|
+
ok: true;
|
|
447
|
+
updatedAt: number;
|
|
448
|
+
}>;
|
|
449
|
+
/** Delete a save slot. */
|
|
450
|
+
deleteSave(slot: string): Promise<{
|
|
451
|
+
ok: true;
|
|
452
|
+
}>;
|
|
453
|
+
/** Numeric stats for the current user, or another player's via `userId`. */
|
|
454
|
+
getStats(userId?: number): Promise<{
|
|
455
|
+
stats: Stats;
|
|
456
|
+
}>;
|
|
457
|
+
/** Overwrite a stat. */
|
|
458
|
+
setStat(key: string, value: number): Promise<StatResult>;
|
|
459
|
+
/** Add to a stat (creating it at `amount` when absent). */
|
|
460
|
+
incrStat(key: string, amount?: number): Promise<StatResult>;
|
|
461
|
+
/** Keep the larger of the stored and the given value. */
|
|
462
|
+
maxStat(key: string, value: number): Promise<StatResult>;
|
|
463
|
+
/** Submit a score. The board is created on first use; only a player's best score sticks. */
|
|
464
|
+
submitScore<TMeta extends GamePayload = Json>(boardKey: string, score: number, opts?: SubmitScoreOptions<TMeta>): Promise<SubmitScoreResult>;
|
|
465
|
+
/** One board's ranked entries (top `limit`, default 50). Offline: only the player's own best. */
|
|
466
|
+
getLeaderboard(boardKey: string, limit?: number): Promise<LeaderboardResult>;
|
|
467
|
+
/** The boards this game owns (keys and titles, no entries). */
|
|
468
|
+
listLeaderboards(): Promise<{
|
|
469
|
+
boards: Board[];
|
|
470
|
+
}>;
|
|
471
|
+
}
|
|
472
|
+
//#endregion
|
|
473
|
+
//#region src/core/hub-economy.d.ts
|
|
474
|
+
/** Goods to grant: item key to quantity, and coins. */
|
|
475
|
+
type GrantBundle = Omit<EndpointFields<'grantInventoryItems'>, 'slug'>;
|
|
476
|
+
/** Goods taken or given in an exchange or a trade. */
|
|
477
|
+
type TradeBundle = EndpointFields<'exchangeInventoryItems'>['take'];
|
|
478
|
+
/** A trade offer's id, as a number or its text. */
|
|
479
|
+
type TradeId = number | string;
|
|
480
|
+
/** Extras for creating or countering a trade. */
|
|
481
|
+
interface TradeNoteOptions {
|
|
482
|
+
/** A short note to the other player (moderated). */
|
|
483
|
+
readonly note?: string;
|
|
484
|
+
}
|
|
485
|
+
/** Which trades `listTrades` lists. */
|
|
486
|
+
type TradeListOptions = Omit<EndpointFields<'listMyTrades'>, 'slug'>;
|
|
487
|
+
/** Analytics, catalog, favorites, records, inventory and trades. */
|
|
488
|
+
declare class HubEconomy extends HubProgress {
|
|
489
|
+
/** Record a "play". Call once when the game starts. */
|
|
490
|
+
recordPlay(): Promise<void>;
|
|
491
|
+
/** Record a "heartbeat". Call periodically while the game is active. */
|
|
492
|
+
heartbeat(): Promise<void>;
|
|
493
|
+
/** Record a custom event. Never throws; offline, events are buffered and sent on reconnect. */
|
|
494
|
+
event(type: string): Promise<void>;
|
|
495
|
+
/** This game's play counts. */
|
|
496
|
+
analytics(): Promise<GameAnalytics>;
|
|
497
|
+
/** Catalog-wide play counts with a per-game breakdown. */
|
|
498
|
+
globalAnalytics(): Promise<GlobalAnalytics>;
|
|
499
|
+
/** The listed games, for "jump to another game" navigation. */
|
|
500
|
+
listGames(): Promise<{
|
|
501
|
+
games: GameInfo$1[];
|
|
502
|
+
}>;
|
|
503
|
+
/** Every board of every game, each with its top `top` entries (default 5). */
|
|
504
|
+
allLeaderboards(top?: number): Promise<EndpointReply<'listTopOfEveryLeaderboard'>>;
|
|
505
|
+
/**
|
|
506
|
+
* The starred games (slugs), shown first in the menu's game list. Kept per
|
|
507
|
+
* account by the hub and mirrored to `localStorage`, so it shows offline.
|
|
508
|
+
*/
|
|
509
|
+
favorites(): Promise<{
|
|
510
|
+
games: string[];
|
|
511
|
+
}>;
|
|
512
|
+
/** Star (`isOn = true`) or unstar a game. Needs a connection. */
|
|
513
|
+
setFavorite(slug: string, isOn: boolean): Promise<{
|
|
514
|
+
games: string[];
|
|
515
|
+
}>;
|
|
516
|
+
/** The player's leaderboard standings, grouped by game (every game, or one via `forSlug`). Empty offline or signed out. */
|
|
517
|
+
myRecords(forSlug?: string): Promise<EndpointReply<'listMyLeaderboardRecords'>>;
|
|
518
|
+
/** This game's inventory and coin balance for the current user. */
|
|
519
|
+
getInventory(): Promise<InventorySnapshot>;
|
|
520
|
+
/** Another player's available holdings (to compose a trade). */
|
|
521
|
+
playerInventory(userId: number): Promise<InventorySnapshot>;
|
|
522
|
+
/** Add goods to the player (gameplay rewards); answers the new holdings. */
|
|
523
|
+
grant(bundle: GrantBundle): Promise<EndpointReply<'grantInventoryItems'>>;
|
|
524
|
+
/** An atomic swap with the house: remove `take`, add `give`. */
|
|
525
|
+
exchange(take?: TradeBundle, give?: TradeBundle): Promise<EndpointReply<'exchangeInventoryItems'>>;
|
|
526
|
+
/** Sell items to the house for coins. */
|
|
527
|
+
sell(items: Record<string, number>, coins: number): Promise<EndpointReply<'exchangeInventoryItems'>>;
|
|
528
|
+
/** Buy items from the house with coins. */
|
|
529
|
+
buy(coins: number, items: Record<string, number>): Promise<EndpointReply<'exchangeInventoryItems'>>;
|
|
530
|
+
/** Wipe the player's progress in this game (saves, stats, inventory and coins). */
|
|
531
|
+
resetGame(): Promise<{
|
|
532
|
+
ok: true;
|
|
533
|
+
}>;
|
|
534
|
+
/** Players this player can trade with in this game. */
|
|
535
|
+
listPlayers(): Promise<EndpointReply<'listTradePartners'>>;
|
|
536
|
+
/** The player's trades (`box`: `incoming` or `outgoing`; `status` filters). */
|
|
537
|
+
listTrades(opts?: TradeListOptions): Promise<EndpointReply<'listMyTrades'>>;
|
|
538
|
+
/** Offer a trade to another player (by id or name). */
|
|
539
|
+
createTrade(toUser: number | string, give?: TradeBundle, want?: TradeBundle, opts?: TradeNoteOptions): Promise<EndpointReply<'createTrade'>>;
|
|
540
|
+
/** Accept a trade offered to the player. */
|
|
541
|
+
acceptTrade(id: TradeId): Promise<EndpointReply<'acceptTrade'>>;
|
|
542
|
+
/** Decline a trade offered to the player. */
|
|
543
|
+
declineTrade(id: TradeId): Promise<EndpointReply<'declineTrade'>>;
|
|
544
|
+
/** Cancel a trade the player offered. */
|
|
545
|
+
cancelTrade(id: TradeId): Promise<EndpointReply<'cancelTrade'>>;
|
|
546
|
+
/** Answer a trade with a counter-offer. */
|
|
547
|
+
counterTrade(id: TradeId, give?: TradeBundle, want?: TradeBundle, opts?: TradeNoteOptions): Promise<EndpointReply<'counterTradeOffer'>>;
|
|
548
|
+
}
|
|
549
|
+
//#endregion
|
|
550
|
+
//#region src/core/menu-control.d.ts
|
|
551
|
+
declare global {
|
|
552
|
+
interface Window {
|
|
553
|
+
/** The last requested menu-button visibility (absent: visible). */
|
|
554
|
+
__HUB_MENU_VISIBLE__?: boolean;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
/** Control over the injected hub menu button. */
|
|
558
|
+
interface HubMenuControl {
|
|
559
|
+
/**
|
|
560
|
+
* Show (`true`) or hide (`false`) the menu button. Hidden means faded out,
|
|
561
|
+
* not focusable and `aria-hidden`; an open drawer stays open until closed,
|
|
562
|
+
* and the gamepad Select button still opens it. A small corner hotspot
|
|
563
|
+
* peeks it back for a few seconds on hover or tap, so players can always
|
|
564
|
+
* reach it.
|
|
565
|
+
*/
|
|
566
|
+
setVisible(isVisible: boolean): void;
|
|
567
|
+
/** Show the menu button. */
|
|
568
|
+
show(): void;
|
|
569
|
+
/** Hide the menu button. */
|
|
570
|
+
hide(): void;
|
|
571
|
+
/** The last requested visibility (`true` unless a game hid it). */
|
|
572
|
+
readonly visible: boolean;
|
|
573
|
+
}
|
|
574
|
+
//#endregion
|
|
575
|
+
//#region src/core/version/hub-version.d.ts
|
|
576
|
+
/** How a hub regards a client version. */
|
|
577
|
+
type ClientSupport =
|
|
578
|
+
/** In `supported` and not `deprecated`. */
|
|
579
|
+
'supported' |
|
|
580
|
+
/** Still supported, but `deprecated`: update soon. */
|
|
581
|
+
'deprecated' |
|
|
582
|
+
/** Outside `supported`: update now. */
|
|
583
|
+
'unsupported' |
|
|
584
|
+
/** The hub predates versioning (the old hub): nothing to compare. */
|
|
585
|
+
'unknown';
|
|
586
|
+
//#endregion
|
|
587
|
+
//#region src/core/hub.d.ts
|
|
588
|
+
/** The hub client. Use the ready-made {@link hub}, or `createHub()` for another slug or API base. */
|
|
589
|
+
declare class Hub extends HubEconomy {
|
|
590
|
+
/** This client's package version (sent as `x-hub-client`). */
|
|
591
|
+
readonly clientVersion: string;
|
|
592
|
+
/**
|
|
593
|
+
* The hub's version and the client versions it supports (`GET /_api/version`),
|
|
594
|
+
* read once per page. `null` for a hub from before versioning.
|
|
595
|
+
*/
|
|
596
|
+
hubVersion(): Promise<HubVersion | null>;
|
|
597
|
+
/** How the hub regards this client: `supported`, `deprecated`, `unsupported`, or `unknown` (an older hub). */
|
|
598
|
+
clientSupport(): Promise<ClientSupport>;
|
|
599
|
+
/**
|
|
600
|
+
* The input system (keyboard, touch and gamepad): `hub.input.define({ ... })`,
|
|
601
|
+
* `hub.input.value('jump')`. Page-wide; remaps are saved locally and to the
|
|
602
|
+
* reserved `__controls` save slot.
|
|
603
|
+
*/
|
|
604
|
+
get input(): InputSystem;
|
|
605
|
+
/** Hub UI covering the game (menu, dialogs, chat): open/close events and `autoPause`. Page-wide. */
|
|
606
|
+
get overlay(): ReturnType<typeof getUiStack>;
|
|
607
|
+
/** Show or hide the injected hub menu button (page-wide). */
|
|
608
|
+
get menu(): HubMenuControl;
|
|
609
|
+
/**
|
|
610
|
+
* Daily challenges: call `hub.daily.define({ play })` once at load and
|
|
611
|
+
* `hub.daily.complete({ ... })` on finish. Page-wide, shared with the
|
|
612
|
+
* injected menu, which can start a clicked day on the same instance.
|
|
613
|
+
*/
|
|
614
|
+
get daily(): DailySystem;
|
|
615
|
+
/** Tell friends what the player is doing in this game. */
|
|
616
|
+
get presence(): typeof presenceForwarder;
|
|
617
|
+
/** Friends, players and the hub's social dialogs. */
|
|
618
|
+
get social(): typeof socialForwarder;
|
|
619
|
+
/** Invites, launches, the leave guard and own-server tickets. */
|
|
620
|
+
get mp(): typeof multiplayerForwarder;
|
|
621
|
+
/** Hub relay rooms, for games without a server. */
|
|
622
|
+
get rooms(): typeof roomsForwarder;
|
|
623
|
+
/** Toast behaviour during intense play. */
|
|
624
|
+
get notify(): typeof notifyForwarder;
|
|
625
|
+
/** Races: a single-player game becomes multiplayer by racing. */
|
|
626
|
+
get race(): typeof raceForwarder;
|
|
627
|
+
/** What the daily system needs from this client: its REST calls and window events. */
|
|
628
|
+
private dailyHost;
|
|
629
|
+
}
|
|
630
|
+
/** A ready-to-use client, with the slug and API base detected from the page. */
|
|
631
|
+
declare const hub: Hub;
|
|
632
|
+
/** Create a client for another slug or API base, or with other offline behaviour. */
|
|
633
|
+
declare function createHub(options?: HubOptions): Hub;
|
|
634
|
+
//#endregion
|
|
635
|
+
//#region src/core/errors.d.ts
|
|
636
|
+
/**
|
|
637
|
+
* The code a client gives a call the hub does not have yet (a newer client on
|
|
638
|
+
* an older hub, plan §4.3.3). Deploy the hub first, or use an older client.
|
|
639
|
+
*/
|
|
640
|
+
declare const UNSUPPORTED_BY_HUB = "unsupported_by_hub";
|
|
641
|
+
/** The code the social runtime gives a call it could not send (no connection). */
|
|
642
|
+
declare const OFFLINE_CODE = "offline";
|
|
643
|
+
/**
|
|
644
|
+
* A machine-readable error code: one of the contract's public codes
|
|
645
|
+
* (`content_rejected`, `rate_limited`, `suspended`, `claim_required`, ...),
|
|
646
|
+
* {@link UNSUPPORTED_BY_HUB}, or a code a newer hub added.
|
|
647
|
+
*/
|
|
648
|
+
type HubErrorCode = ErrorCode | typeof UNSUPPORTED_BY_HUB | typeof OFFLINE_CODE | (string & Record<never, never>);
|
|
649
|
+
/** The machine-readable extras the hub attaches to an error body. */
|
|
650
|
+
interface HubErrorDetails {
|
|
651
|
+
/** A stable error code, for code to branch on. */
|
|
652
|
+
readonly code?: HubErrorCode | undefined;
|
|
653
|
+
/** Why content was refused (`link`, `language`, `muted`, `chat_off`, ...). */
|
|
654
|
+
readonly reason?: RejectReason | (string & Record<never, never>) | undefined;
|
|
655
|
+
/** A kid-friendly sentence to show the player. */
|
|
656
|
+
readonly hint?: string | undefined;
|
|
657
|
+
/** How long to wait before retrying, in ms (rate limits, mutes). */
|
|
658
|
+
readonly retryAfterMs?: number | undefined;
|
|
659
|
+
/** When a suspension or mute ends (epoch ms). */
|
|
660
|
+
readonly until?: number | undefined;
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Thrown by every hub call that fails. `status` is the HTTP status when the
|
|
664
|
+
* hub answered (401 = not signed in, 404 = unknown game or board, 413 = too
|
|
665
|
+
* large), or `undefined` for a transport failure (offline, no host). Social
|
|
666
|
+
* and multiplayer errors also carry {@link HubErrorDetails}.
|
|
667
|
+
*/
|
|
668
|
+
declare class HubError extends Error {
|
|
669
|
+
/** The HTTP status, or `undefined` when the hub could not be reached. */
|
|
670
|
+
readonly status: number | undefined;
|
|
671
|
+
/** A stable error code (see {@link HubErrorCode}). */
|
|
672
|
+
readonly code: HubErrorCode | undefined;
|
|
673
|
+
/** Why content was refused. */
|
|
674
|
+
readonly reason: string | undefined;
|
|
675
|
+
/** A kid-friendly sentence to show the player. */
|
|
676
|
+
readonly hint: string | undefined;
|
|
677
|
+
/** How long to wait before retrying, in ms. */
|
|
678
|
+
readonly retryAfterMs: number | undefined;
|
|
679
|
+
/** When a suspension or mute ends (epoch ms). */
|
|
680
|
+
readonly until: number | undefined;
|
|
681
|
+
/** An error with a player-safe `message`, the HTTP `status` (if any) and the body's extras. */
|
|
682
|
+
constructor(message: string, status?: number, details?: HubErrorDetails);
|
|
683
|
+
/** `true` when the failure was a network or transport error, not an HTTP status. */
|
|
684
|
+
get isOffline(): boolean;
|
|
685
|
+
}
|
|
686
|
+
/** Thrown when an action that genuinely needs the hub is attempted offline. */
|
|
687
|
+
declare class OfflineError extends HubError {
|
|
688
|
+
/** An offline error; the default message is "This needs a connection.". */
|
|
689
|
+
constructor(message?: string);
|
|
690
|
+
}
|
|
691
|
+
/**
|
|
692
|
+
* Text was refused by the safety filter (HTTP 422, or a socket ack with
|
|
693
|
+
* `code: 'content_rejected'`). Keep the player's draft and show `hint`; when
|
|
694
|
+
* `reason` is `muted` or `rate_limited`, `retryAfterMs` says how long to wait.
|
|
695
|
+
*/
|
|
696
|
+
declare class ContentRejectedError extends HubError {
|
|
697
|
+
/** A content reject with the hub's message, status and extras. */
|
|
698
|
+
constructor(message: string, status: number | undefined, details: HubErrorDetails);
|
|
699
|
+
}
|
|
700
|
+
//#endregion
|
|
701
|
+
//#region src/core/version/client-version.gen.d.ts
|
|
702
|
+
/** This client's package version, sent as `x-hub-client` on REST calls and `client` in `hello`. */
|
|
703
|
+
declare const HUB_CLIENT_VERSION = "2.0.0-next.1";
|
|
704
|
+
//#endregion
|
|
705
|
+
export { SubmitScoreResult as $, BoardWithTop as A, Json$1 as B, CLIENT_VERSION_HEADER as C, QueuedScoreOptions as D, QueueOpInput as E, GlobalAnalytics as F, Profile as G, LeaderboardResult as H, HubOptions as I, SaveMeta as J, ProfileSummary as K, HubStatus as L, GameInfo$1 as M, GameLeaderboards as N, BufferedEvent as O, GameRecords as P, SubmitScoreOptions as Q, Inventory as R, SyncResult as S, QueueOp as T, MeResponse as U, LeaderboardEntry as V, Metrics$1 as W, SortDir$1 as X, SnapshotResponse as Y, Stats$1 as Z, TradeNoteOptions as _, HubErrorDetails as a, StatResult as b, Hub as c, ClientSupport as d, User as et, HubMenuControl as f, TradeListOptions as g, TradeId as h, HubErrorCode as i, GamePayload as it, GameAnalytics as j, Board$1 as k, createHub as l, TradeBundle as m, ContentRejectedError as n, EndpointName as nt, OfflineError as o, GrantBundle as p, Save as q, HubError as r, EndpointReply as rt, UNSUPPORTED_BY_HUB as s, HUB_CLIENT_VERSION as t, EndpointFields as tt, hub as u, AuthResponse as v, ProfilePatch as w, SyncConflict as x, ProfileUpdate as y, InventorySnapshot as z };
|
|
706
|
+
//# sourceMappingURL=index.d.ts.map
|