@looplay/sdk 0.8.9 → 0.8.11
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 +167 -59
- package/dist/looplay-sdk.cjs.js.map +1 -1
- package/dist/looplay-sdk.esm.js +167 -59
- package/dist/looplay-sdk.esm.js.map +1 -1
- package/dist/looplay-sdk.min.js +5 -5
- package/dist/looplay-sdk.min.js.map +1 -1
- package/dist/types/apps/api-client.d.ts +27 -4
- package/dist/types/apps/http.d.ts +2 -2
- package/dist/types/apps/service-client.d.ts +8 -0
- package/dist/types/iframe/iframe-auth.d.ts +12 -3
- package/dist/types/looplay-sdk.d.ts +11 -2
- package/dist/types/version.d.ts +1 -1
- package/package.json +1 -1
package/dist/looplay-sdk.esm.js
CHANGED
|
@@ -137,8 +137,45 @@ var LooplayAuth = class {
|
|
|
137
137
|
}
|
|
138
138
|
};
|
|
139
139
|
|
|
140
|
+
// src/constants.ts
|
|
141
|
+
var DEFAULT_API_URL = "https://miniapp-api.looplay.gg";
|
|
142
|
+
function resolveEnvParentOrigin() {
|
|
143
|
+
try {
|
|
144
|
+
if (typeof import.meta !== "undefined" && import.meta.env?.VITE_PARENT_ORIGIN) {
|
|
145
|
+
const val = import.meta.env.VITE_PARENT_ORIGIN;
|
|
146
|
+
if (typeof val === "string" && val.trim().length > 0) return val.trim();
|
|
147
|
+
}
|
|
148
|
+
} catch {
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
if (typeof process !== "undefined" && process.env?.VITE_PARENT_ORIGIN) {
|
|
152
|
+
const val = process.env.VITE_PARENT_ORIGIN;
|
|
153
|
+
if (typeof val === "string" && val.trim().length > 0) return val.trim();
|
|
154
|
+
}
|
|
155
|
+
} catch {
|
|
156
|
+
}
|
|
157
|
+
return void 0;
|
|
158
|
+
}
|
|
159
|
+
function resolveEnvApiUrl() {
|
|
160
|
+
try {
|
|
161
|
+
if (typeof import.meta !== "undefined" && import.meta.env) {
|
|
162
|
+
const val = import.meta.env.VITE_API_URL ?? import.meta.env.VITE_LOOPLAY_API_URL;
|
|
163
|
+
if (typeof val === "string" && val.trim().length > 0) return val.trim();
|
|
164
|
+
}
|
|
165
|
+
} catch {
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
if (typeof process !== "undefined" && process.env) {
|
|
169
|
+
const val = process.env.VITE_API_URL ?? process.env.VITE_LOOPLAY_API_URL;
|
|
170
|
+
if (typeof val === "string" && val.trim().length > 0) return val.trim();
|
|
171
|
+
}
|
|
172
|
+
} catch {
|
|
173
|
+
}
|
|
174
|
+
return void 0;
|
|
175
|
+
}
|
|
176
|
+
|
|
140
177
|
// src/version.ts
|
|
141
|
-
var LOOPLAY_SDK_VERSION = "0.8.
|
|
178
|
+
var LOOPLAY_SDK_VERSION = "0.8.11";
|
|
142
179
|
|
|
143
180
|
// src/apps/http.ts
|
|
144
181
|
function getFetchFn(fetchOverride) {
|
|
@@ -164,8 +201,9 @@ var HttpClient = class {
|
|
|
164
201
|
baseUrl;
|
|
165
202
|
fetchFn;
|
|
166
203
|
defaultHeaders;
|
|
167
|
-
constructor(options) {
|
|
168
|
-
|
|
204
|
+
constructor(options = {}) {
|
|
205
|
+
const rawBaseUrl = typeof options.baseUrl === "string" && options.baseUrl.trim().length > 0 ? options.baseUrl.trim() : resolveEnvApiUrl() ?? DEFAULT_API_URL;
|
|
206
|
+
this.baseUrl = rawBaseUrl.replace(/\/$/, "");
|
|
169
207
|
this.fetchFn = getFetchFn(options.fetch);
|
|
170
208
|
this.defaultHeaders = {
|
|
171
209
|
"x-looplay-sdk-version": LOOPLAY_SDK_VERSION,
|
|
@@ -231,9 +269,18 @@ var HttpClient = class {
|
|
|
231
269
|
// src/apps/service-client.ts
|
|
232
270
|
var ServiceClient = class {
|
|
233
271
|
http;
|
|
272
|
+
playSessionTokens = /* @__PURE__ */ new Map();
|
|
273
|
+
onPlaySessionIssuedListener;
|
|
234
274
|
constructor(options) {
|
|
235
275
|
this.http = new HttpClient(options);
|
|
236
276
|
}
|
|
277
|
+
/**
|
|
278
|
+
* Internal hook for ApiClient to subscribe to issued/renewed play sessions.
|
|
279
|
+
* @internal
|
|
280
|
+
*/
|
|
281
|
+
_setOnPlaySessionIssued(listener) {
|
|
282
|
+
this.onPlaySessionIssuedListener = listener;
|
|
283
|
+
}
|
|
237
284
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
238
285
|
// Auth
|
|
239
286
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -267,11 +314,16 @@ var ServiceClient = class {
|
|
|
267
314
|
}
|
|
268
315
|
/** Signs a fresh `playSessionToken` — required by `completePlaySession`/`completeGameplayMatch`/`recordGameplayAction`. */
|
|
269
316
|
async startPlaySession(gameKey, auth = {}, body = {}) {
|
|
270
|
-
|
|
317
|
+
const dto = await this.http.request("POST", "/sdk/games/play-sessions/start", {
|
|
271
318
|
...auth,
|
|
272
319
|
headers: { "x-game-key": gameKey, ...this.trackingHeaders(auth) },
|
|
273
320
|
body
|
|
274
321
|
});
|
|
322
|
+
if (dto?.playSessionId && dto?.playSessionToken) {
|
|
323
|
+
this.playSessionTokens.set(dto.playSessionId, dto.playSessionToken);
|
|
324
|
+
}
|
|
325
|
+
this.onPlaySessionIssuedListener?.(dto, gameKey, auth);
|
|
326
|
+
return dto;
|
|
275
327
|
}
|
|
276
328
|
/**
|
|
277
329
|
* Re-issues a fresh `playSessionToken` for the SAME `playSessionId` — call
|
|
@@ -280,33 +332,44 @@ var ServiceClient = class {
|
|
|
280
332
|
* long-running sessions keep a single `playSessionId` throughout.
|
|
281
333
|
*/
|
|
282
334
|
async renewPlaySession(gameKey, auth = {}, body) {
|
|
283
|
-
|
|
335
|
+
const dto = await this.http.request("POST", "/sdk/games/play-sessions/renew", {
|
|
284
336
|
...auth,
|
|
285
337
|
headers: { "x-game-key": gameKey, ...this.trackingHeaders(auth) },
|
|
286
338
|
body
|
|
287
339
|
});
|
|
340
|
+
if (dto?.playSessionId && dto?.playSessionToken) {
|
|
341
|
+
this.playSessionTokens.set(dto.playSessionId, dto.playSessionToken);
|
|
342
|
+
}
|
|
343
|
+
this.onPlaySessionIssuedListener?.(dto, gameKey, auth);
|
|
344
|
+
return dto;
|
|
288
345
|
}
|
|
289
346
|
async completePlaySession(gameKey, auth, body) {
|
|
347
|
+
const playSessionToken = body.playSessionToken || (body.playSessionId ? this.playSessionTokens.get(body.playSessionId) : void 0);
|
|
348
|
+
const resolvedBody = playSessionToken ? { ...body, playSessionToken } : body;
|
|
290
349
|
await this.http.request("POST", "/sdk/games/play-sessions/complete", {
|
|
291
350
|
...auth,
|
|
292
351
|
headers: { "x-game-key": gameKey, ...this.trackingHeaders(auth) },
|
|
293
|
-
body
|
|
352
|
+
body: resolvedBody
|
|
294
353
|
});
|
|
295
354
|
return true;
|
|
296
355
|
}
|
|
297
356
|
async completeGameplayMatch(gameKey, auth, body) {
|
|
357
|
+
const playSessionToken = body.playSessionToken || (body.playSessionId ? this.playSessionTokens.get(body.playSessionId) : void 0);
|
|
358
|
+
const resolvedBody = playSessionToken ? { ...body, playSessionToken } : body;
|
|
298
359
|
await this.http.request("POST", "/sdk/games/matches/complete", {
|
|
299
360
|
...auth,
|
|
300
361
|
headers: { "x-game-key": gameKey, ...this.trackingHeaders(auth) },
|
|
301
|
-
body
|
|
362
|
+
body: resolvedBody
|
|
302
363
|
});
|
|
303
364
|
return true;
|
|
304
365
|
}
|
|
305
366
|
async recordGameplayAction(gameKey, auth, body) {
|
|
367
|
+
const playSessionToken = body.playSessionToken || (body.playSessionId ? this.playSessionTokens.get(body.playSessionId) : void 0);
|
|
368
|
+
const resolvedBody = playSessionToken ? { ...body, playSessionToken } : body;
|
|
306
369
|
return this.http.request("POST", "/sdk/games/actions/record", {
|
|
307
370
|
...auth,
|
|
308
371
|
headers: { "x-game-key": gameKey, ...this.trackingHeaders(auth) },
|
|
309
|
-
body
|
|
372
|
+
body: resolvedBody
|
|
310
373
|
});
|
|
311
374
|
}
|
|
312
375
|
/**
|
|
@@ -461,13 +524,26 @@ var ApiClient = class {
|
|
|
461
524
|
playSession;
|
|
462
525
|
playSessionPromiseKey;
|
|
463
526
|
playSessionPromise;
|
|
464
|
-
constructor(options) {
|
|
465
|
-
|
|
527
|
+
constructor(options = {}) {
|
|
528
|
+
const baseUrl = typeof options.baseUrl === "string" && options.baseUrl.trim().length > 0 ? options.baseUrl.trim() : resolveEnvApiUrl() ?? DEFAULT_API_URL;
|
|
529
|
+
if (!baseUrl) throw new MissingBaseUrlError();
|
|
466
530
|
this.raw = new ServiceClient({
|
|
467
|
-
baseUrl
|
|
531
|
+
baseUrl,
|
|
468
532
|
fetch: options.fetch,
|
|
469
533
|
defaultHeaders: options.defaultHeaders
|
|
470
534
|
});
|
|
535
|
+
this.raw._setOnPlaySessionIssued((dto, gameKey, auth) => {
|
|
536
|
+
if (dto?.playSessionId && dto?.playSessionToken) {
|
|
537
|
+
this.currentPlaySessionId = dto.playSessionId;
|
|
538
|
+
this.playSession = {
|
|
539
|
+
cacheKey: [gameKey, dto.playSessionId, this.getTrackingAuthKey(auth)].join(":"),
|
|
540
|
+
gameKey,
|
|
541
|
+
playSessionId: dto.playSessionId,
|
|
542
|
+
playSessionToken: dto.playSessionToken,
|
|
543
|
+
expiresAtMs: dto.expiresAt ? new Date(dto.expiresAt).getTime() : Date.now() + 2 * 3600 * 1e3
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
});
|
|
471
547
|
this.getAccessToken = options.getAccessToken;
|
|
472
548
|
this.getAnonymousId = options.getAnonymousId;
|
|
473
549
|
}
|
|
@@ -599,6 +675,31 @@ var ApiClient = class {
|
|
|
599
675
|
this.playSession = void 0;
|
|
600
676
|
return this.currentPlaySessionId;
|
|
601
677
|
}
|
|
678
|
+
/**
|
|
679
|
+
* Starts a new play session on the server and caches the signed immediately.
|
|
680
|
+
*/
|
|
681
|
+
async startPlaySessionAsync(gameKey, body = {}) {
|
|
682
|
+
const auth = await this.resolveTrackingAuth();
|
|
683
|
+
const playSessionId = body.playSessionId ?? this.currentPlaySessionId ?? this.startPlaySession();
|
|
684
|
+
return this.raw.startPlaySession(gameKey, auth, { ...body, playSessionId });
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* Explicitly sets or updates the active play session token cache.
|
|
688
|
+
*/
|
|
689
|
+
setPlaySession(playSession) {
|
|
690
|
+
this.currentPlaySessionId = playSession.playSessionId;
|
|
691
|
+
this.playSession = {
|
|
692
|
+
cacheKey: [playSession.gameKey, playSession.playSessionId].join(":"),
|
|
693
|
+
gameKey: playSession.gameKey,
|
|
694
|
+
playSessionId: playSession.playSessionId,
|
|
695
|
+
playSessionToken: playSession.playSessionToken,
|
|
696
|
+
expiresAtMs: playSession.expiresAtMs ?? Date.now() + 2 * 3600 * 1e3
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
/** Returns the active cached play session, or undefined if none has been issued yet. */
|
|
700
|
+
getCurrentPlaySession() {
|
|
701
|
+
return this.playSession;
|
|
702
|
+
}
|
|
602
703
|
async trackPlay(gameKey, playTimeSeconds) {
|
|
603
704
|
const auth = await this.resolveTrackingAuth();
|
|
604
705
|
const playSessionId = this.currentPlaySessionId ?? this.startPlaySession();
|
|
@@ -682,43 +783,6 @@ var ApiClient = class {
|
|
|
682
783
|
}
|
|
683
784
|
};
|
|
684
785
|
|
|
685
|
-
// src/constants.ts
|
|
686
|
-
var DEFAULT_API_URL = "https://miniapp-api.looplay.gg";
|
|
687
|
-
function resolveEnvParentOrigin() {
|
|
688
|
-
try {
|
|
689
|
-
if (typeof import.meta !== "undefined" && import.meta.env?.VITE_PARENT_ORIGIN) {
|
|
690
|
-
const val = import.meta.env.VITE_PARENT_ORIGIN;
|
|
691
|
-
if (typeof val === "string" && val.trim().length > 0) return val.trim();
|
|
692
|
-
}
|
|
693
|
-
} catch {
|
|
694
|
-
}
|
|
695
|
-
try {
|
|
696
|
-
if (typeof process !== "undefined" && process.env?.VITE_PARENT_ORIGIN) {
|
|
697
|
-
const val = process.env.VITE_PARENT_ORIGIN;
|
|
698
|
-
if (typeof val === "string" && val.trim().length > 0) return val.trim();
|
|
699
|
-
}
|
|
700
|
-
} catch {
|
|
701
|
-
}
|
|
702
|
-
return void 0;
|
|
703
|
-
}
|
|
704
|
-
function resolveEnvApiUrl() {
|
|
705
|
-
try {
|
|
706
|
-
if (typeof import.meta !== "undefined" && import.meta.env) {
|
|
707
|
-
const val = import.meta.env.VITE_API_URL ?? import.meta.env.VITE_LOOPLAY_API_URL;
|
|
708
|
-
if (typeof val === "string" && val.trim().length > 0) return val.trim();
|
|
709
|
-
}
|
|
710
|
-
} catch {
|
|
711
|
-
}
|
|
712
|
-
try {
|
|
713
|
-
if (typeof process !== "undefined" && process.env) {
|
|
714
|
-
const val = process.env.VITE_API_URL ?? process.env.VITE_LOOPLAY_API_URL;
|
|
715
|
-
if (typeof val === "string" && val.trim().length > 0) return val.trim();
|
|
716
|
-
}
|
|
717
|
-
} catch {
|
|
718
|
-
}
|
|
719
|
-
return void 0;
|
|
720
|
-
}
|
|
721
|
-
|
|
722
786
|
// src/looplay-sdk.ts
|
|
723
787
|
var LooplaySDK = class {
|
|
724
788
|
auth;
|
|
@@ -728,21 +792,19 @@ var LooplaySDK = class {
|
|
|
728
792
|
constructor(options = {}) {
|
|
729
793
|
const {
|
|
730
794
|
auth,
|
|
731
|
-
baseUrl = resolveEnvApiUrl() ?? DEFAULT_API_URL,
|
|
732
795
|
fetch,
|
|
733
796
|
defaultHeaders
|
|
734
797
|
} = options;
|
|
798
|
+
const baseUrl = typeof options.baseUrl === "string" && options.baseUrl.trim().length > 0 ? options.baseUrl.trim() : resolveEnvApiUrl() ?? DEFAULT_API_URL;
|
|
735
799
|
if (auth) {
|
|
736
800
|
this.auth = new LooplayAuth(auth);
|
|
737
801
|
}
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
});
|
|
745
|
-
}
|
|
802
|
+
this.api = new ApiClient({
|
|
803
|
+
baseUrl,
|
|
804
|
+
fetch,
|
|
805
|
+
defaultHeaders,
|
|
806
|
+
getAccessToken: async () => this.auth?.getAccessToken()
|
|
807
|
+
});
|
|
746
808
|
}
|
|
747
809
|
async init(params) {
|
|
748
810
|
this.gameId = params.gameId;
|
|
@@ -757,6 +819,15 @@ var LooplaySDK = class {
|
|
|
757
819
|
getGameId() {
|
|
758
820
|
return this.gameId;
|
|
759
821
|
}
|
|
822
|
+
get currentPlaySessionId() {
|
|
823
|
+
return this.api?.currentPlaySessionId;
|
|
824
|
+
}
|
|
825
|
+
get playSession() {
|
|
826
|
+
return this.api?.playSession;
|
|
827
|
+
}
|
|
828
|
+
unsafeRaw() {
|
|
829
|
+
return this.api?.unsafeRaw();
|
|
830
|
+
}
|
|
760
831
|
async getMyProfile() {
|
|
761
832
|
this.assertInitialized();
|
|
762
833
|
if (!this.api) throw new MissingBaseUrlError();
|
|
@@ -775,6 +846,16 @@ var LooplaySDK = class {
|
|
|
775
846
|
if (!this.api) throw new MissingBaseUrlError();
|
|
776
847
|
return this.api.startPlaySession();
|
|
777
848
|
}
|
|
849
|
+
/**
|
|
850
|
+
* Starts a new play session asynchronously on the backend; returns the issued PlaySessionDto
|
|
851
|
+
* (containing playSessionId and playSessionToken).
|
|
852
|
+
*/
|
|
853
|
+
async startPlaySessionAsync(body) {
|
|
854
|
+
this.assertInitialized();
|
|
855
|
+
if (!this.api) throw new MissingBaseUrlError();
|
|
856
|
+
if (!this.gameId) throw new NotInitializedError();
|
|
857
|
+
return this.api.startPlaySessionAsync(this.gameId, body);
|
|
858
|
+
}
|
|
778
859
|
async trackPlay(playTimeSeconds) {
|
|
779
860
|
this.assertInitialized();
|
|
780
861
|
if (!this.api) throw new MissingBaseUrlError();
|
|
@@ -1004,7 +1085,8 @@ var LooplayIframeAuth = class {
|
|
|
1004
1085
|
return this.state.jwt;
|
|
1005
1086
|
}
|
|
1006
1087
|
getApiUrl() {
|
|
1007
|
-
|
|
1088
|
+
const raw = toOptionalString(this.state.apiUrl) ?? toOptionalString(this.options.apiUrl) ?? resolveEnvApiUrl() ?? DEFAULT_API_URL;
|
|
1089
|
+
return raw.trim();
|
|
1008
1090
|
}
|
|
1009
1091
|
/** Resolves to the configured `appId`, falling back to whatever the parent pushed as `gameId`. */
|
|
1010
1092
|
getGameId() {
|
|
@@ -1150,6 +1232,15 @@ var LooplayIframeAuth = class {
|
|
|
1150
1232
|
});
|
|
1151
1233
|
return this.client;
|
|
1152
1234
|
}
|
|
1235
|
+
get currentPlaySessionId() {
|
|
1236
|
+
return this.getClient().currentPlaySessionId;
|
|
1237
|
+
}
|
|
1238
|
+
get playSession() {
|
|
1239
|
+
return this.getClient().playSession;
|
|
1240
|
+
}
|
|
1241
|
+
unsafeRaw() {
|
|
1242
|
+
return this.getClient().unsafeRaw();
|
|
1243
|
+
}
|
|
1153
1244
|
/** Call once when the game view opens, before any play/match tracking. */
|
|
1154
1245
|
trackView() {
|
|
1155
1246
|
const gameId = this.getGameId();
|
|
@@ -1166,6 +1257,20 @@ var LooplayIframeAuth = class {
|
|
|
1166
1257
|
startPlaySession() {
|
|
1167
1258
|
return this.getClient().startPlaySession();
|
|
1168
1259
|
}
|
|
1260
|
+
/**
|
|
1261
|
+
* Starts a new play session asynchronously on the backend; returns the issued PlaySessionDto
|
|
1262
|
+
* (containing playSessionId and playSessionToken) or null if auth/tracking is not ready.
|
|
1263
|
+
*/
|
|
1264
|
+
async startPlaySessionAsync(body) {
|
|
1265
|
+
const gameId = this.getGameId();
|
|
1266
|
+
if (!this.canTrack() || !gameId) {
|
|
1267
|
+
this.debug("startPlaySessionAsync skipped; auth is not ready", {
|
|
1268
|
+
hasGameId: Boolean(gameId)
|
|
1269
|
+
});
|
|
1270
|
+
return null;
|
|
1271
|
+
}
|
|
1272
|
+
return this.getClient().startPlaySessionAsync(gameId, body);
|
|
1273
|
+
}
|
|
1169
1274
|
trackPlay(playTimeSeconds) {
|
|
1170
1275
|
const gameId = this.getGameId();
|
|
1171
1276
|
if (!this.canTrack() || !gameId) {
|
|
@@ -1379,7 +1484,10 @@ ${gameId}`;
|
|
|
1379
1484
|
}
|
|
1380
1485
|
}
|
|
1381
1486
|
resolveParentOrigin() {
|
|
1382
|
-
if (this.options.parentOrigin)
|
|
1487
|
+
if (this.options.parentOrigin) {
|
|
1488
|
+
const opt = toOptionalString(this.options.parentOrigin);
|
|
1489
|
+
if (opt) return opt;
|
|
1490
|
+
}
|
|
1383
1491
|
const envOrigin = resolveEnvParentOrigin();
|
|
1384
1492
|
if (envOrigin) return envOrigin;
|
|
1385
1493
|
if (typeof document === "undefined" || !document.referrer) return null;
|