@wvdsh/sdk-js 1.3.8 → 1.3.10

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +38 -23
  2. package/dist/index.js +257 -164
  3. package/package.json +2 -2
package/dist/index.d.ts CHANGED
@@ -730,28 +730,6 @@ declare class FriendsManager extends WavedashManager {
730
730
  listFriends(): Promise<Friend[]>;
731
731
  }
732
732
 
733
- /**
734
- * Logger interface and implementation
735
- * Simply logs to the console with customizable log level
736
- *
737
- * In the future we could extend this to write .log files to IndexedDB or cache storage
738
- */
739
- interface Logger {
740
- debug(message: string, ...args: unknown[]): void;
741
- info(message: string, ...args: unknown[]): void;
742
- warn(message: string, ...args: unknown[]): void;
743
- error(message: string, ...args: unknown[]): void;
744
- }
745
- declare class WavedashLogger implements Logger {
746
- private logLevel;
747
- constructor(logLevel?: number);
748
- setLogLevel(level: number): void;
749
- debug(message: string, ...args: unknown[]): void;
750
- info(message: string, ...args: unknown[]): void;
751
- warn(message: string, ...args: unknown[]): void;
752
- error(message: string, ...args: unknown[]): void;
753
- }
754
-
755
733
  /**
756
734
  * Utilities for handling iframe messaging between the iframe'd Wavedash SDK and the parent window.
757
735
  * Assumes window is defined and this is only ever running inside an iframe.
@@ -778,6 +756,36 @@ declare class IFrameMessenger {
778
756
  requestFromParent<T extends keyof IFrameEventPayloadMap>(requestType: T, data?: Record<string, unknown>): Promise<IFrameEventPayloadMap[T]>;
779
757
  }
780
758
 
759
+ /**
760
+ * Utilities for messaging between the SDK and the service worker
761
+ * that proxies API requests on its behalf.
762
+ */
763
+ type SwMessage<T = unknown> = {
764
+ type: string;
765
+ payload?: T;
766
+ };
767
+ type SwReply = (message: SwMessage) => void;
768
+ type SwListener = (payload: unknown, reply: SwReply) => void;
769
+ declare class SwMessenger {
770
+ private listeners;
771
+ constructor();
772
+ /**
773
+ * Register a handler for an incoming message type from the SW. The handler
774
+ * receives the message payload and a `reply` function that routes the
775
+ * response back via the transferred MessagePort when present, falling back
776
+ * to a controller postMessage otherwise.
777
+ */
778
+ addEventListener(type: string, listener: SwListener): void;
779
+ removeEventListener(type: string, listener: SwListener): void;
780
+ /**
781
+ * Fire-and-forget message to the active service worker controller. No-op
782
+ * when no SW is controlling the page (first load before activation, or
783
+ * environments without SW support).
784
+ */
785
+ postToServiceWorker(message: SwMessage): boolean;
786
+ private handleMessage;
787
+ }
788
+
781
789
  declare class WavedashSDK extends EventTarget {
782
790
  private _initialized;
783
791
  get initialized(): boolean;
@@ -867,8 +875,8 @@ declare class WavedashSDK extends EventTarget {
867
875
  convexClient: ConvexClient;
868
876
  engineCallbackReceiver: string;
869
877
  engineInstance: EngineInstance | null;
870
- logger: WavedashLogger;
871
878
  iframeMessenger: IFrameMessenger;
879
+ swMessenger: SwMessenger;
872
880
  p2pManager: P2PManager;
873
881
  fullscreenManager: FullscreenManager;
874
882
  overlayManager: OverlayManager;
@@ -1167,6 +1175,13 @@ declare class WavedashSDK extends EventTarget {
1167
1175
  */
1168
1176
  private destroy;
1169
1177
  private setupSessionEndListeners;
1178
+ /**
1179
+ * Respond to the service worker's `embed.creds-request` with the SDK's
1180
+ * current gameplay JWT. The SW asks when it wakes from termination with no
1181
+ * in-memory or IDB credentials (e.g. Safari ITP storage decay) — we're the
1182
+ * fastest live source. JWT only; sessionToken is owned by the SW + cookies.
1183
+ */
1184
+ private setupSwCredsListener;
1170
1185
  }
1171
1186
  declare global {
1172
1187
  interface Window {
package/dist/index.js CHANGED
@@ -93,6 +93,44 @@ var WavedashManager = class {
93
93
  }
94
94
  };
95
95
 
96
+ // src/utils/logger.ts
97
+ var LOG_LEVEL = {
98
+ DEBUG: 0,
99
+ // Most verbose
100
+ INFO: 1,
101
+ WARN: 2,
102
+ ERROR: 3
103
+ };
104
+ var WavedashLogger = class {
105
+ constructor(logLevel = LOG_LEVEL.WARN) {
106
+ this.logLevel = logLevel;
107
+ }
108
+ setLogLevel(level) {
109
+ this.logLevel = level;
110
+ }
111
+ debug(message, ...args) {
112
+ if (this.logLevel <= LOG_LEVEL.DEBUG) {
113
+ console.log(`[WavedashJS] ${message}`, ...args);
114
+ }
115
+ }
116
+ info(message, ...args) {
117
+ if (this.logLevel <= LOG_LEVEL.INFO) {
118
+ console.log(`[WavedashJS] ${message}`, ...args);
119
+ }
120
+ }
121
+ warn(message, ...args) {
122
+ if (this.logLevel <= LOG_LEVEL.WARN) {
123
+ console.warn(`[WavedashJS] ${message}`, ...args);
124
+ }
125
+ }
126
+ error(message, ...args) {
127
+ if (this.logLevel <= LOG_LEVEL.ERROR) {
128
+ console.error(`[WavedashJS] ${message}`, ...args);
129
+ }
130
+ }
131
+ };
132
+ var logger = new WavedashLogger();
133
+
96
134
  // src/services/lobby.ts
97
135
  var _LobbyManager = class _LobbyManager extends WavedashManager {
98
136
  constructor(sdk) {
@@ -153,7 +191,7 @@ var _LobbyManager = class _LobbyManager extends WavedashManager {
153
191
  for (const user of previousUsers) {
154
192
  if (!newUserIds.has(user.userId)) {
155
193
  if (user.userId === this.sdk.getUserId()) {
156
- this.sdk.logger.warn(
194
+ logger.warn(
157
195
  "USER WAS KICKED FROM LOBBY! Received notification for myself leaving."
158
196
  );
159
197
  }
@@ -169,7 +207,7 @@ var _LobbyManager = class _LobbyManager extends WavedashManager {
169
207
  }
170
208
  if (this.lobbyId) {
171
209
  this.p2pUpdateQueue = this.p2pUpdateQueue.then(() => this.updateP2PConnections(newUsers)).catch((error) => {
172
- this.sdk.logger.error("Error in queued P2P update:", error);
210
+ logger.error("Error in queued P2P update:", error);
173
211
  });
174
212
  }
175
213
  };
@@ -204,7 +242,7 @@ var _LobbyManager = class _LobbyManager extends WavedashManager {
204
242
  {},
205
243
  this.processInviteUpdates,
206
244
  (error) => {
207
- this.sdk.logger.error(`Lobby invites subscription error: ${error}`);
245
+ logger.error(`Lobby invites subscription error: ${error}`);
208
246
  }
209
247
  );
210
248
  }
@@ -232,7 +270,7 @@ var _LobbyManager = class _LobbyManager extends WavedashManager {
232
270
  }
233
271
  getLobbyUsers(lobbyId) {
234
272
  if (this.lobbyId !== lobbyId) {
235
- this.sdk.logger.error(
273
+ logger.error(
236
274
  "Must be a member of the lobby to access user list"
237
275
  );
238
276
  return [];
@@ -241,7 +279,7 @@ var _LobbyManager = class _LobbyManager extends WavedashManager {
241
279
  }
242
280
  getHostId(lobbyId) {
243
281
  if (this.lobbyId !== lobbyId) {
244
- this.sdk.logger.error(
282
+ logger.error(
245
283
  "Must be a member of the lobby to access the host ID"
246
284
  );
247
285
  return null;
@@ -317,11 +355,11 @@ var _LobbyManager = class _LobbyManager extends WavedashManager {
317
355
  sendLobbyMessage(lobbyId, message) {
318
356
  const args = { lobbyId, message };
319
357
  if (message.length === 0) {
320
- this.sdk.logger.error("Message cannot be empty");
358
+ logger.error("Message cannot be empty");
321
359
  return false;
322
360
  }
323
361
  if (message.length > LOBBY_MESSAGE_MAX_LENGTH) {
324
- this.sdk.logger.error(
362
+ logger.error(
325
363
  `Message cannot be longer than ${LOBBY_MESSAGE_MAX_LENGTH} characters`
326
364
  );
327
365
  return false;
@@ -329,7 +367,7 @@ var _LobbyManager = class _LobbyManager extends WavedashManager {
329
367
  try {
330
368
  this.sdk.convexClient.mutation(api.sdk.gameLobby.sendMessage, args);
331
369
  } catch (error) {
332
- this.sdk.logger.error(`Error sending lobby message: ${error}`);
370
+ logger.error(`Error sending lobby message: ${error}`);
333
371
  return false;
334
372
  }
335
373
  return true;
@@ -372,7 +410,7 @@ var _LobbyManager = class _LobbyManager extends WavedashManager {
372
410
  this.lobbyMetadata = response.metadata;
373
411
  this.sdk.friendsManager.cacheUsers(response.users);
374
412
  const onLobbySubscriptionError = (error) => {
375
- this.sdk.logger.error(`Lobby subscription error: ${error.message}`);
413
+ logger.error(`Lobby subscription error: ${error.message}`);
376
414
  if (error.message.includes("not a member")) {
377
415
  this.handleLobbyKicked(LobbyKickedReason.KICKED);
378
416
  } else {
@@ -406,7 +444,7 @@ var _LobbyManager = class _LobbyManager extends WavedashManager {
406
444
  if (response.users.length > 1) {
407
445
  this.p2pUpdateQueue = this.updateP2PConnections(response.users).catch(
408
446
  (error) => {
409
- this.sdk.logger.error("Error initializing P2P on join:", error);
447
+ logger.error("Error initializing P2P on join:", error);
410
448
  }
411
449
  );
412
450
  }
@@ -419,7 +457,7 @@ var _LobbyManager = class _LobbyManager extends WavedashManager {
419
457
  users: response.users,
420
458
  metadata: response.metadata
421
459
  });
422
- this.sdk.logger.debug("Subscribed to lobby:", response.lobbyId);
460
+ logger.debug("Subscribed to lobby:", response.lobbyId);
423
461
  }
424
462
  /**
425
463
  * Handle being kicked or removed from a lobby (subscription error)
@@ -429,7 +467,7 @@ var _LobbyManager = class _LobbyManager extends WavedashManager {
429
467
  handleLobbyKicked(reason = LobbyKickedReason.KICKED) {
430
468
  const lobbyId = this.lobbyId;
431
469
  if (!lobbyId) return;
432
- this.sdk.logger.warn(
470
+ logger.warn(
433
471
  `User was removed from lobby: ${lobbyId} (reason: ${reason})`
434
472
  );
435
473
  this.cleanupLobbyState();
@@ -516,7 +554,7 @@ var _LobbyManager = class _LobbyManager extends WavedashManager {
516
554
  lobbyId: this.lobbyId,
517
555
  updates
518
556
  }).catch((error) => {
519
- this.sdk.logger.error("Error updating lobby metadata:", error);
557
+ logger.error("Error updating lobby metadata:", error);
520
558
  }).finally(() => {
521
559
  this.inFlightMetadataUpdate = null;
522
560
  if (Object.keys(this.pendingMetadataUpdates).length > 0) {
@@ -538,7 +576,7 @@ var _LobbyManager = class _LobbyManager extends WavedashManager {
538
576
  try {
539
577
  if (newUsers.length <= 1) {
540
578
  this.sdk.p2pManager.disconnectP2P();
541
- this.sdk.logger.debug(
579
+ logger.debug(
542
580
  "Only one user in lobby, P2P connections disconnected"
543
581
  );
544
582
  return;
@@ -552,11 +590,11 @@ var _LobbyManager = class _LobbyManager extends WavedashManager {
552
590
  this.lobbyId,
553
591
  wavedashUsers
554
592
  );
555
- this.sdk.logger.debug(
593
+ logger.debug(
556
594
  `P2P connections updated for lobby ${this.lobbyId} with ${wavedashUsers.length} users`
557
595
  );
558
596
  } catch (error) {
559
- this.sdk.logger.error("Error updating P2P connections:", error);
597
+ logger.error("Error updating P2P connections:", error);
560
598
  }
561
599
  }
562
600
  };
@@ -701,7 +739,7 @@ var FileSystemManager = class extends WavedashManager {
701
739
  });
702
740
  if (!response.ok) {
703
741
  const msg = `Failed to delete remote file ${filePath}: ${response.status} (${response.statusText})`;
704
- this.sdk.logger.error(msg);
742
+ logger.error(msg);
705
743
  throw new Error(msg);
706
744
  }
707
745
  return filePath;
@@ -760,9 +798,9 @@ var FileSystemManager = class extends WavedashManager {
760
798
  return path;
761
799
  }
762
800
  async writeLocalFile(filePath, data) {
763
- this.sdk.logger.debug(`Writing local file: ${filePath}`);
801
+ logger.debug(`Writing local file: ${filePath}`);
764
802
  if (this.sdk.engineInstance?.FS) {
765
- this.sdk.logger.error(
803
+ logger.error(
766
804
  `${this.sdk.engineInstance.type} engine detected, use engine's builtin file access to save files.`
767
805
  );
768
806
  return false;
@@ -771,14 +809,14 @@ var FileSystemManager = class extends WavedashManager {
771
809
  await writeToIndexedDB(filePath, data);
772
810
  return true;
773
811
  } catch (error) {
774
- this.sdk.logger.error(`Failed to write local file: ${error}`);
812
+ logger.error(`Failed to write local file: ${error}`);
775
813
  return false;
776
814
  }
777
815
  }
778
816
  async readLocalFile(filePath) {
779
- this.sdk.logger.debug(`Reading local file: ${filePath}`);
817
+ logger.debug(`Reading local file: ${filePath}`);
780
818
  if (this.sdk.engineInstance?.FS) {
781
- this.sdk.logger.error(
819
+ logger.error(
782
820
  `${this.sdk.engineInstance.type} engine detected, use engine's builtin file access to read files.`
783
821
  );
784
822
  return null;
@@ -789,7 +827,7 @@ var FileSystemManager = class extends WavedashManager {
789
827
  const arrayBuffer = await blob.arrayBuffer();
790
828
  return new Uint8Array(arrayBuffer);
791
829
  } catch (error) {
792
- this.sdk.logger.error(`Failed to read local file: ${error}`);
830
+ logger.error(`Failed to read local file: ${error}`);
793
831
  return null;
794
832
  }
795
833
  }
@@ -798,9 +836,9 @@ var FileSystemManager = class extends WavedashManager {
798
836
  // ================
799
837
  // Helper to upload a local file to a presigned URL
800
838
  async upload(presignedUploadUrl, filePath) {
801
- this.sdk.logger.debug(`Uploading ${filePath} to: ${presignedUploadUrl}`);
839
+ logger.debug(`Uploading ${filePath} to: ${presignedUploadUrl}`);
802
840
  if (this.sdk.engineInstance && !this.sdk.engineInstance.FS) {
803
- this.sdk.logger.error("Engine instance is missing the Emscripten FS API");
841
+ logger.error("Engine instance is missing the Emscripten FS API");
804
842
  return false;
805
843
  }
806
844
  let success = false;
@@ -813,9 +851,9 @@ var FileSystemManager = class extends WavedashManager {
813
851
  }
814
852
  // Helper to download a file from a URL and save locally
815
853
  async download(url, filePath) {
816
- this.sdk.logger.debug(`Downloading ${filePath} from: ${url}`);
854
+ logger.debug(`Downloading ${filePath} from: ${url}`);
817
855
  if (this.sdk.engineInstance && !this.sdk.engineInstance.FS) {
818
- this.sdk.logger.error("Engine instance is missing the Emscripten FS API");
856
+ logger.error("Engine instance is missing the Emscripten FS API");
819
857
  return false;
820
858
  }
821
859
  const jwt = await this.sdk.ensureGameplayJwt();
@@ -826,7 +864,7 @@ var FileSystemManager = class extends WavedashManager {
826
864
  }
827
865
  });
828
866
  if (!response.ok) {
829
- this.sdk.logger.error(
867
+ logger.error(
830
868
  `Failed to download remote file: ${response.status} (${response.statusText})`
831
869
  );
832
870
  return false;
@@ -848,10 +886,10 @@ var FileSystemManager = class extends WavedashManager {
848
886
  const success = await this.writeLocalFile(filePath, dataArray);
849
887
  if (!success) return false;
850
888
  }
851
- this.sdk.logger.debug(`Successfully saved to: ${filePath}`);
889
+ logger.debug(`Successfully saved to: ${filePath}`);
852
890
  return true;
853
891
  } catch (error) {
854
- this.sdk.logger.error(
892
+ logger.error(
855
893
  `Failed to save file ${filePath}: ${error instanceof Error ? error.message : String(error)}`
856
894
  );
857
895
  return false;
@@ -888,7 +926,7 @@ var FileSystemManager = class extends WavedashManager {
888
926
  try {
889
927
  const blob = await this.readLocalFileBlob(indexedDBKey);
890
928
  if (!blob) {
891
- this.sdk.logger.error(`File not found in IndexedDB: ${indexedDBKey}`);
929
+ logger.error(`File not found in IndexedDB: ${indexedDBKey}`);
892
930
  return false;
893
931
  }
894
932
  const response = await fetch(presignedUploadUrl, {
@@ -898,7 +936,7 @@ var FileSystemManager = class extends WavedashManager {
898
936
  });
899
937
  return response.ok;
900
938
  } catch (error) {
901
- this.sdk.logger.error(`Error uploading from IndexedDB: ${error}`);
939
+ logger.error(`Error uploading from IndexedDB: ${error}`);
902
940
  return false;
903
941
  }
904
942
  }
@@ -920,14 +958,14 @@ var FileSystemManager = class extends WavedashManager {
920
958
  return response.ok;
921
959
  } catch (error) {
922
960
  const msg = error instanceof Error ? error.message : String(error);
923
- this.sdk.logger.error(`Error uploading from FS: ${msg}`);
961
+ logger.error(`Error uploading from FS: ${msg}`);
924
962
  return false;
925
963
  }
926
964
  }
927
965
  async readLocalFileBlob(filePath) {
928
- this.sdk.logger.debug(`Reading local file (blob): ${filePath}`);
966
+ logger.debug(`Reading local file (blob): ${filePath}`);
929
967
  if (this.sdk.engineInstance?.FS) {
930
- this.sdk.logger.error(
968
+ logger.error(
931
969
  `${this.sdk.engineInstance.type} engine detected, use engine's builtin file access to read files.`
932
970
  );
933
971
  return null;
@@ -937,7 +975,7 @@ var FileSystemManager = class extends WavedashManager {
937
975
  if (!record) return null;
938
976
  return toBlobFromIndexedDBValue(record);
939
977
  } catch (error) {
940
- this.sdk.logger.error(`Failed to read local file blob: ${error}`);
978
+ logger.error(`Failed to read local file blob: ${error}`);
941
979
  return null;
942
980
  }
943
981
  }
@@ -1265,7 +1303,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1265
1303
  return this.updateP2PConnection(members);
1266
1304
  }
1267
1305
  if (this.initializationInProgress && this.initializationLobbyId === lobbyId) {
1268
- this.sdk.logger.debug(
1306
+ logger.debug(
1269
1307
  "P2P initialization already in progress, waiting..."
1270
1308
  );
1271
1309
  await this.initializationInProgress;
@@ -1333,7 +1371,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1333
1371
  if (!this.currentConnection) {
1334
1372
  throw new Error("No existing P2P connection to update");
1335
1373
  }
1336
- this.sdk.logger.debug("Updating P2P connection with new member list");
1374
+ logger.debug("Updating P2P connection with new member list");
1337
1375
  const currentPeerUserIds = new Set(
1338
1376
  Object.keys(this.currentConnection.peers)
1339
1377
  );
@@ -1348,7 +1386,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1348
1386
  existingPeer.username = member.username;
1349
1387
  }
1350
1388
  } else {
1351
- this.sdk.logger.debug(
1389
+ logger.debug(
1352
1390
  `Adding new peer: ${member.username} (${member.id})`
1353
1391
  );
1354
1392
  this.currentConnection.peers[member.id] = {
@@ -1362,7 +1400,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1362
1400
  const currentUserId = this.sdk.getUserId();
1363
1401
  const connectionPromises = connectionsToCreate.map((userId) => {
1364
1402
  const shouldCreateChannels = currentUserId < userId;
1365
- this.sdk.logger.debug(
1403
+ logger.debug(
1366
1404
  `Creating connection to new peer ${userId}, shouldCreateChannels: ${shouldCreateChannels}`
1367
1405
  );
1368
1406
  return this.createPeerConnection(
@@ -1377,13 +1415,13 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1377
1415
  );
1378
1416
  if (peersToInitiate.length > 0) {
1379
1417
  const offerPromises = peersToInitiate.map((userId) => {
1380
- this.sdk.logger.debug(
1418
+ logger.debug(
1381
1419
  `Initiating offer to new peer ${userId} (lower userId rule)`
1382
1420
  );
1383
1421
  return this.createOfferToPeer(userId);
1384
1422
  });
1385
1423
  await Promise.all(offerPromises);
1386
- this.sdk.logger.debug(
1424
+ logger.debug(
1387
1425
  `Initiated ${offerPromises.length} offers to new peers`
1388
1426
  );
1389
1427
  }
@@ -1393,7 +1431,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1393
1431
  )) {
1394
1432
  if (!newPeerUserIds.has(userId)) {
1395
1433
  const peer = this.currentConnection.peers[userId];
1396
- this.sdk.logger.debug(`Peer left: ${peer.username} (${userId})`);
1434
+ logger.debug(`Peer left: ${peer.username} (${userId})`);
1397
1435
  const pc = this.peerConnections.get(userId);
1398
1436
  if (pc) {
1399
1437
  pc.close();
@@ -1415,7 +1453,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1415
1453
  this.subscribeToSignalingMessages(connection);
1416
1454
  if (this.signalingSubscriptionReady) {
1417
1455
  await this.signalingSubscriptionReady;
1418
- this.sdk.logger.debug("Signaling subscription confirmed ready");
1456
+ logger.debug("Signaling subscription confirmed ready");
1419
1457
  }
1420
1458
  await this.establishPeerConnections(connection);
1421
1459
  }
@@ -1461,7 +1499,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1461
1499
  await this.handleSignalingMessage(message, connection);
1462
1500
  this.processedSignalingMessages.add(message._id);
1463
1501
  } catch (error) {
1464
- this.sdk.logger.error("Error handling signaling message:", error);
1502
+ logger.error("Error handling signaling message:", error);
1465
1503
  }
1466
1504
  }
1467
1505
  if (newMessageIds.length > 0) {
@@ -1474,7 +1512,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1474
1512
  this.pendingProcessedMessageIds.delete(messageId);
1475
1513
  }
1476
1514
  } catch (error) {
1477
- this.sdk.logger.error(
1515
+ logger.error(
1478
1516
  "Failed to mark signaling messages as processed:",
1479
1517
  error
1480
1518
  );
@@ -1491,7 +1529,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1491
1529
  const remoteUserId = message.fromUserId;
1492
1530
  if (!this.peerConnections.has(remoteUserId)) {
1493
1531
  if (message.messageType === P2P_SIGNALING_MESSAGE_TYPE.OFFER) {
1494
- this.sdk.logger.debug(
1532
+ logger.debug(
1495
1533
  `Received offer from ${remoteUserId} before peer connection exists, creating on-demand`
1496
1534
  );
1497
1535
  if (!connection.peers[remoteUserId]) {
@@ -1508,13 +1546,13 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1508
1546
  // shouldCreateChannels = false, we'll receive them via ondatachannel
1509
1547
  );
1510
1548
  if (!success) {
1511
- this.sdk.logger.error(
1549
+ logger.error(
1512
1550
  `Failed to create on-demand peer connection for ${remoteUserId}`
1513
1551
  );
1514
1552
  return;
1515
1553
  }
1516
1554
  } else {
1517
- this.sdk.logger.warn(
1555
+ logger.warn(
1518
1556
  `No peer connection for user ${remoteUserId}, dropping ${message.messageType} message`
1519
1557
  );
1520
1558
  return;
@@ -1524,14 +1562,14 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1524
1562
  switch (message.messageType) {
1525
1563
  case P2P_SIGNALING_MESSAGE_TYPE.OFFER: {
1526
1564
  this.iceRestartInProgress.delete(remoteUserId);
1527
- this.sdk.logger.debug(`Processing offer from peer ${remoteUserId}:`);
1565
+ logger.debug(`Processing offer from peer ${remoteUserId}:`);
1528
1566
  await pc.setRemoteDescription(
1529
1567
  new RTCSessionDescription(message.data)
1530
1568
  );
1531
1569
  await this.flushPendingIceCandidates(remoteUserId, pc);
1532
1570
  const answer = await pc.createAnswer();
1533
1571
  await pc.setLocalDescription(answer);
1534
- this.sdk.logger.debug(
1572
+ logger.debug(
1535
1573
  ` Answer created, waiting for ondatachannel events...`
1536
1574
  );
1537
1575
  const answerData = {
@@ -1556,7 +1594,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1556
1594
  const pending = this.pendingIceCandidates.get(remoteUserId) || [];
1557
1595
  pending.push(iceData);
1558
1596
  this.pendingIceCandidates.set(remoteUserId, pending);
1559
- this.sdk.logger.debug(
1597
+ logger.debug(
1560
1598
  `Buffered ICE candidate for ${remoteUserId} (remote description not yet set, ${pending.length} buffered)`
1561
1599
  );
1562
1600
  } else {
@@ -1565,7 +1603,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1565
1603
  break;
1566
1604
  }
1567
1605
  default:
1568
- this.sdk.logger.warn(
1606
+ logger.warn(
1569
1607
  "Unknown signaling message type:",
1570
1608
  message.messageType
1571
1609
  );
@@ -1582,7 +1620,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1582
1620
  try {
1583
1621
  await pc.addIceCandidate(new RTCIceCandidate(candidate));
1584
1622
  } catch (error) {
1585
- this.sdk.logger.warn(
1623
+ logger.warn(
1586
1624
  `Failed to add buffered ICE candidate for ${remoteUserId}:`,
1587
1625
  error
1588
1626
  );
@@ -1592,13 +1630,13 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1592
1630
  }
1593
1631
  }
1594
1632
  async establishPeerConnections(connection) {
1595
- this.sdk.logger.debug("Establishing WebRTC connections to peers...");
1633
+ logger.debug("Establishing WebRTC connections to peers...");
1596
1634
  const currentUserId = this.sdk.getUserId();
1597
1635
  const connectionPromises = [];
1598
1636
  Object.entries(connection.peers).forEach(
1599
1637
  ([userId, peer]) => {
1600
1638
  const shouldCreateChannels = currentUserId < userId;
1601
- this.sdk.logger.debug(
1639
+ logger.debug(
1602
1640
  `Creating connection to peer ${userId} (${peer.username}), shouldCreateChannels: ${shouldCreateChannels}`
1603
1641
  );
1604
1642
  connectionPromises.push(
@@ -1610,17 +1648,17 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1610
1648
  const peersToInitiate = Object.keys(connection.peers).filter((userId) => currentUserId < userId);
1611
1649
  if (peersToInitiate.length > 0) {
1612
1650
  const offerPromises = peersToInitiate.map((userId) => {
1613
- this.sdk.logger.debug(
1651
+ logger.debug(
1614
1652
  `Initiating offer to peer ${userId} (lower userId rule)`
1615
1653
  );
1616
1654
  return this.createOfferToPeer(userId);
1617
1655
  });
1618
1656
  await Promise.all(offerPromises);
1619
- this.sdk.logger.debug(
1657
+ logger.debug(
1620
1658
  `Created ${connectionPromises.length} peer connections and initiated ${offerPromises.length} offers`
1621
1659
  );
1622
1660
  } else {
1623
- this.sdk.logger.debug(
1661
+ logger.debug(
1624
1662
  `Created ${connectionPromises.length} peer connections, no offers to initiate`
1625
1663
  );
1626
1664
  }
@@ -1632,11 +1670,11 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1632
1670
  }
1633
1671
  const reliableChannel = this.reliableChannels.get(remoteUserId);
1634
1672
  const unreliableChannel = this.unreliableChannels.get(remoteUserId);
1635
- this.sdk.logger.debug(`Creating offer to peer ${remoteUserId}:`);
1636
- this.sdk.logger.debug(
1673
+ logger.debug(`Creating offer to peer ${remoteUserId}:`);
1674
+ logger.debug(
1637
1675
  ` Reliable channel state: ${reliableChannel?.readyState || "none"}`
1638
1676
  );
1639
- this.sdk.logger.debug(
1677
+ logger.debug(
1640
1678
  ` Unreliable channel state: ${unreliableChannel?.readyState || "none"}`
1641
1679
  );
1642
1680
  const offer = await pc.createOffer();
@@ -1653,7 +1691,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1653
1691
  async createPeerConnection(remoteUserId, connection, shouldCreateChannels = false) {
1654
1692
  const iceServers = await this.getIceServers();
1655
1693
  if (!iceServers) {
1656
- this.sdk.logger.error(
1694
+ logger.error(
1657
1695
  `No ICE servers available for peer ${remoteUserId}`
1658
1696
  );
1659
1697
  this.sdk.gameEventManager.notifyGame(
@@ -1677,7 +1715,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1677
1715
  rtcpMuxPolicy: "require"
1678
1716
  });
1679
1717
  if (shouldCreateChannels) {
1680
- this.sdk.logger.debug(`Creating data channels for peer ${remoteUserId}`);
1718
+ logger.debug(`Creating data channels for peer ${remoteUserId}`);
1681
1719
  if (this.config.enableReliableChannel) {
1682
1720
  const reliableChannel = pc.createDataChannel("reliable", {
1683
1721
  ordered: true,
@@ -1705,17 +1743,17 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1705
1743
  );
1706
1744
  }
1707
1745
  } else {
1708
- this.sdk.logger.debug(
1746
+ logger.debug(
1709
1747
  `Will receive data channels from peer ${remoteUserId} via ondatachannel`
1710
1748
  );
1711
1749
  }
1712
1750
  pc.onicecandidate = (event) => {
1713
1751
  if (event.candidate) {
1714
1752
  const candidateType = event.candidate.candidate.includes("typ host") ? "host" : event.candidate.candidate.includes("typ srflx") ? "srflx (STUN)" : event.candidate.candidate.includes("typ relay") ? "relay (TURN)" : "unknown";
1715
- this.sdk.logger.debug(
1753
+ logger.debug(
1716
1754
  `Peer ${remoteUserId} gathered ICE candidate: ${candidateType}`
1717
1755
  );
1718
- this.sdk.logger.debug(` Candidate: ${event.candidate.candidate}`);
1756
+ logger.debug(` Candidate: ${event.candidate.candidate}`);
1719
1757
  const candidateData = {
1720
1758
  candidate: event.candidate.candidate,
1721
1759
  sdpMid: event.candidate.sdpMid,
@@ -1730,7 +1768,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1730
1768
  };
1731
1769
  pc.ondatachannel = (event) => {
1732
1770
  const channel = event.channel;
1733
- this.sdk.logger.debug(
1771
+ logger.debug(
1734
1772
  `Received ${channel.label} data channel from peer ${remoteUserId}`
1735
1773
  );
1736
1774
  if (channel.label === "reliable") {
@@ -1745,21 +1783,21 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1745
1783
  );
1746
1784
  };
1747
1785
  pc.onconnectionstatechange = () => {
1748
- this.sdk.logger.debug(
1786
+ logger.debug(
1749
1787
  `Peer ${remoteUserId} connection state: ${pc.connectionState}`
1750
1788
  );
1751
1789
  if (pc.connectionState === "connected") {
1752
- this.sdk.logger.debug(
1790
+ logger.debug(
1753
1791
  ` Peer ${remoteUserId} fully connected, expecting ondatachannel events now...`
1754
1792
  );
1755
1793
  }
1756
1794
  };
1757
1795
  pc.oniceconnectionstatechange = () => {
1758
- this.sdk.logger.debug(
1796
+ logger.debug(
1759
1797
  `Peer ${remoteUserId} ICE connection state: ${pc.iceConnectionState}`
1760
1798
  );
1761
1799
  if (pc.iceConnectionState === "connected") {
1762
- this.sdk.logger.debug(
1800
+ logger.debug(
1763
1801
  ` ICE connected to peer ${remoteUserId}, data channels should be available...`
1764
1802
  );
1765
1803
  this.iceRestartAttempts.delete(remoteUserId);
@@ -1777,7 +1815,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1777
1815
  }
1778
1816
  }
1779
1817
  } else if (pc.iceConnectionState === "failed") {
1780
- this.sdk.logger.debug(
1818
+ logger.debug(
1781
1819
  `ICE connection to peer ${remoteUserId} failed, will retry in 500ms...`
1782
1820
  );
1783
1821
  if (!this.reconnectingPeers.has(remoteUserId)) {
@@ -1795,20 +1833,20 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1795
1833
  }
1796
1834
  setTimeout(() => {
1797
1835
  if (pc.iceConnectionState === "failed") {
1798
- this.sdk.logger.warn(
1836
+ logger.warn(
1799
1837
  `ICE connection to peer ${remoteUserId} still failed after delay, attempting ICE restart...`
1800
1838
  );
1801
1839
  this.attemptIceRestart(remoteUserId, pc);
1802
1840
  }
1803
1841
  }, 500);
1804
1842
  } else if (pc.iceConnectionState === "disconnected") {
1805
- this.sdk.logger.debug(
1843
+ logger.debug(
1806
1844
  `ICE connection to peer ${remoteUserId} disconnected, may recover...`
1807
1845
  );
1808
1846
  }
1809
1847
  };
1810
1848
  pc.onicegatheringstatechange = () => {
1811
- this.sdk.logger.debug(
1849
+ logger.debug(
1812
1850
  `Peer ${remoteUserId} ICE gathering state: ${pc.iceGatheringState}`
1813
1851
  );
1814
1852
  };
@@ -1822,20 +1860,20 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1822
1860
  async attemptIceRestart(remoteUserId, pc) {
1823
1861
  const currentUserId = this.sdk.getUserId();
1824
1862
  if (currentUserId > remoteUserId) {
1825
- this.sdk.logger.debug(
1863
+ logger.debug(
1826
1864
  `Waiting for peer ${remoteUserId} to initiate ICE restart (they have lower userId)`
1827
1865
  );
1828
1866
  return;
1829
1867
  }
1830
1868
  if (this.iceRestartInProgress.has(remoteUserId)) {
1831
- this.sdk.logger.debug(
1869
+ logger.debug(
1832
1870
  `ICE restart already in progress for peer ${remoteUserId}, skipping`
1833
1871
  );
1834
1872
  return;
1835
1873
  }
1836
1874
  const attempts = this.iceRestartAttempts.get(remoteUserId) || 0;
1837
1875
  if (attempts >= this.MAX_ICE_RESTART_ATTEMPTS) {
1838
- this.sdk.logger.error(
1876
+ logger.error(
1839
1877
  `Max ICE restart attempts (${this.MAX_ICE_RESTART_ATTEMPTS}) reached for peer ${remoteUserId}, giving up`
1840
1878
  );
1841
1879
  this.reconnectingPeers.delete(remoteUserId);
@@ -1856,7 +1894,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1856
1894
  }
1857
1895
  this.iceRestartAttempts.set(remoteUserId, attempts + 1);
1858
1896
  this.iceRestartInProgress.add(remoteUserId);
1859
- this.sdk.logger.debug(
1897
+ logger.debug(
1860
1898
  `ICE restart attempt ${attempts + 1}/${this.MAX_ICE_RESTART_ATTEMPTS} for peer ${remoteUserId}`
1861
1899
  );
1862
1900
  try {
@@ -1871,9 +1909,9 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1871
1909
  type: P2P_SIGNALING_MESSAGE_TYPE.OFFER,
1872
1910
  data: offerData
1873
1911
  });
1874
- this.sdk.logger.debug(`ICE restart offer sent to peer ${remoteUserId}`);
1912
+ logger.debug(`ICE restart offer sent to peer ${remoteUserId}`);
1875
1913
  } catch (error) {
1876
- this.sdk.logger.error(
1914
+ logger.error(
1877
1915
  `Failed to initiate ICE restart for peer ${remoteUserId}:`,
1878
1916
  error
1879
1917
  );
@@ -1881,7 +1919,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1881
1919
  }
1882
1920
  setupDataChannelHandlers(channel, remoteUserId, type) {
1883
1921
  channel.onopen = () => {
1884
- this.sdk.logger.debug(
1922
+ logger.debug(
1885
1923
  `${type} data channel opened with peer ${remoteUserId}`
1886
1924
  );
1887
1925
  if (this.isPeerReady(remoteUserId) && !this.establishedPeers.has(remoteUserId)) {
@@ -1902,7 +1940,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1902
1940
  this.enqueueMessage(event.data, remoteUserId);
1903
1941
  };
1904
1942
  channel.onerror = (error) => {
1905
- this.sdk.logger.error(
1943
+ logger.error(
1906
1944
  `Data channel error with peer ${remoteUserId}:`,
1907
1945
  error
1908
1946
  );
@@ -1919,7 +1957,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1919
1957
  }
1920
1958
  };
1921
1959
  channel.onclose = () => {
1922
- this.sdk.logger.debug(
1960
+ logger.debug(
1923
1961
  `${type} data channel closed with peer ${remoteUserId}`
1924
1962
  );
1925
1963
  this.establishedPeers.delete(remoteUserId);
@@ -1943,42 +1981,42 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1943
1981
  this.ensureInitialized();
1944
1982
  try {
1945
1983
  if (!this.currentConnection) {
1946
- this.sdk.logger.error(
1984
+ logger.error(
1947
1985
  `P2P send called before P2P is initialized, dropping message.`
1948
1986
  );
1949
1987
  this.reportPacketDrop(appChannel, "SEND", "PEER_NOT_READY");
1950
1988
  return false;
1951
1989
  }
1952
1990
  if (!payload) {
1953
- this.sdk.logger.error(
1991
+ logger.error(
1954
1992
  `P2P send called with missing payload, dropping message.`
1955
1993
  );
1956
1994
  this.reportPacketDrop(appChannel, "SEND", "INVALID_PAYLOAD_SIZE");
1957
1995
  return false;
1958
1996
  }
1959
1997
  if (!Number.isInteger(appChannel) || appChannel < 0 || appChannel >= this.MAX_CHANNELS) {
1960
- this.sdk.logger.error(
1998
+ logger.error(
1961
1999
  `P2P appChannel must be an integer in [0, ${this.MAX_CHANNELS}), received ${appChannel}, dropping message.`
1962
2000
  );
1963
2001
  this.reportPacketDrop(-1, "SEND", "INVALID_CHANNEL");
1964
2002
  return false;
1965
2003
  }
1966
2004
  if (payloadSize <= 0) {
1967
- this.sdk.logger.error(
2005
+ logger.error(
1968
2006
  `P2P payloadSize must be greater than 0, received ${payloadSize}, dropping message.`
1969
2007
  );
1970
2008
  this.reportPacketDrop(appChannel, "SEND", "INVALID_PAYLOAD_SIZE");
1971
2009
  return false;
1972
2010
  }
1973
2011
  if (payloadSize > this.MAX_PAYLOAD_SIZE) {
1974
- this.sdk.logger.error(
2012
+ logger.error(
1975
2013
  `P2P payload too large: ${payloadSize} bytes exceeds max ${this.MAX_PAYLOAD_SIZE} bytes, dropping message.`
1976
2014
  );
1977
2015
  this.reportPacketDrop(appChannel, "SEND", "PAYLOAD_TOO_LARGE");
1978
2016
  return false;
1979
2017
  }
1980
2018
  if (payloadSize > payload.length) {
1981
- this.sdk.logger.error(
2019
+ logger.error(
1982
2020
  `payloadSize is greater than payload buffer length: ${payloadSize} > ${payload.length}, dropping message.`
1983
2021
  );
1984
2022
  this.reportPacketDrop(appChannel, "SEND", "INVALID_PAYLOAD_SIZE");
@@ -1993,7 +2031,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
1993
2031
  try {
1994
2032
  channel.send(messageData);
1995
2033
  } catch (error) {
1996
- this.sdk.logger.error(
2034
+ logger.error(
1997
2035
  `P2P broadcast to peer ${peerUserId} failed:`,
1998
2036
  error
1999
2037
  );
@@ -2002,7 +2040,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
2002
2040
  } else {
2003
2041
  const channel = channelMap.get(toUserId);
2004
2042
  if (!channel || channel.readyState !== "open") {
2005
- this.sdk.logger.error(
2043
+ logger.error(
2006
2044
  `P2P no open channel to peer ${toUserId}, dropping message.`
2007
2045
  );
2008
2046
  this.reportPacketDrop(appChannel, "SEND", "PEER_NOT_READY");
@@ -2011,7 +2049,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
2011
2049
  try {
2012
2050
  channel.send(messageData);
2013
2051
  } catch (error) {
2014
- this.sdk.logger.error(
2052
+ logger.error(
2015
2053
  `P2P send to peer ${toUserId} failed, dropping message:`,
2016
2054
  error
2017
2055
  );
@@ -2021,7 +2059,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
2021
2059
  }
2022
2060
  return true;
2023
2061
  } catch (error) {
2024
- this.sdk.logger.error(`Error sending P2P message:`, error);
2062
+ logger.error(`Error sending P2P message:`, error);
2025
2063
  return false;
2026
2064
  }
2027
2065
  }
@@ -2042,9 +2080,9 @@ var _P2PManager = class _P2PManager extends WavedashManager {
2042
2080
  data: message.data
2043
2081
  }
2044
2082
  );
2045
- this.sdk.logger.debug("Sent signaling message:", message.type);
2083
+ logger.debug("Sent signaling message:", message.type);
2046
2084
  } catch (error) {
2047
- this.sdk.logger.error("Failed to send signaling message:", error);
2085
+ logger.error("Failed to send signaling message:", error);
2048
2086
  throw error;
2049
2087
  }
2050
2088
  }
@@ -2130,7 +2168,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
2130
2168
  messageCount: 0,
2131
2169
  incomingDataView
2132
2170
  });
2133
- this.sdk.logger.debug(
2171
+ logger.debug(
2134
2172
  `Allocated P2P ring buffer for channel ${channel} (${(queueDataSize / 1024 / 1024).toFixed(1)}MB)`
2135
2173
  );
2136
2174
  }
@@ -2200,7 +2238,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
2200
2238
  enqueueMessage(wireData, fromUserId) {
2201
2239
  try {
2202
2240
  if (wireData.byteLength < this.WIRE_PAYLOAD_OFFSET) {
2203
- this.sdk.logger.warn("Binary message too short to extract channel");
2241
+ logger.warn("Binary message too short to extract channel");
2204
2242
  this.reportPacketDrop(-1, "RECEIVE", "MALFORMED");
2205
2243
  return;
2206
2244
  }
@@ -2208,7 +2246,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
2208
2246
  const channel = wireBytes[this.WIRE_CHANNEL_OFFSET];
2209
2247
  if (!this.channelQueues.has(channel)) {
2210
2248
  if (channel >= this.MAX_CHANNELS) {
2211
- this.sdk.logger.warn(
2249
+ logger.warn(
2212
2250
  `Channel ${channel} exceeds max channels (${this.MAX_CHANNELS}), dropping message`
2213
2251
  );
2214
2252
  this.reportPacketDrop(channel, "RECEIVE", "INVALID_CHANNEL");
@@ -2218,7 +2256,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
2218
2256
  }
2219
2257
  const queue = this.channelQueues.get(channel);
2220
2258
  if (queue.messageCount >= this.QUEUE_SIZE) {
2221
- this.sdk.logger.warn(
2259
+ logger.warn(
2222
2260
  `P2P message queue full for channel ${channel}, dropping message`
2223
2261
  );
2224
2262
  this.reportPacketDrop(channel, "RECEIVE", "QUEUE_FULL");
@@ -2228,7 +2266,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
2228
2266
  const storedSize = this.PAYLOAD_OFFSET + payloadLength;
2229
2267
  const maxMessageSize = this.MESSAGE_SIZE - this.MESSAGE_SLOT_HEADER_SIZE;
2230
2268
  if (storedSize > maxMessageSize) {
2231
- this.sdk.logger.warn(
2269
+ logger.warn(
2232
2270
  `Message too large for queue: ${storedSize} > ${maxMessageSize}, dropping message.`
2233
2271
  );
2234
2272
  this.reportPacketDrop(channel, "RECEIVE", "PAYLOAD_TOO_LARGE");
@@ -2268,7 +2306,7 @@ var _P2PManager = class _P2PManager extends WavedashManager {
2268
2306
  queue.writeIndex = (queue.writeIndex + 1) % this.QUEUE_SIZE;
2269
2307
  queue.messageCount++;
2270
2308
  } catch (error) {
2271
- this.sdk.logger.error(`Error enqueuing binary P2P message:`, error);
2309
+ logger.error(`Error enqueuing binary P2P message:`, error);
2272
2310
  }
2273
2311
  }
2274
2312
  // Returns the max payload size (what game engines should report as max packet size)
@@ -2486,7 +2524,7 @@ var StatsManager = class extends WavedashManager {
2486
2524
  );
2487
2525
  this.subscribe();
2488
2526
  this.requestStats().catch((error) => {
2489
- this.sdk.logger.error("Initial stats fetch failed:", error);
2527
+ logger.error("Initial stats fetch failed:", error);
2490
2528
  });
2491
2529
  }
2492
2530
  destroy() {
@@ -2509,7 +2547,7 @@ var StatsManager = class extends WavedashManager {
2509
2547
  this.knownStatIds = new Set(ids);
2510
2548
  },
2511
2549
  (error) => {
2512
- this.sdk.logger.error("Stat identifiers subscription error:", error);
2550
+ logger.error("Stat identifiers subscription error:", error);
2513
2551
  }
2514
2552
  ),
2515
2553
  this.sdk.convexClient.onUpdate(
@@ -2519,7 +2557,7 @@ var StatsManager = class extends WavedashManager {
2519
2557
  this.knownAchievementIds = new Set(ids);
2520
2558
  },
2521
2559
  (error) => {
2522
- this.sdk.logger.error(
2560
+ logger.error(
2523
2561
  "Achievement identifiers subscription error:",
2524
2562
  error
2525
2563
  );
@@ -2535,7 +2573,7 @@ var StatsManager = class extends WavedashManager {
2535
2573
  }
2536
2574
  },
2537
2575
  (error) => {
2538
- this.sdk.logger.error("Achievement subscription error:", error);
2576
+ logger.error("Achievement subscription error:", error);
2539
2577
  }
2540
2578
  )
2541
2579
  );
@@ -2586,7 +2624,7 @@ var StatsManager = class extends WavedashManager {
2586
2624
  });
2587
2625
  }).catch((error) => {
2588
2626
  const message = error instanceof Error ? error.message : `Error storing stats: ${error}`;
2589
- this.sdk.logger.error(message);
2627
+ logger.error(message);
2590
2628
  this.sdk.gameEventManager.notifyGame(WavedashEvents.STATS_STORED, {
2591
2629
  success: false,
2592
2630
  message
@@ -2750,7 +2788,7 @@ var HeartbeatManager = class extends WavedashManager {
2750
2788
  this.lastHeartbeatTime = Date.now();
2751
2789
  }
2752
2790
  }).catch((error) => {
2753
- this.sdk.logger.error(`Heartbeat failed: ${error}`);
2791
+ logger.error(`Heartbeat failed: ${error}`);
2754
2792
  }).finally(() => {
2755
2793
  this.heartbeatInFlight = false;
2756
2794
  });
@@ -2769,7 +2807,7 @@ var HeartbeatManager = class extends WavedashManager {
2769
2807
  });
2770
2808
  return true;
2771
2809
  } catch (error) {
2772
- this.sdk.logger.error(`Error updating presence: ${error}`);
2810
+ logger.error(`Error updating presence: ${error}`);
2773
2811
  return false;
2774
2812
  }
2775
2813
  }
@@ -2796,7 +2834,7 @@ var HeartbeatManager = class extends WavedashManager {
2796
2834
  );
2797
2835
  } else if (!this.isConnected && wasConnected) {
2798
2836
  this.disconnectedAt = Date.now();
2799
- this.sdk.logger.warn(
2837
+ logger.warn(
2800
2838
  "Backend disconnected - attempting to reconnect..."
2801
2839
  );
2802
2840
  this.sdk.gameEventManager.notifyGame(
@@ -2816,7 +2854,7 @@ var HeartbeatManager = class extends WavedashManager {
2816
2854
  this.sentDisconnectedEvent = false;
2817
2855
  }
2818
2856
  } catch (error) {
2819
- this.sdk.logger.error("Error testing connection:", error);
2857
+ logger.error("Error testing connection:", error);
2820
2858
  }
2821
2859
  }
2822
2860
  isCurrentlyConnected() {
@@ -2836,7 +2874,7 @@ var GameEventManager = class extends WavedashManager {
2836
2874
  notifyGame(event, payload) {
2837
2875
  if (!this.sdk.eventsReady) {
2838
2876
  this.eventQueue.push({ event, payload });
2839
- this.sdk.logger.debug(`Queued event: ${event}`);
2877
+ logger.debug(`Queued event: ${event}`);
2840
2878
  return;
2841
2879
  }
2842
2880
  if (!this.sdk.engineInstance) {
@@ -2854,7 +2892,7 @@ var GameEventManager = class extends WavedashManager {
2854
2892
  data
2855
2893
  );
2856
2894
  } else {
2857
- this.sdk.logger.error("Engine instance not set. Dropping event:", event);
2895
+ logger.error("Engine instance not set. Dropping event:", event);
2858
2896
  }
2859
2897
  }
2860
2898
  flushEventQueue() {
@@ -3097,43 +3135,6 @@ var FriendsManager = class extends WavedashManager {
3097
3135
  }
3098
3136
  };
3099
3137
 
3100
- // src/utils/logger.ts
3101
- var LOG_LEVEL = {
3102
- DEBUG: 0,
3103
- // Most verbose
3104
- INFO: 1,
3105
- WARN: 2,
3106
- ERROR: 3
3107
- };
3108
- var WavedashLogger = class {
3109
- constructor(logLevel = LOG_LEVEL.WARN) {
3110
- this.logLevel = logLevel;
3111
- }
3112
- setLogLevel(level) {
3113
- this.logLevel = level;
3114
- }
3115
- debug(message, ...args) {
3116
- if (this.logLevel <= LOG_LEVEL.DEBUG) {
3117
- console.log(`[WavedashJS] ${message}`, ...args);
3118
- }
3119
- }
3120
- info(message, ...args) {
3121
- if (this.logLevel <= LOG_LEVEL.INFO) {
3122
- console.log(`[WavedashJS] ${message}`, ...args);
3123
- }
3124
- }
3125
- warn(message, ...args) {
3126
- if (this.logLevel <= LOG_LEVEL.WARN) {
3127
- console.warn(`[WavedashJS] ${message}`, ...args);
3128
- }
3129
- }
3130
- error(message, ...args) {
3131
- if (this.logLevel <= LOG_LEVEL.ERROR) {
3132
- console.error(`[WavedashJS] ${message}`, ...args);
3133
- }
3134
- }
3135
- };
3136
-
3137
3138
  // src/utils/parentOrigin.ts
3138
3139
  var _parentOrigin = "";
3139
3140
  function setParentOrigin(origin) {
@@ -3228,6 +3229,69 @@ var IFrameMessenger = class {
3228
3229
  }
3229
3230
  };
3230
3231
 
3232
+ // src/utils/swMessenger.ts
3233
+ var SwMessenger = class {
3234
+ constructor() {
3235
+ this.handleMessage = (event) => {
3236
+ const data = event.data;
3237
+ const type = data?.type;
3238
+ if (!type) return;
3239
+ const set = this.listeners.get(type);
3240
+ if (!set || set.size === 0) return;
3241
+ const port = event.ports?.[0];
3242
+ const reply = (message) => {
3243
+ if (port) {
3244
+ try {
3245
+ port.postMessage(message);
3246
+ } catch (err) {
3247
+ logger.warn("Failed to reply to SW via port", err);
3248
+ }
3249
+ }
3250
+ this.postToServiceWorker(message);
3251
+ };
3252
+ for (const listener of set) listener(data?.payload, reply);
3253
+ };
3254
+ this.listeners = /* @__PURE__ */ new Map();
3255
+ if (typeof navigator !== "undefined" && navigator.serviceWorker) {
3256
+ navigator.serviceWorker.addEventListener("message", this.handleMessage);
3257
+ }
3258
+ }
3259
+ /**
3260
+ * Register a handler for an incoming message type from the SW. The handler
3261
+ * receives the message payload and a `reply` function that routes the
3262
+ * response back via the transferred MessagePort when present, falling back
3263
+ * to a controller postMessage otherwise.
3264
+ */
3265
+ addEventListener(type, listener) {
3266
+ let set = this.listeners.get(type);
3267
+ if (!set) {
3268
+ set = /* @__PURE__ */ new Set();
3269
+ this.listeners.set(type, set);
3270
+ }
3271
+ set.add(listener);
3272
+ }
3273
+ removeEventListener(type, listener) {
3274
+ this.listeners.get(type)?.delete(listener);
3275
+ }
3276
+ /**
3277
+ * Fire-and-forget message to the active service worker controller. No-op
3278
+ * when no SW is controlling the page (first load before activation, or
3279
+ * environments without SW support).
3280
+ */
3281
+ postToServiceWorker(message) {
3282
+ if (typeof navigator === "undefined" || !navigator.serviceWorker) {
3283
+ return false;
3284
+ }
3285
+ try {
3286
+ navigator.serviceWorker.controller?.postMessage(message);
3287
+ return true;
3288
+ } catch (err) {
3289
+ logger.warn("Failed to post message to service worker", err);
3290
+ return false;
3291
+ }
3292
+ }
3293
+ };
3294
+
3231
3295
  // src/index.ts
3232
3296
  import { IFRAME_MESSAGE_TYPE as IFRAME_MESSAGE_TYPE5, UrlParams } from "@wvdsh/api";
3233
3297
 
@@ -3378,7 +3442,7 @@ var WavedashSDK = class extends EventTarget {
3378
3442
  this.iframeMessenger = iframeMessenger;
3379
3443
  this.ugcHost = sdkConfig.ugcHost;
3380
3444
  this.uploadsHost = sdkConfig.uploadsHost;
3381
- this.logger = new WavedashLogger();
3445
+ this.swMessenger = new SwMessenger();
3382
3446
  this.p2pManager = new P2PManager(this);
3383
3447
  this.lobbyManager = new LobbyManager(this);
3384
3448
  this.statsManager = new StatsManager(this);
@@ -3411,10 +3475,11 @@ var WavedashSDK = class extends EventTarget {
3411
3475
  }
3412
3476
  ]);
3413
3477
  this.setupSessionEndListeners();
3478
+ this.setupSwCredsListener();
3414
3479
  this.launchParams = sdkConfig.launchParams ?? {};
3415
3480
  this.setupWarningTimeout = setTimeout(() => {
3416
3481
  this.setupWarningTimeout = null;
3417
- this.logger.warn(
3482
+ logger.warn(
3418
3483
  "Wavedash.init(), Wavedash.loadComplete(), or Wavedash.updateLoadProgressZeroToOne() not called yet"
3419
3484
  );
3420
3485
  }, 1e4);
@@ -3437,24 +3502,24 @@ var WavedashSDK = class extends EventTarget {
3437
3502
  init(config) {
3438
3503
  this.loadComplete();
3439
3504
  if (this._initialized) {
3440
- this.logger.warn("init called twice! Already initialized, skipping init");
3505
+ logger.warn("init called twice! Already initialized, skipping init");
3441
3506
  return false;
3442
3507
  }
3443
3508
  if (typeof config === "string") {
3444
3509
  try {
3445
3510
  config = JSON.parse(config);
3446
3511
  } catch (error) {
3447
- this.logger.error("Initialized with invalid config:", error);
3512
+ logger.error("Initialized with invalid config:", error);
3448
3513
  return false;
3449
3514
  }
3450
3515
  }
3451
3516
  this.config = config ?? {};
3452
3517
  this._initialized = true;
3453
- this.logger.setLogLevel(
3518
+ logger.setLogLevel(
3454
3519
  this.config.debug ? LOG_LEVEL.DEBUG : LOG_LEVEL.WARN
3455
3520
  );
3456
3521
  this.p2pManager.init(this.config.p2p);
3457
- this.logger.debug("Initialized with config:", this.config);
3522
+ logger.debug("Initialized with config:", this.config);
3458
3523
  if (!this.config.deferEvents) {
3459
3524
  this.readyForEvents();
3460
3525
  }
@@ -3601,13 +3666,13 @@ var WavedashSDK = class extends EventTarget {
3601
3666
  * @returns The user's JWT signed by the Wavedash backend
3602
3667
  */
3603
3668
  async getUserJwt() {
3604
- this.logger.debug("getUserJwt");
3669
+ logger.debug("getUserJwt");
3605
3670
  try {
3606
3671
  const data = await this.ensureGameplayJwt();
3607
3672
  return this.formatResponse({ success: true, data });
3608
3673
  } catch (error) {
3609
3674
  const message = error instanceof Error ? error.message : String(error);
3610
- this.logger.error("getUserJwt", message);
3675
+ logger.error("getUserJwt", message);
3611
3676
  return this.formatResponse({ success: false, data: null, message });
3612
3677
  }
3613
3678
  }
@@ -4251,29 +4316,29 @@ var WavedashSDK = class extends EventTarget {
4251
4316
  // require config or produce events (lobby join/create, P2P).
4252
4317
  ensureInit() {
4253
4318
  if (!this._initialized) {
4254
- this.logger.error("SDK not initialized. Call WavedashJS.init first.");
4319
+ logger.error("SDK not initialized. Call WavedashJS.init first.");
4255
4320
  throw new Error("SDK not initialized");
4256
4321
  }
4257
4322
  }
4258
4323
  async apiCall(manager, method, argSpecs, ...args) {
4259
- this.logger.debug(method, ...args);
4324
+ logger.debug(method, ...args);
4260
4325
  try {
4261
4326
  validateArgs(method, argSpecs, args);
4262
4327
  const data = await manager[method](...args);
4263
4328
  return this.formatResponse({ success: true, data });
4264
4329
  } catch (error) {
4265
4330
  const message = error instanceof Error ? error.message : String(error);
4266
- this.logger.error(method, message);
4331
+ logger.error(method, message);
4267
4332
  return this.formatResponse({ success: false, data: null, message });
4268
4333
  }
4269
4334
  }
4270
4335
  apiCallSync(target, method, argSpecs, ...args) {
4271
- this.logger.debug(method, ...args);
4336
+ logger.debug(method, ...args);
4272
4337
  try {
4273
4338
  validateArgs(method, argSpecs, args);
4274
4339
  } catch (error) {
4275
4340
  const message = error instanceof Error ? error.message : String(error);
4276
- this.logger.error(method, message);
4341
+ logger.error(method, message);
4277
4342
  throw error;
4278
4343
  }
4279
4344
  return this.formatResponse(target[method](...args));
@@ -4324,6 +4389,10 @@ var WavedashSDK = class extends EventTarget {
4324
4389
  iframeMessenger.postToParent(IFRAME_MESSAGE_TYPE5.GAMEPLAY_JWT_READY, {
4325
4390
  gameplayJwt: this.gameplayJwt
4326
4391
  });
4392
+ this.swMessenger.postToServiceWorker({
4393
+ type: "embed.jwt-update",
4394
+ payload: { gameplayJwt: this.gameplayJwt }
4395
+ });
4327
4396
  return this.gameplayJwt;
4328
4397
  })().finally(() => {
4329
4398
  if (this.gameplayJwtPromise === promise) {
@@ -4357,6 +4426,30 @@ var WavedashSDK = class extends EventTarget {
4357
4426
  () => this.destroy()
4358
4427
  );
4359
4428
  }
4429
+ /**
4430
+ * Respond to the service worker's `embed.creds-request` with the SDK's
4431
+ * current gameplay JWT. The SW asks when it wakes from termination with no
4432
+ * in-memory or IDB credentials (e.g. Safari ITP storage decay) — we're the
4433
+ * fastest live source. JWT only; sessionToken is owned by the SW + cookies.
4434
+ */
4435
+ setupSwCredsListener() {
4436
+ this.swMessenger.addEventListener(
4437
+ "embed.creds-request",
4438
+ async (_payload, reply) => {
4439
+ let jwt;
4440
+ try {
4441
+ jwt = await this.ensureGameplayJwt();
4442
+ } catch (err) {
4443
+ logger.warn("Failed to resolve JWT for creds-request", err);
4444
+ return;
4445
+ }
4446
+ reply({
4447
+ type: "embed.creds-response",
4448
+ payload: { gameplayJwt: jwt }
4449
+ });
4450
+ }
4451
+ );
4452
+ }
4360
4453
  };
4361
4454
  function setupWavedashSDK() {
4362
4455
  const existing = window.Wavedash;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wvdsh/sdk-js",
3
- "version": "1.3.8",
3
+ "version": "1.3.10",
4
4
  "type": "module",
5
5
  "description": "Wavedash JavaScript SDK",
6
6
  "main": "./dist/client.js",
@@ -50,7 +50,7 @@
50
50
  },
51
51
  "dependencies": {
52
52
  "@wvdsh/api": "^0.1.16",
53
- "convex": "^1.34.0",
53
+ "convex": "^1.38.0",
54
54
  "lodash.throttle": "^4.1.1"
55
55
  }
56
56
  }