@looplay/sdk 0.5.1 → 0.7.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/README.md +141 -4
- package/dist/looplay-sdk.cjs.js +133 -79
- package/dist/looplay-sdk.cjs.js.map +1 -1
- package/dist/looplay-sdk.esm.js +133 -79
- 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 +121 -18
- package/dist/types/apps/api-client.d.ts +36 -17
- package/dist/types/apps/service-client.d.ts +20 -15
- package/dist/types/index.d.ts +0 -1
- package/dist/types/types.d.ts +2 -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,139 @@ 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
|
+
* One-call convenience: when set, the server also records this action
|
|
29
|
+
* (e.g. `"GAME_STARTED"`) right after issuing the attempt, using the
|
|
30
|
+
* freshly signed `attemptId`/`attemptToken` — skips a separate
|
|
31
|
+
* `recordGameplayAction` call. See `matchId`/`value`/`refId`/`eventId`/
|
|
32
|
+
* `payload` below for the action's own fields.
|
|
33
|
+
*/
|
|
34
|
+
actionCode?: string;
|
|
35
|
+
matchId?: string;
|
|
36
|
+
value?: number;
|
|
37
|
+
refId?: string;
|
|
38
|
+
eventId?: string;
|
|
39
|
+
payload?: Record<string, unknown>;
|
|
40
|
+
}
|
|
41
|
+
export interface GameplayAttemptSessionDto {
|
|
42
|
+
trackingSessionId: string;
|
|
43
|
+
attemptId: string;
|
|
44
|
+
attemptToken: string;
|
|
45
|
+
issuedAt: string;
|
|
46
|
+
expiresAt: string;
|
|
47
|
+
}
|
|
48
|
+
export interface CompleteGameplayAttemptRequest {
|
|
49
|
+
/** Total play duration of this attempt, in seconds. */
|
|
50
|
+
playTimeSeconds?: number;
|
|
51
|
+
/** Canonical identifier for one play attempt. */
|
|
52
|
+
attemptId: string;
|
|
53
|
+
/** Signed by the server when the gameplay attempt starts — see `StartGameplayAttemptRequest`. */
|
|
54
|
+
attemptToken: string;
|
|
55
|
+
}
|
|
56
|
+
export interface CompleteGameplayMatchRequest {
|
|
57
|
+
attemptId: string;
|
|
58
|
+
attemptToken: string;
|
|
59
|
+
/** Idempotency anchor — same matchId = same event, dedup-safe. */
|
|
60
|
+
matchId: string;
|
|
61
|
+
matchDurationSeconds: number;
|
|
62
|
+
isCompleted?: boolean;
|
|
63
|
+
isWin?: boolean;
|
|
64
|
+
}
|
|
65
|
+
export interface RecordGameplayActionRequest {
|
|
66
|
+
attemptId: string;
|
|
67
|
+
attemptToken: string;
|
|
68
|
+
matchId?: string;
|
|
69
|
+
actionCode: string;
|
|
70
|
+
value?: number;
|
|
71
|
+
/**
|
|
72
|
+
* Stable refId for dedup. When present the event is idempotent per
|
|
73
|
+
* (userId, gameId, actionCode, refId). When absent a timestamp is used.
|
|
74
|
+
*/
|
|
75
|
+
refId?: string;
|
|
76
|
+
/** Preferred name for the action occurrence id. Same semantics as refId. */
|
|
77
|
+
eventId?: string;
|
|
78
|
+
payload?: Record<string, unknown>;
|
|
79
|
+
}
|
|
29
80
|
export interface PagingResponse<T> {
|
|
30
81
|
items: T[];
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
82
|
+
totalItems: number;
|
|
83
|
+
pageIndex: number;
|
|
84
|
+
pageSize: number;
|
|
85
|
+
totalPages: number;
|
|
34
86
|
}
|
|
35
|
-
export interface
|
|
87
|
+
export interface GameStoreOfferItemDto {
|
|
88
|
+
assetCode: string;
|
|
89
|
+
assetName: string;
|
|
90
|
+
quantity: number;
|
|
91
|
+
}
|
|
92
|
+
export interface GameStoreOfferDto {
|
|
36
93
|
id: string;
|
|
37
94
|
gameId: string;
|
|
38
|
-
|
|
95
|
+
storeId?: string;
|
|
96
|
+
offerCode: string;
|
|
39
97
|
name: string;
|
|
98
|
+
sectionCode?: string | null;
|
|
40
99
|
priceCoin: number;
|
|
100
|
+
discountPercent: number;
|
|
101
|
+
effectivePriceCoin: number;
|
|
102
|
+
startAt?: string | null;
|
|
103
|
+
endAt?: string | null;
|
|
104
|
+
sortOrder: number;
|
|
41
105
|
isActive: boolean;
|
|
106
|
+
items: GameStoreOfferItemDto[];
|
|
42
107
|
}
|
|
43
|
-
export interface
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
108
|
+
export interface GameStoreSectionWithOffersDto {
|
|
109
|
+
id: string;
|
|
110
|
+
gameId: string;
|
|
111
|
+
code: string;
|
|
112
|
+
name: string;
|
|
113
|
+
sortOrder: number;
|
|
114
|
+
isActive: boolean;
|
|
115
|
+
offers: GameStoreOfferDto[];
|
|
48
116
|
}
|
|
49
|
-
|
|
50
|
-
|
|
117
|
+
/** Player-facing storefront for a game. */
|
|
118
|
+
export interface GameStoreDto {
|
|
119
|
+
storeId?: string;
|
|
120
|
+
sections: GameStoreSectionWithOffersDto[];
|
|
121
|
+
/** Active offers with no sectionCode — rendered outside any section. */
|
|
122
|
+
unsectionedOffers: GameStoreOfferDto[];
|
|
123
|
+
}
|
|
124
|
+
export interface GameStoreOfferPurchaseResultDto {
|
|
125
|
+
offerCode: string;
|
|
51
126
|
name: string;
|
|
52
127
|
quantity: number;
|
|
53
128
|
priceCoin: number;
|
|
54
129
|
totalCoin: number;
|
|
55
130
|
requestId: string;
|
|
131
|
+
items: GameStoreOfferItemDto[];
|
|
132
|
+
}
|
|
133
|
+
/** Public asset (SKU) catalog entry — no price; price lives on the offer that sells it. */
|
|
134
|
+
export interface GameAssetDto {
|
|
135
|
+
id: string;
|
|
136
|
+
gameId: string;
|
|
137
|
+
assetCode: string;
|
|
138
|
+
name: string;
|
|
139
|
+
isActive: boolean;
|
|
140
|
+
}
|
|
141
|
+
/** An asset the authenticated player currently owns. */
|
|
142
|
+
export interface GameOwnedAssetDto {
|
|
143
|
+
assetCode: string;
|
|
144
|
+
assetName: string;
|
|
145
|
+
quantity: number;
|
|
146
|
+
}
|
|
147
|
+
/** Mirrors the backend's `AppPlatform` enum — kept as a literal union to avoid a cross-repo enum dependency. */
|
|
148
|
+
export type AppPlatform = 'telegram' | 'tiktok' | 'web' | 'base' | 'worldapp';
|
|
149
|
+
/** Mirrors the backend's `MobileOs` enum. */
|
|
150
|
+
export type MobileOs = 'ios' | 'android';
|
|
151
|
+
/**
|
|
152
|
+
* Query for `GET sdk/task` / `GET sdk/task/finished`.
|
|
153
|
+
* - `platform` defaults to `'telegram'` on the backend when omitted.
|
|
154
|
+
* - `os` is optional; when set, returns (os-specific + general) tasks.
|
|
155
|
+
*/
|
|
156
|
+
export interface TaskListQuery {
|
|
157
|
+
platform?: AppPlatform;
|
|
158
|
+
os?: MobileOs;
|
|
56
159
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { EmitGameEventResponse, GameAssetDto,
|
|
1
|
+
import type { EmitGameEventResponse, GameAssetDto, GameEventKey, GameOwnedAssetDto, 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,10 +21,11 @@ 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
|
-
/** Expose the underlying route-level client (requires manual bearerToken passing). */
|
|
27
|
+
/** Expose the underlying route-level client (requires manual bearerToken/gameKey passing). */
|
|
26
28
|
unsafeRaw(): ServiceClient;
|
|
27
|
-
listGames(query?: Record<string, any>): Promise<PagingResponse<any>>;
|
|
28
29
|
private requireToken;
|
|
29
30
|
/**
|
|
30
31
|
* Resolves auth for the tracking endpoints: a real bearer token if logged
|
|
@@ -41,35 +42,53 @@ export declare class ApiClient {
|
|
|
41
42
|
* just without unified session tracing.
|
|
42
43
|
*/
|
|
43
44
|
private ensureTrackingSession;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Signs (and caches until near expiry) the `attemptToken` required by
|
|
47
|
+
* `trackPlay`/`trackMatch`/`emit` for the current attempt — does not
|
|
48
|
+
* swallow failures, unlike `ensureTrackingSession`, since these calls
|
|
49
|
+
* are rejected outright without a valid token.
|
|
50
|
+
*/
|
|
51
|
+
private ensureGameplayAttempt;
|
|
52
|
+
/**
|
|
53
|
+
* Call once when the game view opens, before any play/match tracking.
|
|
54
|
+
* `gameKey` is the game's public `appId`.
|
|
55
|
+
*/
|
|
56
|
+
trackView(gameKey: string): Promise<boolean>;
|
|
48
57
|
/**
|
|
49
58
|
* Starts a new play attempt and returns its id. Call when the user
|
|
50
|
-
* presses Play; `trackPlay`
|
|
59
|
+
* presses Play; `trackPlay`/`trackMatch`/`emit` reuse this id (and the
|
|
60
|
+
* signed `attemptToken` backing it) across calls until the next
|
|
51
61
|
* `startAttempt()`, auto-starting one on first use if none was started.
|
|
52
62
|
*/
|
|
53
63
|
startAttempt(): string;
|
|
54
|
-
trackPlay(
|
|
55
|
-
trackMatch(
|
|
56
|
-
|
|
64
|
+
trackPlay(gameKey: string, playTimeSeconds?: number): Promise<boolean>;
|
|
65
|
+
trackMatch(gameKey: string, body: {
|
|
66
|
+
matchId: string;
|
|
67
|
+
matchDurationSeconds: number;
|
|
68
|
+
isCompleted?: boolean;
|
|
69
|
+
isWin?: boolean;
|
|
70
|
+
}): Promise<boolean>;
|
|
71
|
+
emit(gameKey: string, actionCode: GameEventKey | string, opts?: {
|
|
57
72
|
value?: number;
|
|
58
73
|
refId?: string;
|
|
59
74
|
payload?: Record<string, unknown>;
|
|
60
75
|
}): Promise<EmitGameEventResponse>;
|
|
61
|
-
/**
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
|
|
76
|
+
/** Fetches the storefront (sections + offers) for the integration's game. Read-only, no auth required. */
|
|
77
|
+
getStore(gameKey: string): Promise<GameStoreDto>;
|
|
78
|
+
/** Public catalog of purchasable/ownable assets for the game. Read-only, no auth required. */
|
|
79
|
+
listGameAssets(gameKey: string): Promise<GameAssetDto[]>;
|
|
80
|
+
/** Assets the authenticated player already owns for this game. */
|
|
81
|
+
listMyGameAssets(gameKey: string): Promise<GameOwnedAssetDto[]>;
|
|
82
|
+
/** Purchase history for the authenticated player in the game's store. */
|
|
83
|
+
listMyStorePurchases(gameKey: string): Promise<GameStoreOfferPurchaseResultDto[]>;
|
|
65
84
|
getMyProfile(): Promise<any>;
|
|
66
85
|
getMyBalance(): Promise<any>;
|
|
67
86
|
getBalances(query?: Record<string, any>): Promise<any>;
|
|
68
87
|
getBalanceHistory(query?: Record<string, any>): Promise<PagingResponse<any>>;
|
|
69
88
|
listReferrals(query?: Record<string, any>): Promise<PagingResponse<any>>;
|
|
70
89
|
setReferral(body: Record<string, any>): Promise<boolean>;
|
|
71
|
-
listTasks(): Promise<any[]>;
|
|
72
|
-
listFinishedTasks(): Promise<any[]>;
|
|
90
|
+
listTasks(query?: TaskListQuery): Promise<any[]>;
|
|
91
|
+
listFinishedTasks(query?: TaskListQuery): Promise<any[]>;
|
|
73
92
|
startTask(body: Record<string, any>): Promise<any>;
|
|
74
93
|
claimTask(body: Record<string, any>): Promise<any>;
|
|
75
94
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { type HttpClientOptions } from './http';
|
|
2
|
-
import type { AuthResultDto,
|
|
2
|
+
import type { AuthResultDto, CompleteGameplayAttemptRequest, CompleteGameplayMatchRequest, EmitGameEventResponse, GameAssetDto, GameOwnedAssetDto, GameplayAttemptSessionDto, GameStoreDto, GameStoreOfferPurchaseResultDto, GameTrackingSessionDto, PagingResponse, 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 {
|
|
@@ -27,30 +27,35 @@ export declare class ServiceClient {
|
|
|
27
27
|
telegramLogin(telegramInitData: string): Promise<AuthResultDto>;
|
|
28
28
|
refresh(refreshToken: string): Promise<AuthResultDto>;
|
|
29
29
|
logout(refreshToken: string): Promise<boolean>;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
emitGameEvent(auth: TrackingAuth, gameId: string, body: EmitGameEventRequest): Promise<EmitGameEventResponse>;
|
|
30
|
+
recordGameView(gameKey: string, auth?: TrackingAuth): Promise<boolean>;
|
|
31
|
+
/** Signs a fresh `attemptToken` — required by `completeGameplayAttempt`/`completeGameplayMatch`/`recordGameplayAction`. */
|
|
32
|
+
startGameplayAttempt(gameKey: string, auth?: TrackingAuth, body?: StartGameplayAttemptRequest): Promise<GameplayAttemptSessionDto>;
|
|
33
|
+
completeGameplayAttempt(gameKey: string, auth: TrackingAuth, body: CompleteGameplayAttemptRequest): Promise<boolean>;
|
|
34
|
+
completeGameplayMatch(gameKey: string, auth: TrackingAuth, body: CompleteGameplayMatchRequest): Promise<boolean>;
|
|
35
|
+
recordGameplayAction(gameKey: string, auth: TrackingAuth, body: RecordGameplayActionRequest): Promise<EmitGameEventResponse>;
|
|
37
36
|
/**
|
|
38
37
|
* Anonymous runtimes must call this before any tracking call; logged-in
|
|
39
38
|
* runtimes should still call it to get a `trackingSessionId` for unified
|
|
40
39
|
* tracing — see `GameTrackingSessionDto`.
|
|
41
40
|
*/
|
|
42
|
-
|
|
41
|
+
bootstrapTrackingSession(anonId?: string): Promise<GameTrackingSessionDto>;
|
|
43
42
|
private trackingHeaders;
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
/** Public storefront (sections + offers) for the integration's game. Read-only. */
|
|
44
|
+
getStore(gameKey: string): Promise<GameStoreDto>;
|
|
45
|
+
/** Public catalog of purchasable/ownable assets for the game. Read-only. */
|
|
46
|
+
listGameAssets(gameKey: string): Promise<GameAssetDto[]>;
|
|
47
|
+
/** Assets the authenticated player already owns for this game. */
|
|
48
|
+
listMyGameAssets(bearerToken: string, gameKey: string): Promise<GameOwnedAssetDto[]>;
|
|
49
|
+
/** The authenticated player's past store purchases for this game. */
|
|
50
|
+
listMyStorePurchases(bearerToken: string, gameKey: string): Promise<GameStoreOfferPurchaseResultDto[]>;
|
|
46
51
|
getBalances(bearerToken: string, query?: Record<string, any>): Promise<any>;
|
|
47
52
|
getBalanceHistory(bearerToken: string, query?: Record<string, any>): Promise<PagingResponse<any>>;
|
|
48
53
|
getMyProfile(bearerToken: string): Promise<any>;
|
|
49
54
|
getMyBalance(bearerToken: string): Promise<any>;
|
|
50
55
|
listReferrals(bearerToken: string, query?: Record<string, any>): Promise<PagingResponse<any>>;
|
|
51
56
|
setReferral(bearerToken: string, body: Record<string, any>): Promise<boolean>;
|
|
52
|
-
listTasks(bearerToken: string): Promise<any[]>;
|
|
53
|
-
listFinishedTasks(bearerToken: string): Promise<any[]>;
|
|
57
|
+
listTasks(bearerToken: string, query?: TaskListQuery): Promise<any[]>;
|
|
58
|
+
listFinishedTasks(bearerToken: string, query?: TaskListQuery): Promise<any[]>;
|
|
54
59
|
startTask(bearerToken: string, body: Record<string, any>): Promise<any>;
|
|
55
60
|
claimTask(bearerToken: string, body: Record<string, any>): Promise<any>;
|
|
56
61
|
}
|
package/dist/types/index.d.ts
CHANGED
package/dist/types/types.d.ts
CHANGED
|
@@ -7,7 +7,8 @@ export interface LooplaySDKCreateOptions {
|
|
|
7
7
|
defaultHeaders?: Record<string, string>;
|
|
8
8
|
}
|
|
9
9
|
export interface LooplayInitParams {
|
|
10
|
+
/** The game's public `appId` — same value as `x-game-key`, from your creator dashboard. */
|
|
10
11
|
gameId: string;
|
|
11
|
-
/** 'none': skip verification | 'strict':
|
|
12
|
+
/** 'none': skip verification | 'strict': resolve gameId via a read-only, unauthenticated call */
|
|
12
13
|
verifyMode?: 'none' | 'strict';
|
|
13
14
|
}
|