@wvdsh/sdk-js 1.3.10 → 1.3.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.d.ts +1 -1
- package/dist/index.d.ts +42 -20
- package/dist/index.js +212 -131
- package/package.json +2 -2
package/dist/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { WavedashSDK } from './index.js';
|
|
2
|
-
export { BackendConnectionPayload, EngineInstance, Friend, FullscreenChangedPayload, Leaderboard, LeaderboardDisplayType, LeaderboardEntries, LeaderboardSortOrder, Lobby, LobbyDataUpdatedPayload, LobbyInvite, LobbyInvitePayload, LobbyJoinResponse, LobbyJoinedPayload, LobbyKickedPayload, LobbyKickedReason, LobbyMessage, LobbyMessagePayload, LobbyUser, LobbyUserChangeType, LobbyUsersUpdatedPayload, LobbyVisibility, P2PConfig, P2PConnection, P2PConnectionEstablishedPayload, P2PConnectionFailedPayload, P2PMessage, P2PPacketDropReason, P2PPacketDroppedPayload, P2PPeer, P2PPeerDisconnectedPayload, P2PPeerReconnectedPayload, P2PPeerReconnectingPayload, RemoteFileMetadata, StatsStoredPayload, UGCType, UGCVisibility, UpsertedLeaderboardEntry, WavedashConfig, WavedashEvent, WavedashEventMap, WavedashResponse } from './index.js';
|
|
2
|
+
export { BackendConnectionPayload, EngineInstance, Friend, FullscreenChangedPayload, Leaderboard, LeaderboardDisplayType, LeaderboardEntries, LeaderboardSortOrder, ListUGCItemsArgs, Lobby, LobbyDataUpdatedPayload, LobbyInvite, LobbyInvitePayload, LobbyJoinResponse, LobbyJoinedPayload, LobbyKickedPayload, LobbyKickedReason, LobbyMessage, LobbyMessagePayload, LobbyUser, LobbyUserChangeType, LobbyUsersUpdatedPayload, LobbyVisibility, P2PConfig, P2PConnection, P2PConnectionEstablishedPayload, P2PConnectionFailedPayload, P2PMessage, P2PPacketDropReason, P2PPacketDroppedPayload, P2PPeer, P2PPeerDisconnectedPayload, P2PPeerReconnectedPayload, P2PPeerReconnectingPayload, PaginatedUGCItems, RemoteFileMetadata, StatsStoredPayload, UGCItem, UGCType, UGCVisibility, UpdateUGCItemArgs, UpsertedLeaderboardEntry, WavedashConfig, WavedashEvent, WavedashEventMap, WavedashResponse } from './index.js';
|
|
3
3
|
export { GameLaunchParams } from '@wvdsh/api';
|
|
4
4
|
export { GenericId as Id } from 'convex/values';
|
|
5
5
|
import 'convex/browser';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ConvexClient } from 'convex/browser';
|
|
2
2
|
import { GenericId } from 'convex/values';
|
|
3
3
|
export { GenericId as Id } from 'convex/values';
|
|
4
|
-
import { FunctionReturnType } from 'convex/server';
|
|
4
|
+
import { FunctionReturnType, FunctionArgs } from 'convex/server';
|
|
5
5
|
import { LOBBY_VISIBILITY, api, UGC_TYPE, UGC_VISIBILITY, LEADERBOARD_SORT_ORDER, LEADERBOARD_DISPLAY_TYPE, GAME_ENGINE, SDKUser, IFrameEventPayloadMap, IFRAME_MESSAGE_TYPE, SDKConfig, GameLaunchParams } from '@wvdsh/api';
|
|
6
6
|
export { GameLaunchParams } from '@wvdsh/api';
|
|
7
7
|
|
|
@@ -71,6 +71,13 @@ type LeaderboardSortOrder = (typeof LEADERBOARD_SORT_ORDER)[keyof typeof LEADERB
|
|
|
71
71
|
type LeaderboardDisplayType = (typeof LEADERBOARD_DISPLAY_TYPE)[keyof typeof LEADERBOARD_DISPLAY_TYPE];
|
|
72
72
|
type UGCType = (typeof UGC_TYPE)[keyof typeof UGC_TYPE];
|
|
73
73
|
type UGCVisibility = (typeof UGC_VISIBILITY)[keyof typeof UGC_VISIBILITY];
|
|
74
|
+
type UpdateUGCItemArgs = Omit<FunctionArgs<typeof api.sdk.userGeneratedContent.updateUGCItem>, "ugcId" | "createPresignedUploadUrl"> & {
|
|
75
|
+
filePath?: string;
|
|
76
|
+
};
|
|
77
|
+
type UGCItem = FunctionReturnType<typeof api.sdk.userGeneratedContent.listUGCItems>["page"][0];
|
|
78
|
+
type PaginatedUGCItems = FunctionReturnType<typeof api.sdk.userGeneratedContent.listUGCItems>;
|
|
79
|
+
type RawListUGCItemsArgs = FunctionArgs<typeof api.sdk.userGeneratedContent.listUGCItems>;
|
|
80
|
+
type ListUGCItemsArgs = Omit<RawListUGCItemsArgs, "filters"> & NonNullable<RawListUGCItemsArgs["filters"]>;
|
|
74
81
|
type LobbyUser = FunctionReturnType<typeof api.sdk.gameLobby.lobbyUsers>[0];
|
|
75
82
|
type LobbyMessage = FunctionReturnType<typeof api.sdk.gameLobby.lobbyMessages>[0];
|
|
76
83
|
type Lobby = FunctionReturnType<typeof api.sdk.gameLobby.listAvailable>[0];
|
|
@@ -385,14 +392,25 @@ declare class FileSystemManager extends WavedashManager {
|
|
|
385
392
|
*/
|
|
386
393
|
deleteRemoteFile(filePath: string): Promise<string>;
|
|
387
394
|
/**
|
|
388
|
-
* Downloads a remote file to a local location
|
|
395
|
+
* Downloads a remote file to a local location.
|
|
396
|
+
* Throws on failure; the error message is the server's HTTP status (e.g. "404 (Not Found)")
|
|
397
|
+
* or a network-level description if the server didn't respond. See also: {@link remoteFileExists}
|
|
389
398
|
* @param filePath - The path of the remote file to download
|
|
390
399
|
* @returns The path of the local file that the remote file was downloaded to
|
|
391
400
|
*/
|
|
392
401
|
downloadRemoteFile(filePath: string): Promise<string>;
|
|
393
402
|
/**
|
|
394
|
-
*
|
|
395
|
-
*
|
|
403
|
+
* Checks whether a remote file exists by issuing a HEAD request.
|
|
404
|
+
* Does NOT throw for the "file does not exist" case — returns false.
|
|
405
|
+
* Throws only for real errors (network failure, auth failure, server error).
|
|
406
|
+
* @param filePath - The path of the remote file to check
|
|
407
|
+
* @returns true if the remote file exists, false otherwise
|
|
408
|
+
*/
|
|
409
|
+
remoteFileExists(filePath: string): Promise<boolean>;
|
|
410
|
+
/**
|
|
411
|
+
* Lists each file in a remote directory, including its subdirectories.
|
|
412
|
+
* Returns only file paths, no directory paths.
|
|
413
|
+
* An empty or non-existent directory returns an empty array — not an error.
|
|
396
414
|
* @param path - The path of the remote directory to list
|
|
397
415
|
* @returns A list of metadata for each file in the remote directory
|
|
398
416
|
*/
|
|
@@ -401,7 +419,7 @@ declare class FileSystemManager extends WavedashManager {
|
|
|
401
419
|
writeLocalFile(filePath: string, data: Uint8Array): Promise<boolean>;
|
|
402
420
|
readLocalFile(filePath: string): Promise<Uint8Array | null>;
|
|
403
421
|
upload(presignedUploadUrl: string, filePath: string): Promise<boolean>;
|
|
404
|
-
download(url: string, filePath: string): Promise<
|
|
422
|
+
download(url: string, filePath: string): Promise<void>;
|
|
405
423
|
private getRemoteStorageOrigin;
|
|
406
424
|
private getRemoteStorageUrl;
|
|
407
425
|
private uploadFromIndexedDb;
|
|
@@ -418,9 +436,10 @@ declare class FileSystemManager extends WavedashManager {
|
|
|
418
436
|
declare class UGCManager extends WavedashManager {
|
|
419
437
|
constructor(sdk: WavedashSDK);
|
|
420
438
|
createUGCItem(ugcType: UGCType, title?: string, description?: string, visibility?: UGCVisibility, filePath?: string): Promise<GenericId<"userGeneratedContent">>;
|
|
421
|
-
updateUGCItem(ugcId: GenericId<"userGeneratedContent">,
|
|
439
|
+
updateUGCItem(ugcId: GenericId<"userGeneratedContent">, updates?: UpdateUGCItemArgs): Promise<GenericId<"userGeneratedContent">>;
|
|
422
440
|
deleteUGCItem(ugcId: GenericId<"userGeneratedContent">): Promise<GenericId<"userGeneratedContent">>;
|
|
423
441
|
downloadUGCItem(ugcId: GenericId<"userGeneratedContent">, filePath: string): Promise<GenericId<"userGeneratedContent">>;
|
|
442
|
+
listUGCItems(args?: ListUGCItemsArgs): Promise<PaginatedUGCItems>;
|
|
424
443
|
}
|
|
425
444
|
|
|
426
445
|
/**
|
|
@@ -623,7 +642,7 @@ declare class HeartbeatManager extends WavedashManager {
|
|
|
623
642
|
* @param data - Data to send to the backend
|
|
624
643
|
* @returns true if the presence was updated successfully
|
|
625
644
|
*/
|
|
626
|
-
updateUserPresence(data?: Record<string,
|
|
645
|
+
updateUserPresence(data?: Record<string, string | number | boolean | null>): Promise<boolean>;
|
|
627
646
|
/**
|
|
628
647
|
* Tests the connection to the backend
|
|
629
648
|
*/
|
|
@@ -837,7 +856,6 @@ declare class WavedashSDK extends EventTarget {
|
|
|
837
856
|
};
|
|
838
857
|
UGCVisibility: {
|
|
839
858
|
readonly PUBLIC: 0;
|
|
840
|
-
readonly FRIENDS_ONLY: 1;
|
|
841
859
|
readonly PRIVATE: 2;
|
|
842
860
|
};
|
|
843
861
|
AvatarSize: {
|
|
@@ -987,21 +1005,19 @@ declare class WavedashSDK extends EventTarget {
|
|
|
987
1005
|
createUGCItem(ugcType: UGCType, title?: string, description?: string, visibility?: UGCVisibility, filePath?: string): Promise<WavedashResponse<GenericId<"userGeneratedContent">>>;
|
|
988
1006
|
/**
|
|
989
1007
|
* Updates a UGC item and uploads the file to the server if a filePath is provided
|
|
990
|
-
*
|
|
991
|
-
* @param
|
|
992
|
-
*
|
|
993
|
-
* @param description
|
|
994
|
-
* @param visibility
|
|
995
|
-
* @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.
|
|
1008
|
+
* @param ugcId - The ID of the UGC item to update
|
|
1009
|
+
* @param updates - Object containing the fields to update. May also be passed
|
|
1010
|
+
* as a JSON string by engine bridges (Godot) that can't marshal a dict.
|
|
996
1011
|
* @returns ugcId
|
|
997
1012
|
*/
|
|
998
|
-
updateUGCItem(ugcId: GenericId<"userGeneratedContent">,
|
|
1013
|
+
updateUGCItem(ugcId: GenericId<"userGeneratedContent">, updates?: UpdateUGCItemArgs): Promise<WavedashResponse<GenericId<"userGeneratedContent">>>;
|
|
999
1014
|
/**
|
|
1000
1015
|
* Delete a UGC item: removes the row, the R2 object, and frees up the
|
|
1001
1016
|
* user's storage quota by the size of the deleted upload.
|
|
1002
1017
|
*/
|
|
1003
1018
|
deleteUGCItem(ugcId: GenericId<"userGeneratedContent">): Promise<WavedashResponse<GenericId<"userGeneratedContent">>>;
|
|
1004
1019
|
downloadUGCItem(ugcId: GenericId<"userGeneratedContent">, filePath: string): Promise<WavedashResponse<GenericId<"userGeneratedContent">>>;
|
|
1020
|
+
listUGCItems(args?: ListUGCItemsArgs): Promise<WavedashResponse<PaginatedUGCItems>>;
|
|
1005
1021
|
/**
|
|
1006
1022
|
* Deletes a remote file from storage
|
|
1007
1023
|
* @param filePath - The path of the remote file to delete
|
|
@@ -1009,12 +1025,19 @@ declare class WavedashSDK extends EventTarget {
|
|
|
1009
1025
|
*/
|
|
1010
1026
|
deleteRemoteFile(filePath: string): Promise<WavedashResponse<string>>;
|
|
1011
1027
|
/**
|
|
1012
|
-
* Downloads a remote file to a local location
|
|
1028
|
+
* Downloads a remote file to a local location.
|
|
1029
|
+
* Returns success=false (with the server status in `message`) if the file
|
|
1030
|
+
* doesn't exist or any other error occurs. See also: {@link remoteFileExists}
|
|
1013
1031
|
* @param filePath - The path of the remote file to download
|
|
1014
|
-
* @param downloadTo - Optionally provide a path to download the file to, defaults to the same path as the remote file
|
|
1015
1032
|
* @returns The path of the local file that the remote file was downloaded to
|
|
1016
1033
|
*/
|
|
1017
1034
|
downloadRemoteFile(filePath: string): Promise<WavedashResponse<string>>;
|
|
1035
|
+
/**
|
|
1036
|
+
* Checks whether a remote file exists. Sends a lightweight HEAD request to check for existence.
|
|
1037
|
+
* @param filePath - The path of the remote file to check
|
|
1038
|
+
* @returns true if the remote file exists, false if it does not.
|
|
1039
|
+
*/
|
|
1040
|
+
remoteFileExists(filePath: string): Promise<WavedashResponse<boolean>>;
|
|
1018
1041
|
/**
|
|
1019
1042
|
* Uploads a local file to remote storage
|
|
1020
1043
|
* @param filePath - The path of the local file to upload
|
|
@@ -1140,11 +1163,10 @@ declare class WavedashSDK extends EventTarget {
|
|
|
1140
1163
|
getLobbyInviteLink(copyToClipboard?: boolean): Promise<WavedashResponse<string>>;
|
|
1141
1164
|
/**
|
|
1142
1165
|
* Updates rich user presence so friends can see what the player is doing in game
|
|
1143
|
-
* TODO: data param should be more strongly typed
|
|
1144
1166
|
* @param data Game data to send to the backend
|
|
1145
1167
|
* @returns true if the presence was updated successfully
|
|
1146
1168
|
*/
|
|
1147
|
-
updateUserPresence(data?: Record<string,
|
|
1169
|
+
updateUserPresence(data?: Record<string, string | number | boolean | null>): Promise<WavedashResponse<boolean>>;
|
|
1148
1170
|
private isGodot;
|
|
1149
1171
|
private formatResponse;
|
|
1150
1172
|
private ensureInit;
|
|
@@ -1191,4 +1213,4 @@ declare global {
|
|
|
1191
1213
|
|
|
1192
1214
|
declare function setupWavedashSDK(): WavedashSDK;
|
|
1193
1215
|
|
|
1194
|
-
export { type BackendConnectionPayload, type EngineInstance, type Friend, type FullscreenChangedPayload, type Leaderboard, type LeaderboardDisplayType, type LeaderboardEntries, type LeaderboardSortOrder, type Lobby, type LobbyDataUpdatedPayload, type LobbyInvite, type LobbyInvitePayload, type LobbyJoinResponse, type LobbyJoinedPayload, type LobbyKickedPayload, type LobbyKickedReason, type LobbyMessage, type LobbyMessagePayload, type LobbyUser, type 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 RemoteFileMetadata, type StatsStoredPayload, type UGCType, type UGCVisibility, type UpsertedLeaderboardEntry, type WavedashConfig, type WavedashEvent, type WavedashEventMap, type WavedashResponse, WavedashSDK, setupWavedashSDK };
|
|
1216
|
+
export { type BackendConnectionPayload, type EngineInstance, type Friend, type FullscreenChangedPayload, type Leaderboard, type LeaderboardDisplayType, type LeaderboardEntries, type LeaderboardSortOrder, type ListUGCItemsArgs, type Lobby, type LobbyDataUpdatedPayload, type LobbyInvite, type LobbyInvitePayload, type LobbyJoinResponse, type LobbyJoinedPayload, type LobbyKickedPayload, type LobbyKickedReason, type LobbyMessage, type LobbyMessagePayload, type LobbyUser, type 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 PaginatedUGCItems, type RemoteFileMetadata, type StatsStoredPayload, type UGCItem, type UGCType, type UGCVisibility, type UpdateUGCItemArgs, type UpsertedLeaderboardEntry, type WavedashConfig, type WavedashEvent, type WavedashEventMap, type WavedashResponse, WavedashSDK, setupWavedashSDK };
|
package/dist/index.js
CHANGED
|
@@ -270,18 +270,14 @@ var _LobbyManager = class _LobbyManager extends WavedashManager {
|
|
|
270
270
|
}
|
|
271
271
|
getLobbyUsers(lobbyId) {
|
|
272
272
|
if (this.lobbyId !== lobbyId) {
|
|
273
|
-
logger.error(
|
|
274
|
-
"Must be a member of the lobby to access user list"
|
|
275
|
-
);
|
|
273
|
+
logger.error("Must be a member of the lobby to access user list");
|
|
276
274
|
return [];
|
|
277
275
|
}
|
|
278
276
|
return this.lobbyUsers;
|
|
279
277
|
}
|
|
280
278
|
getHostId(lobbyId) {
|
|
281
279
|
if (this.lobbyId !== lobbyId) {
|
|
282
|
-
logger.error(
|
|
283
|
-
"Must be a member of the lobby to access the host ID"
|
|
284
|
-
);
|
|
280
|
+
logger.error("Must be a member of the lobby to access the host ID");
|
|
285
281
|
return null;
|
|
286
282
|
}
|
|
287
283
|
return this.lobbyHostId;
|
|
@@ -467,9 +463,7 @@ var _LobbyManager = class _LobbyManager extends WavedashManager {
|
|
|
467
463
|
handleLobbyKicked(reason = LobbyKickedReason.KICKED) {
|
|
468
464
|
const lobbyId = this.lobbyId;
|
|
469
465
|
if (!lobbyId) return;
|
|
470
|
-
logger.warn(
|
|
471
|
-
`User was removed from lobby: ${lobbyId} (reason: ${reason})`
|
|
472
|
-
);
|
|
466
|
+
logger.warn(`User was removed from lobby: ${lobbyId} (reason: ${reason})`);
|
|
473
467
|
this.cleanupLobbyState();
|
|
474
468
|
this.sdk.iframeMessenger.postToParent(IFRAME_MESSAGE_TYPE.LOBBY_LEFT, {
|
|
475
469
|
lobbyId
|
|
@@ -576,9 +570,7 @@ var _LobbyManager = class _LobbyManager extends WavedashManager {
|
|
|
576
570
|
try {
|
|
577
571
|
if (newUsers.length <= 1) {
|
|
578
572
|
this.sdk.p2pManager.disconnectP2P();
|
|
579
|
-
logger.debug(
|
|
580
|
-
"Only one user in lobby, P2P connections disconnected"
|
|
581
|
-
);
|
|
573
|
+
logger.debug("Only one user in lobby, P2P connections disconnected");
|
|
582
574
|
return;
|
|
583
575
|
}
|
|
584
576
|
const wavedashUsers = newUsers.map((lobbyUser) => ({
|
|
@@ -745,21 +737,41 @@ var FileSystemManager = class extends WavedashManager {
|
|
|
745
737
|
return filePath;
|
|
746
738
|
}
|
|
747
739
|
/**
|
|
748
|
-
* Downloads a remote file to a local location
|
|
740
|
+
* Downloads a remote file to a local location.
|
|
741
|
+
* Throws on failure; the error message is the server's HTTP status (e.g. "404 (Not Found)")
|
|
742
|
+
* or a network-level description if the server didn't respond. See also: {@link remoteFileExists}
|
|
749
743
|
* @param filePath - The path of the remote file to download
|
|
750
744
|
* @returns The path of the local file that the remote file was downloaded to
|
|
751
745
|
*/
|
|
752
746
|
async downloadRemoteFile(filePath) {
|
|
753
747
|
const url = this.getRemoteStorageUrl(filePath);
|
|
754
|
-
|
|
755
|
-
if (!success) {
|
|
756
|
-
throw new Error(`Failed to download file: ${filePath}`);
|
|
757
|
-
}
|
|
748
|
+
await this.download(url, filePath);
|
|
758
749
|
return filePath;
|
|
759
750
|
}
|
|
760
751
|
/**
|
|
761
|
-
*
|
|
762
|
-
*
|
|
752
|
+
* Checks whether a remote file exists by issuing a HEAD request.
|
|
753
|
+
* Does NOT throw for the "file does not exist" case — returns false.
|
|
754
|
+
* Throws only for real errors (network failure, auth failure, server error).
|
|
755
|
+
* @param filePath - The path of the remote file to check
|
|
756
|
+
* @returns true if the remote file exists, false otherwise
|
|
757
|
+
*/
|
|
758
|
+
async remoteFileExists(filePath) {
|
|
759
|
+
const url = this.getRemoteStorageUrl(filePath);
|
|
760
|
+
const jwt = await this.sdk.ensureGameplayJwt();
|
|
761
|
+
const response = await fetch(url, {
|
|
762
|
+
method: "HEAD",
|
|
763
|
+
headers: {
|
|
764
|
+
Authorization: `Bearer ${jwt}`
|
|
765
|
+
}
|
|
766
|
+
});
|
|
767
|
+
if (response.status === 404) return false;
|
|
768
|
+
if (response.ok) return true;
|
|
769
|
+
throw new Error(`${response.status} (${response.statusText})`);
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* Lists each file in a remote directory, including its subdirectories.
|
|
773
|
+
* Returns only file paths, no directory paths.
|
|
774
|
+
* An empty or non-existent directory returns an empty array — not an error.
|
|
763
775
|
* @param path - The path of the remote directory to list
|
|
764
776
|
* @returns A list of metadata for each file in the remote directory
|
|
765
777
|
*/
|
|
@@ -772,6 +784,7 @@ var FileSystemManager = class extends WavedashManager {
|
|
|
772
784
|
Authorization: `Bearer ${jwt}`
|
|
773
785
|
}
|
|
774
786
|
});
|
|
787
|
+
if (response.status === 404) return [];
|
|
775
788
|
if (!response.ok) {
|
|
776
789
|
throw new Error(`${response.status} (${response.statusText})`);
|
|
777
790
|
}
|
|
@@ -785,8 +798,14 @@ var FileSystemManager = class extends WavedashManager {
|
|
|
785
798
|
const files = await this.listRemoteDirectory(path);
|
|
786
799
|
const downloadPromises = files.map(async (file) => {
|
|
787
800
|
const url = this.getRemoteStorageUrl(file.key);
|
|
788
|
-
|
|
789
|
-
|
|
801
|
+
try {
|
|
802
|
+
await this.download(url, file.key);
|
|
803
|
+
return { fileName: file.name, success: true };
|
|
804
|
+
} catch (error) {
|
|
805
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
806
|
+
logger.error(`Failed to download ${file.name}: ${message}`);
|
|
807
|
+
return { fileName: file.name, success: false };
|
|
808
|
+
}
|
|
790
809
|
});
|
|
791
810
|
const downloadResults = await Promise.all(downloadPromises);
|
|
792
811
|
const failedDownloads = downloadResults.filter((result) => !result.success);
|
|
@@ -849,12 +868,15 @@ var FileSystemManager = class extends WavedashManager {
|
|
|
849
868
|
}
|
|
850
869
|
return success;
|
|
851
870
|
}
|
|
852
|
-
// Helper to download a file from a URL and save locally
|
|
871
|
+
// Helper to download a file from a URL and save locally.
|
|
872
|
+
// Throws on any failure with a message containing the HTTP status (e.g.
|
|
873
|
+
// "404 (Not Found)") for server-side failures, or a network/FS error
|
|
874
|
+
// description otherwise. Callers should let the error propagate; the
|
|
875
|
+
// public apiCall wrapper surfaces the message in WavedashResponse.message.
|
|
853
876
|
async download(url, filePath) {
|
|
854
877
|
logger.debug(`Downloading ${filePath} from: ${url}`);
|
|
855
878
|
if (this.sdk.engineInstance && !this.sdk.engineInstance.FS) {
|
|
856
|
-
|
|
857
|
-
return false;
|
|
879
|
+
throw new Error("Engine instance is missing the Emscripten FS API");
|
|
858
880
|
}
|
|
859
881
|
const jwt = await this.sdk.ensureGameplayJwt();
|
|
860
882
|
const response = await fetch(url, {
|
|
@@ -864,36 +886,34 @@ var FileSystemManager = class extends WavedashManager {
|
|
|
864
886
|
}
|
|
865
887
|
});
|
|
866
888
|
if (!response.ok) {
|
|
867
|
-
|
|
868
|
-
`Failed to download remote file: ${response.status} (${response.statusText})`
|
|
869
|
-
);
|
|
870
|
-
return false;
|
|
889
|
+
throw new Error(`${response.status} (${response.statusText})`);
|
|
871
890
|
}
|
|
872
891
|
const blob = await response.blob();
|
|
873
892
|
const arrayBuffer = await blob.arrayBuffer();
|
|
874
893
|
const dataArray = new Uint8Array(arrayBuffer);
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
} catch (_error) {
|
|
882
|
-
}
|
|
894
|
+
if (this.sdk.engineInstance) {
|
|
895
|
+
const dirPath = filePath.substring(0, filePath.lastIndexOf("/"));
|
|
896
|
+
if (dirPath) {
|
|
897
|
+
try {
|
|
898
|
+
this.sdk.engineInstance.FS.mkdirTree(dirPath);
|
|
899
|
+
} catch (_error) {
|
|
883
900
|
}
|
|
901
|
+
}
|
|
902
|
+
try {
|
|
884
903
|
this.sdk.engineInstance.FS.writeFile(filePath, dataArray);
|
|
885
|
-
}
|
|
886
|
-
const
|
|
887
|
-
|
|
904
|
+
} catch (error) {
|
|
905
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
906
|
+
throw new Error(`Failed to save file ${filePath} to engine FS: ${msg}`);
|
|
907
|
+
}
|
|
908
|
+
} else {
|
|
909
|
+
const success = await this.writeLocalFile(filePath, dataArray);
|
|
910
|
+
if (!success) {
|
|
911
|
+
throw new Error(
|
|
912
|
+
`Failed to save file ${filePath} to local IndexedDB storage`
|
|
913
|
+
);
|
|
888
914
|
}
|
|
889
|
-
logger.debug(`Successfully saved to: ${filePath}`);
|
|
890
|
-
return true;
|
|
891
|
-
} catch (error) {
|
|
892
|
-
logger.error(
|
|
893
|
-
`Failed to save file ${filePath}: ${error instanceof Error ? error.message : String(error)}`
|
|
894
|
-
);
|
|
895
|
-
return false;
|
|
896
915
|
}
|
|
916
|
+
logger.debug(`Successfully saved to: ${filePath}`);
|
|
897
917
|
}
|
|
898
918
|
// ================
|
|
899
919
|
// Private Methods
|
|
@@ -1013,7 +1033,8 @@ var UGCManager = class extends WavedashManager {
|
|
|
1013
1033
|
}
|
|
1014
1034
|
return ugcId;
|
|
1015
1035
|
}
|
|
1016
|
-
async updateUGCItem(ugcId,
|
|
1036
|
+
async updateUGCItem(ugcId, updates = {}) {
|
|
1037
|
+
const { title, description, visibility, filePath } = updates;
|
|
1017
1038
|
const { uploadUrl } = await this.sdk.convexClient.mutation(
|
|
1018
1039
|
api3.sdk.userGeneratedContent.updateUGCItem,
|
|
1019
1040
|
{
|
|
@@ -1051,15 +1072,26 @@ var UGCManager = class extends WavedashManager {
|
|
|
1051
1072
|
api3.sdk.userGeneratedContent.getUGCItemDownloadUrl,
|
|
1052
1073
|
{ ugcId }
|
|
1053
1074
|
);
|
|
1054
|
-
|
|
1055
|
-
downloadUrl,
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
throw new Error(`Failed to download UGC item: ${ugcId}`);
|
|
1075
|
+
try {
|
|
1076
|
+
await this.sdk.fileSystemManager.download(downloadUrl, filePath);
|
|
1077
|
+
} catch (error) {
|
|
1078
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
1079
|
+
throw new Error(`Failed to download UGC item ${ugcId}: ${msg}`);
|
|
1060
1080
|
}
|
|
1061
1081
|
return ugcId;
|
|
1062
1082
|
}
|
|
1083
|
+
async listUGCItems(args = {}) {
|
|
1084
|
+
const { createdBy, ugcType, titleSearch, numItems, continueCursor } = args;
|
|
1085
|
+
const filters = createdBy !== void 0 || ugcType !== void 0 || titleSearch !== void 0 ? { createdBy, ugcType, titleSearch } : void 0;
|
|
1086
|
+
return await this.sdk.convexClient.query(
|
|
1087
|
+
api3.sdk.userGeneratedContent.listUGCItems,
|
|
1088
|
+
{
|
|
1089
|
+
filters,
|
|
1090
|
+
numItems,
|
|
1091
|
+
continueCursor
|
|
1092
|
+
}
|
|
1093
|
+
);
|
|
1094
|
+
}
|
|
1063
1095
|
};
|
|
1064
1096
|
|
|
1065
1097
|
// src/services/leaderboards.ts
|
|
@@ -1303,9 +1335,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
|
|
|
1303
1335
|
return this.updateP2PConnection(members);
|
|
1304
1336
|
}
|
|
1305
1337
|
if (this.initializationInProgress && this.initializationLobbyId === lobbyId) {
|
|
1306
|
-
logger.debug(
|
|
1307
|
-
"P2P initialization already in progress, waiting..."
|
|
1308
|
-
);
|
|
1338
|
+
logger.debug("P2P initialization already in progress, waiting...");
|
|
1309
1339
|
await this.initializationInProgress;
|
|
1310
1340
|
if (this.currentConnection) {
|
|
1311
1341
|
return this.updateP2PConnection(members);
|
|
@@ -1386,9 +1416,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
|
|
|
1386
1416
|
existingPeer.username = member.username;
|
|
1387
1417
|
}
|
|
1388
1418
|
} else {
|
|
1389
|
-
logger.debug(
|
|
1390
|
-
`Adding new peer: ${member.username} (${member.id})`
|
|
1391
|
-
);
|
|
1419
|
+
logger.debug(`Adding new peer: ${member.username} (${member.id})`);
|
|
1392
1420
|
this.currentConnection.peers[member.id] = {
|
|
1393
1421
|
userId: member.id,
|
|
1394
1422
|
username: member.username
|
|
@@ -1421,9 +1449,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
|
|
|
1421
1449
|
return this.createOfferToPeer(userId);
|
|
1422
1450
|
});
|
|
1423
1451
|
await Promise.all(offerPromises);
|
|
1424
|
-
logger.debug(
|
|
1425
|
-
`Initiated ${offerPromises.length} offers to new peers`
|
|
1426
|
-
);
|
|
1452
|
+
logger.debug(`Initiated ${offerPromises.length} offers to new peers`);
|
|
1427
1453
|
}
|
|
1428
1454
|
}
|
|
1429
1455
|
for (const userId of Object.keys(
|
|
@@ -1512,10 +1538,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
|
|
|
1512
1538
|
this.pendingProcessedMessageIds.delete(messageId);
|
|
1513
1539
|
}
|
|
1514
1540
|
} catch (error) {
|
|
1515
|
-
logger.error(
|
|
1516
|
-
"Failed to mark signaling messages as processed:",
|
|
1517
|
-
error
|
|
1518
|
-
);
|
|
1541
|
+
logger.error("Failed to mark signaling messages as processed:", error);
|
|
1519
1542
|
for (const messageId of newMessageIds) {
|
|
1520
1543
|
this.pendingProcessedMessageIds.delete(messageId);
|
|
1521
1544
|
}
|
|
@@ -1569,9 +1592,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
|
|
|
1569
1592
|
await this.flushPendingIceCandidates(remoteUserId, pc);
|
|
1570
1593
|
const answer = await pc.createAnswer();
|
|
1571
1594
|
await pc.setLocalDescription(answer);
|
|
1572
|
-
logger.debug(
|
|
1573
|
-
` Answer created, waiting for ondatachannel events...`
|
|
1574
|
-
);
|
|
1595
|
+
logger.debug(` Answer created, waiting for ondatachannel events...`);
|
|
1575
1596
|
const answerData = {
|
|
1576
1597
|
type: answer.type,
|
|
1577
1598
|
sdp: answer.sdp
|
|
@@ -1603,10 +1624,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
|
|
|
1603
1624
|
break;
|
|
1604
1625
|
}
|
|
1605
1626
|
default:
|
|
1606
|
-
logger.warn(
|
|
1607
|
-
"Unknown signaling message type:",
|
|
1608
|
-
message.messageType
|
|
1609
|
-
);
|
|
1627
|
+
logger.warn("Unknown signaling message type:", message.messageType);
|
|
1610
1628
|
}
|
|
1611
1629
|
}
|
|
1612
1630
|
/**
|
|
@@ -1648,9 +1666,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
|
|
|
1648
1666
|
const peersToInitiate = Object.keys(connection.peers).filter((userId) => currentUserId < userId);
|
|
1649
1667
|
if (peersToInitiate.length > 0) {
|
|
1650
1668
|
const offerPromises = peersToInitiate.map((userId) => {
|
|
1651
|
-
logger.debug(
|
|
1652
|
-
`Initiating offer to peer ${userId} (lower userId rule)`
|
|
1653
|
-
);
|
|
1669
|
+
logger.debug(`Initiating offer to peer ${userId} (lower userId rule)`);
|
|
1654
1670
|
return this.createOfferToPeer(userId);
|
|
1655
1671
|
});
|
|
1656
1672
|
await Promise.all(offerPromises);
|
|
@@ -1691,9 +1707,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
|
|
|
1691
1707
|
async createPeerConnection(remoteUserId, connection, shouldCreateChannels = false) {
|
|
1692
1708
|
const iceServers = await this.getIceServers();
|
|
1693
1709
|
if (!iceServers) {
|
|
1694
|
-
logger.error(
|
|
1695
|
-
`No ICE servers available for peer ${remoteUserId}`
|
|
1696
|
-
);
|
|
1710
|
+
logger.error(`No ICE servers available for peer ${remoteUserId}`);
|
|
1697
1711
|
this.sdk.gameEventManager.notifyGame(
|
|
1698
1712
|
WavedashEvents.P2P_CONNECTION_FAILED,
|
|
1699
1713
|
{
|
|
@@ -1919,9 +1933,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
|
|
|
1919
1933
|
}
|
|
1920
1934
|
setupDataChannelHandlers(channel, remoteUserId, type) {
|
|
1921
1935
|
channel.onopen = () => {
|
|
1922
|
-
logger.debug(
|
|
1923
|
-
`${type} data channel opened with peer ${remoteUserId}`
|
|
1924
|
-
);
|
|
1936
|
+
logger.debug(`${type} data channel opened with peer ${remoteUserId}`);
|
|
1925
1937
|
if (this.isPeerReady(remoteUserId) && !this.establishedPeers.has(remoteUserId)) {
|
|
1926
1938
|
this.establishedPeers.add(remoteUserId);
|
|
1927
1939
|
const peer = this.currentConnection?.peers[remoteUserId];
|
|
@@ -1940,10 +1952,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
|
|
|
1940
1952
|
this.enqueueMessage(event.data, remoteUserId);
|
|
1941
1953
|
};
|
|
1942
1954
|
channel.onerror = (error) => {
|
|
1943
|
-
logger.error(
|
|
1944
|
-
`Data channel error with peer ${remoteUserId}:`,
|
|
1945
|
-
error
|
|
1946
|
-
);
|
|
1955
|
+
logger.error(`Data channel error with peer ${remoteUserId}:`, error);
|
|
1947
1956
|
const peer = this.currentConnection?.peers[remoteUserId];
|
|
1948
1957
|
if (peer) {
|
|
1949
1958
|
this.sdk.gameEventManager.notifyGame(
|
|
@@ -1957,9 +1966,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
|
|
|
1957
1966
|
}
|
|
1958
1967
|
};
|
|
1959
1968
|
channel.onclose = () => {
|
|
1960
|
-
logger.debug(
|
|
1961
|
-
`${type} data channel closed with peer ${remoteUserId}`
|
|
1962
|
-
);
|
|
1969
|
+
logger.debug(`${type} data channel closed with peer ${remoteUserId}`);
|
|
1963
1970
|
this.establishedPeers.delete(remoteUserId);
|
|
1964
1971
|
this.reconnectingPeers.delete(remoteUserId);
|
|
1965
1972
|
const peer = this.currentConnection?.peers[remoteUserId];
|
|
@@ -1988,9 +1995,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
|
|
|
1988
1995
|
return false;
|
|
1989
1996
|
}
|
|
1990
1997
|
if (!payload) {
|
|
1991
|
-
logger.error(
|
|
1992
|
-
`P2P send called with missing payload, dropping message.`
|
|
1993
|
-
);
|
|
1998
|
+
logger.error(`P2P send called with missing payload, dropping message.`);
|
|
1994
1999
|
this.reportPacketDrop(appChannel, "SEND", "INVALID_PAYLOAD_SIZE");
|
|
1995
2000
|
return false;
|
|
1996
2001
|
}
|
|
@@ -2031,10 +2036,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
|
|
|
2031
2036
|
try {
|
|
2032
2037
|
channel.send(messageData);
|
|
2033
2038
|
} catch (error) {
|
|
2034
|
-
logger.error(
|
|
2035
|
-
`P2P broadcast to peer ${peerUserId} failed:`,
|
|
2036
|
-
error
|
|
2037
|
-
);
|
|
2039
|
+
logger.error(`P2P broadcast to peer ${peerUserId} failed:`, error);
|
|
2038
2040
|
}
|
|
2039
2041
|
});
|
|
2040
2042
|
} else {
|
|
@@ -2517,11 +2519,10 @@ var StatsManager = class extends WavedashManager {
|
|
|
2517
2519
|
// storeNow=true (and storeStats()) call .flush() to fire the pending invocation
|
|
2518
2520
|
// immediately. The in-flight gate in persist() covers mutations that outlast
|
|
2519
2521
|
// the throttle window, which would otherwise overlap and cause OCC conflicts.
|
|
2520
|
-
this.throttledPersist = throttle2(
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
);
|
|
2522
|
+
this.throttledPersist = throttle2(() => this.persist(), STORE_THROTTLE_MS, {
|
|
2523
|
+
leading: false,
|
|
2524
|
+
trailing: true
|
|
2525
|
+
});
|
|
2525
2526
|
this.subscribe();
|
|
2526
2527
|
this.requestStats().catch((error) => {
|
|
2527
2528
|
logger.error("Initial stats fetch failed:", error);
|
|
@@ -2557,10 +2558,7 @@ var StatsManager = class extends WavedashManager {
|
|
|
2557
2558
|
this.knownAchievementIds = new Set(ids);
|
|
2558
2559
|
},
|
|
2559
2560
|
(error) => {
|
|
2560
|
-
logger.error(
|
|
2561
|
-
"Achievement identifiers subscription error:",
|
|
2562
|
-
error
|
|
2563
|
-
);
|
|
2561
|
+
logger.error("Achievement identifiers subscription error:", error);
|
|
2564
2562
|
}
|
|
2565
2563
|
),
|
|
2566
2564
|
this.sdk.convexClient.onUpdate(
|
|
@@ -2834,9 +2832,7 @@ var HeartbeatManager = class extends WavedashManager {
|
|
|
2834
2832
|
);
|
|
2835
2833
|
} else if (!this.isConnected && wasConnected) {
|
|
2836
2834
|
this.disconnectedAt = Date.now();
|
|
2837
|
-
logger.warn(
|
|
2838
|
-
"Backend disconnected - attempting to reconnect..."
|
|
2839
|
-
);
|
|
2835
|
+
logger.warn("Backend disconnected - attempting to reconnect...");
|
|
2840
2836
|
this.sdk.gameEventManager.notifyGame(
|
|
2841
2837
|
WavedashEvents.BACKEND_RECONNECTING,
|
|
2842
2838
|
connection
|
|
@@ -3118,7 +3114,7 @@ var FriendsManager = class extends WavedashManager {
|
|
|
3118
3114
|
/**
|
|
3119
3115
|
* Replace the leaderboard-page cache with the users from a single page of
|
|
3120
3116
|
* leaderboard entries.
|
|
3121
|
-
*
|
|
3117
|
+
*
|
|
3122
3118
|
* In general devs should just use the username and userAvatarUrl returned
|
|
3123
3119
|
* from `listLeaderboardEntries` directly, but we cache the latest leaderboard
|
|
3124
3120
|
* page here just so getUserAvatarUrl and getUsername still work for the current page.
|
|
@@ -3379,11 +3375,29 @@ function vUnion(...variants) {
|
|
|
3379
3375
|
throw new Error(`${path}: no variant matched, got ${describeValue(value)}`);
|
|
3380
3376
|
};
|
|
3381
3377
|
}
|
|
3378
|
+
function vObject(shape) {
|
|
3379
|
+
return (value, path) => {
|
|
3380
|
+
const obj = vRecord(value, path);
|
|
3381
|
+
for (const key of Object.keys(obj)) {
|
|
3382
|
+
if (!(key in shape)) {
|
|
3383
|
+
throw new Error(`${path}: unrecognized property "${key}"`);
|
|
3384
|
+
}
|
|
3385
|
+
}
|
|
3386
|
+
for (const key of Object.keys(shape)) {
|
|
3387
|
+
shape[key](obj[key], `${path}.${key}`);
|
|
3388
|
+
}
|
|
3389
|
+
return obj;
|
|
3390
|
+
};
|
|
3391
|
+
}
|
|
3382
3392
|
function validateArgs(methodName, specs, values) {
|
|
3393
|
+
const shape = {};
|
|
3394
|
+
const obj = {};
|
|
3383
3395
|
for (let i = 0; i < specs.length; i++) {
|
|
3384
3396
|
const [argName, validator] = specs[i];
|
|
3385
|
-
|
|
3397
|
+
shape[argName] = validator;
|
|
3398
|
+
obj[argName] = values[i];
|
|
3386
3399
|
}
|
|
3400
|
+
vObject(shape)(obj, methodName);
|
|
3387
3401
|
}
|
|
3388
3402
|
function describeValue(value) {
|
|
3389
3403
|
if (value === void 0) return "undefined";
|
|
@@ -3515,9 +3529,7 @@ var WavedashSDK = class extends EventTarget {
|
|
|
3515
3529
|
}
|
|
3516
3530
|
this.config = config ?? {};
|
|
3517
3531
|
this._initialized = true;
|
|
3518
|
-
logger.setLogLevel(
|
|
3519
|
-
this.config.debug ? LOG_LEVEL.DEBUG : LOG_LEVEL.WARN
|
|
3520
|
-
);
|
|
3532
|
+
logger.setLogLevel(this.config.debug ? LOG_LEVEL.DEBUG : LOG_LEVEL.WARN);
|
|
3521
3533
|
this.p2pManager.init(this.config.p2p);
|
|
3522
3534
|
logger.debug("Initialized with config:", this.config);
|
|
3523
3535
|
if (!this.config.deferEvents) {
|
|
@@ -3836,30 +3848,45 @@ var WavedashSDK = class extends EventTarget {
|
|
|
3836
3848
|
}
|
|
3837
3849
|
/**
|
|
3838
3850
|
* Updates a UGC item and uploads the file to the server if a filePath is provided
|
|
3839
|
-
*
|
|
3840
|
-
* @param
|
|
3841
|
-
*
|
|
3842
|
-
* @param description
|
|
3843
|
-
* @param visibility
|
|
3844
|
-
* @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.
|
|
3851
|
+
* @param ugcId - The ID of the UGC item to update
|
|
3852
|
+
* @param updates - Object containing the fields to update. May also be passed
|
|
3853
|
+
* as a JSON string by engine bridges (Godot) that can't marshal a dict.
|
|
3845
3854
|
* @returns ugcId
|
|
3846
3855
|
*/
|
|
3847
|
-
async updateUGCItem(ugcId,
|
|
3856
|
+
async updateUGCItem(ugcId, updates = {}) {
|
|
3857
|
+
if (typeof updates === "string") {
|
|
3858
|
+
const raw = updates;
|
|
3859
|
+
try {
|
|
3860
|
+
updates = JSON.parse(raw);
|
|
3861
|
+
} catch (error) {
|
|
3862
|
+
const message = `updateUGCItem: invalid JSON: ${raw}`;
|
|
3863
|
+
logger.error(message, error);
|
|
3864
|
+
return this.formatResponse({
|
|
3865
|
+
success: false,
|
|
3866
|
+
data: null,
|
|
3867
|
+
message
|
|
3868
|
+
});
|
|
3869
|
+
}
|
|
3870
|
+
}
|
|
3848
3871
|
return this.apiCall(
|
|
3849
3872
|
this.ugcManager,
|
|
3850
3873
|
"updateUGCItem",
|
|
3851
3874
|
[
|
|
3852
3875
|
["ugcId", vId("userGeneratedContent")],
|
|
3853
|
-
[
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3876
|
+
[
|
|
3877
|
+
"updates",
|
|
3878
|
+
vOptional(
|
|
3879
|
+
vObject({
|
|
3880
|
+
title: vOptional(vString),
|
|
3881
|
+
description: vOptional(vString),
|
|
3882
|
+
visibility: vOptional(vEnum(UGC_VISIBILITY, "UGCVisibility")),
|
|
3883
|
+
filePath: vOptional(vString)
|
|
3884
|
+
})
|
|
3885
|
+
)
|
|
3886
|
+
]
|
|
3857
3887
|
],
|
|
3858
3888
|
ugcId,
|
|
3859
|
-
|
|
3860
|
-
description,
|
|
3861
|
-
visibility,
|
|
3862
|
-
filePath
|
|
3889
|
+
updates
|
|
3863
3890
|
);
|
|
3864
3891
|
}
|
|
3865
3892
|
/**
|
|
@@ -3886,6 +3913,47 @@ var WavedashSDK = class extends EventTarget {
|
|
|
3886
3913
|
filePath
|
|
3887
3914
|
);
|
|
3888
3915
|
}
|
|
3916
|
+
async listUGCItems(args = {}) {
|
|
3917
|
+
if (typeof args === "string") {
|
|
3918
|
+
const raw = args;
|
|
3919
|
+
try {
|
|
3920
|
+
args = JSON.parse(raw);
|
|
3921
|
+
} catch (error) {
|
|
3922
|
+
const message = `listUGCItems: invalid JSON: ${raw}`;
|
|
3923
|
+
logger.error(message, error);
|
|
3924
|
+
return this.formatResponse({
|
|
3925
|
+
success: false,
|
|
3926
|
+
data: null,
|
|
3927
|
+
message
|
|
3928
|
+
});
|
|
3929
|
+
}
|
|
3930
|
+
}
|
|
3931
|
+
return this.apiCall(
|
|
3932
|
+
this.ugcManager,
|
|
3933
|
+
"listUGCItems",
|
|
3934
|
+
[
|
|
3935
|
+
[
|
|
3936
|
+
"args",
|
|
3937
|
+
vOptional((value, path) => {
|
|
3938
|
+
const obj = vObject({
|
|
3939
|
+
createdBy: vOptional(vId("users")),
|
|
3940
|
+
ugcType: vOptional(vEnum(UGC_TYPE, "UGCType")),
|
|
3941
|
+
titleSearch: vOptional(vString),
|
|
3942
|
+
numItems: vOptional(vNumber),
|
|
3943
|
+
continueCursor: vOptional(vString)
|
|
3944
|
+
})(value, path);
|
|
3945
|
+
if (obj.continueCursor !== void 0 && (obj.createdBy !== void 0 || obj.ugcType !== void 0 || obj.titleSearch !== void 0 || obj.numItems !== void 0)) {
|
|
3946
|
+
throw new Error(
|
|
3947
|
+
`${path}: continueCursor should be the only argument if present`
|
|
3948
|
+
);
|
|
3949
|
+
}
|
|
3950
|
+
return obj;
|
|
3951
|
+
})
|
|
3952
|
+
]
|
|
3953
|
+
],
|
|
3954
|
+
args
|
|
3955
|
+
);
|
|
3956
|
+
}
|
|
3889
3957
|
// ================================
|
|
3890
3958
|
// Save state / Remote File Storage
|
|
3891
3959
|
// ================================
|
|
@@ -3903,9 +3971,10 @@ var WavedashSDK = class extends EventTarget {
|
|
|
3903
3971
|
);
|
|
3904
3972
|
}
|
|
3905
3973
|
/**
|
|
3906
|
-
* Downloads a remote file to a local location
|
|
3974
|
+
* Downloads a remote file to a local location.
|
|
3975
|
+
* Returns success=false (with the server status in `message`) if the file
|
|
3976
|
+
* doesn't exist or any other error occurs. See also: {@link remoteFileExists}
|
|
3907
3977
|
* @param filePath - The path of the remote file to download
|
|
3908
|
-
* @param downloadTo - Optionally provide a path to download the file to, defaults to the same path as the remote file
|
|
3909
3978
|
* @returns The path of the local file that the remote file was downloaded to
|
|
3910
3979
|
*/
|
|
3911
3980
|
async downloadRemoteFile(filePath) {
|
|
@@ -3916,6 +3985,19 @@ var WavedashSDK = class extends EventTarget {
|
|
|
3916
3985
|
filePath
|
|
3917
3986
|
);
|
|
3918
3987
|
}
|
|
3988
|
+
/**
|
|
3989
|
+
* Checks whether a remote file exists. Sends a lightweight HEAD request to check for existence.
|
|
3990
|
+
* @param filePath - The path of the remote file to check
|
|
3991
|
+
* @returns true if the remote file exists, false if it does not.
|
|
3992
|
+
*/
|
|
3993
|
+
async remoteFileExists(filePath) {
|
|
3994
|
+
return this.apiCall(
|
|
3995
|
+
this.fileSystemManager,
|
|
3996
|
+
"remoteFileExists",
|
|
3997
|
+
[["filePath", vString]],
|
|
3998
|
+
filePath
|
|
3999
|
+
);
|
|
4000
|
+
}
|
|
3919
4001
|
/**
|
|
3920
4002
|
* Uploads a local file to remote storage
|
|
3921
4003
|
* @param filePath - The path of the local file to upload
|
|
@@ -4287,7 +4369,6 @@ var WavedashSDK = class extends EventTarget {
|
|
|
4287
4369
|
// ==============================
|
|
4288
4370
|
/**
|
|
4289
4371
|
* Updates rich user presence so friends can see what the player is doing in game
|
|
4290
|
-
* TODO: data param should be more strongly typed
|
|
4291
4372
|
* @param data Game data to send to the backend
|
|
4292
4373
|
* @returns true if the presence was updated successfully
|
|
4293
4374
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wvdsh/sdk-js",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Wavedash JavaScript SDK",
|
|
6
6
|
"main": "./dist/client.js",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"typescript-eslint": "^8.52.0"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@wvdsh/api": "^0.1.
|
|
52
|
+
"@wvdsh/api": "^0.1.27",
|
|
53
53
|
"convex": "^1.38.0",
|
|
54
54
|
"lodash.throttle": "^4.1.1"
|
|
55
55
|
}
|