@wvdsh/sdk-js 1.3.4 → 1.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +15 -15
- package/dist/index.js +117 -65
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -278,6 +278,8 @@ declare class LobbyManager extends WavedashManager {
|
|
|
278
278
|
private recentMessageIds;
|
|
279
279
|
private maybeBeingDeletedLobbyIds;
|
|
280
280
|
private resetMaybeBeingDeletedLobbyIdTimeouts;
|
|
281
|
+
private static readonly METADATA_UPDATE_THROTTLE_MS;
|
|
282
|
+
private inFlightMetadataUpdate;
|
|
281
283
|
private cachedLobbies;
|
|
282
284
|
private unsubscribeLobbyInvites;
|
|
283
285
|
private seenInviteIds;
|
|
@@ -295,7 +297,6 @@ declare class LobbyManager extends WavedashManager {
|
|
|
295
297
|
getHostId(lobbyId: GenericId<"lobbies">): GenericId<"users"> | null;
|
|
296
298
|
getLobbyData(lobbyId: GenericId<"lobbies">, key: string): string | number | null;
|
|
297
299
|
deleteLobbyData(lobbyId: GenericId<"lobbies">, key: string): boolean;
|
|
298
|
-
private debouncedMetadataUpdate;
|
|
299
300
|
setLobbyData(lobbyId: GenericId<"lobbies">, key: string, value: string | number | null): boolean;
|
|
300
301
|
getLobbyMaxPlayers(lobbyId: GenericId<"lobbies">): number;
|
|
301
302
|
getNumLobbyUsers(lobbyId: GenericId<"lobbies">): number;
|
|
@@ -333,7 +334,8 @@ declare class LobbyManager extends WavedashManager {
|
|
|
333
334
|
* Called during session end to ensure no lingering listeners.
|
|
334
335
|
*/
|
|
335
336
|
destroy(): void;
|
|
336
|
-
private
|
|
337
|
+
private throttledSetMetadata;
|
|
338
|
+
private setMetadata;
|
|
337
339
|
/**
|
|
338
340
|
* Process user updates and emit individual user events
|
|
339
341
|
* @param newUsers - The updated list of lobby users
|
|
@@ -416,6 +418,7 @@ declare class UGCManager extends WavedashManager {
|
|
|
416
418
|
constructor(sdk: WavedashSDK);
|
|
417
419
|
createUGCItem(ugcType: UGCType, title?: string, description?: string, visibility?: UGCVisibility, filePath?: string): Promise<GenericId<"userGeneratedContent">>;
|
|
418
420
|
updateUGCItem(ugcId: GenericId<"userGeneratedContent">, title?: string, description?: string, visibility?: UGCVisibility, filePath?: string): Promise<GenericId<"userGeneratedContent">>;
|
|
421
|
+
deleteUGCItem(ugcId: GenericId<"userGeneratedContent">): Promise<GenericId<"userGeneratedContent">>;
|
|
419
422
|
downloadUGCItem(ugcId: GenericId<"userGeneratedContent">, filePath: string): Promise<GenericId<"userGeneratedContent">>;
|
|
420
423
|
}
|
|
421
424
|
|
|
@@ -555,10 +558,6 @@ declare class P2PManager extends WavedashManager {
|
|
|
555
558
|
private decodeBinaryMessage;
|
|
556
559
|
}
|
|
557
560
|
|
|
558
|
-
type StatEntry = {
|
|
559
|
-
identifier: string;
|
|
560
|
-
value: number;
|
|
561
|
-
};
|
|
562
561
|
declare class StatsManager extends WavedashManager {
|
|
563
562
|
private stats;
|
|
564
563
|
private unlockedAchievements;
|
|
@@ -568,24 +567,23 @@ declare class StatsManager extends WavedashManager {
|
|
|
568
567
|
private knownAchievementIds;
|
|
569
568
|
private loaded;
|
|
570
569
|
private subscriptions;
|
|
571
|
-
private
|
|
570
|
+
private inFlightPersist;
|
|
571
|
+
private flushRequested;
|
|
572
572
|
constructor(sdk: WavedashSDK);
|
|
573
573
|
destroy(): void;
|
|
574
574
|
private isReady;
|
|
575
575
|
private subscribe;
|
|
576
576
|
requestStats(): Promise<boolean>;
|
|
577
|
-
private
|
|
577
|
+
private throttledPersist;
|
|
578
578
|
storeStats(): boolean;
|
|
579
|
+
private requestPersistFlush;
|
|
579
580
|
private persist;
|
|
580
581
|
getStat(identifier: string): number;
|
|
581
582
|
setStat(identifier: string, value: number, storeNow?: boolean): boolean;
|
|
582
583
|
getAchievement(identifier: string): boolean;
|
|
583
584
|
setAchievement(identifier: string, storeNow?: boolean): boolean;
|
|
584
585
|
/** @destructive - Returns the pending stats and achievements and resets the dirty collections */
|
|
585
|
-
getPendingData
|
|
586
|
-
stats: StatEntry[];
|
|
587
|
-
achievements: string[];
|
|
588
|
-
} | null;
|
|
586
|
+
private getPendingData;
|
|
589
587
|
}
|
|
590
588
|
|
|
591
589
|
/**
|
|
@@ -990,6 +988,11 @@ declare class WavedashSDK extends EventTarget {
|
|
|
990
988
|
* @returns ugcId
|
|
991
989
|
*/
|
|
992
990
|
updateUGCItem(ugcId: GenericId<"userGeneratedContent">, title?: string, description?: string, visibility?: UGCVisibility, filePath?: string): Promise<WavedashResponse<GenericId<"userGeneratedContent">>>;
|
|
991
|
+
/**
|
|
992
|
+
* Delete a UGC item: removes the row, the R2 object, and frees up the
|
|
993
|
+
* user's storage quota by the size of the deleted upload.
|
|
994
|
+
*/
|
|
995
|
+
deleteUGCItem(ugcId: GenericId<"userGeneratedContent">): Promise<WavedashResponse<GenericId<"userGeneratedContent">>>;
|
|
993
996
|
downloadUGCItem(ugcId: GenericId<"userGeneratedContent">, filePath: string): Promise<WavedashResponse<GenericId<"userGeneratedContent">>>;
|
|
994
997
|
/**
|
|
995
998
|
* Deletes a remote file from storage
|
|
@@ -1161,9 +1164,6 @@ declare class WavedashSDK extends EventTarget {
|
|
|
1161
1164
|
ensureGameplayJwt(): Promise<string>;
|
|
1162
1165
|
/**
|
|
1163
1166
|
* Tear down every manager. Called on the parent's `END_SESSION` signal
|
|
1164
|
-
* (committed leaves only — see GameRunnerComponent.svelte). Idempotent.
|
|
1165
|
-
* Each manager's `destroy()` defaults to a no-op; managers with ongoing
|
|
1166
|
-
* state (subscriptions, intervals, peer connections) override it.
|
|
1167
1167
|
*/
|
|
1168
1168
|
private destroy;
|
|
1169
1169
|
private setupSessionEndListeners;
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { ConvexClient } from "convex/browser";
|
|
3
3
|
|
|
4
4
|
// src/services/lobby.ts
|
|
5
|
-
import
|
|
5
|
+
import throttle from "lodash.throttle";
|
|
6
6
|
|
|
7
7
|
// src/constants.ts
|
|
8
8
|
import {
|
|
@@ -94,7 +94,7 @@ var WavedashManager = class {
|
|
|
94
94
|
};
|
|
95
95
|
|
|
96
96
|
// src/services/lobby.ts
|
|
97
|
-
var
|
|
97
|
+
var _LobbyManager = class _LobbyManager extends WavedashManager {
|
|
98
98
|
constructor(sdk) {
|
|
99
99
|
super(sdk);
|
|
100
100
|
// Track current lobby state
|
|
@@ -109,6 +109,7 @@ var LobbyManager = class extends WavedashManager {
|
|
|
109
109
|
this.recentMessageIds = [];
|
|
110
110
|
this.maybeBeingDeletedLobbyIds = /* @__PURE__ */ new Set();
|
|
111
111
|
this.resetMaybeBeingDeletedLobbyIdTimeouts = /* @__PURE__ */ new Map();
|
|
112
|
+
this.inFlightMetadataUpdate = null;
|
|
112
113
|
// Cache results of queries for a list of lobbies
|
|
113
114
|
// We'll cache metadata and num users for each lobby and return that info synchronously when requested by the game
|
|
114
115
|
this.cachedLobbies = {};
|
|
@@ -117,9 +118,13 @@ var LobbyManager = class extends WavedashManager {
|
|
|
117
118
|
this.seenInviteIds = /* @__PURE__ */ new Set();
|
|
118
119
|
// Queue for serializing P2P connection updates to prevent race conditions
|
|
119
120
|
this.p2pUpdateQueue = Promise.resolve();
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
// leading: false so the first call doesn't fire synchronously inside setLobbyData
|
|
122
|
+
// (which is called from a tight loop); trailing: true to flush coalesced updates
|
|
123
|
+
// at the end of the window.
|
|
124
|
+
this.throttledSetMetadata = throttle(
|
|
125
|
+
() => this.setMetadata(),
|
|
126
|
+
_LobbyManager.METADATA_UPDATE_THROTTLE_MS,
|
|
127
|
+
{ leading: false, trailing: true }
|
|
123
128
|
);
|
|
124
129
|
/**
|
|
125
130
|
* Process user updates and emit individual user events
|
|
@@ -266,7 +271,7 @@ var LobbyManager = class extends WavedashManager {
|
|
|
266
271
|
this.lobbyMetadata[key] = value;
|
|
267
272
|
}
|
|
268
273
|
this.pendingMetadataUpdates[key] = value;
|
|
269
|
-
this.
|
|
274
|
+
this.throttledSetMetadata();
|
|
270
275
|
return true;
|
|
271
276
|
}
|
|
272
277
|
getLobbyMaxPlayers(lobbyId) {
|
|
@@ -443,7 +448,7 @@ var LobbyManager = class extends WavedashManager {
|
|
|
443
448
|
cleanupLobbyState() {
|
|
444
449
|
const currentLobbyId = this.lobbyId;
|
|
445
450
|
this.lobbyId = null;
|
|
446
|
-
this.
|
|
451
|
+
this.throttledSetMetadata.cancel();
|
|
447
452
|
this.pendingMetadataUpdates = {};
|
|
448
453
|
if (this.unsubscribeLobbyMessages) {
|
|
449
454
|
this.unsubscribeLobbyMessages();
|
|
@@ -501,14 +506,22 @@ var LobbyManager = class extends WavedashManager {
|
|
|
501
506
|
this.seenInviteIds.clear();
|
|
502
507
|
this.cachedLobbies = {};
|
|
503
508
|
}
|
|
504
|
-
|
|
509
|
+
setMetadata() {
|
|
510
|
+
if (this.inFlightMetadataUpdate !== null) return;
|
|
511
|
+
if (this.lobbyId === null) return;
|
|
512
|
+
if (Object.keys(this.pendingMetadataUpdates).length === 0) return;
|
|
505
513
|
const updates = this.pendingMetadataUpdates;
|
|
506
514
|
this.pendingMetadataUpdates = {};
|
|
507
|
-
this.sdk.convexClient.mutation(api.sdk.gameLobby.setLobbyMetadata, {
|
|
515
|
+
this.inFlightMetadataUpdate = this.sdk.convexClient.mutation(api.sdk.gameLobby.setLobbyMetadata, {
|
|
508
516
|
lobbyId: this.lobbyId,
|
|
509
517
|
updates
|
|
510
518
|
}).catch((error) => {
|
|
511
519
|
this.sdk.logger.error("Error updating lobby metadata:", error);
|
|
520
|
+
}).finally(() => {
|
|
521
|
+
this.inFlightMetadataUpdate = null;
|
|
522
|
+
if (Object.keys(this.pendingMetadataUpdates).length > 0) {
|
|
523
|
+
this.throttledSetMetadata();
|
|
524
|
+
}
|
|
512
525
|
});
|
|
513
526
|
}
|
|
514
527
|
// ================
|
|
@@ -547,6 +560,10 @@ var LobbyManager = class extends WavedashManager {
|
|
|
547
560
|
}
|
|
548
561
|
}
|
|
549
562
|
};
|
|
563
|
+
// Throttle (not debounce) batches rapid setLobbyData calls; the in-flight
|
|
564
|
+
// gate in setMetadata prevents OCC self-conflicts.
|
|
565
|
+
_LobbyManager.METADATA_UPDATE_THROTTLE_MS = 150;
|
|
566
|
+
var LobbyManager = _LobbyManager;
|
|
550
567
|
|
|
551
568
|
// src/utils/indexedDB.ts
|
|
552
569
|
var LOCAL_STORAGE_DB_NAME = "/userfs";
|
|
@@ -674,9 +691,19 @@ var FileSystemManager = class extends WavedashManager {
|
|
|
674
691
|
* @returns The path of the remote file that was deleted
|
|
675
692
|
*/
|
|
676
693
|
async deleteRemoteFile(filePath) {
|
|
677
|
-
|
|
678
|
-
|
|
694
|
+
const url = this.getRemoteStorageUrl(filePath);
|
|
695
|
+
const jwt = await this.sdk.ensureGameplayJwt();
|
|
696
|
+
const response = await fetch(url, {
|
|
697
|
+
method: "DELETE",
|
|
698
|
+
headers: {
|
|
699
|
+
Authorization: `Bearer ${jwt}`
|
|
700
|
+
}
|
|
679
701
|
});
|
|
702
|
+
if (!response.ok) {
|
|
703
|
+
const msg = `Failed to delete remote file ${filePath}: ${response.status} (${response.statusText})`;
|
|
704
|
+
this.sdk.logger.error(msg);
|
|
705
|
+
throw new Error(msg);
|
|
706
|
+
}
|
|
680
707
|
return filePath;
|
|
681
708
|
}
|
|
682
709
|
/**
|
|
@@ -942,10 +969,6 @@ var UGCManager = class extends WavedashManager {
|
|
|
942
969
|
uploadUrl,
|
|
943
970
|
filePath
|
|
944
971
|
);
|
|
945
|
-
await this.sdk.convexClient.mutation(
|
|
946
|
-
api3.sdk.userGeneratedContent.finishUGCUpload,
|
|
947
|
-
{ success, ugcId }
|
|
948
|
-
);
|
|
949
972
|
if (!success) {
|
|
950
973
|
throw new Error(`Failed to upload UGC item: ${filePath}`);
|
|
951
974
|
}
|
|
@@ -972,16 +995,19 @@ var UGCManager = class extends WavedashManager {
|
|
|
972
995
|
uploadUrl,
|
|
973
996
|
filePath
|
|
974
997
|
);
|
|
975
|
-
await this.sdk.convexClient.mutation(
|
|
976
|
-
api3.sdk.userGeneratedContent.finishUGCUpload,
|
|
977
|
-
{ success, ugcId }
|
|
978
|
-
);
|
|
979
998
|
if (!success) {
|
|
980
999
|
throw new Error(`Failed to upload UGC item: ${filePath}`);
|
|
981
1000
|
}
|
|
982
1001
|
}
|
|
983
1002
|
return ugcId;
|
|
984
1003
|
}
|
|
1004
|
+
async deleteUGCItem(ugcId) {
|
|
1005
|
+
await this.sdk.convexClient.mutation(
|
|
1006
|
+
api3.sdk.userGeneratedContent.deleteUGCItem,
|
|
1007
|
+
{ ugcId }
|
|
1008
|
+
);
|
|
1009
|
+
return ugcId;
|
|
1010
|
+
}
|
|
985
1011
|
async downloadUGCItem(ugcId, filePath) {
|
|
986
1012
|
const downloadUrl = await this.sdk.convexClient.query(
|
|
987
1013
|
api3.sdk.userGeneratedContent.getUGCItemDownloadUrl,
|
|
@@ -2415,9 +2441,8 @@ var P2PManager = _P2PManager;
|
|
|
2415
2441
|
|
|
2416
2442
|
// src/services/stats.ts
|
|
2417
2443
|
import { api as api6 } from "@wvdsh/api";
|
|
2418
|
-
import
|
|
2419
|
-
var
|
|
2420
|
-
var PERIODIC_PERSIST_MS = 1e4;
|
|
2444
|
+
import throttle2 from "lodash.throttle";
|
|
2445
|
+
var STORE_THROTTLE_MS = 1e3;
|
|
2421
2446
|
var StatsManager = class extends WavedashManager {
|
|
2422
2447
|
constructor(sdk) {
|
|
2423
2448
|
super(sdk);
|
|
@@ -2435,32 +2460,33 @@ var StatsManager = class extends WavedashManager {
|
|
|
2435
2460
|
this.loaded = { stats: false, achievements: false };
|
|
2436
2461
|
// Subscription cleanup
|
|
2437
2462
|
this.subscriptions = [];
|
|
2438
|
-
//
|
|
2439
|
-
this.
|
|
2463
|
+
// Single in-flight persist mutation; prevents OCC self-conflicts.
|
|
2464
|
+
this.inFlightPersist = null;
|
|
2465
|
+
// Set when a storeNow flush hits the in-flight gate; persist's .finally()
|
|
2466
|
+
// checks this and fires immediately on the next cycle instead of waiting
|
|
2467
|
+
// out the throttle window. (lodash treats the gated flush as a successful
|
|
2468
|
+
// invocation, so without this flag a contended storeNow waits ~THROTTLE_MS.)
|
|
2469
|
+
this.flushRequested = false;
|
|
2440
2470
|
// ================
|
|
2441
2471
|
// Store / Persist
|
|
2442
2472
|
// ================
|
|
2443
|
-
//
|
|
2444
|
-
//
|
|
2445
|
-
//
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2473
|
+
// leading: false so a single setStat doesn't fire synchronously inside the
|
|
2474
|
+
// setter; trailing: true to flush coalesced edits at the end of the window.
|
|
2475
|
+
// storeNow=true (and storeStats()) call .flush() to fire the pending invocation
|
|
2476
|
+
// immediately. The in-flight gate in persist() covers mutations that outlast
|
|
2477
|
+
// the throttle window, which would otherwise overlap and cause OCC conflicts.
|
|
2478
|
+
this.throttledPersist = throttle2(
|
|
2479
|
+
() => this.persist(),
|
|
2480
|
+
STORE_THROTTLE_MS,
|
|
2481
|
+
{ leading: false, trailing: true }
|
|
2482
|
+
);
|
|
2450
2483
|
this.subscribe();
|
|
2451
2484
|
this.requestStats().catch((error) => {
|
|
2452
2485
|
this.sdk.logger.error("Initial stats fetch failed:", error);
|
|
2453
2486
|
});
|
|
2454
|
-
this.periodicPersistInterval = setInterval(() => {
|
|
2455
|
-
void this.persist();
|
|
2456
|
-
}, PERIODIC_PERSIST_MS);
|
|
2457
2487
|
}
|
|
2458
2488
|
destroy() {
|
|
2459
|
-
this.
|
|
2460
|
-
if (this.periodicPersistInterval !== null) {
|
|
2461
|
-
clearInterval(this.periodicPersistInterval);
|
|
2462
|
-
this.periodicPersistInterval = null;
|
|
2463
|
-
}
|
|
2489
|
+
this.throttledPersist.cancel();
|
|
2464
2490
|
for (const unsub of this.subscriptions) unsub();
|
|
2465
2491
|
this.subscriptions = [];
|
|
2466
2492
|
}
|
|
@@ -2525,35 +2551,51 @@ var StatsManager = class extends WavedashManager {
|
|
|
2525
2551
|
}
|
|
2526
2552
|
storeStats() {
|
|
2527
2553
|
if (!this.isReady()) return false;
|
|
2528
|
-
this.
|
|
2529
|
-
this.
|
|
2554
|
+
this.throttledPersist();
|
|
2555
|
+
this.requestPersistFlush();
|
|
2530
2556
|
return true;
|
|
2531
2557
|
}
|
|
2532
|
-
|
|
2558
|
+
// Force-fire the throttled persist now. If a mutation is already in flight,
|
|
2559
|
+
// the gate will swallow the flush(), so we also flag flushRequested so the
|
|
2560
|
+
// next .finally() flushes again instead of waiting a full throttle window.
|
|
2561
|
+
requestPersistFlush() {
|
|
2562
|
+
if (this.inFlightPersist !== null) this.flushRequested = true;
|
|
2563
|
+
this.throttledPersist.flush();
|
|
2564
|
+
}
|
|
2565
|
+
persist() {
|
|
2566
|
+
if (this.inFlightPersist !== null) return;
|
|
2567
|
+
if (this.dirtyStats.size === 0 && this.dirtyAchievements.size === 0) return;
|
|
2533
2568
|
const pending = this.getPendingData();
|
|
2534
2569
|
if (!pending) return;
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
]);
|
|
2570
|
+
this.inFlightPersist = Promise.all([
|
|
2571
|
+
pending.stats.length > 0 ? this.sdk.convexClient.mutation(
|
|
2572
|
+
api6.sdk.gameAchievements.setUserGameStats,
|
|
2573
|
+
{ stats: pending.stats }
|
|
2574
|
+
) : Promise.resolve(),
|
|
2575
|
+
pending.achievements.length > 0 ? this.sdk.convexClient.mutation(
|
|
2576
|
+
api6.sdk.gameAchievements.setUserGameAchievements,
|
|
2577
|
+
{ achievements: pending.achievements }
|
|
2578
|
+
) : Promise.resolve()
|
|
2579
|
+
]).then(() => {
|
|
2546
2580
|
this.sdk.gameEventManager.notifyGame(WavedashEvents.STATS_STORED, {
|
|
2547
2581
|
success: true
|
|
2548
2582
|
});
|
|
2549
|
-
}
|
|
2583
|
+
}).catch((error) => {
|
|
2550
2584
|
const message = error instanceof Error ? error.message : `Error storing stats: ${error}`;
|
|
2551
2585
|
this.sdk.logger.error(message);
|
|
2552
2586
|
this.sdk.gameEventManager.notifyGame(WavedashEvents.STATS_STORED, {
|
|
2553
2587
|
success: false,
|
|
2554
2588
|
message
|
|
2555
2589
|
});
|
|
2556
|
-
}
|
|
2590
|
+
}).finally(() => {
|
|
2591
|
+
this.inFlightPersist = null;
|
|
2592
|
+
const shouldFlushNow = this.flushRequested;
|
|
2593
|
+
this.flushRequested = false;
|
|
2594
|
+
if (this.dirtyStats.size > 0 || this.dirtyAchievements.size > 0) {
|
|
2595
|
+
this.throttledPersist();
|
|
2596
|
+
if (shouldFlushNow) this.throttledPersist.flush();
|
|
2597
|
+
}
|
|
2598
|
+
});
|
|
2557
2599
|
}
|
|
2558
2600
|
// ================
|
|
2559
2601
|
// Stats
|
|
@@ -2567,8 +2609,9 @@ var StatsManager = class extends WavedashManager {
|
|
|
2567
2609
|
if (this.stats.get(identifier) !== value) {
|
|
2568
2610
|
this.stats.set(identifier, value);
|
|
2569
2611
|
this.dirtyStats.add(identifier);
|
|
2612
|
+
this.throttledPersist();
|
|
2570
2613
|
}
|
|
2571
|
-
if (storeNow) this.
|
|
2614
|
+
if (storeNow) this.requestPersistFlush();
|
|
2572
2615
|
return true;
|
|
2573
2616
|
}
|
|
2574
2617
|
// ================
|
|
@@ -2585,13 +2628,11 @@ var StatsManager = class extends WavedashManager {
|
|
|
2585
2628
|
if (!this.unlockedAchievements.has(identifier)) {
|
|
2586
2629
|
this.unlockedAchievements.add(identifier);
|
|
2587
2630
|
this.dirtyAchievements.add(identifier);
|
|
2631
|
+
this.throttledPersist();
|
|
2588
2632
|
}
|
|
2589
|
-
if (storeNow) this.
|
|
2633
|
+
if (storeNow) this.requestPersistFlush();
|
|
2590
2634
|
return true;
|
|
2591
2635
|
}
|
|
2592
|
-
// ================
|
|
2593
|
-
// Session End
|
|
2594
|
-
// ================
|
|
2595
2636
|
/** @destructive - Returns the pending stats and achievements and resets the dirty collections */
|
|
2596
2637
|
getPendingData() {
|
|
2597
2638
|
if (this.dirtyStats.size === 0 && this.dirtyAchievements.size === 0) {
|
|
@@ -2696,8 +2737,10 @@ var HeartbeatManager = class extends WavedashManager {
|
|
|
2696
2737
|
if (!reestablish && this.heartbeatInFlight) return;
|
|
2697
2738
|
this.heartbeatInFlight = true;
|
|
2698
2739
|
this.sdk.convexClient.mutation(api7.sdk.presence.heartbeat, {
|
|
2699
|
-
...reestablish ? {
|
|
2700
|
-
|
|
2740
|
+
...reestablish ? {
|
|
2741
|
+
data: { forceUpdate: true },
|
|
2742
|
+
deviceFingerprint: this.deviceFingerprint
|
|
2743
|
+
} : {}
|
|
2701
2744
|
}).then((accepted) => {
|
|
2702
2745
|
if (accepted) {
|
|
2703
2746
|
this.lastHeartbeatTime = Date.now();
|
|
@@ -3719,6 +3762,18 @@ var WavedashSDK = class extends EventTarget {
|
|
|
3719
3762
|
filePath
|
|
3720
3763
|
);
|
|
3721
3764
|
}
|
|
3765
|
+
/**
|
|
3766
|
+
* Delete a UGC item: removes the row, the R2 object, and frees up the
|
|
3767
|
+
* user's storage quota by the size of the deleted upload.
|
|
3768
|
+
*/
|
|
3769
|
+
async deleteUGCItem(ugcId) {
|
|
3770
|
+
return this.apiCall(
|
|
3771
|
+
this.ugcManager,
|
|
3772
|
+
"deleteUGCItem",
|
|
3773
|
+
[["ugcId", vId("userGeneratedContent")]],
|
|
3774
|
+
ugcId
|
|
3775
|
+
);
|
|
3776
|
+
}
|
|
3722
3777
|
async downloadUGCItem(ugcId, filePath) {
|
|
3723
3778
|
return this.apiCall(
|
|
3724
3779
|
this.ugcManager,
|
|
@@ -4253,9 +4308,6 @@ var WavedashSDK = class extends EventTarget {
|
|
|
4253
4308
|
}
|
|
4254
4309
|
/**
|
|
4255
4310
|
* Tear down every manager. Called on the parent's `END_SESSION` signal
|
|
4256
|
-
* (committed leaves only — see GameRunnerComponent.svelte). Idempotent.
|
|
4257
|
-
* Each manager's `destroy()` defaults to a no-op; managers with ongoing
|
|
4258
|
-
* state (subscriptions, intervals, peer connections) override it.
|
|
4259
4311
|
*/
|
|
4260
4312
|
destroy() {
|
|
4261
4313
|
if (this.destroyed) return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wvdsh/sdk-js",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Wavedash JavaScript SDK",
|
|
6
6
|
"main": "./dist/client.js",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@eslint/js": "^9.39.2",
|
|
43
|
-
"@types/lodash.
|
|
43
|
+
"@types/lodash.throttle": "^4.1.9",
|
|
44
44
|
"eslint": "^9.39.2",
|
|
45
45
|
"eslint-config-prettier": "^10.1.8",
|
|
46
46
|
"prettier": "^3.7.4",
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
"typescript-eslint": "^8.52.0"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@wvdsh/api": "^0.1.
|
|
52
|
+
"@wvdsh/api": "^0.1.14",
|
|
53
53
|
"convex": "^1.34.0",
|
|
54
|
-
"lodash.
|
|
54
|
+
"lodash.throttle": "^4.1.1"
|
|
55
55
|
}
|
|
56
56
|
}
|