@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.esm.js
CHANGED
|
@@ -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 =
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
526
|
-
|
|
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;
|
|
@@ -731,9 +774,23 @@ var LooplaySDK = class {
|
|
|
731
774
|
if (!this.api) throw new MissingBaseUrlError();
|
|
732
775
|
await this.api.listGameAssets(params.gameId);
|
|
733
776
|
}
|
|
777
|
+
/**
|
|
778
|
+
* Best-effort self-report — must never block init(). A missing/misconfigured
|
|
779
|
+
* whitelist (a separate setup step from SDK integration) makes the backend
|
|
780
|
+
* reject this call; if that rejection propagated, the whole init() would
|
|
781
|
+
* reject too and every other SDK method would throw NotInitializedError,
|
|
782
|
+
* breaking a game over what's really just an unfinished onboarding step.
|
|
783
|
+
*/
|
|
734
784
|
async detectIntegration(params) {
|
|
735
785
|
if (!this.api) return;
|
|
736
|
-
|
|
786
|
+
try {
|
|
787
|
+
await this.api.detectIntegration(params.gameId);
|
|
788
|
+
} catch (error) {
|
|
789
|
+
console.warn(
|
|
790
|
+
"[LooplaySDK] detectIntegration failed (SDK will still initialize) \u2014 check that this game has a whitelisted origin/domain configured:",
|
|
791
|
+
error
|
|
792
|
+
);
|
|
793
|
+
}
|
|
737
794
|
}
|
|
738
795
|
};
|
|
739
796
|
|
|
@@ -1105,7 +1162,16 @@ var LooplayIframeAuth = class {
|
|
|
1105
1162
|
this.debug("emitGameEvent dispatched", { gameId, actionCode, ...opts });
|
|
1106
1163
|
return this.getClient().emit(gameId, actionCode, opts);
|
|
1107
1164
|
}
|
|
1108
|
-
/**
|
|
1165
|
+
/**
|
|
1166
|
+
* Idempotent; auto-emits GAME_STARTED exactly once per distinct auth
|
|
1167
|
+
* session (bearer or anonymous). SDK integration self-reporting for the
|
|
1168
|
+
* iframe path lives in `detectIntegrationOnce()` (fired from `setState()`
|
|
1169
|
+
* on every auth/config change, not gated behind lifecycle tracking being
|
|
1170
|
+
* enabled at all) — without it, games embedded via iframe would never
|
|
1171
|
+
* trigger the active detect call, only the passive heartbeat that
|
|
1172
|
+
* tracking calls leave behind (which doesn't fire while the game is still
|
|
1173
|
+
* IN_REVIEW/not LIVE, since tracking is blocked until then).
|
|
1174
|
+
*/
|
|
1109
1175
|
initLifecycleTracking() {
|
|
1110
1176
|
if (this.lifecycleTrackingInitialized || typeof window === "undefined")
|
|
1111
1177
|
return;
|
|
@@ -1234,8 +1300,11 @@ ${identity}`;
|
|
|
1234
1300
|
}
|
|
1235
1301
|
}
|
|
1236
1302
|
setState(next) {
|
|
1303
|
+
const currentApiUrl = this.getApiUrl();
|
|
1237
1304
|
this.state = next;
|
|
1238
|
-
this.
|
|
1305
|
+
if (this.getApiUrl() !== currentApiUrl) {
|
|
1306
|
+
this.client = null;
|
|
1307
|
+
}
|
|
1239
1308
|
this.debug("auth state updated", {
|
|
1240
1309
|
gameId: this.getGameId(),
|
|
1241
1310
|
apiUrl: this.getApiUrl(),
|
|
@@ -1310,6 +1379,6 @@ ${gameId}`;
|
|
|
1310
1379
|
}
|
|
1311
1380
|
};
|
|
1312
1381
|
|
|
1313
|
-
export { ApiClient, BrowserLocalStorageAuthStorage, HttpClient, HttpError, LooplayAuth, LooplayIframeAuth, LooplaySDK, LooplaySDKError, MemoryAuthStorage, MissingAuthError, MissingBaseUrlError, NotAuthenticatedError, NotInitializedError, ServiceClient, TelegramAuthProvider };
|
|
1382
|
+
export { ApiClient, BrowserLocalStorageAuthStorage, HttpClient, HttpError, LOOPLAY_SDK_VERSION, LooplayAuth, LooplayIframeAuth, LooplaySDK, LooplaySDKError, MemoryAuthStorage, MissingAuthError, MissingBaseUrlError, NotAuthenticatedError, NotInitializedError, ServiceClient, TelegramAuthProvider };
|
|
1314
1383
|
//# sourceMappingURL=looplay-sdk.esm.js.map
|
|
1315
1384
|
//# sourceMappingURL=looplay-sdk.esm.js.map
|