@wvdsh/sdk-js 0.0.38 → 1.2.2
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/LICENSE +191 -0
- package/README.md +4 -49
- package/dist/index.d.ts +972 -0
- package/dist/index.js +7783 -7574
- package/package.json +18 -4
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,972 @@
|
|
|
1
|
+
import { ConvexClient } from 'convex/browser';
|
|
2
|
+
import { GenericId } from 'convex/values';
|
|
3
|
+
export { GenericId as Id } from 'convex/values';
|
|
4
|
+
import { FunctionReturnType } from 'convex/server';
|
|
5
|
+
import { PublicApiType, api, GAME_ENGINE, SDKUser, IFRAME_MESSAGE_TYPE, IFrameEventPayloadMap, SDKConfig, GameLaunchParams } from '@wvdsh/api';
|
|
6
|
+
export { GameLaunchParams } from '@wvdsh/api';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* SDK-to-Engine Events
|
|
10
|
+
*
|
|
11
|
+
* Defines all events that the SDK sends to the game engine.
|
|
12
|
+
* These are maintained manually in the SDK (not autogenerated from backend).
|
|
13
|
+
*
|
|
14
|
+
* The game engine listens for these events to react to SDK updates.
|
|
15
|
+
*/
|
|
16
|
+
declare const WavedashEvents: {
|
|
17
|
+
readonly LOBBY_MESSAGE: "LobbyMessage";
|
|
18
|
+
readonly LOBBY_JOINED: "LobbyJoined";
|
|
19
|
+
readonly LOBBY_KICKED: "LobbyKicked";
|
|
20
|
+
readonly LOBBY_USERS_UPDATED: "LobbyUsersUpdated";
|
|
21
|
+
readonly LOBBY_DATA_UPDATED: "LobbyDataUpdated";
|
|
22
|
+
readonly LOBBY_INVITE: "LobbyInvite";
|
|
23
|
+
readonly P2P_CONNECTION_ESTABLISHED: "P2PConnectionEstablished";
|
|
24
|
+
readonly P2P_CONNECTION_FAILED: "P2PConnectionFailed";
|
|
25
|
+
readonly P2P_PEER_DISCONNECTED: "P2PPeerDisconnected";
|
|
26
|
+
readonly P2P_PEER_RECONNECTING: "P2PPeerReconnecting";
|
|
27
|
+
readonly P2P_PEER_RECONNECTED: "P2PPeerReconnected";
|
|
28
|
+
readonly P2P_PACKET_DROPPED: "P2PPacketDropped";
|
|
29
|
+
readonly STATS_STORED: "StatsStored";
|
|
30
|
+
readonly BACKEND_CONNECTED: "BackendConnected";
|
|
31
|
+
readonly BACKEND_DISCONNECTED: "BackendDisconnected";
|
|
32
|
+
readonly BACKEND_RECONNECTING: "BackendReconnecting";
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
type LobbyVisibility = PublicApiType["sdk"]["gameLobby"]["createAndJoinLobby"]["_args"]["visibility"];
|
|
36
|
+
type LobbyUser = FunctionReturnType<typeof api.sdk.gameLobby.lobbyUsers>[0];
|
|
37
|
+
type LobbyMessage = FunctionReturnType<typeof api.sdk.gameLobby.lobbyMessages>[0];
|
|
38
|
+
type Lobby = FunctionReturnType<typeof api.sdk.gameLobby.listAvailable>[0];
|
|
39
|
+
type LobbyJoinResponse = FunctionReturnType<typeof api.sdk.gameLobby.joinLobby>;
|
|
40
|
+
type LobbyInvite = FunctionReturnType<typeof api.sdk.gameLobby.getLobbyInvites>[0];
|
|
41
|
+
type Friend = FunctionReturnType<typeof api.sdk.friends.listFriends>[0];
|
|
42
|
+
type UGCType = PublicApiType["sdk"]["userGeneratedContent"]["createUGCItem"]["_args"]["ugcType"];
|
|
43
|
+
type UGCVisibility = PublicApiType["sdk"]["userGeneratedContent"]["createUGCItem"]["_args"]["visibility"];
|
|
44
|
+
type LeaderboardSortOrder = PublicApiType["sdk"]["leaderboards"]["getOrCreateLeaderboard"]["_args"]["sortOrder"];
|
|
45
|
+
type LeaderboardDisplayType = PublicApiType["sdk"]["leaderboards"]["getOrCreateLeaderboard"]["_args"]["displayType"];
|
|
46
|
+
type Leaderboard = FunctionReturnType<typeof api.sdk.leaderboards.getLeaderboard>;
|
|
47
|
+
type LeaderboardEntries = FunctionReturnType<typeof api.sdk.leaderboards.listEntriesAroundUser>["entries"];
|
|
48
|
+
type UpsertedLeaderboardEntry = FunctionReturnType<typeof api.sdk.leaderboards.upsertLeaderboardEntry>["entry"] & {
|
|
49
|
+
userId: GenericId<"users">;
|
|
50
|
+
username: string;
|
|
51
|
+
};
|
|
52
|
+
type P2PTurnCredentials = FunctionReturnType<typeof api.sdk.turnCredentials.getOrCreate>;
|
|
53
|
+
type P2PSignalingMessage = Omit<FunctionReturnType<typeof api.sdk.p2pSignaling.getSignalingMessages>[0], "data"> & {
|
|
54
|
+
data: RTCSessionDescriptionInit | RTCIceCandidateInit;
|
|
55
|
+
};
|
|
56
|
+
type WavedashEvent = (typeof WavedashEvents)[keyof typeof WavedashEvents];
|
|
57
|
+
|
|
58
|
+
interface WavedashConfig {
|
|
59
|
+
debug?: boolean;
|
|
60
|
+
remoteStorageOrigin?: string;
|
|
61
|
+
p2p?: Partial<P2PConfig>;
|
|
62
|
+
deferEvents?: boolean;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
interface RemoteFileMetadata {
|
|
66
|
+
exists: boolean;
|
|
67
|
+
key: string;
|
|
68
|
+
name: string;
|
|
69
|
+
lastModified: number;
|
|
70
|
+
size: number;
|
|
71
|
+
etag: string;
|
|
72
|
+
}
|
|
73
|
+
interface EngineInstance {
|
|
74
|
+
type: (typeof GAME_ENGINE)[keyof typeof GAME_ENGINE];
|
|
75
|
+
SendMessage(objectName: string, methodName: WavedashEvent, value?: string | number | boolean): void;
|
|
76
|
+
FS: {
|
|
77
|
+
readFile(path: string, opts?: Record<string, unknown>): string | Uint8Array;
|
|
78
|
+
writeFile(path: string, data: string | ArrayBufferView, opts?: Record<string, unknown>): void;
|
|
79
|
+
mkdirTree(path: string, mode?: number): void;
|
|
80
|
+
syncfs(populate: boolean, callback?: (err: unknown) => void): void;
|
|
81
|
+
analyzePath(path: string): {
|
|
82
|
+
exists: boolean;
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
unityPersistentDataPath?: string;
|
|
86
|
+
}
|
|
87
|
+
interface WavedashResponse<T> {
|
|
88
|
+
success: boolean;
|
|
89
|
+
data: T | null;
|
|
90
|
+
message?: string;
|
|
91
|
+
}
|
|
92
|
+
/** Payload for LobbyJoined event - emitted on successful lobby join or create */
|
|
93
|
+
interface LobbyJoinedPayload {
|
|
94
|
+
lobbyId: GenericId<"lobbies">;
|
|
95
|
+
hostId: GenericId<"users">;
|
|
96
|
+
users: LobbyUser[];
|
|
97
|
+
metadata: Record<string, unknown>;
|
|
98
|
+
}
|
|
99
|
+
/** Reasons why a user was kicked from a lobby */
|
|
100
|
+
declare const LobbyKickedReason: {
|
|
101
|
+
readonly KICKED: "KICKED";
|
|
102
|
+
readonly ERROR: "ERROR";
|
|
103
|
+
};
|
|
104
|
+
type LobbyKickedReason = (typeof LobbyKickedReason)[keyof typeof LobbyKickedReason];
|
|
105
|
+
/** Payload for LobbyKicked event - emitted when removed from a lobby */
|
|
106
|
+
interface LobbyKickedPayload {
|
|
107
|
+
lobbyId: GenericId<"lobbies">;
|
|
108
|
+
reason: LobbyKickedReason;
|
|
109
|
+
}
|
|
110
|
+
/** Change types for lobby user updates */
|
|
111
|
+
declare const LobbyUserChangeType: {
|
|
112
|
+
readonly JOINED: "JOINED";
|
|
113
|
+
readonly LEFT: "LEFT";
|
|
114
|
+
};
|
|
115
|
+
type LobbyUserChangeType = (typeof LobbyUserChangeType)[keyof typeof LobbyUserChangeType];
|
|
116
|
+
/** Payload for LobbyUsersUpdated event - emitted when a user joins or leaves */
|
|
117
|
+
interface LobbyUsersUpdatedPayload extends LobbyUser {
|
|
118
|
+
changeType: LobbyUserChangeType;
|
|
119
|
+
}
|
|
120
|
+
/** Payload for LobbyDataUpdated event - the full lobby metadata */
|
|
121
|
+
type LobbyDataUpdatedPayload = Record<string, unknown>;
|
|
122
|
+
/** Payload for LobbyMessage event - a message received in the lobby */
|
|
123
|
+
type LobbyMessagePayload = LobbyMessage;
|
|
124
|
+
/** Payload for LobbyInvite event - an invite to join a lobby */
|
|
125
|
+
type LobbyInvitePayload = LobbyInvite;
|
|
126
|
+
/** Payload for StatsStored event - emitted when stats/achievements are persisted */
|
|
127
|
+
interface StatsStoredPayload {
|
|
128
|
+
success: boolean;
|
|
129
|
+
message?: string;
|
|
130
|
+
}
|
|
131
|
+
/** Payload for P2PConnectionEstablished event */
|
|
132
|
+
interface P2PConnectionEstablishedPayload {
|
|
133
|
+
userId: GenericId<"users">;
|
|
134
|
+
username: string;
|
|
135
|
+
}
|
|
136
|
+
/** Payload for P2PConnectionFailed event */
|
|
137
|
+
interface P2PConnectionFailedPayload {
|
|
138
|
+
userId: GenericId<"users">;
|
|
139
|
+
username: string;
|
|
140
|
+
error: string;
|
|
141
|
+
}
|
|
142
|
+
/** Payload for P2PPeerDisconnected event */
|
|
143
|
+
interface P2PPeerDisconnectedPayload {
|
|
144
|
+
userId: GenericId<"users">;
|
|
145
|
+
username: string;
|
|
146
|
+
}
|
|
147
|
+
/** Payload for P2PPeerReconnecting event */
|
|
148
|
+
interface P2PPeerReconnectingPayload {
|
|
149
|
+
userId: GenericId<"users">;
|
|
150
|
+
username: string;
|
|
151
|
+
}
|
|
152
|
+
/** Payload for P2PPeerReconnected event */
|
|
153
|
+
interface P2PPeerReconnectedPayload {
|
|
154
|
+
userId: GenericId<"users">;
|
|
155
|
+
username: string;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Reason a P2P packet was dropped. Each reason implies a different
|
|
159
|
+
* game-side remedy.
|
|
160
|
+
*/
|
|
161
|
+
type P2PPacketDropReason = "QUEUE_FULL" | "PAYLOAD_TOO_LARGE" | "INVALID_PAYLOAD_SIZE" | "INVALID_CHANNEL" | "MALFORMED" | "PEER_NOT_READY";
|
|
162
|
+
/**
|
|
163
|
+
* Payload for P2PPacketDropped event.
|
|
164
|
+
*
|
|
165
|
+
* Emitted whenever the SDK drops a P2P packet — either outgoing (rejected
|
|
166
|
+
* by local validation) or incoming (rejected by the receive-side ring
|
|
167
|
+
* buffer / framing layer).
|
|
168
|
+
*
|
|
169
|
+
* Events are aggregated per `(channel, direction, reason)` tuple with a
|
|
170
|
+
* short window so bursty drops don't flood the game, while sparse drops
|
|
171
|
+
* still fire promptly.
|
|
172
|
+
*/
|
|
173
|
+
interface P2PPacketDroppedPayload {
|
|
174
|
+
channel: number;
|
|
175
|
+
direction: "SEND" | "RECEIVE";
|
|
176
|
+
reason: P2PPacketDropReason;
|
|
177
|
+
droppedCount: number;
|
|
178
|
+
droppedTotal: number;
|
|
179
|
+
}
|
|
180
|
+
/** Payload for BackendConnected, BackendDisconnected, BackendReconnecting events */
|
|
181
|
+
interface BackendConnectionPayload {
|
|
182
|
+
isConnected: boolean;
|
|
183
|
+
hasEverConnected: boolean;
|
|
184
|
+
connectionCount: number;
|
|
185
|
+
connectionRetries: number;
|
|
186
|
+
}
|
|
187
|
+
interface P2PPeer {
|
|
188
|
+
userId: GenericId<"users">;
|
|
189
|
+
username: string;
|
|
190
|
+
}
|
|
191
|
+
interface P2PConnection {
|
|
192
|
+
lobbyId: GenericId<"lobbies">;
|
|
193
|
+
peers: Record<GenericId<"users">, P2PPeer>;
|
|
194
|
+
}
|
|
195
|
+
interface P2PMessage {
|
|
196
|
+
fromUserId: GenericId<"users">;
|
|
197
|
+
channel: number;
|
|
198
|
+
payload: Uint8Array;
|
|
199
|
+
}
|
|
200
|
+
interface P2PConfig {
|
|
201
|
+
enableReliableChannel: boolean;
|
|
202
|
+
enableUnreliableChannel: boolean;
|
|
203
|
+
messageSize?: number;
|
|
204
|
+
maxIncomingMessages?: number;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Lobby service
|
|
209
|
+
*
|
|
210
|
+
* Implements each of the lobby methods of the Wavedash SDK
|
|
211
|
+
*/
|
|
212
|
+
|
|
213
|
+
declare class LobbyManager {
|
|
214
|
+
private sdk;
|
|
215
|
+
private unsubscribeLobbyMessages;
|
|
216
|
+
private unsubscribeLobbyUsers;
|
|
217
|
+
private unsubscribeLobbyData;
|
|
218
|
+
private lobbyId;
|
|
219
|
+
private lobbyUsers;
|
|
220
|
+
private lobbyHostId;
|
|
221
|
+
private lobbyMetadata;
|
|
222
|
+
private pendingMetadataUpdates;
|
|
223
|
+
private recentMessageIds;
|
|
224
|
+
private maybeBeingDeletedLobbyIds;
|
|
225
|
+
private resetMaybeBeingDeletedLobbyIdTimeouts;
|
|
226
|
+
private cachedLobbies;
|
|
227
|
+
private unsubscribeLobbyInvites;
|
|
228
|
+
private seenInviteIds;
|
|
229
|
+
private p2pUpdateQueue;
|
|
230
|
+
constructor(sdk: WavedashSDK);
|
|
231
|
+
createLobby(visibility: LobbyVisibility, maxPlayers?: number): Promise<GenericId<"lobbies">>;
|
|
232
|
+
/**
|
|
233
|
+
* Join a lobby
|
|
234
|
+
* @param lobbyId - The ID of the lobby to join
|
|
235
|
+
* @returns true on success. Full lobby context comes via LobbyJoined event.
|
|
236
|
+
* @emits LobbyJoined event on success with full lobby context
|
|
237
|
+
*/
|
|
238
|
+
joinLobby(lobbyId: GenericId<"lobbies">): Promise<boolean>;
|
|
239
|
+
getLobbyUsers(lobbyId: GenericId<"lobbies">): LobbyUser[];
|
|
240
|
+
getHostId(lobbyId: GenericId<"lobbies">): GenericId<"users"> | null;
|
|
241
|
+
getLobbyData(lobbyId: GenericId<"lobbies">, key: string): string | number | null;
|
|
242
|
+
deleteLobbyData(lobbyId: GenericId<"lobbies">, key: string): boolean;
|
|
243
|
+
private debouncedMetadataUpdate;
|
|
244
|
+
setLobbyData(lobbyId: GenericId<"lobbies">, key: string, value: string | number | null): boolean;
|
|
245
|
+
getLobbyMaxPlayers(lobbyId: GenericId<"lobbies">): number;
|
|
246
|
+
getNumLobbyUsers(lobbyId: GenericId<"lobbies">): number;
|
|
247
|
+
leaveLobby(lobbyId: GenericId<"lobbies">): Promise<GenericId<"lobbies">>;
|
|
248
|
+
listAvailableLobbies(friendsOnly?: boolean): Promise<Lobby[]>;
|
|
249
|
+
sendLobbyMessage(lobbyId: GenericId<"lobbies">, message: string): boolean;
|
|
250
|
+
inviteUserToLobby(lobbyId: GenericId<"lobbies">, userId: GenericId<"users">): Promise<boolean>;
|
|
251
|
+
getLobbyInviteLink(copyToClipboard?: boolean): Promise<string>;
|
|
252
|
+
/**
|
|
253
|
+
* Initialize local lobby state and subscribe to all relevant updates.
|
|
254
|
+
* Sets up Convex subscriptions for messages, users, and metadata.
|
|
255
|
+
* Emits LobbyJoined event to the game engine.
|
|
256
|
+
* @precondition - The user has already joined the lobby via mutation
|
|
257
|
+
* @param response - The full response from createAndJoinLobby or joinLobby mutation
|
|
258
|
+
*/
|
|
259
|
+
private handleLobbyJoin;
|
|
260
|
+
/**
|
|
261
|
+
* Handle being kicked or removed from a lobby (subscription error)
|
|
262
|
+
* This is called when a subscription fails with "User is not a member of this lobby"
|
|
263
|
+
* Multiple subscriptions may error at once, so we guard against emitting multiple events
|
|
264
|
+
*/
|
|
265
|
+
private handleLobbyKicked;
|
|
266
|
+
/**
|
|
267
|
+
* Clean up lobby state without emitting events
|
|
268
|
+
* Used internally by handleLobbyJoin() and handleLobbyKicked()
|
|
269
|
+
*/
|
|
270
|
+
private cleanupLobbyState;
|
|
271
|
+
/**
|
|
272
|
+
* Public method to clean up lobby state without emitting events
|
|
273
|
+
* Used for session end cleanup
|
|
274
|
+
*/
|
|
275
|
+
unsubscribeFromCurrentLobby(): void;
|
|
276
|
+
/**
|
|
277
|
+
* Fully destroy the LobbyManager, cleaning up all subscriptions and timeouts.
|
|
278
|
+
* Called during session end to ensure no lingering listeners.
|
|
279
|
+
*/
|
|
280
|
+
destroy(): void;
|
|
281
|
+
private processPendingLobbyDataUpdates;
|
|
282
|
+
/**
|
|
283
|
+
* Process user updates and emit individual user events
|
|
284
|
+
* @param newUsers - The updated list of lobby users
|
|
285
|
+
*/
|
|
286
|
+
private processUserUpdates;
|
|
287
|
+
private processMessageUpdates;
|
|
288
|
+
private processInviteUpdates;
|
|
289
|
+
/**
|
|
290
|
+
* Update P2P connections when lobby membership changes
|
|
291
|
+
* @param newUsers - The updated list of lobby users
|
|
292
|
+
*/
|
|
293
|
+
private updateP2PConnections;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* File system service
|
|
298
|
+
* Utilities for syncing local IndexedDB files with remote storage.
|
|
299
|
+
*
|
|
300
|
+
* Exposes a specific remote folder for the game to save user-specific files to.
|
|
301
|
+
* TODO: Extend this to game-level assets as well.
|
|
302
|
+
*/
|
|
303
|
+
|
|
304
|
+
declare class FileSystemManager {
|
|
305
|
+
private sdk;
|
|
306
|
+
private remoteStorageOrigin;
|
|
307
|
+
constructor(sdk: WavedashSDK);
|
|
308
|
+
/**
|
|
309
|
+
* Converts a local filesystem path into a full R2 object key.
|
|
310
|
+
* Normalizes the Unity persistentDataPath and prepends the R2 prefix.
|
|
311
|
+
*/
|
|
312
|
+
private toRemoteKey;
|
|
313
|
+
/**
|
|
314
|
+
* Converts a full R2 object key back into the local filesystem path
|
|
315
|
+
* the engine expects. Inverse of toRemoteKey.
|
|
316
|
+
*/
|
|
317
|
+
private toLocalPath;
|
|
318
|
+
/**
|
|
319
|
+
* Uploads a local file to remote storage
|
|
320
|
+
* @param filePath - The path of the local file to upload
|
|
321
|
+
* @returns The path of the remote file that the local file was uploaded to
|
|
322
|
+
*/
|
|
323
|
+
uploadRemoteFile(filePath: string): Promise<string>;
|
|
324
|
+
/**
|
|
325
|
+
* Deletes a remote file from storage
|
|
326
|
+
* @param filePath - The path of the remote file to delete
|
|
327
|
+
* @returns The path of the remote file that was deleted
|
|
328
|
+
*/
|
|
329
|
+
deleteRemoteFile(filePath: string): Promise<string>;
|
|
330
|
+
/**
|
|
331
|
+
* Downloads a remote file to a local location
|
|
332
|
+
* @param filePath - The path of the remote file to download
|
|
333
|
+
* @returns The path of the local file that the remote file was downloaded to
|
|
334
|
+
*/
|
|
335
|
+
downloadRemoteFile(filePath: string): Promise<string>;
|
|
336
|
+
/**
|
|
337
|
+
* Lists each file in a remote directory, including its subdirectories
|
|
338
|
+
* Returns only file paths, no directory paths
|
|
339
|
+
* @param path - The path of the remote directory to list
|
|
340
|
+
* @returns A list of metadata for each file in the remote directory
|
|
341
|
+
*/
|
|
342
|
+
listRemoteDirectory(path: string): Promise<RemoteFileMetadata[]>;
|
|
343
|
+
downloadRemoteDirectory(path: string): Promise<string>;
|
|
344
|
+
writeLocalFile(filePath: string, data: Uint8Array): Promise<boolean>;
|
|
345
|
+
readLocalFile(filePath: string): Promise<Uint8Array | null>;
|
|
346
|
+
upload(presignedUploadUrl: string, filePath: string): Promise<boolean>;
|
|
347
|
+
download(url: string, filePath: string): Promise<boolean>;
|
|
348
|
+
private getRemoteStorageOrigin;
|
|
349
|
+
private getRemoteStorageUrl;
|
|
350
|
+
private uploadFromIndexedDb;
|
|
351
|
+
private uploadFromFS;
|
|
352
|
+
private readLocalFileBlob;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* UGC service
|
|
357
|
+
*
|
|
358
|
+
* Implements each of the user generated content methods of the Wavedash SDK
|
|
359
|
+
*/
|
|
360
|
+
|
|
361
|
+
declare class UGCManager {
|
|
362
|
+
private sdk;
|
|
363
|
+
constructor(sdk: WavedashSDK);
|
|
364
|
+
createUGCItem(ugcType: UGCType, title?: string, description?: string, visibility?: UGCVisibility, filePath?: string): Promise<GenericId<"userGeneratedContent">>;
|
|
365
|
+
updateUGCItem(ugcId: GenericId<"userGeneratedContent">, title?: string, description?: string, visibility?: UGCVisibility, filePath?: string): Promise<GenericId<"userGeneratedContent">>;
|
|
366
|
+
downloadUGCItem(ugcId: GenericId<"userGeneratedContent">, filePath: string): Promise<GenericId<"userGeneratedContent">>;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Leaderboard service
|
|
371
|
+
*
|
|
372
|
+
* Implements each of the leaderboard methods of the Wavedash SDK
|
|
373
|
+
*/
|
|
374
|
+
|
|
375
|
+
declare class LeaderboardManager {
|
|
376
|
+
private sdk;
|
|
377
|
+
private leaderboardCache;
|
|
378
|
+
constructor(sdk: WavedashSDK);
|
|
379
|
+
getLeaderboard(name: string): Promise<Leaderboard>;
|
|
380
|
+
getOrCreateLeaderboard(name: string, sortOrder: LeaderboardSortOrder, displayType: LeaderboardDisplayType): Promise<Leaderboard>;
|
|
381
|
+
getLeaderboardEntryCount(leaderboardId: GenericId<"leaderboards">): number;
|
|
382
|
+
getMyLeaderboardEntries(leaderboardId: GenericId<"leaderboards">): Promise<LeaderboardEntries>;
|
|
383
|
+
listLeaderboardEntriesAroundUser(leaderboardId: GenericId<"leaderboards">, countAhead: number, countBehind: number, friendsOnly?: boolean): Promise<LeaderboardEntries>;
|
|
384
|
+
listLeaderboardEntries(leaderboardId: GenericId<"leaderboards">, offset: number, limit: number, friendsOnly?: boolean): Promise<LeaderboardEntries>;
|
|
385
|
+
uploadLeaderboardScore(leaderboardId: GenericId<"leaderboards">, score: number, keepBest: boolean, ugcId?: GenericId<"userGeneratedContent">): Promise<UpsertedLeaderboardEntry>;
|
|
386
|
+
private updateCachedTotalEntries;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* P2P networking service
|
|
391
|
+
*
|
|
392
|
+
* Handles WebRTC peer-to-peer connections for lobbies
|
|
393
|
+
*/
|
|
394
|
+
|
|
395
|
+
declare class P2PManager {
|
|
396
|
+
private sdk;
|
|
397
|
+
private config;
|
|
398
|
+
private currentConnection;
|
|
399
|
+
private peerConnections;
|
|
400
|
+
private reliableChannels;
|
|
401
|
+
private unreliableChannels;
|
|
402
|
+
private pendingIceCandidates;
|
|
403
|
+
private iceRestartAttempts;
|
|
404
|
+
private iceRestartInProgress;
|
|
405
|
+
private readonly MAX_ICE_RESTART_ATTEMPTS;
|
|
406
|
+
private reconnectingPeers;
|
|
407
|
+
private establishedPeers;
|
|
408
|
+
private packetDropTrackers;
|
|
409
|
+
private readonly PACKET_DROP_WINDOW_MS;
|
|
410
|
+
private turnCredentials;
|
|
411
|
+
private turnCredentialsInitPromise;
|
|
412
|
+
private unsubscribeFromSignalingMessages;
|
|
413
|
+
private processedSignalingMessages;
|
|
414
|
+
private pendingProcessedMessageIds;
|
|
415
|
+
private initializationInProgress;
|
|
416
|
+
private initializationLobbyId;
|
|
417
|
+
private signalingSubscriptionReady;
|
|
418
|
+
private signalingSubscriptionReadyResolver;
|
|
419
|
+
private channelQueues;
|
|
420
|
+
private readonly MESSAGE_SLOT_HEADER_SIZE;
|
|
421
|
+
private readonly MAX_CHANNELS;
|
|
422
|
+
private readonly USERID_SIZE;
|
|
423
|
+
private readonly CHANNEL_SIZE;
|
|
424
|
+
private readonly DATALENGTH_SIZE;
|
|
425
|
+
private readonly CHANNEL_OFFSET;
|
|
426
|
+
private readonly DATALENGTH_OFFSET;
|
|
427
|
+
private readonly PAYLOAD_OFFSET;
|
|
428
|
+
private readonly WIRE_CHANNEL_SIZE;
|
|
429
|
+
private readonly WIRE_CHANNEL_OFFSET;
|
|
430
|
+
private readonly WIRE_PAYLOAD_OFFSET;
|
|
431
|
+
private static readonly MAX_MESSAGE_SIZE;
|
|
432
|
+
private static readonly MEMORY_WARNING_THRESHOLD_BYTES;
|
|
433
|
+
private QUEUE_SIZE;
|
|
434
|
+
private MESSAGE_SIZE;
|
|
435
|
+
private MAX_PAYLOAD_SIZE;
|
|
436
|
+
private outgoingMessageBuffer;
|
|
437
|
+
private textEncoder;
|
|
438
|
+
private textDecoder;
|
|
439
|
+
private initialized;
|
|
440
|
+
constructor(sdk: WavedashSDK);
|
|
441
|
+
private ensureInitialized;
|
|
442
|
+
init(config?: Partial<P2PConfig>): void;
|
|
443
|
+
initializeP2PForCurrentLobby(lobbyId: GenericId<"lobbies">, members: SDKUser[]): Promise<P2PConnection>;
|
|
444
|
+
/**
|
|
445
|
+
* Internal method that performs the actual P2P initialization.
|
|
446
|
+
* Called by initializeP2PForCurrentLobby with proper locking.
|
|
447
|
+
*/
|
|
448
|
+
private doInitializeP2P;
|
|
449
|
+
/**
|
|
450
|
+
* Get ICE servers, initializing TURN credentials if necessary.
|
|
451
|
+
* Uses a promise to debounce concurrent calls and prevent race conditions.
|
|
452
|
+
*/
|
|
453
|
+
private getIceServers;
|
|
454
|
+
private updateP2PConnection;
|
|
455
|
+
private establishWebRTCConnections;
|
|
456
|
+
private subscribeToSignalingMessages;
|
|
457
|
+
private stopSignalingMessageSubscription;
|
|
458
|
+
private processSignalingMessages;
|
|
459
|
+
private handleSignalingMessage;
|
|
460
|
+
/**
|
|
461
|
+
* Flush any buffered ICE candidates for a peer after remote description is set.
|
|
462
|
+
* This handles the race condition where ICE candidates arrive before the offer/answer.
|
|
463
|
+
*/
|
|
464
|
+
private flushPendingIceCandidates;
|
|
465
|
+
private establishPeerConnections;
|
|
466
|
+
private createOfferToPeer;
|
|
467
|
+
private createPeerConnection;
|
|
468
|
+
/**
|
|
469
|
+
* Attempt to restart ICE when connection fails.
|
|
470
|
+
* Only the peer with the lower userId initiates the restart to avoid conflicts.
|
|
471
|
+
*/
|
|
472
|
+
private attemptIceRestart;
|
|
473
|
+
private setupDataChannelHandlers;
|
|
474
|
+
sendP2PMessage(toUserId: GenericId<"users"> | undefined, appChannel: number | undefined, reliable: boolean | undefined, payload: Uint8Array, payloadSize?: number): boolean;
|
|
475
|
+
private sendSignalingMessage;
|
|
476
|
+
disconnectP2P(): void;
|
|
477
|
+
isPeerReady(userId: GenericId<"users">): boolean;
|
|
478
|
+
isBroadcastReady(): boolean;
|
|
479
|
+
getPeerStatuses(): Record<GenericId<"users">, {
|
|
480
|
+
reliable?: string;
|
|
481
|
+
unreliable?: string;
|
|
482
|
+
ready: boolean;
|
|
483
|
+
}>;
|
|
484
|
+
private createChannelQueue;
|
|
485
|
+
/**
|
|
486
|
+
* Record a packet drop and emit P2P_PACKET_DROPPED with rate-limiting per
|
|
487
|
+
* (channel, direction, reason) tuple. First drop on an idle tuple fires
|
|
488
|
+
* immediately; subsequent drops within PACKET_DROP_WINDOW_MS are coalesced
|
|
489
|
+
* into a single event at the end of the window.
|
|
490
|
+
*/
|
|
491
|
+
private reportPacketDrop;
|
|
492
|
+
private flushPacketDropWindow;
|
|
493
|
+
private emitPacketDropped;
|
|
494
|
+
private clearPacketDropTrackers;
|
|
495
|
+
private enqueueMessage;
|
|
496
|
+
getMaxPayloadSize(): number;
|
|
497
|
+
getMaxIncomingMessages(): number;
|
|
498
|
+
getOutgoingMessageBuffer(): Uint8Array;
|
|
499
|
+
readMessageFromChannel(appChannel: number): P2PMessage | null;
|
|
500
|
+
private readRawMessage;
|
|
501
|
+
drainChannelToBuffer(appChannel: number, buffer?: Uint8Array): Uint8Array;
|
|
502
|
+
private encodeWireMessage;
|
|
503
|
+
private decodeBinaryMessage;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
type StatEntry = {
|
|
507
|
+
identifier: string;
|
|
508
|
+
value: number;
|
|
509
|
+
};
|
|
510
|
+
declare class StatsManager {
|
|
511
|
+
private sdk;
|
|
512
|
+
private stats;
|
|
513
|
+
private unlockedAchievements;
|
|
514
|
+
private dirtyStats;
|
|
515
|
+
private dirtyAchievements;
|
|
516
|
+
private knownStatIds;
|
|
517
|
+
private knownAchievementIds;
|
|
518
|
+
private loaded;
|
|
519
|
+
private subscriptions;
|
|
520
|
+
constructor(sdk: WavedashSDK);
|
|
521
|
+
destroy(): void;
|
|
522
|
+
private isReady;
|
|
523
|
+
private subscribe;
|
|
524
|
+
requestStats(): Promise<boolean>;
|
|
525
|
+
private debouncedPersist;
|
|
526
|
+
storeStats(): boolean;
|
|
527
|
+
private persist;
|
|
528
|
+
getStat(identifier: string): number;
|
|
529
|
+
setStat(identifier: string, value: number, storeNow?: boolean): boolean;
|
|
530
|
+
getAchievement(identifier: string): boolean;
|
|
531
|
+
setAchievement(identifier: string, storeNow?: boolean): boolean;
|
|
532
|
+
/** @destructive - Returns the pending stats and achievements and resets the dirty collections */
|
|
533
|
+
getPendingData(): {
|
|
534
|
+
stats: StatEntry[];
|
|
535
|
+
achievements: string[];
|
|
536
|
+
} | null;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Heartbeat service
|
|
541
|
+
*
|
|
542
|
+
* Polls connection state and allows the game to update rich user presence
|
|
543
|
+
* Lets the game know if backend connection ever changes.
|
|
544
|
+
* Lets the game update userPresence in the backend
|
|
545
|
+
*/
|
|
546
|
+
|
|
547
|
+
declare class HeartbeatManager {
|
|
548
|
+
private sdk;
|
|
549
|
+
private deviceFingerprint;
|
|
550
|
+
private deviceFingerprintReady;
|
|
551
|
+
private testConnectionInterval;
|
|
552
|
+
private heartbeatInterval;
|
|
553
|
+
private isConnected;
|
|
554
|
+
private sentDisconnectedEvent;
|
|
555
|
+
private disconnectedAt;
|
|
556
|
+
private lastHeartbeatTime;
|
|
557
|
+
private heartbeatInFlight;
|
|
558
|
+
private isFirstTick;
|
|
559
|
+
private readonly TEST_CONNECTION_INTERVAL_MS;
|
|
560
|
+
private readonly DISCONNECTED_TIMEOUT_MS;
|
|
561
|
+
constructor(sdk: WavedashSDK);
|
|
562
|
+
/** Start heartbeat and connection-check intervals */
|
|
563
|
+
start(): void;
|
|
564
|
+
/** Stop heartbeat and connection-check intervals */
|
|
565
|
+
stop(): void;
|
|
566
|
+
/** Full teardown — stops intervals and removes all listeners */
|
|
567
|
+
destroy(): void;
|
|
568
|
+
private handleVisibilityChange;
|
|
569
|
+
private tickHeartbeat;
|
|
570
|
+
private sendHeartbeat;
|
|
571
|
+
/**
|
|
572
|
+
* Updates user presence in the backend
|
|
573
|
+
* @param data - Data to send to the backend
|
|
574
|
+
* @returns true if the presence was updated successfully
|
|
575
|
+
*/
|
|
576
|
+
updateUserPresence(data?: Record<string, unknown>): Promise<boolean>;
|
|
577
|
+
/**
|
|
578
|
+
* Tests the connection to the backend
|
|
579
|
+
*/
|
|
580
|
+
private testConnection;
|
|
581
|
+
isCurrentlyConnected(): boolean;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
declare class GameEventManager {
|
|
585
|
+
private sdk;
|
|
586
|
+
private eventQueue;
|
|
587
|
+
constructor(sdk: WavedashSDK);
|
|
588
|
+
notifyGame(event: WavedashEvent, payload: string | number | boolean | object): void;
|
|
589
|
+
private sendGameEvent;
|
|
590
|
+
flushEventQueue(): void;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* Friends service
|
|
595
|
+
*
|
|
596
|
+
* Implements friend-related methods for the Wavedash SDK
|
|
597
|
+
*/
|
|
598
|
+
|
|
599
|
+
declare const AVATAR_SIZE_SMALL = 0;
|
|
600
|
+
declare const AVATAR_SIZE_MEDIUM = 1;
|
|
601
|
+
declare const AVATAR_SIZE_LARGE = 2;
|
|
602
|
+
declare class FriendsManager {
|
|
603
|
+
private sdk;
|
|
604
|
+
private userCache;
|
|
605
|
+
constructor(sdk: WavedashSDK);
|
|
606
|
+
/**
|
|
607
|
+
* Cache users from any source (friends, lobby users)
|
|
608
|
+
* Accepts both Friend format (avatarUrl) and LobbyUser format (userAvatarUrl)
|
|
609
|
+
* @param users - Array of users with userId, username, and optional avatar r2Key
|
|
610
|
+
*/
|
|
611
|
+
cacheUsers(users: Array<{
|
|
612
|
+
userId: GenericId<"users">;
|
|
613
|
+
username: string;
|
|
614
|
+
avatarUrl?: string;
|
|
615
|
+
userAvatarUrl?: string;
|
|
616
|
+
}>): void;
|
|
617
|
+
/**
|
|
618
|
+
* Returns CDN URL with size transformation for a cached user's avatar
|
|
619
|
+
* @param userId - The user ID to get the avatar URL for
|
|
620
|
+
* @param size - Avatar size constant (AVATAR_SIZE_SMALL, AVATAR_SIZE_MEDIUM, or AVATAR_SIZE_LARGE)
|
|
621
|
+
* @returns CDN URL with size transformation, or null if user not cached or has no avatar
|
|
622
|
+
*/
|
|
623
|
+
getUserAvatarUrl(userId: GenericId<"users">, size?: number): string | null;
|
|
624
|
+
/**
|
|
625
|
+
* Returns the cached username for a given user ID
|
|
626
|
+
* @param userId - The user ID to get the username for
|
|
627
|
+
* @returns The username, or null if user not cached
|
|
628
|
+
*/
|
|
629
|
+
getUsername(userId: GenericId<"users">): string | null;
|
|
630
|
+
listFriends(): Promise<Friend[]>;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* Logger interface and implementation
|
|
635
|
+
* Simply logs to the console with customizable log level
|
|
636
|
+
*
|
|
637
|
+
* In the future we could extend this to write .log files to IndexedDB or cache storage
|
|
638
|
+
*/
|
|
639
|
+
interface Logger {
|
|
640
|
+
debug(message: string, ...args: unknown[]): void;
|
|
641
|
+
info(message: string, ...args: unknown[]): void;
|
|
642
|
+
warn(message: string, ...args: unknown[]): void;
|
|
643
|
+
error(message: string, ...args: unknown[]): void;
|
|
644
|
+
}
|
|
645
|
+
declare class WavedashLogger implements Logger {
|
|
646
|
+
private logLevel;
|
|
647
|
+
constructor(logLevel?: number);
|
|
648
|
+
setLogLevel(level: number): void;
|
|
649
|
+
debug(message: string, ...args: unknown[]): void;
|
|
650
|
+
info(message: string, ...args: unknown[]): void;
|
|
651
|
+
warn(message: string, ...args: unknown[]): void;
|
|
652
|
+
error(message: string, ...args: unknown[]): void;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* Utilities for handling iframe messaging between the iframe'd Wavedash SDK and the parent window.
|
|
657
|
+
* Assumes window is defined and this is only ever running inside an iframe.
|
|
658
|
+
*
|
|
659
|
+
* TODO: Look into Vercel's BIDC for this https://github.com/vercel/bidc
|
|
660
|
+
*/
|
|
661
|
+
|
|
662
|
+
declare class IFrameMessenger {
|
|
663
|
+
private pendingRequests;
|
|
664
|
+
private requestIdCounter;
|
|
665
|
+
constructor();
|
|
666
|
+
private handleMessage;
|
|
667
|
+
postToParent(requestType: (typeof IFRAME_MESSAGE_TYPE)[keyof typeof IFRAME_MESSAGE_TYPE], data: Record<string, string | number | boolean>): boolean;
|
|
668
|
+
/**
|
|
669
|
+
* Register global keyboard/mouse handlers for iframe communication.
|
|
670
|
+
* Handles F3 prevention, initial interaction signaling, and Tab+Shift overlay toggle.
|
|
671
|
+
* Called once during SDK setup.
|
|
672
|
+
*/
|
|
673
|
+
registerEventHandlers(): void;
|
|
674
|
+
requestFromParent<T extends keyof IFrameEventPayloadMap>(requestType: T, data?: Record<string, unknown>): Promise<IFrameEventPayloadMap[T]>;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
declare class WavedashSDK extends EventTarget {
|
|
678
|
+
private _initialized;
|
|
679
|
+
get initialized(): boolean;
|
|
680
|
+
private _eventsReady;
|
|
681
|
+
get eventsReady(): boolean;
|
|
682
|
+
private launchParams;
|
|
683
|
+
private sessionEndSent;
|
|
684
|
+
private convexHttpUrl;
|
|
685
|
+
private gameFinishedLoading;
|
|
686
|
+
Events: {
|
|
687
|
+
readonly LOBBY_MESSAGE: "LobbyMessage";
|
|
688
|
+
readonly LOBBY_JOINED: "LobbyJoined";
|
|
689
|
+
readonly LOBBY_KICKED: "LobbyKicked";
|
|
690
|
+
readonly LOBBY_USERS_UPDATED: "LobbyUsersUpdated";
|
|
691
|
+
readonly LOBBY_DATA_UPDATED: "LobbyDataUpdated";
|
|
692
|
+
readonly LOBBY_INVITE: "LobbyInvite";
|
|
693
|
+
readonly P2P_CONNECTION_ESTABLISHED: "P2PConnectionEstablished";
|
|
694
|
+
readonly P2P_CONNECTION_FAILED: "P2PConnectionFailed";
|
|
695
|
+
readonly P2P_PEER_DISCONNECTED: "P2PPeerDisconnected";
|
|
696
|
+
readonly P2P_PEER_RECONNECTING: "P2PPeerReconnecting";
|
|
697
|
+
readonly P2P_PEER_RECONNECTED: "P2PPeerReconnected";
|
|
698
|
+
readonly P2P_PACKET_DROPPED: "P2PPacketDropped";
|
|
699
|
+
readonly STATS_STORED: "StatsStored";
|
|
700
|
+
readonly BACKEND_CONNECTED: "BackendConnected";
|
|
701
|
+
readonly BACKEND_DISCONNECTED: "BackendDisconnected";
|
|
702
|
+
readonly BACKEND_RECONNECTING: "BackendReconnecting";
|
|
703
|
+
};
|
|
704
|
+
protected lobbyManager: LobbyManager;
|
|
705
|
+
protected statsManager: StatsManager;
|
|
706
|
+
protected heartbeatManager: HeartbeatManager;
|
|
707
|
+
protected ugcManager: UGCManager;
|
|
708
|
+
protected leaderboardManager: LeaderboardManager;
|
|
709
|
+
gameEventManager: GameEventManager;
|
|
710
|
+
friendsManager: FriendsManager;
|
|
711
|
+
config: WavedashConfig | null;
|
|
712
|
+
wavedashUser: SDKUser;
|
|
713
|
+
gameCloudId: string;
|
|
714
|
+
fileSystemManager: FileSystemManager;
|
|
715
|
+
convexClient: ConvexClient;
|
|
716
|
+
engineCallbackReceiver: string;
|
|
717
|
+
engineInstance: EngineInstance | null;
|
|
718
|
+
logger: WavedashLogger;
|
|
719
|
+
iframeMessenger: IFrameMessenger;
|
|
720
|
+
p2pManager: P2PManager;
|
|
721
|
+
private gameplayJwt;
|
|
722
|
+
private gameplayJwtPromise;
|
|
723
|
+
ugcHost: string;
|
|
724
|
+
uploadsHost: string;
|
|
725
|
+
constructor(sdkConfig: SDKConfig);
|
|
726
|
+
init(config?: WavedashConfig): boolean;
|
|
727
|
+
/**
|
|
728
|
+
* Signal that the game is ready to receive events (LobbyJoined, LobbyMessage, etc).
|
|
729
|
+
* Called automatically by init() unless deferEvents: true is passed in the config.
|
|
730
|
+
* If deferEvents is true, call this manually after your pre-game setup is complete.
|
|
731
|
+
*/
|
|
732
|
+
readyForEvents(): void;
|
|
733
|
+
loadScript(src: string): Promise<unknown>;
|
|
734
|
+
updateLoadProgressZeroToOne(progress: number): void;
|
|
735
|
+
loadComplete(): void;
|
|
736
|
+
get gameLoaded(): boolean;
|
|
737
|
+
toggleOverlay(): void;
|
|
738
|
+
getUser(): SDKUser;
|
|
739
|
+
/**
|
|
740
|
+
* Get a username. Returns the logged in user's username if no ID is passed.
|
|
741
|
+
* This can only return a username for a user the game has already interacted with, either via listFriends() or shared lobby membership.
|
|
742
|
+
* @param userId - Optional user ID to look up. If omitted, returns the current user's username.
|
|
743
|
+
* @returns The username, or null if a userId was passed but the user has not been seen by the game yet.
|
|
744
|
+
*/
|
|
745
|
+
getUsername(): string;
|
|
746
|
+
getUsername(userId: GenericId<"users">): string | null;
|
|
747
|
+
getUserId(): GenericId<"users">;
|
|
748
|
+
/**
|
|
749
|
+
* Get the current user's gameplay JWT, fetching it if not already cached.
|
|
750
|
+
* This should be used to authenticate requests to your game's own backend,
|
|
751
|
+
* if you have one.
|
|
752
|
+
* @returns The user's JWT signed by the Wavedash backend
|
|
753
|
+
*/
|
|
754
|
+
getUserJwt(): Promise<WavedashResponse<string>>;
|
|
755
|
+
/**
|
|
756
|
+
* Get the key: value mapping of all URL query params present when the game was launched
|
|
757
|
+
* lobby - The lobby ID to join if the user launched with the intention to join a lobby
|
|
758
|
+
* @returns Dictionary of the URL query params that were present when the game was launched
|
|
759
|
+
*/
|
|
760
|
+
getLaunchParams(): GameLaunchParams;
|
|
761
|
+
listFriends(): Promise<WavedashResponse<Friend[]>>;
|
|
762
|
+
/**
|
|
763
|
+
* Get avatar URL for a cached user with size transformation.
|
|
764
|
+
* Users are cached when seen via listFriends() or lobby membership.
|
|
765
|
+
* @param userId - The user ID to get the avatar URL for
|
|
766
|
+
* @param size - Avatar size constant (AVATAR_SIZE_SMALL=0, AVATAR_SIZE_MEDIUM=1, AVATAR_SIZE_LARGE=2)
|
|
767
|
+
* @returns CDN URL with size transformation, or null if user not cached or has no avatar
|
|
768
|
+
*/
|
|
769
|
+
getUserAvatarUrl(userId: GenericId<"users">, size?: number): string | null;
|
|
770
|
+
getLeaderboard(name: string): Promise<WavedashResponse<Leaderboard>>;
|
|
771
|
+
getOrCreateLeaderboard(name: string, sortOrder: LeaderboardSortOrder, displayType: LeaderboardDisplayType): Promise<WavedashResponse<Leaderboard>>;
|
|
772
|
+
getLeaderboardEntryCount(leaderboardId: GenericId<"leaderboards">): number;
|
|
773
|
+
getMyLeaderboardEntries(leaderboardId: GenericId<"leaderboards">): Promise<WavedashResponse<LeaderboardEntries>>;
|
|
774
|
+
listLeaderboardEntriesAroundUser(leaderboardId: GenericId<"leaderboards">, countAhead: number, countBehind: number, friendsOnly?: boolean): Promise<WavedashResponse<LeaderboardEntries>>;
|
|
775
|
+
listLeaderboardEntries(leaderboardId: GenericId<"leaderboards">, offset: number, limit: number, friendsOnly?: boolean): Promise<WavedashResponse<LeaderboardEntries>>;
|
|
776
|
+
uploadLeaderboardScore(leaderboardId: GenericId<"leaderboards">, score: number, keepBest: boolean, ugcId?: GenericId<"userGeneratedContent">): Promise<WavedashResponse<UpsertedLeaderboardEntry>>;
|
|
777
|
+
/**
|
|
778
|
+
* Creates a new UGC item and uploads the file to the server if a filePath is provided
|
|
779
|
+
* @param ugcType
|
|
780
|
+
* @param title
|
|
781
|
+
* @param description
|
|
782
|
+
* @param visibility
|
|
783
|
+
* @param filePath - optional IndexedDB key file path to upload to the server. If not provided, the UGC item will be created but no file will be uploaded.
|
|
784
|
+
* @returns ugcId
|
|
785
|
+
*/
|
|
786
|
+
createUGCItem(ugcType: UGCType, title?: string, description?: string, visibility?: UGCVisibility, filePath?: string): Promise<WavedashResponse<GenericId<"userGeneratedContent">>>;
|
|
787
|
+
/**
|
|
788
|
+
* Updates a UGC item and uploads the file to the server if a filePath is provided
|
|
789
|
+
* TODO: GD Script cannot call with optional arguments, convert this to accept a single dictionary of updates
|
|
790
|
+
* @param ugcId
|
|
791
|
+
* @param title
|
|
792
|
+
* @param description
|
|
793
|
+
* @param visibility
|
|
794
|
+
* @param filePath - optional IndexedDB key file path to upload to the server. If not provided, the UGC item will be updated but no file will be uploaded.
|
|
795
|
+
* @returns ugcId
|
|
796
|
+
*/
|
|
797
|
+
updateUGCItem(ugcId: GenericId<"userGeneratedContent">, title?: string, description?: string, visibility?: UGCVisibility, filePath?: string): Promise<WavedashResponse<GenericId<"userGeneratedContent">>>;
|
|
798
|
+
downloadUGCItem(ugcId: GenericId<"userGeneratedContent">, filePath: string): Promise<WavedashResponse<GenericId<"userGeneratedContent">>>;
|
|
799
|
+
/**
|
|
800
|
+
* Deletes a remote file from storage
|
|
801
|
+
* @param filePath - The path of the remote file to delete
|
|
802
|
+
* @returns The path of the remote file that was deleted
|
|
803
|
+
*/
|
|
804
|
+
deleteRemoteFile(filePath: string): Promise<WavedashResponse<string>>;
|
|
805
|
+
/**
|
|
806
|
+
* Downloads a remote file to a local location
|
|
807
|
+
* @param filePath - The path of the remote file to download
|
|
808
|
+
* @param downloadTo - Optionally provide a path to download the file to, defaults to the same path as the remote file
|
|
809
|
+
* @returns The path of the local file that the remote file was downloaded to
|
|
810
|
+
*/
|
|
811
|
+
downloadRemoteFile(filePath: string): Promise<WavedashResponse<string>>;
|
|
812
|
+
/**
|
|
813
|
+
* Uploads a local file to remote storage
|
|
814
|
+
* @param filePath - The path of the local file to upload
|
|
815
|
+
* @param uploadTo - Optionally provide a path to upload the file to, defaults to the same path as the local file
|
|
816
|
+
* @returns The path of the remote file that the local file was uploaded to
|
|
817
|
+
*/
|
|
818
|
+
uploadRemoteFile(filePath: string): Promise<WavedashResponse<string>>;
|
|
819
|
+
/**
|
|
820
|
+
* Lists a remote directory
|
|
821
|
+
* @param path - The path of the remote directory to list
|
|
822
|
+
* @returns A list of metadata for each file in the remote directory
|
|
823
|
+
*/
|
|
824
|
+
listRemoteDirectory(path: string): Promise<WavedashResponse<RemoteFileMetadata[]>>;
|
|
825
|
+
/**
|
|
826
|
+
* Downloads a remote directory to a local location
|
|
827
|
+
* @param path - The path of the remote directory to download
|
|
828
|
+
* @returns The path of the local directory that the remote directory was downloaded to
|
|
829
|
+
*/
|
|
830
|
+
downloadRemoteDirectory(path: string): Promise<WavedashResponse<string>>;
|
|
831
|
+
/**
|
|
832
|
+
* Persists data to local file storage (IndexeDB).
|
|
833
|
+
* For use in pure JS games.
|
|
834
|
+
* Games built from engines should use their engine's builtin File API to read and write files.
|
|
835
|
+
* @param filePath - The path of the local file to write
|
|
836
|
+
* @param data - The data to write to the local file (byte array)
|
|
837
|
+
* @returns true if the file was written successfully
|
|
838
|
+
*/
|
|
839
|
+
writeLocalFile(filePath: string, data: Uint8Array): Promise<boolean>;
|
|
840
|
+
/**
|
|
841
|
+
* Reads data from local file storage (IndexedDB).
|
|
842
|
+
* For use in pure JS games.
|
|
843
|
+
* Games built from engines should use their engine's builtin File API to read and write files.
|
|
844
|
+
* @param filePath - The path of the local file to read
|
|
845
|
+
* @returns The data read from the local file (byte array)
|
|
846
|
+
*/
|
|
847
|
+
readLocalFile(filePath: string): Promise<Uint8Array | null>;
|
|
848
|
+
getAchievement(identifier: string): boolean;
|
|
849
|
+
getStat(identifier: string): number;
|
|
850
|
+
setAchievement(identifier: string, storeNow?: boolean): boolean;
|
|
851
|
+
setStat(identifier: string, value: number, storeNow?: boolean): boolean;
|
|
852
|
+
requestStats(): Promise<WavedashResponse<boolean>>;
|
|
853
|
+
storeStats(): boolean;
|
|
854
|
+
/**
|
|
855
|
+
* Get the maximum payload size in bytes for a single P2P message.
|
|
856
|
+
* This is derived from the configured messageSize minus protocol overhead.
|
|
857
|
+
*/
|
|
858
|
+
getP2PMaxPayloadSize(): number;
|
|
859
|
+
/**
|
|
860
|
+
* Get the configured max incoming messages per channel queue.
|
|
861
|
+
*/
|
|
862
|
+
getP2PMaxIncomingMessages(): number;
|
|
863
|
+
/**
|
|
864
|
+
* Get a pre-allocated scratch buffer for outgoing messages
|
|
865
|
+
* @returns A Uint8Array buffer that can your game can write the binary payload to before calling sendP2PMessage
|
|
866
|
+
*/
|
|
867
|
+
getP2POutgoingMessageBuffer(): Uint8Array;
|
|
868
|
+
/**
|
|
869
|
+
* Send a message through P2P to a specific peer using their userId
|
|
870
|
+
* @param toUserId - Peer userId to send to (undefined = broadcast)
|
|
871
|
+
* @param appChannel - Optional channel for message routing. All messages still use the same P2P connection under the hood.
|
|
872
|
+
* @param reliable - Send reliably, meaning guaranteed delivery and ordering, but slower (default: true)
|
|
873
|
+
* @param payload - The payload to send (byte array)
|
|
874
|
+
* @param payloadSize - How many bytes from the payload to send. Defaults to payload.length (the entire payload)
|
|
875
|
+
* @returns true if the message was sent out successfully
|
|
876
|
+
*/
|
|
877
|
+
sendP2PMessage(toUserId: GenericId<"users"> | undefined, appChannel: number | undefined, reliable: boolean | undefined, payload: Uint8Array, payloadSize?: number): boolean;
|
|
878
|
+
/**
|
|
879
|
+
* Send the same payload to all peers in the lobby
|
|
880
|
+
* @param appChannel - Optional app-level channel for message routing. All messages still use the same P2P connection under the hood.
|
|
881
|
+
* @param reliable - Send reliably, meaning guaranteed delivery and ordering, but slower (default: true)
|
|
882
|
+
* @param payload - The payload to send (byte array)
|
|
883
|
+
* @param payloadSize - How many bytes from the payload to send. Defaults to payload.length (the entire payload)
|
|
884
|
+
* @returns true if the message was sent out successfully
|
|
885
|
+
*/
|
|
886
|
+
broadcastP2PMessage(appChannel: number | undefined, reliable: boolean | undefined, payload: Uint8Array, payloadSize?: number): boolean;
|
|
887
|
+
/**
|
|
888
|
+
* Read one decoded P2P message from a specific channel.
|
|
889
|
+
* Engine builds (Unity/Godot) should use drainP2PChannelToBuffer for the
|
|
890
|
+
* hot path — it's batched and returns raw bytes without decode overhead.
|
|
891
|
+
* @param appChannel - The channel to read from
|
|
892
|
+
* @returns Decoded P2PMessage, or null if the channel has no pending messages.
|
|
893
|
+
*/
|
|
894
|
+
readP2PMessageFromChannel(appChannel: number): P2PMessage | null;
|
|
895
|
+
/**
|
|
896
|
+
* Drain all messages from a P2P channel into a buffer
|
|
897
|
+
* Data will be presented in a tightly packed format: [size:4 bytes][msg:N bytes][size:4 bytes][msg:N bytes]...
|
|
898
|
+
* JS games can just use readP2PMessageFromChannel to get decoded P2PMessages
|
|
899
|
+
* Game engines should use drainP2PChannelToBuffer for better performance
|
|
900
|
+
* @param appChannel - The channel to drain
|
|
901
|
+
* @param buffer - The buffer to drain the messages into.
|
|
902
|
+
* If provided, the buffer will be filled until full, any remaining messages will be left in the queue.
|
|
903
|
+
* If not provided, a new buffer with all messages will be created and returned.
|
|
904
|
+
* @returns A Uint8Array containing each message in a tightly packed format: [size:4 bytes][msg:N bytes][size:4 bytes][msg:N bytes]...
|
|
905
|
+
*/
|
|
906
|
+
drainP2PChannelToBuffer(appChannel: number, buffer?: Uint8Array): Uint8Array;
|
|
907
|
+
/**
|
|
908
|
+
* Create a new lobby and join it as the host.
|
|
909
|
+
* @param visibility - The visibility of the lobby
|
|
910
|
+
* @param maxPlayers - Optional maximum number of players
|
|
911
|
+
* @returns A WavedashResponse with the created lobbyId.
|
|
912
|
+
* Full lobby context is provided via the LobbyJoined event.
|
|
913
|
+
* @emits LobbyJoined event on success with full lobby context
|
|
914
|
+
*/
|
|
915
|
+
createLobby(visibility: LobbyVisibility, maxPlayers?: number): Promise<WavedashResponse<GenericId<"lobbies">>>;
|
|
916
|
+
/**
|
|
917
|
+
* Join an existing lobby.
|
|
918
|
+
* @param lobbyId - The ID of the lobby to join
|
|
919
|
+
* @returns A WavedashResponse with success/failure.
|
|
920
|
+
* Full lobby context is provided via the LobbyJoined event.
|
|
921
|
+
* @emits LobbyJoined event on success with full lobby context
|
|
922
|
+
*/
|
|
923
|
+
joinLobby(lobbyId: GenericId<"lobbies">): Promise<WavedashResponse<boolean>>;
|
|
924
|
+
listAvailableLobbies(friendsOnly?: boolean): Promise<WavedashResponse<Lobby[]>>;
|
|
925
|
+
getLobbyUsers(lobbyId: GenericId<"lobbies">): LobbyUser[];
|
|
926
|
+
getNumLobbyUsers(lobbyId: GenericId<"lobbies">): number;
|
|
927
|
+
getLobbyHostId(lobbyId: GenericId<"lobbies">): GenericId<"users"> | null;
|
|
928
|
+
getLobbyData(lobbyId: GenericId<"lobbies">, key: string): string | number | null;
|
|
929
|
+
setLobbyData(lobbyId: GenericId<"lobbies">, key: string, value: string | number | null): boolean;
|
|
930
|
+
deleteLobbyData(lobbyId: GenericId<"lobbies">, key: string): boolean;
|
|
931
|
+
leaveLobby(lobbyId: GenericId<"lobbies">): Promise<WavedashResponse<GenericId<"lobbies">>>;
|
|
932
|
+
sendLobbyMessage(lobbyId: GenericId<"lobbies">, message: string): boolean;
|
|
933
|
+
inviteUserToLobby(lobbyId: GenericId<"lobbies">, userId: GenericId<"users">): Promise<WavedashResponse<boolean>>;
|
|
934
|
+
getLobbyInviteLink(copyToClipboard?: boolean): Promise<WavedashResponse<string>>;
|
|
935
|
+
/**
|
|
936
|
+
* Updates rich user presence so friends can see what the player is doing in game
|
|
937
|
+
* TODO: data param should be more strongly typed
|
|
938
|
+
* @param data Game data to send to the backend
|
|
939
|
+
* @returns true if the presence was updated successfully
|
|
940
|
+
*/
|
|
941
|
+
updateUserPresence(data?: Record<string, unknown>): Promise<WavedashResponse<boolean>>;
|
|
942
|
+
private isGodot;
|
|
943
|
+
private formatResponse;
|
|
944
|
+
private ensureInit;
|
|
945
|
+
private apiCall;
|
|
946
|
+
private apiCallSync;
|
|
947
|
+
/**
|
|
948
|
+
* Fetches (or returns cached) gameplay JWT. Callers outside of Convex's
|
|
949
|
+
* setAuth should use {@link ensureGameplayJwt} instead; this method is the
|
|
950
|
+
* fetcher wired into `ConvexClient.setAuth` and honors `forceRefresh` so the
|
|
951
|
+
* server can invalidate a stale token.
|
|
952
|
+
*
|
|
953
|
+
* Concurrent callers share a single in-flight fetch to avoid duplicate
|
|
954
|
+
* requests to the parent's gameplay-token endpoint.
|
|
955
|
+
*/
|
|
956
|
+
private getAuthToken;
|
|
957
|
+
/**
|
|
958
|
+
* Returns the cached gameplay JWT, awaiting the in-flight fetch if one is
|
|
959
|
+
* already running (e.g. from Convex's initial setAuth). Use this anywhere
|
|
960
|
+
* you need to authenticate a request outside of the Convex client.
|
|
961
|
+
*/
|
|
962
|
+
ensureGameplayJwt(): Promise<string>;
|
|
963
|
+
/**
|
|
964
|
+
* Set up listeners for page unload events to end gameplay session.
|
|
965
|
+
* Uses both beforeunload and pagehide for maximum reliability.
|
|
966
|
+
*/
|
|
967
|
+
private setupSessionEndListeners;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
declare function setupWavedashSDK(): WavedashSDK;
|
|
971
|
+
|
|
972
|
+
export { AVATAR_SIZE_LARGE, AVATAR_SIZE_MEDIUM, AVATAR_SIZE_SMALL, type BackendConnectionPayload, type EngineInstance, type Friend, type Leaderboard, type LeaderboardDisplayType, type LeaderboardEntries, type LeaderboardSortOrder, type Lobby, type LobbyDataUpdatedPayload, type LobbyInvite, type LobbyInvitePayload, type LobbyJoinResponse, type LobbyJoinedPayload, type LobbyKickedPayload, LobbyKickedReason, type LobbyMessage, type LobbyMessagePayload, type LobbyUser, LobbyUserChangeType, type LobbyUsersUpdatedPayload, type LobbyVisibility, type P2PConfig, type P2PConnection, type P2PConnectionEstablishedPayload, type P2PConnectionFailedPayload, type P2PMessage, type P2PPacketDropReason, type P2PPacketDroppedPayload, type P2PPeer, type P2PPeerDisconnectedPayload, type P2PPeerReconnectedPayload, type P2PPeerReconnectingPayload, type P2PSignalingMessage, type P2PTurnCredentials, type RemoteFileMetadata, type StatsStoredPayload, type UGCType, type UGCVisibility, type UpsertedLeaderboardEntry, type WavedashConfig, type WavedashEvent, WavedashEvents, type WavedashResponse, WavedashSDK, setupWavedashSDK };
|