@looplay/sdk 0.5.1 → 0.6.0
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 +201 -42
- package/dist/looplay-sdk.cjs.js.map +1 -1
- package/dist/looplay-sdk.esm.js +201 -43
- 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 +130 -17
- package/dist/types/apps/api-client.d.ts +33 -9
- package/dist/types/apps/service-client.d.ts +25 -12
- package/dist/types/errors.d.ts +3 -0
- package/dist/types/index.d.ts +0 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { GameEventKey,
|
|
1
|
+
export type { GameEventKey, EmitGameEventResponse } from '@looplay/types';
|
|
2
2
|
export interface AuthResultDto {
|
|
3
3
|
accessToken: string;
|
|
4
4
|
refreshToken: string;
|
|
@@ -10,11 +10,6 @@ export interface TelegramLoginRequest {
|
|
|
10
10
|
export interface RefreshTokenRequest {
|
|
11
11
|
refreshToken: string;
|
|
12
12
|
}
|
|
13
|
-
export interface TrackGamePlayRequest {
|
|
14
|
-
playTimeSeconds?: number;
|
|
15
|
-
/** Canonical identifier for one play attempt — required by the backend, stable for retries. */
|
|
16
|
-
attemptId: string;
|
|
17
|
-
}
|
|
18
13
|
/**
|
|
19
14
|
* Returned by `POST /sdk/games/tracking/bootstrap`. Anonymous runtimes must
|
|
20
15
|
* fetch this first; logged-in runtimes should still attach `trackingSessionId`
|
|
@@ -26,31 +21,149 @@ export interface GameTrackingSessionDto {
|
|
|
26
21
|
trackingToken: string;
|
|
27
22
|
expiresAt: string;
|
|
28
23
|
}
|
|
24
|
+
export interface StartGameplayAttemptRequest {
|
|
25
|
+
/** Optional client-generated id. When omitted, the server creates one. */
|
|
26
|
+
attemptId?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface GameplayAttemptSessionDto {
|
|
29
|
+
trackingSessionId: string;
|
|
30
|
+
attemptId: string;
|
|
31
|
+
attemptToken: string;
|
|
32
|
+
issuedAt: string;
|
|
33
|
+
expiresAt: string;
|
|
34
|
+
}
|
|
35
|
+
export interface CompleteGameplayAttemptRequest {
|
|
36
|
+
/** Total play duration of this attempt, in seconds. */
|
|
37
|
+
playTimeSeconds?: number;
|
|
38
|
+
/** Canonical identifier for one play attempt. */
|
|
39
|
+
attemptId: string;
|
|
40
|
+
/** Signed by the server when the gameplay attempt starts — see `StartGameplayAttemptRequest`. */
|
|
41
|
+
attemptToken: string;
|
|
42
|
+
}
|
|
43
|
+
export interface CompleteGameplayMatchRequest {
|
|
44
|
+
attemptId: string;
|
|
45
|
+
attemptToken: string;
|
|
46
|
+
/** Idempotency anchor — same matchId = same event, dedup-safe. */
|
|
47
|
+
matchId: string;
|
|
48
|
+
matchDurationSeconds: number;
|
|
49
|
+
isCompleted?: boolean;
|
|
50
|
+
isWin?: boolean;
|
|
51
|
+
}
|
|
52
|
+
export interface RecordGameplayActionRequest {
|
|
53
|
+
attemptId: string;
|
|
54
|
+
attemptToken: string;
|
|
55
|
+
matchId?: string;
|
|
56
|
+
actionCode: string;
|
|
57
|
+
value?: number;
|
|
58
|
+
/**
|
|
59
|
+
* Stable refId for dedup. When present the event is idempotent per
|
|
60
|
+
* (userId, gameId, actionCode, refId). When absent a timestamp is used.
|
|
61
|
+
*/
|
|
62
|
+
refId?: string;
|
|
63
|
+
/** Preferred name for the action occurrence id. Same semantics as refId. */
|
|
64
|
+
eventId?: string;
|
|
65
|
+
payload?: Record<string, unknown>;
|
|
66
|
+
}
|
|
29
67
|
export interface PagingResponse<T> {
|
|
30
68
|
items: T[];
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
69
|
+
totalItems: number;
|
|
70
|
+
pageIndex: number;
|
|
71
|
+
pageSize: number;
|
|
72
|
+
totalPages: number;
|
|
34
73
|
}
|
|
74
|
+
export interface GameStoreOfferItemDto {
|
|
75
|
+
assetCode: string;
|
|
76
|
+
assetName: string;
|
|
77
|
+
quantity: number;
|
|
78
|
+
}
|
|
79
|
+
export interface GameStoreOfferDto {
|
|
80
|
+
id: string;
|
|
81
|
+
gameId: string;
|
|
82
|
+
storeId?: string;
|
|
83
|
+
offerCode: string;
|
|
84
|
+
name: string;
|
|
85
|
+
sectionCode?: string | null;
|
|
86
|
+
priceCoin: number;
|
|
87
|
+
discountPercent: number;
|
|
88
|
+
effectivePriceCoin: number;
|
|
89
|
+
startAt?: string | null;
|
|
90
|
+
endAt?: string | null;
|
|
91
|
+
sortOrder: number;
|
|
92
|
+
isActive: boolean;
|
|
93
|
+
items: GameStoreOfferItemDto[];
|
|
94
|
+
}
|
|
95
|
+
export interface GameStoreSectionWithOffersDto {
|
|
96
|
+
id: string;
|
|
97
|
+
gameId: string;
|
|
98
|
+
code: string;
|
|
99
|
+
name: string;
|
|
100
|
+
sortOrder: number;
|
|
101
|
+
isActive: boolean;
|
|
102
|
+
offers: GameStoreOfferDto[];
|
|
103
|
+
}
|
|
104
|
+
/** Player-facing storefront for a game. */
|
|
105
|
+
export interface GameStoreDto {
|
|
106
|
+
storeId?: string;
|
|
107
|
+
sections: GameStoreSectionWithOffersDto[];
|
|
108
|
+
/** Active offers with no sectionCode — rendered outside any section. */
|
|
109
|
+
unsectionedOffers: GameStoreOfferDto[];
|
|
110
|
+
}
|
|
111
|
+
export interface GameStoreOfferPurchaseResultDto {
|
|
112
|
+
offerCode: string;
|
|
113
|
+
name: string;
|
|
114
|
+
quantity: number;
|
|
115
|
+
priceCoin: number;
|
|
116
|
+
totalCoin: number;
|
|
117
|
+
requestId: string;
|
|
118
|
+
items: GameStoreOfferItemDto[];
|
|
119
|
+
}
|
|
120
|
+
/** Public asset (SKU) catalog entry — no price; price lives on the offer that sells it. */
|
|
35
121
|
export interface GameAssetDto {
|
|
36
122
|
id: string;
|
|
37
123
|
gameId: string;
|
|
38
124
|
assetCode: string;
|
|
39
125
|
name: string;
|
|
40
|
-
priceCoin: number;
|
|
41
126
|
isActive: boolean;
|
|
42
127
|
}
|
|
43
|
-
|
|
128
|
+
/** An asset the authenticated player currently owns. */
|
|
129
|
+
export interface GameOwnedAssetDto {
|
|
130
|
+
assetCode: string;
|
|
131
|
+
assetName: string;
|
|
132
|
+
quantity: number;
|
|
133
|
+
}
|
|
134
|
+
/** JWT tier — `POST sdk/games/store/by-store-id/checkout-intent`. */
|
|
135
|
+
export interface CreateGameStoreCheckoutIntentRequest {
|
|
136
|
+
storeId: string;
|
|
137
|
+
offerCode: string;
|
|
44
138
|
/** Optional client-supplied dedupe key so a retried request returns the same result instead of charging twice. */
|
|
45
139
|
requestId?: string;
|
|
46
140
|
/** Defaults to 1 on the backend. */
|
|
47
141
|
quantity?: number;
|
|
48
142
|
}
|
|
49
|
-
export interface
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
quantity: number;
|
|
53
|
-
priceCoin: number;
|
|
54
|
-
totalCoin: number;
|
|
143
|
+
export interface GameStoreCheckoutIntentDto {
|
|
144
|
+
storeId: string;
|
|
145
|
+
offerCode: string;
|
|
55
146
|
requestId: string;
|
|
147
|
+
quantity: number;
|
|
148
|
+
checkoutToken: string;
|
|
149
|
+
issuedAt: string;
|
|
150
|
+
expiresAt: string;
|
|
151
|
+
}
|
|
152
|
+
/** JWT tier — `POST sdk/games/store/by-store-id/purchase`. */
|
|
153
|
+
export interface PurchaseGameStoreOfferRuntimeRequest extends CreateGameStoreCheckoutIntentRequest {
|
|
154
|
+
/** Signed by the server when the checkout intent is created — see `CreateGameStoreCheckoutIntentRequest`. */
|
|
155
|
+
checkoutToken: string;
|
|
156
|
+
}
|
|
157
|
+
/** Mirrors the backend's `AppPlatform` enum — kept as a literal union to avoid a cross-repo enum dependency. */
|
|
158
|
+
export type AppPlatform = 'telegram' | 'tiktok' | 'web' | 'base' | 'worldapp';
|
|
159
|
+
/** Mirrors the backend's `MobileOs` enum. */
|
|
160
|
+
export type MobileOs = 'ios' | 'android';
|
|
161
|
+
/**
|
|
162
|
+
* Query for `GET sdk/task` / `GET sdk/task/finished`.
|
|
163
|
+
* - `platform` defaults to `'telegram'` on the backend when omitted.
|
|
164
|
+
* - `os` is optional; when set, returns (os-specific + general) tasks.
|
|
165
|
+
*/
|
|
166
|
+
export interface TaskListQuery {
|
|
167
|
+
platform?: AppPlatform;
|
|
168
|
+
os?: MobileOs;
|
|
56
169
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { EmitGameEventResponse,
|
|
1
|
+
import type { EmitGameEventResponse, GameEventKey, GameStoreDto, GameStoreOfferPurchaseResultDto, PagingResponse, TaskListQuery } from './LooplaySDK.types';
|
|
2
2
|
import { ServiceClient } from './service-client';
|
|
3
3
|
import type { ServiceClientOptions } from './service-client';
|
|
4
4
|
export interface ApiClientOptions extends Omit<ServiceClientOptions, 'baseUrl'> {
|
|
@@ -21,6 +21,8 @@ export declare class ApiClient {
|
|
|
21
21
|
private trackingSession?;
|
|
22
22
|
private trackingSessionPromise?;
|
|
23
23
|
private currentAttemptId?;
|
|
24
|
+
private gameplayAttempt?;
|
|
25
|
+
private gameplayAttemptPromise?;
|
|
24
26
|
constructor(options: ApiClientOptions);
|
|
25
27
|
/** Expose the underlying route-level client (requires manual bearerToken passing). */
|
|
26
28
|
unsafeRaw(): ServiceClient;
|
|
@@ -41,35 +43,57 @@ export declare class ApiClient {
|
|
|
41
43
|
* just without unified session tracing.
|
|
42
44
|
*/
|
|
43
45
|
private ensureTrackingSession;
|
|
46
|
+
/**
|
|
47
|
+
* Signs (and caches until near expiry) the `attemptToken` required by
|
|
48
|
+
* `trackPlay`/`trackMatch`/`emit` for the current attempt — does not
|
|
49
|
+
* swallow failures, unlike `ensureTrackingSession`, since these calls
|
|
50
|
+
* are rejected outright without a valid token.
|
|
51
|
+
*/
|
|
52
|
+
private ensureGameplayAttempt;
|
|
44
53
|
getGameDetail(gameId: string): Promise<any>;
|
|
54
|
+
private resolveStoreId;
|
|
45
55
|
listRecentPlayed(query?: Record<string, any>): Promise<PagingResponse<any>>;
|
|
46
56
|
/** Call once when the game view opens, before any play/match tracking. */
|
|
47
57
|
trackView(gameId: string): Promise<boolean>;
|
|
48
58
|
/**
|
|
49
59
|
* Starts a new play attempt and returns its id. Call when the user
|
|
50
|
-
* presses Play; `trackPlay`
|
|
60
|
+
* presses Play; `trackPlay`/`trackMatch`/`emit` reuse this id (and the
|
|
61
|
+
* signed `attemptToken` backing it) across calls until the next
|
|
51
62
|
* `startAttempt()`, auto-starting one on first use if none was started.
|
|
52
63
|
*/
|
|
53
64
|
startAttempt(): string;
|
|
54
65
|
trackPlay(gameId: string, playTimeSeconds?: number): Promise<boolean>;
|
|
55
|
-
trackMatch(gameId: string, body:
|
|
66
|
+
trackMatch(gameId: string, body: {
|
|
67
|
+
matchId: string;
|
|
68
|
+
matchDurationSeconds: number;
|
|
69
|
+
isCompleted?: boolean;
|
|
70
|
+
isWin?: boolean;
|
|
71
|
+
}): Promise<boolean>;
|
|
56
72
|
emit(gameId: string, actionCode: GameEventKey | string, opts?: {
|
|
57
73
|
value?: number;
|
|
58
74
|
refId?: string;
|
|
59
75
|
payload?: Record<string, unknown>;
|
|
60
76
|
}): Promise<EmitGameEventResponse>;
|
|
61
|
-
/**
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
|
|
77
|
+
/** Fetches the storefront (sections + offers) for `gameId`, defined by that game's creator. */
|
|
78
|
+
getStore(gameId: string): Promise<GameStoreDto>;
|
|
79
|
+
/** Purchase history for the authenticated player in `gameId`'s store. */
|
|
80
|
+
listMyStorePurchases(gameId: string): Promise<GameStoreOfferPurchaseResultDto[]>;
|
|
81
|
+
/**
|
|
82
|
+
* Spends coin balance to purchase a store offer — signs a checkout intent
|
|
83
|
+
* first, then redeems it, mirroring the gameplay attempt flow above.
|
|
84
|
+
*/
|
|
85
|
+
purchaseStoreOffer(gameId: string, offerCode: string, opts?: {
|
|
86
|
+
requestId?: string;
|
|
87
|
+
quantity?: number;
|
|
88
|
+
}): Promise<GameStoreOfferPurchaseResultDto>;
|
|
65
89
|
getMyProfile(): Promise<any>;
|
|
66
90
|
getMyBalance(): Promise<any>;
|
|
67
91
|
getBalances(query?: Record<string, any>): Promise<any>;
|
|
68
92
|
getBalanceHistory(query?: Record<string, any>): Promise<PagingResponse<any>>;
|
|
69
93
|
listReferrals(query?: Record<string, any>): Promise<PagingResponse<any>>;
|
|
70
94
|
setReferral(body: Record<string, any>): Promise<boolean>;
|
|
71
|
-
listTasks(): Promise<any[]>;
|
|
72
|
-
listFinishedTasks(): Promise<any[]>;
|
|
95
|
+
listTasks(query?: TaskListQuery): Promise<any[]>;
|
|
96
|
+
listFinishedTasks(query?: TaskListQuery): Promise<any[]>;
|
|
73
97
|
startTask(body: Record<string, any>): Promise<any>;
|
|
74
98
|
claimTask(body: Record<string, any>): Promise<any>;
|
|
75
99
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { type HttpClientOptions } from './http';
|
|
2
|
-
import type { AuthResultDto,
|
|
2
|
+
import type { AuthResultDto, CompleteGameplayAttemptRequest, CompleteGameplayMatchRequest, CreateGameStoreCheckoutIntentRequest, EmitGameEventResponse, GameAssetDto, GameOwnedAssetDto, GameplayAttemptSessionDto, GameStoreCheckoutIntentDto, GameStoreDto, GameStoreOfferPurchaseResultDto, GameTrackingSessionDto, PagingResponse, PurchaseGameStoreOfferRuntimeRequest, RecordGameplayActionRequest, StartGameplayAttemptRequest, TaskListQuery } from './LooplaySDK.types';
|
|
3
3
|
export interface ServiceClientOptions extends HttpClientOptions {
|
|
4
4
|
}
|
|
5
5
|
/**
|
|
6
|
-
* Auth for the tracking endpoints (
|
|
6
|
+
* Auth for the tracking endpoints (view/attempt/match/action), which accept
|
|
7
7
|
* either a real user's `bearerToken` (full tracking, eligible for
|
|
8
8
|
* quest/reward) or an `anonId` for an unauthenticated device
|
|
9
9
|
* (analytics-only — the backend never awards quest/reward progress to an
|
|
10
10
|
* anonymous id). `trackingSessionId`/`anonTrackingToken` come from
|
|
11
|
-
* `
|
|
11
|
+
* `bootstrapTrackingSession()` and should be attached either way, per the
|
|
12
12
|
* platform's tracking contract.
|
|
13
13
|
*/
|
|
14
14
|
export interface TrackingAuth {
|
|
@@ -30,27 +30,40 @@ export declare class ServiceClient {
|
|
|
30
30
|
listGames(query?: Record<string, any>): Promise<PagingResponse<any>>;
|
|
31
31
|
getGameDetail(gameId: string, bearerToken?: string): Promise<any>;
|
|
32
32
|
listRecentPlayed(bearerToken: string, query?: Record<string, any>): Promise<PagingResponse<any>>;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
recordGameView(auth: TrackingAuth, gameId: string): Promise<boolean>;
|
|
34
|
+
/** Signs a fresh `attemptToken` — required by `completeGameplayAttempt`/`completeGameplayMatch`/`recordGameplayAction`. */
|
|
35
|
+
startGameplayAttempt(auth: TrackingAuth, gameId: string, body?: StartGameplayAttemptRequest): Promise<GameplayAttemptSessionDto>;
|
|
36
|
+
completeGameplayAttempt(auth: TrackingAuth, gameId: string, body: CompleteGameplayAttemptRequest): Promise<boolean>;
|
|
37
|
+
completeGameplayMatch(auth: TrackingAuth, gameId: string, body: CompleteGameplayMatchRequest): Promise<boolean>;
|
|
38
|
+
recordGameplayAction(auth: TrackingAuth, gameId: string, body: RecordGameplayActionRequest): Promise<EmitGameEventResponse>;
|
|
37
39
|
/**
|
|
38
40
|
* Anonymous runtimes must call this before any tracking call; logged-in
|
|
39
41
|
* runtimes should still call it to get a `trackingSessionId` for unified
|
|
40
42
|
* tracing — see `GameTrackingSessionDto`.
|
|
41
43
|
*/
|
|
42
|
-
|
|
44
|
+
bootstrapTrackingSession(anonId?: string): Promise<GameTrackingSessionDto>;
|
|
43
45
|
private trackingHeaders;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
getStoreByStoreId(storeId: string): Promise<GameStoreDto>;
|
|
47
|
+
listMyStorePurchasesByStoreId(bearerToken: string, storeId: string): Promise<GameStoreOfferPurchaseResultDto[]>;
|
|
48
|
+
createStoreCheckoutIntent(bearerToken: string, body: CreateGameStoreCheckoutIntentRequest, trackingSessionId?: string): Promise<GameStoreCheckoutIntentDto>;
|
|
49
|
+
purchaseStoreOffer(bearerToken: string, body: PurchaseGameStoreOfferRuntimeRequest, trackingSessionId?: string): Promise<GameStoreOfferPurchaseResultDto>;
|
|
50
|
+
recordGameViewForGameKey(gameKey: string, auth?: TrackingAuth): Promise<boolean>;
|
|
51
|
+
startGameplayAttemptForGameKey(gameKey: string, auth?: TrackingAuth, body?: StartGameplayAttemptRequest): Promise<GameplayAttemptSessionDto>;
|
|
52
|
+
completeGameplayAttemptForGameKey(gameKey: string, auth: TrackingAuth | undefined, body: CompleteGameplayAttemptRequest): Promise<boolean>;
|
|
53
|
+
completeGameplayMatchForGameKey(gameKey: string, auth: TrackingAuth | undefined, body: CompleteGameplayMatchRequest): Promise<boolean>;
|
|
54
|
+
recordGameplayActionForGameKey(gameKey: string, auth: TrackingAuth | undefined, body: RecordGameplayActionRequest): Promise<EmitGameEventResponse>;
|
|
55
|
+
getStoreForGameKey(gameKey: string): Promise<GameStoreDto>;
|
|
56
|
+
listGameAssetsForGameKey(gameKey: string): Promise<GameAssetDto[]>;
|
|
57
|
+
listMyOwnedAssetsForGameKey(bearerToken: string, gameKey: string): Promise<GameOwnedAssetDto[]>;
|
|
58
|
+
listMyStorePurchasesForGameKey(bearerToken: string, gameKey: string): Promise<GameStoreOfferPurchaseResultDto[]>;
|
|
46
59
|
getBalances(bearerToken: string, query?: Record<string, any>): Promise<any>;
|
|
47
60
|
getBalanceHistory(bearerToken: string, query?: Record<string, any>): Promise<PagingResponse<any>>;
|
|
48
61
|
getMyProfile(bearerToken: string): Promise<any>;
|
|
49
62
|
getMyBalance(bearerToken: string): Promise<any>;
|
|
50
63
|
listReferrals(bearerToken: string, query?: Record<string, any>): Promise<PagingResponse<any>>;
|
|
51
64
|
setReferral(bearerToken: string, body: Record<string, any>): Promise<boolean>;
|
|
52
|
-
listTasks(bearerToken: string): Promise<any[]>;
|
|
53
|
-
listFinishedTasks(bearerToken: string): Promise<any[]>;
|
|
65
|
+
listTasks(bearerToken: string, query?: TaskListQuery): Promise<any[]>;
|
|
66
|
+
listFinishedTasks(bearerToken: string, query?: TaskListQuery): Promise<any[]>;
|
|
54
67
|
startTask(bearerToken: string, body: Record<string, any>): Promise<any>;
|
|
55
68
|
claimTask(bearerToken: string, body: Record<string, any>): Promise<any>;
|
|
56
69
|
}
|
package/dist/types/errors.d.ts
CHANGED
package/dist/types/index.d.ts
CHANGED