@wvdsh/sdk-js 1.3.12 → 1.3.13
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 +53 -5
- package/dist/index.js +253 -14
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -627,6 +627,7 @@ declare class HeartbeatManager extends WavedashManager {
|
|
|
627
627
|
private isFirstTick;
|
|
628
628
|
private readonly TEST_CONNECTION_INTERVAL_MS;
|
|
629
629
|
private readonly DISCONNECTED_TIMEOUT_MS;
|
|
630
|
+
private cachedPresenceData;
|
|
630
631
|
constructor(sdk: WavedashSDK);
|
|
631
632
|
/** Start heartbeat and connection-check intervals */
|
|
632
633
|
start(): void;
|
|
@@ -638,11 +639,11 @@ declare class HeartbeatManager extends WavedashManager {
|
|
|
638
639
|
private tickHeartbeat;
|
|
639
640
|
private sendHeartbeat;
|
|
640
641
|
/**
|
|
641
|
-
* Updates user presence in the backend
|
|
642
|
+
* Updates user presence in the backend.
|
|
642
643
|
* @param data - Data to send to the backend
|
|
643
644
|
* @returns true if the presence was updated successfully
|
|
644
645
|
*/
|
|
645
|
-
updateUserPresence(data
|
|
646
|
+
updateUserPresence(data: Record<string, string | number | boolean | null>): Promise<boolean>;
|
|
646
647
|
/**
|
|
647
648
|
* Tests the connection to the backend
|
|
648
649
|
*/
|
|
@@ -713,6 +714,47 @@ declare class OverlayManager extends WavedashManager {
|
|
|
713
714
|
private handleKeyDown;
|
|
714
715
|
}
|
|
715
716
|
|
|
717
|
+
/**
|
|
718
|
+
* AudioManager
|
|
719
|
+
*
|
|
720
|
+
* Mutes & unmutes the game in response to MUTE_CHANGED iframe messages, without
|
|
721
|
+
* the game needing to know anything about it.
|
|
722
|
+
*
|
|
723
|
+
* Web Audio: subclass `AudioContext` so `ctx.destination` resolves to a master
|
|
724
|
+
* GainNode that we control. The master gain wires to the real native destination,
|
|
725
|
+
* so `node.connect(ctx.destination)` and any other game code is unaffected.
|
|
726
|
+
*
|
|
727
|
+
* HTML Media (`<audio>`/`<video>`): override `HTMLMediaElement.prototype.muted`
|
|
728
|
+
* to record the game's intended state, but write `true` to the underlying element
|
|
729
|
+
* whenever the SDK is muted. Tracked elements come from three sources:
|
|
730
|
+
* 1. Pre-existing DOM media (`querySelectorAll`)
|
|
731
|
+
* 2. `new Audio()` constructor shim (covers detached SFX)
|
|
732
|
+
* 3. MutationObserver for any media added to the DOM later (covers innerHTML,
|
|
733
|
+
* framework rendering, createElement + append, etc.)
|
|
734
|
+
*/
|
|
735
|
+
declare class AudioManager extends WavedashManager {
|
|
736
|
+
private _isMuted;
|
|
737
|
+
private contexts;
|
|
738
|
+
private elements;
|
|
739
|
+
private intendedMuted;
|
|
740
|
+
private originalAudioContext;
|
|
741
|
+
private originalWebKitAudioContext;
|
|
742
|
+
private originalAudio;
|
|
743
|
+
private originalMutedDescriptor;
|
|
744
|
+
private mutationObserver;
|
|
745
|
+
constructor(sdk: WavedashSDK);
|
|
746
|
+
isMuted(): boolean;
|
|
747
|
+
private handleMute;
|
|
748
|
+
/**
|
|
749
|
+
* Track a media element and (if SDK is currently muted) silence it.
|
|
750
|
+
* Idempotent — safe to call multiple times for the same element.
|
|
751
|
+
*/
|
|
752
|
+
private trackElement;
|
|
753
|
+
private installShims;
|
|
754
|
+
private shimAudioContextClass;
|
|
755
|
+
destroy(): void;
|
|
756
|
+
}
|
|
757
|
+
|
|
716
758
|
/**
|
|
717
759
|
* Friends service
|
|
718
760
|
*
|
|
@@ -898,6 +940,7 @@ declare class WavedashSDK extends EventTarget {
|
|
|
898
940
|
p2pManager: P2PManager;
|
|
899
941
|
fullscreenManager: FullscreenManager;
|
|
900
942
|
overlayManager: OverlayManager;
|
|
943
|
+
audioManager: AudioManager;
|
|
901
944
|
private managers;
|
|
902
945
|
private gameplayJwt;
|
|
903
946
|
private gameplayJwtPromise;
|
|
@@ -1162,11 +1205,16 @@ declare class WavedashSDK extends EventTarget {
|
|
|
1162
1205
|
inviteUserToLobby(lobbyId: GenericId<"lobbies">, userId: GenericId<"users">): Promise<WavedashResponse<boolean>>;
|
|
1163
1206
|
getLobbyInviteLink(copyToClipboard?: boolean): Promise<WavedashResponse<string>>;
|
|
1164
1207
|
/**
|
|
1165
|
-
* Updates rich user presence so friends can see what the player is doing in game
|
|
1166
|
-
*
|
|
1208
|
+
* Updates rich user presence so friends can see what the player is doing in game.
|
|
1209
|
+
* Supported keys:
|
|
1210
|
+
* `status` — one-line activity shown as the primary line (e.g. "Traveling in a group")
|
|
1211
|
+
* `details` — secondary context shown beneath the status (e.g. current zone or mode)
|
|
1212
|
+
*
|
|
1213
|
+
* Pass an empty dictionary to clear all presence fields.
|
|
1214
|
+
* @param data Presence fields to update.
|
|
1167
1215
|
* @returns true if the presence was updated successfully
|
|
1168
1216
|
*/
|
|
1169
|
-
updateUserPresence(data
|
|
1217
|
+
updateUserPresence(data: Record<string, string | number | boolean | null>): Promise<WavedashResponse<boolean>>;
|
|
1170
1218
|
private isGodot;
|
|
1171
1219
|
private formatResponse;
|
|
1172
1220
|
private ensureInit;
|
package/dist/index.js
CHANGED
|
@@ -2709,6 +2709,7 @@ var HeartbeatManager = class extends WavedashManager {
|
|
|
2709
2709
|
this.isFirstTick = true;
|
|
2710
2710
|
this.TEST_CONNECTION_INTERVAL_MS = 1e3;
|
|
2711
2711
|
this.DISCONNECTED_TIMEOUT_MS = 9e4;
|
|
2712
|
+
this.cachedPresenceData = {};
|
|
2712
2713
|
this.handleVisibilityChange = () => {
|
|
2713
2714
|
if (document.visibilityState === "visible") {
|
|
2714
2715
|
this.start();
|
|
@@ -2778,7 +2779,7 @@ var HeartbeatManager = class extends WavedashManager {
|
|
|
2778
2779
|
this.heartbeatInFlight = true;
|
|
2779
2780
|
this.sdk.convexClient.mutation(api7.sdk.presence.heartbeat, {
|
|
2780
2781
|
...reestablish ? {
|
|
2781
|
-
data:
|
|
2782
|
+
data: this.cachedPresenceData,
|
|
2782
2783
|
deviceFingerprint: this.deviceFingerprint
|
|
2783
2784
|
} : {}
|
|
2784
2785
|
}).then((accepted) => {
|
|
@@ -2792,15 +2793,15 @@ var HeartbeatManager = class extends WavedashManager {
|
|
|
2792
2793
|
});
|
|
2793
2794
|
}
|
|
2794
2795
|
/**
|
|
2795
|
-
* Updates user presence in the backend
|
|
2796
|
+
* Updates user presence in the backend.
|
|
2796
2797
|
* @param data - Data to send to the backend
|
|
2797
2798
|
* @returns true if the presence was updated successfully
|
|
2798
2799
|
*/
|
|
2799
2800
|
async updateUserPresence(data) {
|
|
2800
2801
|
try {
|
|
2801
|
-
|
|
2802
|
+
this.cachedPresenceData = data;
|
|
2802
2803
|
await this.sdk.convexClient.mutation(api7.sdk.presence.heartbeat, {
|
|
2803
|
-
data
|
|
2804
|
+
data,
|
|
2804
2805
|
deviceFingerprint: this.deviceFingerprint
|
|
2805
2806
|
});
|
|
2806
2807
|
return true;
|
|
@@ -3028,6 +3029,211 @@ var OverlayManager = class extends WavedashManager {
|
|
|
3028
3029
|
}
|
|
3029
3030
|
};
|
|
3030
3031
|
|
|
3032
|
+
// src/services/audio.ts
|
|
3033
|
+
import { IFRAME_MESSAGE_TYPE as IFRAME_MESSAGE_TYPE5 } from "@wvdsh/api";
|
|
3034
|
+
var WeakRefSet = class {
|
|
3035
|
+
constructor() {
|
|
3036
|
+
this.set = /* @__PURE__ */ new Set();
|
|
3037
|
+
}
|
|
3038
|
+
add(value) {
|
|
3039
|
+
for (const ref of this.set) {
|
|
3040
|
+
if (ref.deref() === value) return;
|
|
3041
|
+
}
|
|
3042
|
+
this.set.add(new WeakRef(value));
|
|
3043
|
+
}
|
|
3044
|
+
forEach(callback) {
|
|
3045
|
+
for (const ref of this.set) {
|
|
3046
|
+
const v = ref.deref();
|
|
3047
|
+
if (v === void 0) this.set.delete(ref);
|
|
3048
|
+
else callback(v);
|
|
3049
|
+
}
|
|
3050
|
+
}
|
|
3051
|
+
clear() {
|
|
3052
|
+
this.set.clear();
|
|
3053
|
+
}
|
|
3054
|
+
};
|
|
3055
|
+
var AudioManager = class extends WavedashManager {
|
|
3056
|
+
constructor(sdk) {
|
|
3057
|
+
super(sdk);
|
|
3058
|
+
this._isMuted = false;
|
|
3059
|
+
// Web Audio contexts and their master gain nodes
|
|
3060
|
+
this.contexts = /* @__PURE__ */ new Map();
|
|
3061
|
+
// HTML media elements we know about + their game-intended muted state
|
|
3062
|
+
this.elements = new WeakRefSet();
|
|
3063
|
+
this.intendedMuted = /* @__PURE__ */ new WeakMap();
|
|
3064
|
+
// Originals (restored on destroy)
|
|
3065
|
+
this.originalAudioContext = null;
|
|
3066
|
+
this.originalWebKitAudioContext = null;
|
|
3067
|
+
this.originalAudio = null;
|
|
3068
|
+
this.originalMutedDescriptor = null;
|
|
3069
|
+
this.mutationObserver = null;
|
|
3070
|
+
this.handleMute = (data) => {
|
|
3071
|
+
if (this._isMuted === data.isMuted) return;
|
|
3072
|
+
this._isMuted = data.isMuted;
|
|
3073
|
+
logger.debug(`[AudioManager] muted=${this._isMuted}`);
|
|
3074
|
+
const target = this._isMuted ? 0 : 1;
|
|
3075
|
+
this.contexts.forEach((gain, ctx) => {
|
|
3076
|
+
const now = ctx.currentTime;
|
|
3077
|
+
gain.gain.cancelScheduledValues(now);
|
|
3078
|
+
gain.gain.setValueAtTime(gain.gain.value, now);
|
|
3079
|
+
gain.gain.linearRampToValueAtTime(target, now + 0.05);
|
|
3080
|
+
});
|
|
3081
|
+
const setMutedNative = this.originalMutedDescriptor?.set;
|
|
3082
|
+
if (setMutedNative) {
|
|
3083
|
+
this.elements.forEach((el) => {
|
|
3084
|
+
const intended = this.intendedMuted.get(el) ?? false;
|
|
3085
|
+
setMutedNative.call(el, this._isMuted ? true : intended);
|
|
3086
|
+
});
|
|
3087
|
+
}
|
|
3088
|
+
};
|
|
3089
|
+
this.installShims();
|
|
3090
|
+
this.sdk.iframeMessenger.addEventListener(
|
|
3091
|
+
IFRAME_MESSAGE_TYPE5.MUTE_CHANGED,
|
|
3092
|
+
this.handleMute
|
|
3093
|
+
);
|
|
3094
|
+
}
|
|
3095
|
+
isMuted() {
|
|
3096
|
+
return this._isMuted;
|
|
3097
|
+
}
|
|
3098
|
+
/**
|
|
3099
|
+
* Track a media element and (if SDK is currently muted) silence it.
|
|
3100
|
+
* Idempotent — safe to call multiple times for the same element.
|
|
3101
|
+
*/
|
|
3102
|
+
trackElement(el) {
|
|
3103
|
+
if (this.intendedMuted.has(el)) return;
|
|
3104
|
+
const getMuted = this.originalMutedDescriptor?.get;
|
|
3105
|
+
const setMuted = this.originalMutedDescriptor?.set;
|
|
3106
|
+
const current = getMuted ? getMuted.call(el) : el.muted;
|
|
3107
|
+
this.intendedMuted.set(el, current);
|
|
3108
|
+
this.elements.add(el);
|
|
3109
|
+
if (this._isMuted && !current && setMuted) {
|
|
3110
|
+
setMuted.call(el, true);
|
|
3111
|
+
}
|
|
3112
|
+
}
|
|
3113
|
+
installShims() {
|
|
3114
|
+
if (typeof window === "undefined") return;
|
|
3115
|
+
if (window.AudioContext) {
|
|
3116
|
+
this.originalAudioContext = window.AudioContext;
|
|
3117
|
+
window.AudioContext = this.shimAudioContextClass(window.AudioContext);
|
|
3118
|
+
}
|
|
3119
|
+
const win = window;
|
|
3120
|
+
if (win.webkitAudioContext) {
|
|
3121
|
+
this.originalWebKitAudioContext = win.webkitAudioContext;
|
|
3122
|
+
win.webkitAudioContext = this.shimAudioContextClass(win.webkitAudioContext);
|
|
3123
|
+
}
|
|
3124
|
+
if (window.Audio) {
|
|
3125
|
+
const OriginalAudio = window.Audio;
|
|
3126
|
+
this.originalAudio = OriginalAudio;
|
|
3127
|
+
((manager) => {
|
|
3128
|
+
const Shimmed = function(src) {
|
|
3129
|
+
const audio = new OriginalAudio(src);
|
|
3130
|
+
manager.trackElement(audio);
|
|
3131
|
+
return audio;
|
|
3132
|
+
};
|
|
3133
|
+
Shimmed.prototype = OriginalAudio.prototype;
|
|
3134
|
+
window.Audio = Shimmed;
|
|
3135
|
+
})(this);
|
|
3136
|
+
}
|
|
3137
|
+
if (typeof document !== "undefined") {
|
|
3138
|
+
document.querySelectorAll("audio, video").forEach((el) => {
|
|
3139
|
+
this.trackElement(el);
|
|
3140
|
+
});
|
|
3141
|
+
this.mutationObserver = new MutationObserver((mutations) => {
|
|
3142
|
+
for (const m of mutations) {
|
|
3143
|
+
m.addedNodes.forEach((node) => {
|
|
3144
|
+
if (node instanceof HTMLMediaElement) {
|
|
3145
|
+
this.trackElement(node);
|
|
3146
|
+
} else if (node instanceof HTMLElement) {
|
|
3147
|
+
node.querySelectorAll("audio, video").forEach((el) => {
|
|
3148
|
+
this.trackElement(el);
|
|
3149
|
+
});
|
|
3150
|
+
}
|
|
3151
|
+
});
|
|
3152
|
+
}
|
|
3153
|
+
});
|
|
3154
|
+
this.mutationObserver.observe(document.documentElement, {
|
|
3155
|
+
childList: true,
|
|
3156
|
+
subtree: true
|
|
3157
|
+
});
|
|
3158
|
+
}
|
|
3159
|
+
this.originalMutedDescriptor = Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, "muted") ?? null;
|
|
3160
|
+
const original = this.originalMutedDescriptor;
|
|
3161
|
+
if (original?.get && original?.set) {
|
|
3162
|
+
((manager) => {
|
|
3163
|
+
Object.defineProperty(HTMLMediaElement.prototype, "muted", {
|
|
3164
|
+
configurable: true,
|
|
3165
|
+
get() {
|
|
3166
|
+
const intended = manager.intendedMuted.get(this);
|
|
3167
|
+
return intended !== void 0 ? intended : original.get.call(this);
|
|
3168
|
+
},
|
|
3169
|
+
set(value) {
|
|
3170
|
+
manager.intendedMuted.set(this, value);
|
|
3171
|
+
manager.elements.add(this);
|
|
3172
|
+
original.set.call(this, manager._isMuted ? true : value);
|
|
3173
|
+
}
|
|
3174
|
+
});
|
|
3175
|
+
})(this);
|
|
3176
|
+
}
|
|
3177
|
+
}
|
|
3178
|
+
shimAudioContextClass(Original) {
|
|
3179
|
+
return /* @__PURE__ */ ((manager) => class extends Original {
|
|
3180
|
+
constructor(opts) {
|
|
3181
|
+
super(opts);
|
|
3182
|
+
const masterGain = this.createGain();
|
|
3183
|
+
masterGain.connect(this.destination);
|
|
3184
|
+
masterGain.gain.setValueAtTime(
|
|
3185
|
+
manager._isMuted ? 0 : 1,
|
|
3186
|
+
this.currentTime
|
|
3187
|
+
);
|
|
3188
|
+
Object.defineProperty(this, "destination", {
|
|
3189
|
+
configurable: true,
|
|
3190
|
+
get() {
|
|
3191
|
+
return masterGain;
|
|
3192
|
+
}
|
|
3193
|
+
});
|
|
3194
|
+
manager.contexts.set(this, masterGain);
|
|
3195
|
+
}
|
|
3196
|
+
close() {
|
|
3197
|
+
manager.contexts.delete(this);
|
|
3198
|
+
return super.close();
|
|
3199
|
+
}
|
|
3200
|
+
})(this);
|
|
3201
|
+
}
|
|
3202
|
+
destroy() {
|
|
3203
|
+
this.sdk.iframeMessenger.removeEventListener(
|
|
3204
|
+
IFRAME_MESSAGE_TYPE5.MUTE_CHANGED,
|
|
3205
|
+
this.handleMute
|
|
3206
|
+
);
|
|
3207
|
+
if (this.mutationObserver) {
|
|
3208
|
+
this.mutationObserver.disconnect();
|
|
3209
|
+
this.mutationObserver = null;
|
|
3210
|
+
}
|
|
3211
|
+
if (typeof window !== "undefined") {
|
|
3212
|
+
if (this.originalAudioContext) {
|
|
3213
|
+
window.AudioContext = this.originalAudioContext;
|
|
3214
|
+
}
|
|
3215
|
+
const win = window;
|
|
3216
|
+
if (this.originalWebKitAudioContext && win.webkitAudioContext) {
|
|
3217
|
+
win.webkitAudioContext = this.originalWebKitAudioContext;
|
|
3218
|
+
}
|
|
3219
|
+
if (this.originalAudio) {
|
|
3220
|
+
window.Audio = this.originalAudio;
|
|
3221
|
+
}
|
|
3222
|
+
}
|
|
3223
|
+
if (this.originalMutedDescriptor) {
|
|
3224
|
+
Object.defineProperty(
|
|
3225
|
+
HTMLMediaElement.prototype,
|
|
3226
|
+
"muted",
|
|
3227
|
+
this.originalMutedDescriptor
|
|
3228
|
+
);
|
|
3229
|
+
}
|
|
3230
|
+
this.contexts.clear();
|
|
3231
|
+
this.elements.clear();
|
|
3232
|
+
this.intendedMuted = /* @__PURE__ */ new WeakMap();
|
|
3233
|
+
super.destroy();
|
|
3234
|
+
}
|
|
3235
|
+
};
|
|
3236
|
+
|
|
3031
3237
|
// src/services/friends.ts
|
|
3032
3238
|
import { api as api8 } from "@wvdsh/api";
|
|
3033
3239
|
|
|
@@ -3289,7 +3495,7 @@ var SwMessenger = class {
|
|
|
3289
3495
|
};
|
|
3290
3496
|
|
|
3291
3497
|
// src/index.ts
|
|
3292
|
-
import { IFRAME_MESSAGE_TYPE as
|
|
3498
|
+
import { IFRAME_MESSAGE_TYPE as IFRAME_MESSAGE_TYPE6, UrlParams } from "@wvdsh/api";
|
|
3293
3499
|
|
|
3294
3500
|
// src/utils/validation.ts
|
|
3295
3501
|
var CONVEX_ID_REGEX = /^[0-9a-z]{31,37}$/;
|
|
@@ -3333,6 +3539,13 @@ var vRecord = (value, path) => {
|
|
|
3333
3539
|
`${path}: expected plain object, got ${describeValue(value)}`
|
|
3334
3540
|
);
|
|
3335
3541
|
}
|
|
3542
|
+
for (const [key, val] of Object.entries(value)) {
|
|
3543
|
+
if (typeof val === "object" && val !== null) {
|
|
3544
|
+
throw new Error(
|
|
3545
|
+
`${path}: expected flat record with no nested objects, but key "${key}" contains ${describeValue(val)}`
|
|
3546
|
+
);
|
|
3547
|
+
}
|
|
3548
|
+
}
|
|
3336
3549
|
return value;
|
|
3337
3550
|
};
|
|
3338
3551
|
function vId(tableName) {
|
|
@@ -3377,7 +3590,12 @@ function vUnion(...variants) {
|
|
|
3377
3590
|
}
|
|
3378
3591
|
function vObject(shape) {
|
|
3379
3592
|
return (value, path) => {
|
|
3380
|
-
|
|
3593
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
3594
|
+
throw new Error(
|
|
3595
|
+
`${path}: expected plain object, got ${describeValue(value)}`
|
|
3596
|
+
);
|
|
3597
|
+
}
|
|
3598
|
+
const obj = value;
|
|
3381
3599
|
for (const key of Object.keys(obj)) {
|
|
3382
3600
|
if (!(key in shape)) {
|
|
3383
3601
|
throw new Error(`${path}: unrecognized property "${key}"`);
|
|
@@ -3468,6 +3686,7 @@ var WavedashSDK = class extends EventTarget {
|
|
|
3468
3686
|
this.gameEventManager = new GameEventManager(this);
|
|
3469
3687
|
this.fullscreenManager = new FullscreenManager(this);
|
|
3470
3688
|
this.overlayManager = new OverlayManager(this);
|
|
3689
|
+
this.audioManager = new AudioManager(this);
|
|
3471
3690
|
this.managers = [
|
|
3472
3691
|
this.p2pManager,
|
|
3473
3692
|
this.lobbyManager,
|
|
@@ -3479,7 +3698,8 @@ var WavedashSDK = class extends EventTarget {
|
|
|
3479
3698
|
this.friendsManager,
|
|
3480
3699
|
this.gameEventManager,
|
|
3481
3700
|
this.fullscreenManager,
|
|
3482
|
-
this.overlayManager
|
|
3701
|
+
this.overlayManager,
|
|
3702
|
+
this.audioManager
|
|
3483
3703
|
];
|
|
3484
3704
|
this.friendsManager.cacheUsers([
|
|
3485
3705
|
{
|
|
@@ -3611,7 +3831,7 @@ var WavedashSDK = class extends EventTarget {
|
|
|
3611
3831
|
[progress]
|
|
3612
3832
|
);
|
|
3613
3833
|
this.clearSetupWarning();
|
|
3614
|
-
iframeMessenger.postToParent(
|
|
3834
|
+
iframeMessenger.postToParent(IFRAME_MESSAGE_TYPE6.PROGRESS_UPDATE, {
|
|
3615
3835
|
progress
|
|
3616
3836
|
});
|
|
3617
3837
|
}
|
|
@@ -3620,7 +3840,7 @@ var WavedashSDK = class extends EventTarget {
|
|
|
3620
3840
|
if (this.gameFinishedLoading) return;
|
|
3621
3841
|
this.gameFinishedLoading = true;
|
|
3622
3842
|
this.heartbeatManager.start();
|
|
3623
|
-
iframeMessenger.postToParent(
|
|
3843
|
+
iframeMessenger.postToParent(IFRAME_MESSAGE_TYPE6.LOADING_COMPLETE, {});
|
|
3624
3844
|
this.overlayManager.takeFocus();
|
|
3625
3845
|
}
|
|
3626
3846
|
get gameLoaded() {
|
|
@@ -4368,15 +4588,34 @@ var WavedashSDK = class extends EventTarget {
|
|
|
4368
4588
|
// User Presence
|
|
4369
4589
|
// ==============================
|
|
4370
4590
|
/**
|
|
4371
|
-
* Updates rich user presence so friends can see what the player is doing in game
|
|
4372
|
-
*
|
|
4591
|
+
* Updates rich user presence so friends can see what the player is doing in game.
|
|
4592
|
+
* Supported keys:
|
|
4593
|
+
* `status` — one-line activity shown as the primary line (e.g. "Traveling in a group")
|
|
4594
|
+
* `details` — secondary context shown beneath the status (e.g. current zone or mode)
|
|
4595
|
+
*
|
|
4596
|
+
* Pass an empty dictionary to clear all presence fields.
|
|
4597
|
+
* @param data Presence fields to update.
|
|
4373
4598
|
* @returns true if the presence was updated successfully
|
|
4374
4599
|
*/
|
|
4375
4600
|
async updateUserPresence(data) {
|
|
4601
|
+
if (typeof data === "string") {
|
|
4602
|
+
const raw = data;
|
|
4603
|
+
try {
|
|
4604
|
+
data = JSON.parse(raw);
|
|
4605
|
+
} catch (error) {
|
|
4606
|
+
const message = `updateUserPresence: invalid JSON: ${raw}`;
|
|
4607
|
+
logger.error(message, error);
|
|
4608
|
+
return this.formatResponse({
|
|
4609
|
+
success: false,
|
|
4610
|
+
data: null,
|
|
4611
|
+
message
|
|
4612
|
+
});
|
|
4613
|
+
}
|
|
4614
|
+
}
|
|
4376
4615
|
return this.apiCall(
|
|
4377
4616
|
this.heartbeatManager,
|
|
4378
4617
|
"updateUserPresence",
|
|
4379
|
-
[["data",
|
|
4618
|
+
[["data", vRecord]],
|
|
4380
4619
|
data
|
|
4381
4620
|
);
|
|
4382
4621
|
}
|
|
@@ -4467,7 +4706,7 @@ var WavedashSDK = class extends EventTarget {
|
|
|
4467
4706
|
throw new Error(`Failed to refresh gameplay token: ${response.status}`);
|
|
4468
4707
|
}
|
|
4469
4708
|
this.gameplayJwt = await response.text();
|
|
4470
|
-
iframeMessenger.postToParent(
|
|
4709
|
+
iframeMessenger.postToParent(IFRAME_MESSAGE_TYPE6.GAMEPLAY_JWT_READY, {
|
|
4471
4710
|
gameplayJwt: this.gameplayJwt
|
|
4472
4711
|
});
|
|
4473
4712
|
this.swMessenger.postToServiceWorker({
|
|
@@ -4503,7 +4742,7 @@ var WavedashSDK = class extends EventTarget {
|
|
|
4503
4742
|
}
|
|
4504
4743
|
setupSessionEndListeners() {
|
|
4505
4744
|
iframeMessenger.addEventListener(
|
|
4506
|
-
|
|
4745
|
+
IFRAME_MESSAGE_TYPE6.END_SESSION,
|
|
4507
4746
|
() => this.destroy()
|
|
4508
4747
|
);
|
|
4509
4748
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wvdsh/sdk-js",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Wavedash JavaScript SDK",
|
|
6
6
|
"main": "./dist/client.js",
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
"typescript-eslint": "^8.52.0"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@wvdsh/api": "^0.1.
|
|
53
|
-
"convex": "^1.
|
|
52
|
+
"@wvdsh/api": "^0.1.28",
|
|
53
|
+
"convex": "^1.39.1",
|
|
54
54
|
"lodash.throttle": "^4.1.1"
|
|
55
55
|
}
|
|
56
56
|
}
|