@playcademy/sdk 0.1.14 → 0.1.16

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.js CHANGED
@@ -281,6 +281,333 @@ function isInIframe() {
281
281
  }
282
282
  }
283
283
 
284
+ // src/core/connection/monitor.ts
285
+ class ConnectionMonitor {
286
+ state = "online";
287
+ callbacks = new Set;
288
+ heartbeatInterval;
289
+ consecutiveFailures = 0;
290
+ isMonitoring = false;
291
+ config;
292
+ constructor(config) {
293
+ this.config = {
294
+ baseUrl: config.baseUrl,
295
+ heartbeatInterval: config.heartbeatInterval ?? 1e4,
296
+ heartbeatTimeout: config.heartbeatTimeout ?? 5000,
297
+ failureThreshold: config.failureThreshold ?? 2,
298
+ enableHeartbeat: config.enableHeartbeat ?? true,
299
+ enableOfflineEvents: config.enableOfflineEvents ?? true
300
+ };
301
+ this._detectInitialState();
302
+ }
303
+ start() {
304
+ if (this.isMonitoring)
305
+ return;
306
+ this.isMonitoring = true;
307
+ if (this.config.enableOfflineEvents && typeof window !== "undefined") {
308
+ window.addEventListener("online", this._handleOnline);
309
+ window.addEventListener("offline", this._handleOffline);
310
+ }
311
+ if (this.config.enableHeartbeat) {
312
+ this._startHeartbeat();
313
+ }
314
+ }
315
+ stop() {
316
+ if (!this.isMonitoring)
317
+ return;
318
+ this.isMonitoring = false;
319
+ if (typeof window !== "undefined") {
320
+ window.removeEventListener("online", this._handleOnline);
321
+ window.removeEventListener("offline", this._handleOffline);
322
+ }
323
+ if (this.heartbeatInterval) {
324
+ clearInterval(this.heartbeatInterval);
325
+ this.heartbeatInterval = undefined;
326
+ }
327
+ }
328
+ onChange(callback) {
329
+ this.callbacks.add(callback);
330
+ return () => this.callbacks.delete(callback);
331
+ }
332
+ getState() {
333
+ return this.state;
334
+ }
335
+ async checkNow() {
336
+ await this._performHeartbeat();
337
+ return this.state;
338
+ }
339
+ reportRequestFailure(error) {
340
+ const isNetworkError = error instanceof TypeError || error instanceof Error && error.message.includes("fetch");
341
+ if (!isNetworkError)
342
+ return;
343
+ this.consecutiveFailures++;
344
+ if (this.consecutiveFailures >= this.config.failureThreshold) {
345
+ this._setState("degraded", "Multiple consecutive request failures");
346
+ }
347
+ }
348
+ reportRequestSuccess() {
349
+ if (this.consecutiveFailures > 0) {
350
+ this.consecutiveFailures = 0;
351
+ if (this.state === "degraded") {
352
+ this._setState("online", "Requests succeeding again");
353
+ }
354
+ }
355
+ }
356
+ _detectInitialState() {
357
+ if (typeof navigator !== "undefined" && !navigator.onLine) {
358
+ this.state = "offline";
359
+ }
360
+ }
361
+ _handleOnline = () => {
362
+ this.consecutiveFailures = 0;
363
+ this._setState("online", "Browser online event");
364
+ };
365
+ _handleOffline = () => {
366
+ this._setState("offline", "Browser offline event");
367
+ };
368
+ _startHeartbeat() {
369
+ this._performHeartbeat();
370
+ this.heartbeatInterval = setInterval(() => {
371
+ this._performHeartbeat();
372
+ }, this.config.heartbeatInterval);
373
+ }
374
+ async _performHeartbeat() {
375
+ if (typeof navigator !== "undefined" && !navigator.onLine) {
376
+ return;
377
+ }
378
+ try {
379
+ const controller = new AbortController;
380
+ const timeoutId = setTimeout(() => controller.abort(), this.config.heartbeatTimeout);
381
+ const response = await fetch(`${this.config.baseUrl}/ping`, {
382
+ method: "GET",
383
+ signal: controller.signal,
384
+ cache: "no-store"
385
+ });
386
+ clearTimeout(timeoutId);
387
+ if (response.ok) {
388
+ this.consecutiveFailures = 0;
389
+ if (this.state !== "online") {
390
+ this._setState("online", "Heartbeat successful");
391
+ }
392
+ } else {
393
+ this._handleHeartbeatFailure("Heartbeat returned non-OK status");
394
+ }
395
+ } catch (error) {
396
+ this._handleHeartbeatFailure(error instanceof Error ? error.message : "Heartbeat failed");
397
+ }
398
+ }
399
+ _handleHeartbeatFailure(reason) {
400
+ this.consecutiveFailures++;
401
+ if (this.consecutiveFailures >= this.config.failureThreshold) {
402
+ if (typeof navigator !== "undefined" && !navigator.onLine) {
403
+ this._setState("offline", reason);
404
+ } else {
405
+ this._setState("degraded", reason);
406
+ }
407
+ }
408
+ }
409
+ _setState(newState, reason) {
410
+ if (this.state === newState)
411
+ return;
412
+ const oldState = this.state;
413
+ this.state = newState;
414
+ console.debug(`[ConnectionMonitor] ${oldState} → ${newState}: ${reason}`);
415
+ this.callbacks.forEach((callback) => {
416
+ try {
417
+ callback(newState, reason);
418
+ } catch (error) {
419
+ console.error("[ConnectionMonitor] Error in callback:", error);
420
+ }
421
+ });
422
+ }
423
+ }
424
+
425
+ // src/messaging.ts
426
+ class PlaycademyMessaging {
427
+ listeners = new Map;
428
+ send(type, payload, options) {
429
+ if (options?.target) {
430
+ this.sendViaPostMessage(type, payload, options.target, options.origin || "*");
431
+ return;
432
+ }
433
+ const context = this.getMessagingContext(type);
434
+ if (context.shouldUsePostMessage) {
435
+ this.sendViaPostMessage(type, payload, context.target, context.origin);
436
+ } else {
437
+ this.sendViaCustomEvent(type, payload);
438
+ }
439
+ }
440
+ listen(type, handler) {
441
+ const postMessageListener = (event) => {
442
+ const messageEvent = event;
443
+ if (messageEvent.data?.type === type) {
444
+ handler(messageEvent.data.payload || messageEvent.data);
445
+ }
446
+ };
447
+ const customEventListener = (event) => {
448
+ handler(event.detail);
449
+ };
450
+ if (!this.listeners.has(type)) {
451
+ this.listeners.set(type, new Map);
452
+ }
453
+ const listenerMap = this.listeners.get(type);
454
+ listenerMap.set(handler, {
455
+ postMessage: postMessageListener,
456
+ customEvent: customEventListener
457
+ });
458
+ window.addEventListener("message", postMessageListener);
459
+ window.addEventListener(type, customEventListener);
460
+ }
461
+ unlisten(type, handler) {
462
+ const typeListeners = this.listeners.get(type);
463
+ if (!typeListeners || !typeListeners.has(handler)) {
464
+ return;
465
+ }
466
+ const listeners = typeListeners.get(handler);
467
+ window.removeEventListener("message", listeners.postMessage);
468
+ window.removeEventListener(type, listeners.customEvent);
469
+ typeListeners.delete(handler);
470
+ if (typeListeners.size === 0) {
471
+ this.listeners.delete(type);
472
+ }
473
+ }
474
+ getMessagingContext(eventType) {
475
+ const isIframe = typeof window !== "undefined" && window.self !== window.top;
476
+ const iframeToParentEvents = [
477
+ "PLAYCADEMY_READY" /* READY */,
478
+ "PLAYCADEMY_EXIT" /* EXIT */,
479
+ "PLAYCADEMY_TELEMETRY" /* TELEMETRY */,
480
+ "PLAYCADEMY_KEY_EVENT" /* KEY_EVENT */,
481
+ "PLAYCADEMY_DISPLAY_ALERT" /* DISPLAY_ALERT */
482
+ ];
483
+ const shouldUsePostMessage = isIframe && iframeToParentEvents.includes(eventType);
484
+ return {
485
+ shouldUsePostMessage,
486
+ target: shouldUsePostMessage ? window.parent : undefined,
487
+ origin: "*"
488
+ };
489
+ }
490
+ sendViaPostMessage(type, payload, target = window.parent, origin = "*") {
491
+ const messageData = { type };
492
+ if (payload !== undefined) {
493
+ messageData.payload = payload;
494
+ }
495
+ target.postMessage(messageData, origin);
496
+ }
497
+ sendViaCustomEvent(type, payload) {
498
+ window.dispatchEvent(new CustomEvent(type, { detail: payload }));
499
+ }
500
+ }
501
+ var MessageEvents, messaging;
502
+ var init_messaging = __esm(() => {
503
+ ((MessageEvents2) => {
504
+ MessageEvents2["INIT"] = "PLAYCADEMY_INIT";
505
+ MessageEvents2["TOKEN_REFRESH"] = "PLAYCADEMY_TOKEN_REFRESH";
506
+ MessageEvents2["PAUSE"] = "PLAYCADEMY_PAUSE";
507
+ MessageEvents2["RESUME"] = "PLAYCADEMY_RESUME";
508
+ MessageEvents2["FORCE_EXIT"] = "PLAYCADEMY_FORCE_EXIT";
509
+ MessageEvents2["OVERLAY"] = "PLAYCADEMY_OVERLAY";
510
+ MessageEvents2["CONNECTION_STATE"] = "PLAYCADEMY_CONNECTION_STATE";
511
+ MessageEvents2["READY"] = "PLAYCADEMY_READY";
512
+ MessageEvents2["EXIT"] = "PLAYCADEMY_EXIT";
513
+ MessageEvents2["TELEMETRY"] = "PLAYCADEMY_TELEMETRY";
514
+ MessageEvents2["KEY_EVENT"] = "PLAYCADEMY_KEY_EVENT";
515
+ MessageEvents2["DISPLAY_ALERT"] = "PLAYCADEMY_DISPLAY_ALERT";
516
+ MessageEvents2["AUTH_STATE_CHANGE"] = "PLAYCADEMY_AUTH_STATE_CHANGE";
517
+ MessageEvents2["AUTH_CALLBACK"] = "PLAYCADEMY_AUTH_CALLBACK";
518
+ })(MessageEvents ||= {});
519
+ messaging = new PlaycademyMessaging;
520
+ });
521
+
522
+ // src/core/connection/utils.ts
523
+ function createDisplayAlert(authContext) {
524
+ return (message, options) => {
525
+ if (authContext?.isInIframe && typeof window !== "undefined" && window.parent !== window) {
526
+ window.parent.postMessage({
527
+ type: "PLAYCADEMY_DISPLAY_ALERT",
528
+ message,
529
+ options
530
+ }, "*");
531
+ } else {
532
+ const prefix = options?.type === "error" ? "❌" : options?.type === "warning" ? "⚠️" : "ℹ️";
533
+ console.log(`${prefix} ${message}`);
534
+ }
535
+ };
536
+ }
537
+
538
+ // src/core/connection/manager.ts
539
+ class ConnectionManager {
540
+ monitor;
541
+ authContext;
542
+ disconnectHandler;
543
+ connectionChangeCallback;
544
+ currentState = "online";
545
+ additionalDisconnectHandlers = new Set;
546
+ constructor(config) {
547
+ this.authContext = config.authContext;
548
+ this.disconnectHandler = config.onDisconnect;
549
+ this.connectionChangeCallback = config.onConnectionChange;
550
+ if (config.authContext?.isInIframe) {
551
+ this._setupPlatformListener();
552
+ }
553
+ }
554
+ getState() {
555
+ return this.monitor?.getState() ?? this.currentState;
556
+ }
557
+ async checkNow() {
558
+ if (!this.monitor) {
559
+ return this.currentState;
560
+ }
561
+ return await this.monitor.checkNow();
562
+ }
563
+ reportRequestSuccess() {
564
+ this.monitor?.reportRequestSuccess();
565
+ }
566
+ reportRequestFailure(error) {
567
+ this.monitor?.reportRequestFailure(error);
568
+ }
569
+ onDisconnect(callback) {
570
+ this.additionalDisconnectHandlers.add(callback);
571
+ return () => {
572
+ this.additionalDisconnectHandlers.delete(callback);
573
+ };
574
+ }
575
+ stop() {
576
+ this.monitor?.stop();
577
+ }
578
+ _setupPlatformListener() {
579
+ messaging.listen("PLAYCADEMY_CONNECTION_STATE" /* CONNECTION_STATE */, ({ state, reason }) => {
580
+ this.currentState = state;
581
+ this._handleConnectionChange(state, reason);
582
+ });
583
+ }
584
+ _handleConnectionChange(state, reason) {
585
+ this.connectionChangeCallback?.(state, reason);
586
+ if (state === "offline" || state === "degraded") {
587
+ const context = {
588
+ state,
589
+ reason,
590
+ timestamp: Date.now(),
591
+ displayAlert: createDisplayAlert(this.authContext)
592
+ };
593
+ if (this.disconnectHandler) {
594
+ this.disconnectHandler(context);
595
+ }
596
+ this.additionalDisconnectHandlers.forEach((handler) => {
597
+ handler(context);
598
+ });
599
+ }
600
+ }
601
+ }
602
+ var init_manager = __esm(() => {
603
+ init_messaging();
604
+ });
605
+
606
+ // src/core/connection/index.ts
607
+ var init_connection = __esm(() => {
608
+ init_manager();
609
+ });
610
+
284
611
  // src/core/errors.ts
285
612
  function extractApiErrorInfo(error) {
286
613
  if (!(error instanceof ApiError)) {
@@ -664,100 +991,6 @@ var init_identity = __esm(() => {
664
991
  init_login();
665
992
  });
666
993
 
667
- // src/messaging.ts
668
- class PlaycademyMessaging {
669
- listeners = new Map;
670
- send(type, payload, options) {
671
- if (options?.target) {
672
- this.sendViaPostMessage(type, payload, options.target, options.origin || "*");
673
- return;
674
- }
675
- const context = this.getMessagingContext(type);
676
- if (context.shouldUsePostMessage) {
677
- this.sendViaPostMessage(type, payload, context.target, context.origin);
678
- } else {
679
- this.sendViaCustomEvent(type, payload);
680
- }
681
- }
682
- listen(type, handler) {
683
- const postMessageListener = (event) => {
684
- const messageEvent = event;
685
- if (messageEvent.data?.type === type) {
686
- handler(messageEvent.data.payload || messageEvent.data);
687
- }
688
- };
689
- const customEventListener = (event) => {
690
- handler(event.detail);
691
- };
692
- if (!this.listeners.has(type)) {
693
- this.listeners.set(type, new Map);
694
- }
695
- const listenerMap = this.listeners.get(type);
696
- listenerMap.set(handler, {
697
- postMessage: postMessageListener,
698
- customEvent: customEventListener
699
- });
700
- window.addEventListener("message", postMessageListener);
701
- window.addEventListener(type, customEventListener);
702
- }
703
- unlisten(type, handler) {
704
- const typeListeners = this.listeners.get(type);
705
- if (!typeListeners || !typeListeners.has(handler)) {
706
- return;
707
- }
708
- const listeners = typeListeners.get(handler);
709
- window.removeEventListener("message", listeners.postMessage);
710
- window.removeEventListener(type, listeners.customEvent);
711
- typeListeners.delete(handler);
712
- if (typeListeners.size === 0) {
713
- this.listeners.delete(type);
714
- }
715
- }
716
- getMessagingContext(eventType) {
717
- const isIframe = typeof window !== "undefined" && window.self !== window.top;
718
- const iframeToParentEvents = [
719
- "PLAYCADEMY_READY" /* READY */,
720
- "PLAYCADEMY_EXIT" /* EXIT */,
721
- "PLAYCADEMY_TELEMETRY" /* TELEMETRY */,
722
- "PLAYCADEMY_KEY_EVENT" /* KEY_EVENT */
723
- ];
724
- const shouldUsePostMessage = isIframe && iframeToParentEvents.includes(eventType);
725
- return {
726
- shouldUsePostMessage,
727
- target: shouldUsePostMessage ? window.parent : undefined,
728
- origin: "*"
729
- };
730
- }
731
- sendViaPostMessage(type, payload, target = window.parent, origin = "*") {
732
- const messageData = { type };
733
- if (payload !== undefined) {
734
- messageData.payload = payload;
735
- }
736
- target.postMessage(messageData, origin);
737
- }
738
- sendViaCustomEvent(type, payload) {
739
- window.dispatchEvent(new CustomEvent(type, { detail: payload }));
740
- }
741
- }
742
- var MessageEvents, messaging;
743
- var init_messaging = __esm(() => {
744
- ((MessageEvents2) => {
745
- MessageEvents2["INIT"] = "PLAYCADEMY_INIT";
746
- MessageEvents2["TOKEN_REFRESH"] = "PLAYCADEMY_TOKEN_REFRESH";
747
- MessageEvents2["PAUSE"] = "PLAYCADEMY_PAUSE";
748
- MessageEvents2["RESUME"] = "PLAYCADEMY_RESUME";
749
- MessageEvents2["FORCE_EXIT"] = "PLAYCADEMY_FORCE_EXIT";
750
- MessageEvents2["OVERLAY"] = "PLAYCADEMY_OVERLAY";
751
- MessageEvents2["READY"] = "PLAYCADEMY_READY";
752
- MessageEvents2["EXIT"] = "PLAYCADEMY_EXIT";
753
- MessageEvents2["TELEMETRY"] = "PLAYCADEMY_TELEMETRY";
754
- MessageEvents2["KEY_EVENT"] = "PLAYCADEMY_KEY_EVENT";
755
- MessageEvents2["AUTH_STATE_CHANGE"] = "PLAYCADEMY_AUTH_STATE_CHANGE";
756
- MessageEvents2["AUTH_CALLBACK"] = "PLAYCADEMY_AUTH_CALLBACK";
757
- })(MessageEvents ||= {});
758
- messaging = new PlaycademyMessaging;
759
- });
760
-
761
994
  // src/core/namespaces/runtime.ts
762
995
  function createRuntimeNamespace(client) {
763
996
  const eventListeners = new Map;
@@ -866,7 +1099,7 @@ function createRuntimeNamespace(client) {
866
1099
  }
867
1100
  return counts;
868
1101
  },
869
- cdn: {
1102
+ assets: {
870
1103
  url(pathOrStrings, ...values) {
871
1104
  const gameUrl = client["initPayload"]?.gameUrl;
872
1105
  let path;
@@ -894,19 +1127,19 @@ function createRuntimeNamespace(client) {
894
1127
  return fetch(gameUrl + cleanPath, options);
895
1128
  },
896
1129
  json: async (path) => {
897
- const response = await client.runtime.cdn.fetch(path);
1130
+ const response = await client.runtime.assets.fetch(path);
898
1131
  return response.json();
899
1132
  },
900
1133
  blob: async (path) => {
901
- const response = await client.runtime.cdn.fetch(path);
1134
+ const response = await client.runtime.assets.fetch(path);
902
1135
  return response.blob();
903
1136
  },
904
1137
  text: async (path) => {
905
- const response = await client.runtime.cdn.fetch(path);
1138
+ const response = await client.runtime.assets.fetch(path);
906
1139
  return response.text();
907
1140
  },
908
1141
  arrayBuffer: async (path) => {
909
- const response = await client.runtime.cdn.fetch(path);
1142
+ const response = await client.runtime.assets.fetch(path);
910
1143
  return response.arrayBuffer();
911
1144
  }
912
1145
  }
@@ -2593,7 +2826,7 @@ async function waitForPlaycademyInit(allowedParentOrigins) {
2593
2826
  });
2594
2827
  }
2595
2828
  function createStandaloneConfig() {
2596
- console.warn("[Playcademy SDK] Standalone mode detected, creating mock context for local development");
2829
+ console.debug("[Playcademy SDK] Standalone mode detected, creating mock context for sandbox development");
2597
2830
  const mockConfig = {
2598
2831
  baseUrl: "http://localhost:4321",
2599
2832
  gameUrl: window.location.origin,
@@ -2618,7 +2851,9 @@ async function init(options) {
2618
2851
  gameUrl: config.gameUrl,
2619
2852
  token: config.token,
2620
2853
  gameId: config.gameId,
2621
- autoStartSession: window.self !== window.top
2854
+ autoStartSession: window.self !== window.top,
2855
+ onDisconnect: options?.onDisconnect,
2856
+ enableConnectionMonitoring: options?.enableConnectionMonitoring
2622
2857
  });
2623
2858
  client["initPayload"] = config;
2624
2859
  messaging.listen("PLAYCADEMY_TOKEN_REFRESH" /* TOKEN_REFRESH */, ({ token }) => client.setToken(token));
@@ -2687,6 +2922,7 @@ __export(exports_client, {
2687
2922
  var PlaycademyClient;
2688
2923
  var init_client = __esm(() => {
2689
2924
  init_src();
2925
+ init_connection();
2690
2926
  init_errors();
2691
2927
  init_namespaces();
2692
2928
  init_request();
@@ -2701,6 +2937,7 @@ var init_client = __esm(() => {
2701
2937
  internalClientSessionId;
2702
2938
  authContext;
2703
2939
  initPayload;
2940
+ connectionManager;
2704
2941
  constructor(config) {
2705
2942
  this.baseUrl = config?.baseUrl?.endsWith("/api") ? config.baseUrl : `${config?.baseUrl}/api`;
2706
2943
  this.gameUrl = config?.gameUrl;
@@ -2709,6 +2946,7 @@ var init_client = __esm(() => {
2709
2946
  this.authStrategy = createAuthStrategy(config?.token ?? null, config?.tokenType);
2710
2947
  this._detectAuthContext();
2711
2948
  this._initializeInternalSession().catch(() => {});
2949
+ this._initializeConnectionMonitor();
2712
2950
  }
2713
2951
  getBaseUrl() {
2714
2952
  const isRelative = this.baseUrl.startsWith("/");
@@ -2743,6 +2981,20 @@ var init_client = __esm(() => {
2743
2981
  onAuthChange(callback) {
2744
2982
  this.on("authChange", (payload) => callback(payload.token));
2745
2983
  }
2984
+ onDisconnect(callback) {
2985
+ if (!this.connectionManager) {
2986
+ return () => {};
2987
+ }
2988
+ return this.connectionManager.onDisconnect(callback);
2989
+ }
2990
+ getConnectionState() {
2991
+ return this.connectionManager?.getState() ?? "unknown";
2992
+ }
2993
+ async checkConnection() {
2994
+ if (!this.connectionManager)
2995
+ return "unknown";
2996
+ return await this.connectionManager.checkNow();
2997
+ }
2746
2998
  _setAuthContext(context) {
2747
2999
  this.authContext = context;
2748
3000
  }
@@ -2760,28 +3012,42 @@ var init_client = __esm(() => {
2760
3012
  ...options?.headers,
2761
3013
  ...this.authStrategy.getHeaders()
2762
3014
  };
2763
- return request({
2764
- path,
2765
- method,
2766
- body: options?.body,
2767
- baseUrl: this.baseUrl,
2768
- extraHeaders: effectiveHeaders,
2769
- raw: options?.raw
2770
- });
3015
+ try {
3016
+ const result = await request({
3017
+ path,
3018
+ method,
3019
+ body: options?.body,
3020
+ baseUrl: this.baseUrl,
3021
+ extraHeaders: effectiveHeaders,
3022
+ raw: options?.raw
3023
+ });
3024
+ this.connectionManager?.reportRequestSuccess();
3025
+ return result;
3026
+ } catch (error) {
3027
+ this.connectionManager?.reportRequestFailure(error);
3028
+ throw error;
3029
+ }
2771
3030
  }
2772
3031
  async requestGameBackend(path, method, body, headers, raw) {
2773
3032
  const effectiveHeaders = {
2774
3033
  ...headers,
2775
3034
  ...this.authStrategy.getHeaders()
2776
3035
  };
2777
- return request({
2778
- path,
2779
- method,
2780
- body,
2781
- baseUrl: this.getGameBackendUrl(),
2782
- extraHeaders: effectiveHeaders,
2783
- raw
2784
- });
3036
+ try {
3037
+ const result = await request({
3038
+ path,
3039
+ method,
3040
+ body,
3041
+ baseUrl: this.getGameBackendUrl(),
3042
+ extraHeaders: effectiveHeaders,
3043
+ raw
3044
+ });
3045
+ this.connectionManager?.reportRequestSuccess();
3046
+ return result;
3047
+ } catch (error) {
3048
+ this.connectionManager?.reportRequestFailure(error);
3049
+ throw error;
3050
+ }
2785
3051
  }
2786
3052
  _ensureGameId() {
2787
3053
  if (!this.gameId) {
@@ -2792,6 +3058,25 @@ var init_client = __esm(() => {
2792
3058
  _detectAuthContext() {
2793
3059
  this.authContext = { isInIframe: isInIframe() };
2794
3060
  }
3061
+ _initializeConnectionMonitor() {
3062
+ if (typeof window === "undefined")
3063
+ return;
3064
+ const isEnabled = this.config.enableConnectionMonitoring ?? true;
3065
+ if (!isEnabled)
3066
+ return;
3067
+ try {
3068
+ this.connectionManager = new ConnectionManager({
3069
+ baseUrl: this.baseUrl,
3070
+ authContext: this.authContext,
3071
+ onDisconnect: this.config.onDisconnect,
3072
+ onConnectionChange: (state, reason) => {
3073
+ this.emit("connectionChange", { state, reason });
3074
+ }
3075
+ });
3076
+ } catch (error) {
3077
+ log.error("[Playcademy SDK] Failed to initialize connection manager:", { error });
3078
+ }
3079
+ }
2795
3080
  async _initializeInternalSession() {
2796
3081
  if (!this.gameId || this.internalClientSessionId)
2797
3082
  return;
@@ -2842,6 +3127,7 @@ var init_client = __esm(() => {
2842
3127
  // src/index.ts
2843
3128
  init_client();
2844
3129
  init_errors();
3130
+ init_connection();
2845
3131
  init_messaging();
2846
3132
  export {
2847
3133
  messaging,
@@ -2849,5 +3135,7 @@ export {
2849
3135
  PlaycademyError,
2850
3136
  PlaycademyClient,
2851
3137
  MessageEvents,
3138
+ ConnectionMonitor,
3139
+ ConnectionManager,
2852
3140
  ApiError
2853
3141
  };