@looplay/sdk 0.1.1 → 0.2.1
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/README.md +86 -1
- package/dist/looplay-sdk.cjs.js +344 -29
- package/dist/looplay-sdk.cjs.js.map +1 -1
- package/dist/looplay-sdk.esm.js +344 -30
- package/dist/looplay-sdk.esm.js.map +1 -1
- package/dist/looplay-sdk.min.js +3 -1
- package/dist/looplay-sdk.min.js.map +1 -1
- package/dist/types/apps/api-client.d.ts +13 -0
- package/dist/types/apps/http.d.ts +2 -0
- package/dist/types/apps/service-client.d.ts +14 -4
- package/dist/types/auth/jwt.d.ts +2 -0
- package/dist/types/iframe/iframe-auth.d.ts +59 -0
- package/dist/types/iframe/index.d.ts +2 -0
- package/dist/types/iframe/types.d.ts +48 -0
- package/dist/types/index.d.ts +3 -1
- package/package.json +9 -9
package/dist/looplay-sdk.esm.js
CHANGED
|
@@ -174,6 +174,8 @@ var HttpClient = class {
|
|
|
174
174
|
);
|
|
175
175
|
if (options?.bearerToken) {
|
|
176
176
|
headers.Authorization = `Bearer ${options.bearerToken}`;
|
|
177
|
+
} else if (options?.anonId) {
|
|
178
|
+
headers["x-looplay-anon-id"] = options.anonId;
|
|
177
179
|
}
|
|
178
180
|
let body;
|
|
179
181
|
if (options?.body !== void 0) {
|
|
@@ -255,24 +257,24 @@ var ServiceClient = class {
|
|
|
255
257
|
async listRecentPlayed(bearerToken, query) {
|
|
256
258
|
return this.http.request("GET", "/games/recent-play", { bearerToken, query });
|
|
257
259
|
}
|
|
258
|
-
async trackPlay(
|
|
260
|
+
async trackPlay(auth, gameId, playTimeSeconds) {
|
|
259
261
|
const body = { playTimeSeconds };
|
|
260
262
|
await this.http.request("POST", `/games/${encodeURIComponent(gameId)}/play`, {
|
|
261
|
-
|
|
263
|
+
...auth,
|
|
262
264
|
body
|
|
263
265
|
});
|
|
264
266
|
return true;
|
|
265
267
|
}
|
|
266
|
-
async trackMatchEnd(
|
|
268
|
+
async trackMatchEnd(auth, gameId, body) {
|
|
267
269
|
await this.http.request("POST", `/games/${encodeURIComponent(gameId)}/end`, {
|
|
268
|
-
|
|
270
|
+
...auth,
|
|
269
271
|
body
|
|
270
272
|
});
|
|
271
273
|
return true;
|
|
272
274
|
}
|
|
273
|
-
async emitGameEvent(
|
|
275
|
+
async emitGameEvent(auth, gameId, body) {
|
|
274
276
|
return this.http.request("POST", `/games/${encodeURIComponent(gameId)}/emit`, {
|
|
275
|
-
|
|
277
|
+
...auth,
|
|
276
278
|
body
|
|
277
279
|
});
|
|
278
280
|
}
|
|
@@ -345,6 +347,7 @@ var ServiceClient = class {
|
|
|
345
347
|
var ApiClient = class {
|
|
346
348
|
raw;
|
|
347
349
|
getAccessToken;
|
|
350
|
+
getAnonymousId;
|
|
348
351
|
constructor(options) {
|
|
349
352
|
if (!options.baseUrl) throw new MissingBaseUrlError();
|
|
350
353
|
this.raw = new ServiceClient({
|
|
@@ -353,6 +356,7 @@ var ApiClient = class {
|
|
|
353
356
|
defaultHeaders: options.defaultHeaders
|
|
354
357
|
});
|
|
355
358
|
this.getAccessToken = options.getAccessToken;
|
|
359
|
+
this.getAnonymousId = options.getAnonymousId;
|
|
356
360
|
}
|
|
357
361
|
/** Expose the underlying route-level client (requires manual bearerToken passing). */
|
|
358
362
|
unsafeRaw() {
|
|
@@ -368,8 +372,20 @@ var ApiClient = class {
|
|
|
368
372
|
if (!token) throw new NotAuthenticatedError();
|
|
369
373
|
return token;
|
|
370
374
|
}
|
|
375
|
+
/**
|
|
376
|
+
* Resolves auth for the tracking endpoints: a real bearer token if logged
|
|
377
|
+
* in, otherwise an anonymous device id. Throws only when neither is
|
|
378
|
+
* available — anonymous tracking still requires *some* identity.
|
|
379
|
+
*/
|
|
380
|
+
async resolveTrackingAuth() {
|
|
381
|
+
const bearerToken = await this.getAccessToken?.();
|
|
382
|
+
if (bearerToken) return { bearerToken };
|
|
383
|
+
const anonId = this.getAnonymousId?.();
|
|
384
|
+
if (anonId) return { anonId };
|
|
385
|
+
throw new NotAuthenticatedError();
|
|
386
|
+
}
|
|
371
387
|
async getGameDetail(gameId) {
|
|
372
|
-
const token = await this.
|
|
388
|
+
const token = await this.getAccessToken?.();
|
|
373
389
|
return this.raw.getGameDetail(gameId, token);
|
|
374
390
|
}
|
|
375
391
|
async listRecentPlayed(query) {
|
|
@@ -377,22 +393,22 @@ var ApiClient = class {
|
|
|
377
393
|
return this.raw.listRecentPlayed(token, query);
|
|
378
394
|
}
|
|
379
395
|
async trackPlay(gameId, playTimeSeconds) {
|
|
380
|
-
const
|
|
381
|
-
return this.raw.trackPlay(
|
|
396
|
+
const auth = await this.resolveTrackingAuth();
|
|
397
|
+
return this.raw.trackPlay(auth, gameId, playTimeSeconds);
|
|
382
398
|
}
|
|
383
399
|
async trackMatch(gameId, body) {
|
|
384
|
-
const
|
|
385
|
-
return this.raw.trackMatchEnd(
|
|
400
|
+
const auth = await this.resolveTrackingAuth();
|
|
401
|
+
return this.raw.trackMatchEnd(auth, gameId, body);
|
|
386
402
|
}
|
|
387
403
|
async emit(gameId, actionCode, opts) {
|
|
388
|
-
const
|
|
404
|
+
const auth = await this.resolveTrackingAuth();
|
|
389
405
|
const body = {
|
|
390
406
|
actionCode,
|
|
391
407
|
value: opts?.value,
|
|
392
408
|
refId: opts?.refId,
|
|
393
409
|
payload: opts?.payload
|
|
394
410
|
};
|
|
395
|
-
return this.raw.emitGameEvent(
|
|
411
|
+
return this.raw.emitGameEvent(auth, gameId, body);
|
|
396
412
|
}
|
|
397
413
|
async getMyProfile() {
|
|
398
414
|
const token = await this.requireToken();
|
|
@@ -533,6 +549,26 @@ var LooplaySDK = class {
|
|
|
533
549
|
}
|
|
534
550
|
};
|
|
535
551
|
|
|
552
|
+
// src/auth/jwt.ts
|
|
553
|
+
function decodeJwtClaims(token) {
|
|
554
|
+
if (!token) return void 0;
|
|
555
|
+
const parts = token.split(".");
|
|
556
|
+
if (parts.length < 2) return void 0;
|
|
557
|
+
try {
|
|
558
|
+
const payload = parts[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
559
|
+
const padded = payload + "===".slice((payload.length + 3) % 4);
|
|
560
|
+
if (typeof globalThis.atob !== "function") return void 0;
|
|
561
|
+
const json = globalThis.atob(padded);
|
|
562
|
+
return JSON.parse(json);
|
|
563
|
+
} catch {
|
|
564
|
+
return void 0;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
function decodeJwtExpMs(token) {
|
|
568
|
+
const exp = decodeJwtClaims(token)?.exp;
|
|
569
|
+
return typeof exp === "number" ? exp * 1e3 : void 0;
|
|
570
|
+
}
|
|
571
|
+
|
|
536
572
|
// src/auth/providers/telegram-auth-provider.ts
|
|
537
573
|
var MissingTelegramInitDataError = class extends LooplaySDKError {
|
|
538
574
|
constructor() {
|
|
@@ -546,22 +582,6 @@ var MissingRefreshTokenError = class extends LooplaySDKError {
|
|
|
546
582
|
this.name = "MissingRefreshTokenError";
|
|
547
583
|
}
|
|
548
584
|
};
|
|
549
|
-
function decodeJwtExpMs(token) {
|
|
550
|
-
if (!token) return void 0;
|
|
551
|
-
const parts = token.split(".");
|
|
552
|
-
if (parts.length < 2) return void 0;
|
|
553
|
-
try {
|
|
554
|
-
const payload = parts[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
555
|
-
const padded = payload + "===".slice((payload.length + 3) % 4);
|
|
556
|
-
if (typeof globalThis.atob !== "function") return void 0;
|
|
557
|
-
const json = globalThis.atob(padded);
|
|
558
|
-
const parsed = JSON.parse(json);
|
|
559
|
-
if (typeof parsed.exp !== "number") return void 0;
|
|
560
|
-
return parsed.exp * 1e3;
|
|
561
|
-
} catch {
|
|
562
|
-
return void 0;
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
585
|
var TelegramAuthProvider = class {
|
|
566
586
|
id = "telegram";
|
|
567
587
|
client;
|
|
@@ -627,6 +647,300 @@ var TelegramAuthProvider = class {
|
|
|
627
647
|
}
|
|
628
648
|
};
|
|
629
649
|
|
|
630
|
-
|
|
650
|
+
// src/iframe/iframe-auth.ts
|
|
651
|
+
var DEFAULT_ANON_ID_STORAGE_KEY = "looplay:anon-id";
|
|
652
|
+
var DEFAULT_ANONYMOUS_FALLBACK_TIMEOUT_MS = 4e3;
|
|
653
|
+
var INITIAL_STATE = {
|
|
654
|
+
jwt: null,
|
|
655
|
+
gameId: null,
|
|
656
|
+
apiUrl: null,
|
|
657
|
+
anonymousId: null,
|
|
658
|
+
origin: null,
|
|
659
|
+
receivedAt: null
|
|
660
|
+
};
|
|
661
|
+
var isRecord = (value) => typeof value === "object" && value !== null;
|
|
662
|
+
var toOptionalString = (value) => {
|
|
663
|
+
if (typeof value !== "string") return null;
|
|
664
|
+
const normalized = value.trim();
|
|
665
|
+
return normalized ? normalized : null;
|
|
666
|
+
};
|
|
667
|
+
function generateAnonymousId() {
|
|
668
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
669
|
+
return crypto.randomUUID();
|
|
670
|
+
}
|
|
671
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
672
|
+
const r = Math.random() * 16 | 0;
|
|
673
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
674
|
+
return v.toString(16);
|
|
675
|
+
});
|
|
676
|
+
}
|
|
677
|
+
function readStoredAnonymousId(key) {
|
|
678
|
+
if (typeof window === "undefined" || !window.localStorage) return null;
|
|
679
|
+
try {
|
|
680
|
+
return window.localStorage.getItem(key);
|
|
681
|
+
} catch {
|
|
682
|
+
return null;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
function writeStoredAnonymousId(key, value) {
|
|
686
|
+
if (typeof window === "undefined" || !window.localStorage) return;
|
|
687
|
+
try {
|
|
688
|
+
window.localStorage.setItem(key, value);
|
|
689
|
+
} catch {
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
var LooplayIframeAuth = class {
|
|
693
|
+
state = INITIAL_STATE;
|
|
694
|
+
initialized = false;
|
|
695
|
+
lifecycleTrackingInitialized = false;
|
|
696
|
+
lastGameStartedKey = null;
|
|
697
|
+
client = null;
|
|
698
|
+
listeners = /* @__PURE__ */ new Set();
|
|
699
|
+
options;
|
|
700
|
+
messageListener = null;
|
|
701
|
+
anonymousFallbackTimer = null;
|
|
702
|
+
constructor(options = {}) {
|
|
703
|
+
this.options = options;
|
|
704
|
+
}
|
|
705
|
+
getState() {
|
|
706
|
+
return this.state;
|
|
707
|
+
}
|
|
708
|
+
getJwt() {
|
|
709
|
+
return this.state.jwt;
|
|
710
|
+
}
|
|
711
|
+
getApiUrl() {
|
|
712
|
+
return this.options.apiUrl ?? this.state.apiUrl;
|
|
713
|
+
}
|
|
714
|
+
/** Resolves to the configured `appId`, falling back to whatever the parent pushed as `gameId`. */
|
|
715
|
+
getGameId() {
|
|
716
|
+
return this.options.appId ?? this.state.gameId;
|
|
717
|
+
}
|
|
718
|
+
getAnonymousId() {
|
|
719
|
+
return this.state.anonymousId;
|
|
720
|
+
}
|
|
721
|
+
/** True once authenticated (bearer) or anonymous tracking is ready, given a configured `apiUrl`/`appId`. */
|
|
722
|
+
canTrack() {
|
|
723
|
+
if (!this.getApiUrl() || !this.getGameId()) return false;
|
|
724
|
+
return Boolean(this.state.jwt || this.state.anonymousId);
|
|
725
|
+
}
|
|
726
|
+
subscribe(listener) {
|
|
727
|
+
this.listeners.add(listener);
|
|
728
|
+
listener(this.state);
|
|
729
|
+
return () => this.listeners.delete(listener);
|
|
730
|
+
}
|
|
731
|
+
requestAuth() {
|
|
732
|
+
if (typeof window === "undefined" || window.parent === window) {
|
|
733
|
+
this.debug("standalone mode detected; auth request skipped");
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
this.debug("requesting auth from parent", { targetOrigin: this.resolveParentOrigin() ?? "*" });
|
|
737
|
+
window.parent.postMessage({ type: "LOOPLAY_AUTH_REQUEST" }, this.resolveParentOrigin() ?? "*");
|
|
738
|
+
}
|
|
739
|
+
/** Idempotent; attaches the postMessage listener (if embedded) and arms the anonymous fallback. */
|
|
740
|
+
init() {
|
|
741
|
+
if (this.initialized || typeof window === "undefined") return;
|
|
742
|
+
this.initialized = true;
|
|
743
|
+
const isEmbedded = window.parent !== window;
|
|
744
|
+
this.debug("auth listener initialized", {
|
|
745
|
+
isIframe: isEmbedded,
|
|
746
|
+
parentOrigin: this.resolveParentOrigin()
|
|
747
|
+
});
|
|
748
|
+
if (!isEmbedded) {
|
|
749
|
+
this.activateAnonymousMode();
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
752
|
+
const parentOrigin = this.resolveParentOrigin();
|
|
753
|
+
if (!parentOrigin) {
|
|
754
|
+
console.warn(
|
|
755
|
+
"[LooplaySDK] LooplayIframeAuth could not resolve a parent origin to verify postMessage against (document.referrer is empty). Auth messages from window.parent will be accepted regardless of origin. Pass `parentOrigin` explicitly to harden this."
|
|
756
|
+
);
|
|
757
|
+
}
|
|
758
|
+
this.messageListener = (event) => {
|
|
759
|
+
if (event.source !== window.parent) return;
|
|
760
|
+
if (parentOrigin && event.origin !== parentOrigin) {
|
|
761
|
+
this.debug("ignored auth message from unexpected origin", {
|
|
762
|
+
expectedOrigin: parentOrigin,
|
|
763
|
+
receivedOrigin: event.origin
|
|
764
|
+
});
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
if (!isRecord(event.data) || event.data.type !== "LOOPLAY_AUTH") return;
|
|
768
|
+
this.handleAuthMessage(event.data, event.origin);
|
|
769
|
+
};
|
|
770
|
+
window.addEventListener("message", this.messageListener);
|
|
771
|
+
this.anonymousFallbackTimer = setTimeout(() => {
|
|
772
|
+
if (this.state.jwt) return;
|
|
773
|
+
this.activateAnonymousMode();
|
|
774
|
+
}, this.options.anonymousFallbackTimeoutMs ?? DEFAULT_ANONYMOUS_FALLBACK_TIMEOUT_MS);
|
|
775
|
+
this.requestAuth();
|
|
776
|
+
}
|
|
777
|
+
/** Removes the postMessage listener, cancels timers, and clears subscribers; safe to call multiple times. */
|
|
778
|
+
dispose() {
|
|
779
|
+
if (typeof window !== "undefined" && this.messageListener) {
|
|
780
|
+
window.removeEventListener("message", this.messageListener);
|
|
781
|
+
}
|
|
782
|
+
if (this.anonymousFallbackTimer !== null) {
|
|
783
|
+
clearTimeout(this.anonymousFallbackTimer);
|
|
784
|
+
}
|
|
785
|
+
this.messageListener = null;
|
|
786
|
+
this.anonymousFallbackTimer = null;
|
|
787
|
+
this.initialized = false;
|
|
788
|
+
this.lifecycleTrackingInitialized = false;
|
|
789
|
+
this.listeners.clear();
|
|
790
|
+
}
|
|
791
|
+
/** Lazily builds (and rebuilds on auth change) the `ApiClient` bound to the current auth mode. */
|
|
792
|
+
getClient() {
|
|
793
|
+
if (this.client) return this.client;
|
|
794
|
+
const baseUrl = this.getApiUrl();
|
|
795
|
+
this.debug("creating sdk ApiClient", { baseUrl });
|
|
796
|
+
this.client = new ApiClient({
|
|
797
|
+
baseUrl: baseUrl ?? void 0,
|
|
798
|
+
getAccessToken: async () => this.getJwt() ?? void 0,
|
|
799
|
+
getAnonymousId: () => this.getAnonymousId() ?? void 0
|
|
800
|
+
});
|
|
801
|
+
return this.client;
|
|
802
|
+
}
|
|
803
|
+
trackPlay(playTimeSeconds) {
|
|
804
|
+
const gameId = this.getGameId();
|
|
805
|
+
if (!this.canTrack() || !gameId) {
|
|
806
|
+
this.debug("trackPlay skipped; auth is not ready", { hasGameId: Boolean(gameId) });
|
|
807
|
+
return Promise.resolve(false);
|
|
808
|
+
}
|
|
809
|
+
this.debug("trackPlay dispatched", { gameId, playTimeSeconds });
|
|
810
|
+
return this.getClient().trackPlay(gameId, playTimeSeconds);
|
|
811
|
+
}
|
|
812
|
+
trackMatch(matchId, opts) {
|
|
813
|
+
const gameId = this.getGameId();
|
|
814
|
+
if (!this.canTrack() || !gameId) {
|
|
815
|
+
this.debug("trackMatch skipped; auth is not ready", { matchId });
|
|
816
|
+
return Promise.resolve(false);
|
|
817
|
+
}
|
|
818
|
+
this.debug("trackMatch dispatched", { gameId, matchId, ...opts });
|
|
819
|
+
return this.getClient().trackMatch(gameId, {
|
|
820
|
+
matchId,
|
|
821
|
+
matchDurationSeconds: opts.durationSeconds,
|
|
822
|
+
isCompleted: opts.isCompleted,
|
|
823
|
+
isWin: opts.isWin
|
|
824
|
+
});
|
|
825
|
+
}
|
|
826
|
+
emitGameEvent(actionCode, opts) {
|
|
827
|
+
const gameId = this.getGameId();
|
|
828
|
+
if (!this.canTrack() || !gameId) {
|
|
829
|
+
this.debug("emitGameEvent skipped; auth is not ready", { actionCode });
|
|
830
|
+
return Promise.resolve(null);
|
|
831
|
+
}
|
|
832
|
+
this.debug("emitGameEvent dispatched", { gameId, actionCode, ...opts });
|
|
833
|
+
return this.getClient().emit(gameId, actionCode, opts);
|
|
834
|
+
}
|
|
835
|
+
/** Idempotent; auto-emits GAME_STARTED exactly once per distinct auth session (bearer or anonymous). */
|
|
836
|
+
initLifecycleTracking() {
|
|
837
|
+
if (this.lifecycleTrackingInitialized || typeof window === "undefined") return;
|
|
838
|
+
this.lifecycleTrackingInitialized = true;
|
|
839
|
+
this.debug("lifecycle tracking initialized");
|
|
840
|
+
this.subscribe(() => {
|
|
841
|
+
const key = this.getTrackingKey();
|
|
842
|
+
if (!key || this.lastGameStartedKey === key) return;
|
|
843
|
+
this.lastGameStartedKey = key;
|
|
844
|
+
this.debug("auto GAME_STARTED dispatch");
|
|
845
|
+
void this.emitGameEvent("GAME_STARTED");
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
getTrackingKey() {
|
|
849
|
+
const gameId = this.getGameId();
|
|
850
|
+
const apiUrl = this.getApiUrl();
|
|
851
|
+
const identity = this.state.jwt ?? this.state.anonymousId;
|
|
852
|
+
if (!gameId || !apiUrl || !identity) return null;
|
|
853
|
+
return `${apiUrl}
|
|
854
|
+
${gameId}
|
|
855
|
+
${identity}`;
|
|
856
|
+
}
|
|
857
|
+
/** Generates (or restores) a persisted anonymous device id and activates anonymous tracking. */
|
|
858
|
+
activateAnonymousMode() {
|
|
859
|
+
if (this.state.anonymousId) return;
|
|
860
|
+
const key = this.options.anonymousIdStorageKey ?? DEFAULT_ANON_ID_STORAGE_KEY;
|
|
861
|
+
const anonymousId = readStoredAnonymousId(key) ?? generateAnonymousId();
|
|
862
|
+
writeStoredAnonymousId(key, anonymousId);
|
|
863
|
+
this.lastGameStartedKey = null;
|
|
864
|
+
this.setState({ ...this.state, anonymousId, receivedAt: Date.now() });
|
|
865
|
+
this.debug("anonymous tracking mode active", { anonymousId });
|
|
866
|
+
}
|
|
867
|
+
handleAuthMessage(data, origin) {
|
|
868
|
+
if (this.anonymousFallbackTimer !== null) {
|
|
869
|
+
clearTimeout(this.anonymousFallbackTimer);
|
|
870
|
+
this.anonymousFallbackTimer = null;
|
|
871
|
+
}
|
|
872
|
+
const jwt = toOptionalString(data.jwt);
|
|
873
|
+
const gameId = toOptionalString(data.gameId);
|
|
874
|
+
const apiUrl = toOptionalString(data.apiUrl);
|
|
875
|
+
const resolvedGameId = gameId ?? this.getGameId();
|
|
876
|
+
const resolvedApiUrl = apiUrl ?? this.getApiUrl();
|
|
877
|
+
if (!resolvedGameId || !resolvedApiUrl) {
|
|
878
|
+
this.lastGameStartedKey = null;
|
|
879
|
+
this.setState({
|
|
880
|
+
...this.state,
|
|
881
|
+
jwt: null,
|
|
882
|
+
gameId: null,
|
|
883
|
+
apiUrl: null,
|
|
884
|
+
origin,
|
|
885
|
+
receivedAt: Date.now()
|
|
886
|
+
});
|
|
887
|
+
this.debug("auth message missing game identity; falling back to anonymous tracking");
|
|
888
|
+
this.activateAnonymousMode();
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
if (!jwt) {
|
|
892
|
+
this.lastGameStartedKey = null;
|
|
893
|
+
this.setState({
|
|
894
|
+
...this.state,
|
|
895
|
+
jwt: null,
|
|
896
|
+
gameId: resolvedGameId,
|
|
897
|
+
apiUrl: resolvedApiUrl,
|
|
898
|
+
origin,
|
|
899
|
+
receivedAt: Date.now()
|
|
900
|
+
});
|
|
901
|
+
this.debug("auth message missing jwt; falling back to anonymous tracking", {
|
|
902
|
+
gameId: resolvedGameId,
|
|
903
|
+
apiUrl: resolvedApiUrl
|
|
904
|
+
});
|
|
905
|
+
this.activateAnonymousMode();
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
this.lastGameStartedKey = null;
|
|
909
|
+
this.setState({
|
|
910
|
+
jwt,
|
|
911
|
+
gameId,
|
|
912
|
+
apiUrl,
|
|
913
|
+
anonymousId: null,
|
|
914
|
+
origin,
|
|
915
|
+
receivedAt: Date.now()
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
setState(next) {
|
|
919
|
+
this.state = next;
|
|
920
|
+
this.client = null;
|
|
921
|
+
this.debug("auth state updated", {
|
|
922
|
+
gameId: this.getGameId(),
|
|
923
|
+
apiUrl: this.getApiUrl(),
|
|
924
|
+
origin: next.origin,
|
|
925
|
+
hasJwt: Boolean(next.jwt),
|
|
926
|
+
hasAnonymousId: Boolean(next.anonymousId)
|
|
927
|
+
});
|
|
928
|
+
this.listeners.forEach((listener) => listener(next));
|
|
929
|
+
}
|
|
930
|
+
resolveParentOrigin() {
|
|
931
|
+
if (this.options.parentOrigin) return this.options.parentOrigin;
|
|
932
|
+
if (typeof document === "undefined" || !document.referrer) return null;
|
|
933
|
+
try {
|
|
934
|
+
return new URL(document.referrer).origin;
|
|
935
|
+
} catch {
|
|
936
|
+
return null;
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
debug(message, details) {
|
|
940
|
+
this.options.onDebug?.(message, details);
|
|
941
|
+
}
|
|
942
|
+
};
|
|
943
|
+
|
|
944
|
+
export { ApiClient, BrowserLocalStorageAuthStorage, HttpClient, HttpError, LooplayAuth, LooplayIframeAuth, LooplaySDK, LooplaySDKError, MemoryAuthStorage, MissingAuthError, MissingBaseUrlError, NotAuthenticatedError, NotInitializedError, ServiceClient, TelegramAuthProvider };
|
|
631
945
|
//# sourceMappingURL=looplay-sdk.esm.js.map
|
|
632
946
|
//# sourceMappingURL=looplay-sdk.esm.js.map
|