@looplay/sdk 0.8.6 → 0.8.7

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.
@@ -137,6 +137,9 @@ var LooplayAuth = class {
137
137
  }
138
138
  };
139
139
 
140
+ // src/version.ts
141
+ var LOOPLAY_SDK_VERSION = "0.8.5";
142
+
140
143
  // src/apps/http.ts
141
144
  function getFetchFn(fetchOverride) {
142
145
  if (fetchOverride) {
@@ -164,7 +167,10 @@ var HttpClient = class {
164
167
  constructor(options) {
165
168
  this.baseUrl = options.baseUrl.replace(/\/$/, "");
166
169
  this.fetchFn = getFetchFn(options.fetch);
167
- this.defaultHeaders = options.defaultHeaders ?? {};
170
+ this.defaultHeaders = {
171
+ "x-looplay-sdk-version": LOOPLAY_SDK_VERSION,
172
+ ...options.defaultHeaders ?? {}
173
+ };
168
174
  }
169
175
  async request(method, path, options) {
170
176
  const url = this.buildUrl(path, options?.query);
@@ -267,6 +273,19 @@ var ServiceClient = class {
267
273
  body
268
274
  });
269
275
  }
276
+ /**
277
+ * Re-issues a fresh `playSessionToken` for the SAME `playSessionId` — call
278
+ * this instead of `startPlaySession` when refreshing an about-to-expire
279
+ * (or just-expired, within the server's renewal grace window) token, so
280
+ * long-running sessions keep a single `playSessionId` throughout.
281
+ */
282
+ async renewPlaySession(gameKey, auth = {}, body) {
283
+ return this.http.request("POST", "/sdk/games/play-sessions/renew", {
284
+ ...auth,
285
+ headers: { "x-game-key": gameKey, ...this.trackingHeaders(auth) },
286
+ body
287
+ });
288
+ }
270
289
  async completePlaySession(gameKey, auth, body) {
271
290
  await this.http.request("POST", "/sdk/games/play-sessions/complete", {
272
291
  ...auth,
@@ -436,9 +455,11 @@ var ApiClient = class {
436
455
  getAccessToken;
437
456
  getAnonymousId;
438
457
  trackingSession;
458
+ trackingSessionPromiseKey;
439
459
  trackingSessionPromise;
440
460
  currentPlaySessionId;
441
461
  playSession;
462
+ playSessionPromiseKey;
442
463
  playSessionPromise;
443
464
  constructor(options) {
444
465
  if (!options.baseUrl) throw new MissingBaseUrlError();
@@ -479,7 +500,10 @@ var ApiClient = class {
479
500
  const bearerToken = await this.getAccessToken?.();
480
501
  const anonId = bearerToken ? void 0 : this.getAnonymousId?.();
481
502
  if (!bearerToken && !anonId) throw new NotAuthenticatedError();
482
- const session = await this.ensureTrackingSession(anonId);
503
+ const session = await this.ensureTrackingSession(
504
+ bearerToken ? `bearer:${bearerToken}` : `anon:${anonId}`,
505
+ anonId
506
+ );
483
507
  return {
484
508
  bearerToken,
485
509
  anonId,
@@ -492,14 +516,16 @@ var ApiClient = class {
492
516
  * session. Swallows failures — tracking calls still work without it,
493
517
  * just without unified session tracing.
494
518
  */
495
- async ensureTrackingSession(anonId) {
519
+ async ensureTrackingSession(cacheKey, anonId) {
496
520
  const now = Date.now();
497
- if (this.trackingSession && this.trackingSession.expiresAtMs > now + 3e4) {
521
+ if (this.trackingSession && this.trackingSession.cacheKey === cacheKey && this.trackingSession.expiresAtMs > now + 3e4) {
498
522
  return this.trackingSession;
499
523
  }
500
- if (!this.trackingSessionPromise) {
524
+ if (!this.trackingSessionPromise || this.trackingSessionPromiseKey !== cacheKey) {
525
+ this.trackingSessionPromiseKey = cacheKey;
501
526
  this.trackingSessionPromise = this.raw.bootstrapTrackingSession(anonId).then((dto) => {
502
527
  this.trackingSession = {
528
+ cacheKey,
503
529
  trackingSessionId: dto.trackingSessionId,
504
530
  anonTrackingToken: dto.trackingToken,
505
531
  expiresAtMs: new Date(dto.expiresAt).getTime()
@@ -507,10 +533,18 @@ var ApiClient = class {
507
533
  return this.trackingSession;
508
534
  }).catch(() => void 0).finally(() => {
509
535
  this.trackingSessionPromise = void 0;
536
+ this.trackingSessionPromiseKey = void 0;
510
537
  });
511
538
  }
512
539
  return this.trackingSessionPromise;
513
540
  }
541
+ getTrackingAuthKey(auth) {
542
+ return [
543
+ auth.bearerToken ? `bearer:${auth.bearerToken}` : `anon:${auth.anonId ?? ""}`,
544
+ auth.trackingSessionId ?? "",
545
+ auth.anonTrackingToken ?? ""
546
+ ].join("\n");
547
+ }
514
548
  /**
515
549
  * Signs (and caches until near expiry) the `playSessionToken` required by
516
550
  * `trackPlay`/`trackMatch`/`emit` for the current play session — does not
@@ -519,12 +553,20 @@ var ApiClient = class {
519
553
  */
520
554
  async ensurePlaySession(gameKey, auth, playSessionId) {
521
555
  const now = Date.now();
522
- if (this.playSession && this.playSession.gameKey === gameKey && this.playSession.playSessionId === playSessionId && this.playSession.expiresAtMs > now + 1e4) {
556
+ const cacheKey = [gameKey, playSessionId, this.getTrackingAuthKey(auth)].join("\n");
557
+ if (this.playSession && this.playSession.cacheKey === cacheKey && this.playSession.gameKey === gameKey && this.playSession.playSessionId === playSessionId && this.playSession.expiresAtMs > now + 1e4) {
523
558
  return this.playSession;
524
559
  }
525
- if (!this.playSessionPromise) {
526
- this.playSessionPromise = this.raw.startPlaySession(gameKey, auth, { playSessionId }).then((dto) => {
560
+ const previous = this.playSession && this.playSession.cacheKey === cacheKey && this.playSession.gameKey === gameKey && this.playSession.playSessionId === playSessionId ? this.playSession : void 0;
561
+ if (!this.playSessionPromise || this.playSessionPromiseKey !== cacheKey) {
562
+ this.playSessionPromiseKey = cacheKey;
563
+ const issue = previous ? this.raw.renewPlaySession(gameKey, auth, {
564
+ playSessionId,
565
+ playSessionToken: previous.playSessionToken
566
+ }).catch(() => this.raw.startPlaySession(gameKey, auth, { playSessionId })) : this.raw.startPlaySession(gameKey, auth, { playSessionId });
567
+ this.playSessionPromise = issue.then((dto) => {
527
568
  this.playSession = {
569
+ cacheKey,
528
570
  gameKey,
529
571
  playSessionId: dto.playSessionId,
530
572
  playSessionToken: dto.playSessionToken,
@@ -533,6 +575,7 @@ var ApiClient = class {
533
575
  return this.playSession;
534
576
  }).finally(() => {
535
577
  this.playSessionPromise = void 0;
578
+ this.playSessionPromiseKey = void 0;
536
579
  });
537
580
  }
538
581
  return this.playSessionPromise;
@@ -1105,7 +1148,15 @@ var LooplayIframeAuth = class {
1105
1148
  this.debug("emitGameEvent dispatched", { gameId, actionCode, ...opts });
1106
1149
  return this.getClient().emit(gameId, actionCode, opts);
1107
1150
  }
1108
- /** Idempotent; auto-emits GAME_STARTED exactly once per distinct auth session (bearer or anonymous). */
1151
+ /**
1152
+ * Idempotent; auto-emits GAME_STARTED exactly once per distinct auth
1153
+ * session (bearer or anonymous), and self-reports SDK integration the
1154
+ * same way the standalone `LooplaySDK.init()` does — without this, games
1155
+ * embedded via iframe never trigger the active detect call, only the
1156
+ * passive heartbeat that tracking calls leave behind (which doesn't fire
1157
+ * at all while the game is still IN_REVIEW/not LIVE, since tracking is
1158
+ * blocked until then).
1159
+ */
1109
1160
  initLifecycleTracking() {
1110
1161
  if (this.lifecycleTrackingInitialized || typeof window === "undefined")
1111
1162
  return;
@@ -1115,6 +1166,11 @@ var LooplayIframeAuth = class {
1115
1166
  const key = this.getTrackingKey();
1116
1167
  if (!key || this.lastGameStartedKey === key) return;
1117
1168
  this.lastGameStartedKey = key;
1169
+ const gameId = this.getGameId();
1170
+ if (gameId) {
1171
+ this.debug("auto detectIntegration dispatch", { gameId });
1172
+ void this.getClient().detectIntegration(gameId).catch(() => void 0);
1173
+ }
1118
1174
  this.debug("auto GAME_STARTED dispatch");
1119
1175
  void this.emitGameEvent("GAME_STARTED");
1120
1176
  });
@@ -1234,8 +1290,11 @@ ${identity}`;
1234
1290
  }
1235
1291
  }
1236
1292
  setState(next) {
1293
+ const currentApiUrl = this.getApiUrl();
1237
1294
  this.state = next;
1238
- this.client = null;
1295
+ if (this.getApiUrl() !== currentApiUrl) {
1296
+ this.client = null;
1297
+ }
1239
1298
  this.debug("auth state updated", {
1240
1299
  gameId: this.getGameId(),
1241
1300
  apiUrl: this.getApiUrl(),
@@ -1310,6 +1369,6 @@ ${gameId}`;
1310
1369
  }
1311
1370
  };
1312
1371
 
1313
- export { ApiClient, BrowserLocalStorageAuthStorage, HttpClient, HttpError, LooplayAuth, LooplayIframeAuth, LooplaySDK, LooplaySDKError, MemoryAuthStorage, MissingAuthError, MissingBaseUrlError, NotAuthenticatedError, NotInitializedError, ServiceClient, TelegramAuthProvider };
1372
+ export { ApiClient, BrowserLocalStorageAuthStorage, HttpClient, HttpError, LOOPLAY_SDK_VERSION, LooplayAuth, LooplayIframeAuth, LooplaySDK, LooplaySDKError, MemoryAuthStorage, MissingAuthError, MissingBaseUrlError, NotAuthenticatedError, NotInitializedError, ServiceClient, TelegramAuthProvider };
1314
1373
  //# sourceMappingURL=looplay-sdk.esm.js.map
1315
1374
  //# sourceMappingURL=looplay-sdk.esm.js.map