@looplay/sdk 0.6.0 → 0.8.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 +221 -4
- package/dist/looplay-sdk-realtime.cjs.js +73 -0
- package/dist/looplay-sdk-realtime.cjs.js.map +1 -0
- package/dist/looplay-sdk-realtime.esm.js +71 -0
- package/dist/looplay-sdk-realtime.esm.js.map +1 -0
- package/dist/looplay-sdk-realtime.min.js +3 -0
- package/dist/looplay-sdk-realtime.min.js.map +1 -0
- package/dist/looplay-sdk.cjs.js +133 -162
- package/dist/looplay-sdk.cjs.js.map +1 -1
- package/dist/looplay-sdk.esm.js +134 -162
- package/dist/looplay-sdk.esm.js.map +1 -1
- package/dist/looplay-sdk.min.js +2 -2
- package/dist/looplay-sdk.min.js.map +1 -1
- package/dist/types/apps/LooplaySDK.types.d.ts +54 -6
- package/dist/types/apps/api-client.d.ts +22 -16
- package/dist/types/apps/service-client.d.ts +33 -22
- package/dist/types/apps/ws-client.d.ts +35 -0
- package/dist/types/errors.d.ts +0 -3
- package/dist/types/realtime.d.ts +9 -0
- package/dist/types/types.d.ts +2 -1
- package/package.json +17 -1
package/dist/looplay-sdk.esm.js
CHANGED
|
@@ -29,12 +29,6 @@ var NotAuthenticatedError = class extends LooplaySDKError {
|
|
|
29
29
|
this.name = "NotAuthenticatedError";
|
|
30
30
|
}
|
|
31
31
|
};
|
|
32
|
-
var MissingStoreError = class extends LooplaySDKError {
|
|
33
|
-
constructor(gameId) {
|
|
34
|
-
super(`Game ${gameId} has no storefront configured.`);
|
|
35
|
-
this.name = "MissingStoreError";
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
32
|
|
|
39
33
|
// src/auth/storage.ts
|
|
40
34
|
var MemoryAuthStorage = class {
|
|
@@ -250,54 +244,49 @@ var ServiceClient = class {
|
|
|
250
244
|
return this.http.request("POST", "/account/logout", { body });
|
|
251
245
|
}
|
|
252
246
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
253
|
-
// Games
|
|
247
|
+
// Games — one SDK integration = one game, resolved on every call from the
|
|
248
|
+
// public `x-game-key` header (the game's `appId`). There is no multi-game
|
|
249
|
+
// catalog browsing here (list/search/detail across games) and no `:id`/
|
|
250
|
+
// `storeId` path segments — that's the app-facing surface, out of scope
|
|
251
|
+
// for this per-game SDK. Never use the creator-secret tier
|
|
252
|
+
// (`x-creator-key`/`x-game-secret`) from client/browser code — that would
|
|
253
|
+
// leak the secret to every player.
|
|
254
254
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
255
|
-
async
|
|
256
|
-
|
|
257
|
-
}
|
|
258
|
-
async getGameDetail(gameId, bearerToken) {
|
|
259
|
-
return this.http.request("GET", `/sdk/games/${encodeURIComponent(gameId)}`, {
|
|
260
|
-
bearerToken
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
async listRecentPlayed(bearerToken, query) {
|
|
264
|
-
return this.http.request("GET", "/sdk/games/recent-play", { bearerToken, query });
|
|
265
|
-
}
|
|
266
|
-
async recordGameView(auth, gameId) {
|
|
267
|
-
await this.http.request("POST", `/sdk/games/${encodeURIComponent(gameId)}/views/record`, {
|
|
255
|
+
async recordGameView(gameKey, auth = {}) {
|
|
256
|
+
await this.http.request("POST", "/sdk/games/views/record", {
|
|
268
257
|
...auth,
|
|
269
|
-
headers: this.trackingHeaders(auth)
|
|
258
|
+
headers: { "x-game-key": gameKey, ...this.trackingHeaders(auth) }
|
|
270
259
|
});
|
|
271
260
|
return true;
|
|
272
261
|
}
|
|
273
262
|
/** Signs a fresh `attemptToken` — required by `completeGameplayAttempt`/`completeGameplayMatch`/`recordGameplayAction`. */
|
|
274
|
-
async startGameplayAttempt(
|
|
275
|
-
return this.http.request("POST",
|
|
263
|
+
async startGameplayAttempt(gameKey, auth = {}, body = {}) {
|
|
264
|
+
return this.http.request("POST", "/sdk/games/attempts/start", {
|
|
276
265
|
...auth,
|
|
277
|
-
headers: this.trackingHeaders(auth),
|
|
266
|
+
headers: { "x-game-key": gameKey, ...this.trackingHeaders(auth) },
|
|
278
267
|
body
|
|
279
268
|
});
|
|
280
269
|
}
|
|
281
|
-
async completeGameplayAttempt(
|
|
282
|
-
await this.http.request("POST",
|
|
270
|
+
async completeGameplayAttempt(gameKey, auth, body) {
|
|
271
|
+
await this.http.request("POST", "/sdk/games/attempts/complete", {
|
|
283
272
|
...auth,
|
|
284
|
-
headers: this.trackingHeaders(auth),
|
|
273
|
+
headers: { "x-game-key": gameKey, ...this.trackingHeaders(auth) },
|
|
285
274
|
body
|
|
286
275
|
});
|
|
287
276
|
return true;
|
|
288
277
|
}
|
|
289
|
-
async completeGameplayMatch(
|
|
290
|
-
await this.http.request("POST",
|
|
278
|
+
async completeGameplayMatch(gameKey, auth, body) {
|
|
279
|
+
await this.http.request("POST", "/sdk/games/matches/complete", {
|
|
291
280
|
...auth,
|
|
292
|
-
headers: this.trackingHeaders(auth),
|
|
281
|
+
headers: { "x-game-key": gameKey, ...this.trackingHeaders(auth) },
|
|
293
282
|
body
|
|
294
283
|
});
|
|
295
284
|
return true;
|
|
296
285
|
}
|
|
297
|
-
async recordGameplayAction(
|
|
298
|
-
return this.http.request("POST",
|
|
286
|
+
async recordGameplayAction(gameKey, auth, body) {
|
|
287
|
+
return this.http.request("POST", "/sdk/games/actions/record", {
|
|
299
288
|
...auth,
|
|
300
|
-
headers: this.trackingHeaders(auth),
|
|
289
|
+
headers: { "x-game-key": gameKey, ...this.trackingHeaders(auth) },
|
|
301
290
|
body
|
|
302
291
|
});
|
|
303
292
|
}
|
|
@@ -317,104 +306,90 @@ var ServiceClient = class {
|
|
|
317
306
|
"x-looplay-anon-token": auth.anonTrackingToken
|
|
318
307
|
};
|
|
319
308
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
326
|
-
async getStoreByStoreId(storeId) {
|
|
327
|
-
return this.http.request("GET", `/sdk/games/store/${encodeURIComponent(storeId)}`);
|
|
309
|
+
/** Public storefront (sections + offers) for the integration's game. Read-only. */
|
|
310
|
+
async getStore(gameKey) {
|
|
311
|
+
return this.http.request("GET", "/sdk/games/store/current", {
|
|
312
|
+
headers: { "x-game-key": gameKey }
|
|
313
|
+
});
|
|
328
314
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
315
|
+
/** Public catalog of purchasable/ownable assets for the game. Read-only. */
|
|
316
|
+
async listGameAssets(gameKey) {
|
|
317
|
+
return this.http.request("GET", "/sdk/games/store/assets", {
|
|
318
|
+
headers: { "x-game-key": gameKey }
|
|
332
319
|
});
|
|
333
320
|
}
|
|
334
|
-
|
|
335
|
-
|
|
321
|
+
/** Assets the authenticated player already owns for this game. */
|
|
322
|
+
async listMyGameAssets(bearerToken, gameKey) {
|
|
323
|
+
return this.http.request("GET", "/sdk/games/store/assets/me", {
|
|
336
324
|
bearerToken,
|
|
337
|
-
headers: { "x-game-
|
|
338
|
-
body
|
|
325
|
+
headers: { "x-game-key": gameKey }
|
|
339
326
|
});
|
|
340
327
|
}
|
|
341
|
-
|
|
342
|
-
|
|
328
|
+
/** The authenticated player's past store purchases for this game. */
|
|
329
|
+
async listMyStorePurchases(bearerToken, gameKey) {
|
|
330
|
+
return this.http.request("GET", "/sdk/games/store/purchases/me", {
|
|
343
331
|
bearerToken,
|
|
344
|
-
headers: { "x-game-
|
|
345
|
-
body
|
|
332
|
+
headers: { "x-game-key": gameKey }
|
|
346
333
|
});
|
|
347
334
|
}
|
|
348
335
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
349
|
-
//
|
|
350
|
-
//
|
|
351
|
-
//
|
|
352
|
-
//
|
|
353
|
-
//
|
|
336
|
+
// Self-serve purchase (public tier) — same trust level as tracking: public
|
|
337
|
+
// `x-game-key` + the purchasing player's own bearer token, no backend or
|
|
338
|
+
// secret pair required. Safe to call directly from client/browser code —
|
|
339
|
+
// `checkoutToken` (short-lived, server-signed) plays the same role as
|
|
340
|
+
// `attemptToken` on the tracking routes. `ApiClient.purchaseStoreOffer`
|
|
341
|
+
// wraps this pair for you.
|
|
354
342
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
return true;
|
|
361
|
-
}
|
|
362
|
-
async startGameplayAttemptForGameKey(gameKey, auth = {}, body = {}) {
|
|
363
|
-
return this.http.request("POST", "/sdk/games/runtime/attempts/start", {
|
|
364
|
-
...auth,
|
|
365
|
-
headers: { "x-game-key": gameKey, ...this.trackingHeaders(auth) },
|
|
343
|
+
/** Signs a `checkoutToken` for one purchase — required by `purchaseMyStoreOffer`. */
|
|
344
|
+
async createMyStoreCheckoutIntent(gameKey, bearerToken, body, trackingSessionId) {
|
|
345
|
+
return this.http.request("POST", "/sdk/games/store/checkout-intent/me", {
|
|
346
|
+
bearerToken,
|
|
347
|
+
headers: { "x-game-key": gameKey, "x-game-tracking-session-id": trackingSessionId },
|
|
366
348
|
body
|
|
367
349
|
});
|
|
368
350
|
}
|
|
369
|
-
async
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
headers: { "x-game-key": gameKey,
|
|
351
|
+
async purchaseMyStoreOffer(gameKey, bearerToken, body, trackingSessionId) {
|
|
352
|
+
return this.http.request("POST", "/sdk/games/store/purchase/me", {
|
|
353
|
+
bearerToken,
|
|
354
|
+
headers: { "x-game-key": gameKey, "x-game-tracking-session-id": trackingSessionId },
|
|
373
355
|
body
|
|
374
356
|
});
|
|
375
|
-
return true;
|
|
376
357
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
358
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
359
|
+
// Server-to-server (secret pair) — moves real coin balance. Requires the
|
|
360
|
+
// creator+game *secret* pair (`x-creator-key`/`x-game-secret`), distinct
|
|
361
|
+
// from the public `x-game-key` used everywhere above. Call these ONLY
|
|
362
|
+
// from your own backend (e.g. a Node service holding the secret pair) —
|
|
363
|
+
// never from client/browser code, or the secret is exposed to every
|
|
364
|
+
// player. `ApiClient` deliberately does not expose these — it auto-injects
|
|
365
|
+
// a *player's* access token for browser-facing calls and has no concept
|
|
366
|
+
// of your creator secret. Prefer the self-serve tier above unless you
|
|
367
|
+
// specifically need to initiate a purchase from your backend without the
|
|
368
|
+
// player present.
|
|
369
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
370
|
+
/** Signs a `checkoutToken` for one purchase — required by `purchaseGameStoreOffer`. */
|
|
371
|
+
async createGameStoreCheckoutIntent(auth, body) {
|
|
372
|
+
return this.http.request("POST", "/sdk/games/store/checkout-intent", {
|
|
373
|
+
bearerToken: auth.bearerToken,
|
|
374
|
+
headers: {
|
|
375
|
+
"x-creator-key": auth.creatorKey,
|
|
376
|
+
"x-game-secret": auth.gameSecret,
|
|
377
|
+
"x-game-tracking-session-id": auth.trackingSessionId
|
|
378
|
+
},
|
|
381
379
|
body
|
|
382
380
|
});
|
|
383
|
-
return true;
|
|
384
381
|
}
|
|
385
|
-
async
|
|
386
|
-
return this.http.request("POST", "/sdk/games/
|
|
387
|
-
|
|
388
|
-
headers: {
|
|
382
|
+
async purchaseGameStoreOffer(auth, body) {
|
|
383
|
+
return this.http.request("POST", "/sdk/games/store/purchase", {
|
|
384
|
+
bearerToken: auth.bearerToken,
|
|
385
|
+
headers: {
|
|
386
|
+
"x-creator-key": auth.creatorKey,
|
|
387
|
+
"x-game-secret": auth.gameSecret,
|
|
388
|
+
"x-game-tracking-session-id": auth.trackingSessionId
|
|
389
|
+
},
|
|
389
390
|
body
|
|
390
391
|
});
|
|
391
392
|
}
|
|
392
|
-
async getStoreForGameKey(gameKey) {
|
|
393
|
-
return this.http.request("GET", "/sdk/games/store/current", {
|
|
394
|
-
headers: { "x-game-key": gameKey }
|
|
395
|
-
});
|
|
396
|
-
}
|
|
397
|
-
async listGameAssetsForGameKey(gameKey) {
|
|
398
|
-
return this.http.request("GET", "/sdk/games/store/assets", {
|
|
399
|
-
headers: { "x-game-key": gameKey }
|
|
400
|
-
});
|
|
401
|
-
}
|
|
402
|
-
async listMyOwnedAssetsForGameKey(bearerToken, gameKey) {
|
|
403
|
-
return this.http.request("GET", "/sdk/games/store/assets/me", {
|
|
404
|
-
bearerToken,
|
|
405
|
-
headers: { "x-game-key": gameKey }
|
|
406
|
-
});
|
|
407
|
-
}
|
|
408
|
-
async listMyStorePurchasesForGameKey(bearerToken, gameKey) {
|
|
409
|
-
return this.http.request("GET", "/sdk/games/store/purchases/me", {
|
|
410
|
-
bearerToken,
|
|
411
|
-
headers: { "x-game-key": gameKey }
|
|
412
|
-
});
|
|
413
|
-
}
|
|
414
|
-
// No public/anonymous purchase route exists for the runtime tier —
|
|
415
|
-
// purchases move real coin balance and always require the JWT tier
|
|
416
|
-
// (createStoreCheckoutIntent/purchaseStoreOffer above) or the
|
|
417
|
-
// creator-secret tier, which this SDK intentionally never wires up.
|
|
418
393
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
419
394
|
// Balance
|
|
420
395
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -489,15 +464,15 @@ var ApiClient = class {
|
|
|
489
464
|
this.getAccessToken = options.getAccessToken;
|
|
490
465
|
this.getAnonymousId = options.getAnonymousId;
|
|
491
466
|
}
|
|
492
|
-
/** Expose the underlying route-level client (requires manual bearerToken passing). */
|
|
467
|
+
/** Expose the underlying route-level client (requires manual bearerToken/gameKey passing). */
|
|
493
468
|
unsafeRaw() {
|
|
494
469
|
return this.raw;
|
|
495
470
|
}
|
|
496
|
-
//
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
//
|
|
471
|
+
// Real-time (balance_change / store_purchase_completed WebSocket events)
|
|
472
|
+
// deliberately lives outside this class — import `WsClient` from
|
|
473
|
+
// '@looplay/sdk/realtime' and construct it with the same `getAccessToken`
|
|
474
|
+
// you passed here. Keeps the socket.io-client dependency (and its bundle
|
|
475
|
+
// weight) out of every consumer that doesn't need real-time updates.
|
|
501
476
|
async requireToken() {
|
|
502
477
|
const token = await this.getAccessToken?.();
|
|
503
478
|
if (!token) throw new NotAuthenticatedError();
|
|
@@ -553,15 +528,15 @@ var ApiClient = class {
|
|
|
553
528
|
* swallow failures, unlike `ensureTrackingSession`, since these calls
|
|
554
529
|
* are rejected outright without a valid token.
|
|
555
530
|
*/
|
|
556
|
-
async ensureGameplayAttempt(
|
|
531
|
+
async ensureGameplayAttempt(gameKey, auth, attemptId) {
|
|
557
532
|
const now = Date.now();
|
|
558
|
-
if (this.gameplayAttempt && this.gameplayAttempt.
|
|
533
|
+
if (this.gameplayAttempt && this.gameplayAttempt.gameKey === gameKey && this.gameplayAttempt.attemptId === attemptId && this.gameplayAttempt.expiresAtMs > now + 1e4) {
|
|
559
534
|
return this.gameplayAttempt;
|
|
560
535
|
}
|
|
561
536
|
if (!this.gameplayAttemptPromise) {
|
|
562
|
-
this.gameplayAttemptPromise = this.raw.startGameplayAttempt(
|
|
537
|
+
this.gameplayAttemptPromise = this.raw.startGameplayAttempt(gameKey, auth, { attemptId }).then((dto) => {
|
|
563
538
|
this.gameplayAttempt = {
|
|
564
|
-
|
|
539
|
+
gameKey,
|
|
565
540
|
attemptId: dto.attemptId,
|
|
566
541
|
attemptToken: dto.attemptToken,
|
|
567
542
|
expiresAtMs: new Date(dto.expiresAt).getTime()
|
|
@@ -573,24 +548,13 @@ var ApiClient = class {
|
|
|
573
548
|
}
|
|
574
549
|
return this.gameplayAttemptPromise;
|
|
575
550
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
async
|
|
581
|
-
const detail = await this.getGameDetail(gameId);
|
|
582
|
-
const storeId = detail?.storeId;
|
|
583
|
-
if (!storeId) throw new MissingStoreError(gameId);
|
|
584
|
-
return storeId;
|
|
585
|
-
}
|
|
586
|
-
async listRecentPlayed(query) {
|
|
587
|
-
const token = await this.requireToken();
|
|
588
|
-
return this.raw.listRecentPlayed(token, query);
|
|
589
|
-
}
|
|
590
|
-
/** Call once when the game view opens, before any play/match tracking. */
|
|
591
|
-
async trackView(gameId) {
|
|
551
|
+
/**
|
|
552
|
+
* Call once when the game view opens, before any play/match tracking.
|
|
553
|
+
* `gameKey` is the game's public `appId`.
|
|
554
|
+
*/
|
|
555
|
+
async trackView(gameKey) {
|
|
592
556
|
const auth = await this.resolveTrackingAuth();
|
|
593
|
-
return this.raw.recordGameView(
|
|
557
|
+
return this.raw.recordGameView(gameKey, auth);
|
|
594
558
|
}
|
|
595
559
|
/**
|
|
596
560
|
* Starts a new play attempt and returns its id. Call when the user
|
|
@@ -603,22 +567,22 @@ var ApiClient = class {
|
|
|
603
567
|
this.gameplayAttempt = void 0;
|
|
604
568
|
return this.currentAttemptId;
|
|
605
569
|
}
|
|
606
|
-
async trackPlay(
|
|
570
|
+
async trackPlay(gameKey, playTimeSeconds) {
|
|
607
571
|
const auth = await this.resolveTrackingAuth();
|
|
608
572
|
const attemptId = this.currentAttemptId ?? this.startAttempt();
|
|
609
|
-
const { attemptToken } = await this.ensureGameplayAttempt(
|
|
610
|
-
return this.raw.completeGameplayAttempt(
|
|
573
|
+
const { attemptToken } = await this.ensureGameplayAttempt(gameKey, auth, attemptId);
|
|
574
|
+
return this.raw.completeGameplayAttempt(gameKey, auth, { playTimeSeconds, attemptId, attemptToken });
|
|
611
575
|
}
|
|
612
|
-
async trackMatch(
|
|
576
|
+
async trackMatch(gameKey, body) {
|
|
613
577
|
const auth = await this.resolveTrackingAuth();
|
|
614
578
|
const attemptId = this.currentAttemptId ?? this.startAttempt();
|
|
615
|
-
const { attemptToken } = await this.ensureGameplayAttempt(
|
|
616
|
-
return this.raw.completeGameplayMatch(
|
|
579
|
+
const { attemptToken } = await this.ensureGameplayAttempt(gameKey, auth, attemptId);
|
|
580
|
+
return this.raw.completeGameplayMatch(gameKey, auth, { ...body, attemptId, attemptToken });
|
|
617
581
|
}
|
|
618
|
-
async emit(
|
|
582
|
+
async emit(gameKey, actionCode, opts) {
|
|
619
583
|
const auth = await this.resolveTrackingAuth();
|
|
620
584
|
const attemptId = this.currentAttemptId ?? this.startAttempt();
|
|
621
|
-
const { attemptToken } = await this.ensureGameplayAttempt(
|
|
585
|
+
const { attemptToken } = await this.ensureGameplayAttempt(gameKey, auth, attemptId);
|
|
622
586
|
const body = {
|
|
623
587
|
attemptId,
|
|
624
588
|
attemptToken,
|
|
@@ -627,33 +591,42 @@ var ApiClient = class {
|
|
|
627
591
|
refId: opts?.refId,
|
|
628
592
|
payload: opts?.payload
|
|
629
593
|
};
|
|
630
|
-
return this.raw.recordGameplayAction(
|
|
594
|
+
return this.raw.recordGameplayAction(gameKey, auth, body);
|
|
631
595
|
}
|
|
632
|
-
/** Fetches the storefront (sections + offers) for
|
|
633
|
-
async getStore(
|
|
634
|
-
|
|
635
|
-
return this.raw.getStoreByStoreId(storeId);
|
|
596
|
+
/** Fetches the storefront (sections + offers) for the integration's game. Read-only, no auth required. */
|
|
597
|
+
async getStore(gameKey) {
|
|
598
|
+
return this.raw.getStore(gameKey);
|
|
636
599
|
}
|
|
637
|
-
/**
|
|
638
|
-
async
|
|
639
|
-
|
|
640
|
-
|
|
600
|
+
/** Public catalog of purchasable/ownable assets for the game. Read-only, no auth required. */
|
|
601
|
+
async listGameAssets(gameKey) {
|
|
602
|
+
return this.raw.listGameAssets(gameKey);
|
|
603
|
+
}
|
|
604
|
+
/** Assets the authenticated player already owns for this game. */
|
|
605
|
+
async listMyGameAssets(gameKey) {
|
|
606
|
+
const token = await this.requireToken();
|
|
607
|
+
return this.raw.listMyGameAssets(token, gameKey);
|
|
608
|
+
}
|
|
609
|
+
/** Purchase history for the authenticated player in the game's store. */
|
|
610
|
+
async listMyStorePurchases(gameKey) {
|
|
611
|
+
const token = await this.requireToken();
|
|
612
|
+
return this.raw.listMyStorePurchases(token, gameKey);
|
|
641
613
|
}
|
|
642
614
|
/**
|
|
643
615
|
* Spends coin balance to purchase a store offer — signs a checkout intent
|
|
644
616
|
* first, then redeems it, mirroring the gameplay attempt flow above.
|
|
617
|
+
* Self-serve: only the player's own access token is used, no secret pair
|
|
618
|
+
* required, safe to call directly from the game client. Also see
|
|
619
|
+
* `onStorePurchase` to react to the result in real time from any tab.
|
|
645
620
|
*/
|
|
646
|
-
async purchaseStoreOffer(
|
|
647
|
-
const
|
|
648
|
-
const intent = await this.raw.
|
|
649
|
-
storeId,
|
|
621
|
+
async purchaseStoreOffer(gameKey, offerCode, opts) {
|
|
622
|
+
const token = await this.requireToken();
|
|
623
|
+
const intent = await this.raw.createMyStoreCheckoutIntent(gameKey, token, {
|
|
650
624
|
offerCode,
|
|
651
625
|
requestId: opts?.requestId,
|
|
652
626
|
quantity: opts?.quantity
|
|
653
627
|
});
|
|
654
|
-
return this.raw.
|
|
655
|
-
|
|
656
|
-
offerCode,
|
|
628
|
+
return this.raw.purchaseMyStoreOffer(gameKey, token, {
|
|
629
|
+
offerCode: intent.offerCode,
|
|
657
630
|
requestId: intent.requestId,
|
|
658
631
|
quantity: intent.quantity,
|
|
659
632
|
checkoutToken: intent.checkoutToken
|
|
@@ -789,9 +762,8 @@ var LooplaySDK = class {
|
|
|
789
762
|
}
|
|
790
763
|
async verifyGameId(params) {
|
|
791
764
|
if ((params.verifyMode ?? "none") === "none") return;
|
|
792
|
-
if (!this.auth) throw new MissingAuthError();
|
|
793
765
|
if (!this.api) throw new MissingBaseUrlError();
|
|
794
|
-
await this.api.
|
|
766
|
+
await this.api.listGameAssets(params.gameId);
|
|
795
767
|
}
|
|
796
768
|
};
|
|
797
769
|
|
|
@@ -1343,6 +1315,6 @@ ${identity}`;
|
|
|
1343
1315
|
}
|
|
1344
1316
|
};
|
|
1345
1317
|
|
|
1346
|
-
export { ApiClient, BrowserLocalStorageAuthStorage, HttpClient, HttpError, LooplayAuth, LooplayIframeAuth, LooplaySDK, LooplaySDKError, MemoryAuthStorage, MissingAuthError, MissingBaseUrlError,
|
|
1318
|
+
export { ApiClient, BrowserLocalStorageAuthStorage, HttpClient, HttpError, LooplayAuth, LooplayIframeAuth, LooplaySDK, LooplaySDKError, MemoryAuthStorage, MissingAuthError, MissingBaseUrlError, NotAuthenticatedError, NotInitializedError, ServiceClient, TelegramAuthProvider };
|
|
1347
1319
|
//# sourceMappingURL=looplay-sdk.esm.js.map
|
|
1348
1320
|
//# sourceMappingURL=looplay-sdk.esm.js.map
|