@looplay/sdk 0.8.6 → 0.8.8
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/looplay-sdk.cjs.js +81 -11
- package/dist/looplay-sdk.cjs.js.map +1 -1
- package/dist/looplay-sdk.esm.js +81 -12
- package/dist/looplay-sdk.esm.js.map +1 -1
- package/dist/looplay-sdk.min.js +5 -3
- package/dist/looplay-sdk.min.js.map +1 -1
- package/dist/types/apps/LooplaySDK.types.d.ts +6 -0
- package/dist/types/apps/api-client.d.ts +3 -0
- package/dist/types/apps/service-client.d.ts +8 -1
- package/dist/types/iframe/iframe-auth.d.ts +10 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/looplay-sdk.d.ts +7 -0
- package/dist/types/version.d.ts +1 -0
- package/package.json +1 -1
package/dist/looplay-sdk.cjs.js
CHANGED
|
@@ -139,6 +139,9 @@ var LooplayAuth = class {
|
|
|
139
139
|
}
|
|
140
140
|
};
|
|
141
141
|
|
|
142
|
+
// src/version.ts
|
|
143
|
+
var LOOPLAY_SDK_VERSION = "0.8.5";
|
|
144
|
+
|
|
142
145
|
// src/apps/http.ts
|
|
143
146
|
function getFetchFn(fetchOverride) {
|
|
144
147
|
if (fetchOverride) {
|
|
@@ -166,7 +169,10 @@ var HttpClient = class {
|
|
|
166
169
|
constructor(options) {
|
|
167
170
|
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
168
171
|
this.fetchFn = getFetchFn(options.fetch);
|
|
169
|
-
this.defaultHeaders =
|
|
172
|
+
this.defaultHeaders = {
|
|
173
|
+
"x-looplay-sdk-version": LOOPLAY_SDK_VERSION,
|
|
174
|
+
...options.defaultHeaders ?? {}
|
|
175
|
+
};
|
|
170
176
|
}
|
|
171
177
|
async request(method, path, options) {
|
|
172
178
|
const url = this.buildUrl(path, options?.query);
|
|
@@ -269,6 +275,19 @@ var ServiceClient = class {
|
|
|
269
275
|
body
|
|
270
276
|
});
|
|
271
277
|
}
|
|
278
|
+
/**
|
|
279
|
+
* Re-issues a fresh `playSessionToken` for the SAME `playSessionId` — call
|
|
280
|
+
* this instead of `startPlaySession` when refreshing an about-to-expire
|
|
281
|
+
* (or just-expired, within the server's renewal grace window) token, so
|
|
282
|
+
* long-running sessions keep a single `playSessionId` throughout.
|
|
283
|
+
*/
|
|
284
|
+
async renewPlaySession(gameKey, auth = {}, body) {
|
|
285
|
+
return this.http.request("POST", "/sdk/games/play-sessions/renew", {
|
|
286
|
+
...auth,
|
|
287
|
+
headers: { "x-game-key": gameKey, ...this.trackingHeaders(auth) },
|
|
288
|
+
body
|
|
289
|
+
});
|
|
290
|
+
}
|
|
272
291
|
async completePlaySession(gameKey, auth, body) {
|
|
273
292
|
await this.http.request("POST", "/sdk/games/play-sessions/complete", {
|
|
274
293
|
...auth,
|
|
@@ -438,9 +457,11 @@ var ApiClient = class {
|
|
|
438
457
|
getAccessToken;
|
|
439
458
|
getAnonymousId;
|
|
440
459
|
trackingSession;
|
|
460
|
+
trackingSessionPromiseKey;
|
|
441
461
|
trackingSessionPromise;
|
|
442
462
|
currentPlaySessionId;
|
|
443
463
|
playSession;
|
|
464
|
+
playSessionPromiseKey;
|
|
444
465
|
playSessionPromise;
|
|
445
466
|
constructor(options) {
|
|
446
467
|
if (!options.baseUrl) throw new MissingBaseUrlError();
|
|
@@ -481,7 +502,10 @@ var ApiClient = class {
|
|
|
481
502
|
const bearerToken = await this.getAccessToken?.();
|
|
482
503
|
const anonId = bearerToken ? void 0 : this.getAnonymousId?.();
|
|
483
504
|
if (!bearerToken && !anonId) throw new NotAuthenticatedError();
|
|
484
|
-
const session = await this.ensureTrackingSession(
|
|
505
|
+
const session = await this.ensureTrackingSession(
|
|
506
|
+
bearerToken ? `bearer:${bearerToken}` : `anon:${anonId}`,
|
|
507
|
+
anonId
|
|
508
|
+
);
|
|
485
509
|
return {
|
|
486
510
|
bearerToken,
|
|
487
511
|
anonId,
|
|
@@ -494,14 +518,16 @@ var ApiClient = class {
|
|
|
494
518
|
* session. Swallows failures — tracking calls still work without it,
|
|
495
519
|
* just without unified session tracing.
|
|
496
520
|
*/
|
|
497
|
-
async ensureTrackingSession(anonId) {
|
|
521
|
+
async ensureTrackingSession(cacheKey, anonId) {
|
|
498
522
|
const now = Date.now();
|
|
499
|
-
if (this.trackingSession && this.trackingSession.expiresAtMs > now + 3e4) {
|
|
523
|
+
if (this.trackingSession && this.trackingSession.cacheKey === cacheKey && this.trackingSession.expiresAtMs > now + 3e4) {
|
|
500
524
|
return this.trackingSession;
|
|
501
525
|
}
|
|
502
|
-
if (!this.trackingSessionPromise) {
|
|
526
|
+
if (!this.trackingSessionPromise || this.trackingSessionPromiseKey !== cacheKey) {
|
|
527
|
+
this.trackingSessionPromiseKey = cacheKey;
|
|
503
528
|
this.trackingSessionPromise = this.raw.bootstrapTrackingSession(anonId).then((dto) => {
|
|
504
529
|
this.trackingSession = {
|
|
530
|
+
cacheKey,
|
|
505
531
|
trackingSessionId: dto.trackingSessionId,
|
|
506
532
|
anonTrackingToken: dto.trackingToken,
|
|
507
533
|
expiresAtMs: new Date(dto.expiresAt).getTime()
|
|
@@ -509,10 +535,18 @@ var ApiClient = class {
|
|
|
509
535
|
return this.trackingSession;
|
|
510
536
|
}).catch(() => void 0).finally(() => {
|
|
511
537
|
this.trackingSessionPromise = void 0;
|
|
538
|
+
this.trackingSessionPromiseKey = void 0;
|
|
512
539
|
});
|
|
513
540
|
}
|
|
514
541
|
return this.trackingSessionPromise;
|
|
515
542
|
}
|
|
543
|
+
getTrackingAuthKey(auth) {
|
|
544
|
+
return [
|
|
545
|
+
auth.bearerToken ? `bearer:${auth.bearerToken}` : `anon:${auth.anonId ?? ""}`,
|
|
546
|
+
auth.trackingSessionId ?? "",
|
|
547
|
+
auth.anonTrackingToken ?? ""
|
|
548
|
+
].join("\n");
|
|
549
|
+
}
|
|
516
550
|
/**
|
|
517
551
|
* Signs (and caches until near expiry) the `playSessionToken` required by
|
|
518
552
|
* `trackPlay`/`trackMatch`/`emit` for the current play session — does not
|
|
@@ -521,12 +555,20 @@ var ApiClient = class {
|
|
|
521
555
|
*/
|
|
522
556
|
async ensurePlaySession(gameKey, auth, playSessionId) {
|
|
523
557
|
const now = Date.now();
|
|
524
|
-
|
|
558
|
+
const cacheKey = [gameKey, playSessionId, this.getTrackingAuthKey(auth)].join("\n");
|
|
559
|
+
if (this.playSession && this.playSession.cacheKey === cacheKey && this.playSession.gameKey === gameKey && this.playSession.playSessionId === playSessionId && this.playSession.expiresAtMs > now + 1e4) {
|
|
525
560
|
return this.playSession;
|
|
526
561
|
}
|
|
527
|
-
|
|
528
|
-
|
|
562
|
+
const previous = this.playSession && this.playSession.cacheKey === cacheKey && this.playSession.gameKey === gameKey && this.playSession.playSessionId === playSessionId ? this.playSession : void 0;
|
|
563
|
+
if (!this.playSessionPromise || this.playSessionPromiseKey !== cacheKey) {
|
|
564
|
+
this.playSessionPromiseKey = cacheKey;
|
|
565
|
+
const issue = previous ? this.raw.renewPlaySession(gameKey, auth, {
|
|
566
|
+
playSessionId,
|
|
567
|
+
playSessionToken: previous.playSessionToken
|
|
568
|
+
}).catch(() => this.raw.startPlaySession(gameKey, auth, { playSessionId })) : this.raw.startPlaySession(gameKey, auth, { playSessionId });
|
|
569
|
+
this.playSessionPromise = issue.then((dto) => {
|
|
529
570
|
this.playSession = {
|
|
571
|
+
cacheKey,
|
|
530
572
|
gameKey,
|
|
531
573
|
playSessionId: dto.playSessionId,
|
|
532
574
|
playSessionToken: dto.playSessionToken,
|
|
@@ -535,6 +577,7 @@ var ApiClient = class {
|
|
|
535
577
|
return this.playSession;
|
|
536
578
|
}).finally(() => {
|
|
537
579
|
this.playSessionPromise = void 0;
|
|
580
|
+
this.playSessionPromiseKey = void 0;
|
|
538
581
|
});
|
|
539
582
|
}
|
|
540
583
|
return this.playSessionPromise;
|
|
@@ -733,9 +776,23 @@ var LooplaySDK = class {
|
|
|
733
776
|
if (!this.api) throw new MissingBaseUrlError();
|
|
734
777
|
await this.api.listGameAssets(params.gameId);
|
|
735
778
|
}
|
|
779
|
+
/**
|
|
780
|
+
* Best-effort self-report — must never block init(). A missing/misconfigured
|
|
781
|
+
* whitelist (a separate setup step from SDK integration) makes the backend
|
|
782
|
+
* reject this call; if that rejection propagated, the whole init() would
|
|
783
|
+
* reject too and every other SDK method would throw NotInitializedError,
|
|
784
|
+
* breaking a game over what's really just an unfinished onboarding step.
|
|
785
|
+
*/
|
|
736
786
|
async detectIntegration(params) {
|
|
737
787
|
if (!this.api) return;
|
|
738
|
-
|
|
788
|
+
try {
|
|
789
|
+
await this.api.detectIntegration(params.gameId);
|
|
790
|
+
} catch (error) {
|
|
791
|
+
console.warn(
|
|
792
|
+
"[LooplaySDK] detectIntegration failed (SDK will still initialize) \u2014 check that this game has a whitelisted origin/domain configured:",
|
|
793
|
+
error
|
|
794
|
+
);
|
|
795
|
+
}
|
|
739
796
|
}
|
|
740
797
|
};
|
|
741
798
|
|
|
@@ -1107,7 +1164,16 @@ var LooplayIframeAuth = class {
|
|
|
1107
1164
|
this.debug("emitGameEvent dispatched", { gameId, actionCode, ...opts });
|
|
1108
1165
|
return this.getClient().emit(gameId, actionCode, opts);
|
|
1109
1166
|
}
|
|
1110
|
-
/**
|
|
1167
|
+
/**
|
|
1168
|
+
* Idempotent; auto-emits GAME_STARTED exactly once per distinct auth
|
|
1169
|
+
* session (bearer or anonymous). SDK integration self-reporting for the
|
|
1170
|
+
* iframe path lives in `detectIntegrationOnce()` (fired from `setState()`
|
|
1171
|
+
* on every auth/config change, not gated behind lifecycle tracking being
|
|
1172
|
+
* enabled at all) — without it, games embedded via iframe would never
|
|
1173
|
+
* trigger the active detect call, only the passive heartbeat that
|
|
1174
|
+
* tracking calls leave behind (which doesn't fire while the game is still
|
|
1175
|
+
* IN_REVIEW/not LIVE, since tracking is blocked until then).
|
|
1176
|
+
*/
|
|
1111
1177
|
initLifecycleTracking() {
|
|
1112
1178
|
if (this.lifecycleTrackingInitialized || typeof window === "undefined")
|
|
1113
1179
|
return;
|
|
@@ -1236,8 +1302,11 @@ ${identity}`;
|
|
|
1236
1302
|
}
|
|
1237
1303
|
}
|
|
1238
1304
|
setState(next) {
|
|
1305
|
+
const currentApiUrl = this.getApiUrl();
|
|
1239
1306
|
this.state = next;
|
|
1240
|
-
this.
|
|
1307
|
+
if (this.getApiUrl() !== currentApiUrl) {
|
|
1308
|
+
this.client = null;
|
|
1309
|
+
}
|
|
1241
1310
|
this.debug("auth state updated", {
|
|
1242
1311
|
gameId: this.getGameId(),
|
|
1243
1312
|
apiUrl: this.getApiUrl(),
|
|
@@ -1316,6 +1385,7 @@ exports.ApiClient = ApiClient;
|
|
|
1316
1385
|
exports.BrowserLocalStorageAuthStorage = BrowserLocalStorageAuthStorage;
|
|
1317
1386
|
exports.HttpClient = HttpClient;
|
|
1318
1387
|
exports.HttpError = HttpError;
|
|
1388
|
+
exports.LOOPLAY_SDK_VERSION = LOOPLAY_SDK_VERSION;
|
|
1319
1389
|
exports.LooplayAuth = LooplayAuth;
|
|
1320
1390
|
exports.LooplayIframeAuth = LooplayIframeAuth;
|
|
1321
1391
|
exports.LooplaySDK = LooplaySDK;
|