@gamecore-api/sdk 0.9.0 → 0.13.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/client.d.ts +335 -28
- package/dist/index.js +74 -7
- package/dist/types.d.ts +438 -9
- package/package.json +1 -2
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TelegramInitResponse, User, SiteConfig, ExchangeRates, LegalDocument, Game, GameDetail, Product, SearchResult, Category, CartItem, CheckoutRequest, CheckoutResponse, Order, UserBalance, LevelStatus, Transaction, Notification, Favorite, Review, ReviewStats, CouponResult, ReferralStats, ReferralLink, ReferralCommission, TopupMethod, TopupResponse, TopupStatus, GiftCard, Announcement, AnnouncementBar, SiteUIConfig, PaymentMethod, CatalogSection, SiteStats, ProductFilters, PaginatedResponse } from "./types";
|
|
1
|
+
import type { TelegramInitResponse, TelegramWidgetUser, TelegramAuthResponse, User, SiteConfig, ExchangeRates, LegalDocument, Game, GameDetail, Product, SearchResult, Category, CartItem, CheckoutRequest, CheckoutResponse, Conversation, ConversationDetail, Order, PaymentInfo, CompleteWithBalanceResult, UserBalance, WebPushSubscriptionInput, LevelStatus, Transaction, Notification, Favorite, Review, ReviewCreateResult, ReviewStats, CouponResult, ReferralStats, ReferralLink, ReferralCommission, ReferralPerformance, TopupMethod, TopupResponse, TopupStatus, GiftCard, Announcement, AnnouncementBar, SiteUIConfig, PaymentMethod, CatalogSection, SiteStats, ProductFilters, PaginatedResponse, PagedGamesResponse } from "./types";
|
|
2
2
|
export interface GameCoreOptions {
|
|
3
3
|
/** Site API key (gc_live_xxx or gc_test_xxx) */
|
|
4
4
|
apiKey: string;
|
|
@@ -47,33 +47,141 @@ export declare class GameCoreClient {
|
|
|
47
47
|
}>;
|
|
48
48
|
/** Get per-site catalog sections (category tabs config) */
|
|
49
49
|
getCatalogSections: () => Promise<CatalogSection[]>;
|
|
50
|
-
/**
|
|
50
|
+
/**
|
|
51
|
+
* Get active hero banners for the storefront carousel.
|
|
52
|
+
* Each banner carries optional visual fields plus a `url`
|
|
53
|
+
* destination — `null` means the banner is display-only and
|
|
54
|
+
* should not be rendered as a link.
|
|
55
|
+
*/
|
|
51
56
|
getBanners: () => Promise<{
|
|
52
57
|
id: number;
|
|
53
58
|
title: string | null;
|
|
54
59
|
description: string | null;
|
|
55
60
|
imageUrl: string | null;
|
|
56
61
|
color: string | null;
|
|
62
|
+
url: string | null;
|
|
57
63
|
scope: string;
|
|
58
64
|
priority: number;
|
|
59
65
|
}[]>;
|
|
60
66
|
/** Get announcement bar settings (text, link, enabled) */
|
|
61
67
|
getAnnouncementBar: () => Promise<AnnouncementBar>;
|
|
68
|
+
/**
|
|
69
|
+
* Get sitemap data for self-generated storefront sitemaps.
|
|
70
|
+
* Returns `{ slug, updatedAt }` for every game visible on
|
|
71
|
+
* this site. Use `updatedAt` as `lastModified` in Next.js
|
|
72
|
+
* `sitemap.ts` so Google's crawler respects unchanged pages
|
|
73
|
+
* instead of stamping the whole catalog with `new Date()`.
|
|
74
|
+
*/
|
|
75
|
+
getSitemapData: () => Promise<{
|
|
76
|
+
slug: string;
|
|
77
|
+
updatedAt: string;
|
|
78
|
+
}[]>;
|
|
79
|
+
/**
|
|
80
|
+
* Submit a "please add this game" request. Works for both
|
|
81
|
+
* authenticated users (the server attaches the user id so
|
|
82
|
+
* support can reach back) and anonymous visitors.
|
|
83
|
+
*
|
|
84
|
+
* Rate-limited server-side. The optional `website` field is
|
|
85
|
+
* a honeypot — leave it `undefined` in real code; the
|
|
86
|
+
* storefront can render an invisible input under that name
|
|
87
|
+
* so scrapers self-identify.
|
|
88
|
+
*
|
|
89
|
+
* @returns The new request id and a success flag. A filled
|
|
90
|
+
* honeypot still returns `success: true` with
|
|
91
|
+
* `requestId: -1` so bots cannot distinguish a real save
|
|
92
|
+
* from a silent drop.
|
|
93
|
+
*/
|
|
94
|
+
requestGame: (data: {
|
|
95
|
+
gameName: string;
|
|
96
|
+
comment?: string;
|
|
97
|
+
gameUrl?: string;
|
|
98
|
+
website?: string;
|
|
99
|
+
}) => Promise<{
|
|
100
|
+
success: boolean;
|
|
101
|
+
requestId: number;
|
|
102
|
+
}>;
|
|
62
103
|
};
|
|
63
104
|
auth: {
|
|
64
105
|
/** Start Telegram auth flow → returns bot link for user to click */
|
|
65
106
|
initTelegram: () => Promise<TelegramInitResponse>;
|
|
66
107
|
/** Poll Telegram auth status until authenticated or expired */
|
|
67
108
|
pollTelegramStatus: (token: string, intervalMs?: number) => Promise<User>;
|
|
68
|
-
/**
|
|
69
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Verify Telegram Mini App initData and issue a session cookie.
|
|
111
|
+
* Call this when your storefront is opened inside Telegram via the
|
|
112
|
+
* bot's Mini App / Web App button — `window.Telegram.WebApp.initData`
|
|
113
|
+
* is the raw URL-encoded string you should pass in. The backend
|
|
114
|
+
* validates the HMAC signature against the bot token and mints a
|
|
115
|
+
* normal auth cookie, so the rest of the site stays logged in.
|
|
116
|
+
* Optional `ref` threads a referral code through user creation.
|
|
117
|
+
*/
|
|
118
|
+
verifyMiniApp: (initData: string, ref?: string) => Promise<TelegramAuthResponse>;
|
|
119
|
+
/**
|
|
120
|
+
* Verify Telegram Login Widget payload (JSON POST variant) and
|
|
121
|
+
* issue a session cookie. Use this when you embed the Login Widget
|
|
122
|
+
* with `data-onauth` (JS callback) instead of `data-auth-url`
|
|
123
|
+
* (full-page redirect) — pass the object the widget handed you
|
|
124
|
+
* directly to this method.
|
|
125
|
+
*/
|
|
126
|
+
verifyTelegramWidget: (data: TelegramWidgetUser, ref?: string) => Promise<TelegramAuthResponse>;
|
|
127
|
+
/**
|
|
128
|
+
* Get VK OAuth authorize URL (authorization code flow).
|
|
129
|
+
*
|
|
130
|
+
* Backend generates a single-use state nonce, stores it server-
|
|
131
|
+
* side, and returns a URL pointing at VK with response_type=code.
|
|
132
|
+
* The storefront redirects the user to this URL; VK redirects
|
|
133
|
+
* back to `redirectUri` with ?code=...&state=...; the storefront
|
|
134
|
+
* then calls {@link vkCallback} with those two values.
|
|
135
|
+
*
|
|
136
|
+
* `redirectUri` must exactly match one of the site's allowed
|
|
137
|
+
* origins configured in master-admin — the backend validates
|
|
138
|
+
* this before storing the state. `ref` is an optional referral
|
|
139
|
+
* code that gets threaded through to user registration.
|
|
140
|
+
*/
|
|
141
|
+
getVkAuthUrl: (redirectUri: string, ref?: string) => Promise<{
|
|
70
142
|
url: string;
|
|
143
|
+
state: string;
|
|
144
|
+
}>;
|
|
145
|
+
/**
|
|
146
|
+
* Exchange an authorization code for a session cookie (code flow).
|
|
147
|
+
* Call this after VK redirects back to your storefront with
|
|
148
|
+
* ?code=...&state=... in the query string. The backend validates
|
|
149
|
+
* state (single-use), exchanges the code with VK server-to-server
|
|
150
|
+
* using the site's client_secret, fetches the user profile, and
|
|
151
|
+
* mints a normal auth cookie. The VK access token never reaches
|
|
152
|
+
* the client.
|
|
153
|
+
*/
|
|
154
|
+
vkCallback: (code: string, state: string) => Promise<{
|
|
155
|
+
status: string;
|
|
156
|
+
user: User;
|
|
71
157
|
}>;
|
|
72
|
-
/**
|
|
158
|
+
/**
|
|
159
|
+
* Verify a VK access token from the deprecated implicit flow.
|
|
160
|
+
* @deprecated Use {@link getVkAuthUrl} + {@link vkCallback} instead.
|
|
161
|
+
* This endpoint is kept alive for backwards compatibility while
|
|
162
|
+
* storefronts migrate to the code flow. It will be removed in a
|
|
163
|
+
* future major release.
|
|
164
|
+
*/
|
|
73
165
|
verifyVk: (accessToken: string, ref?: string) => Promise<{
|
|
74
166
|
status: string;
|
|
75
167
|
user: User;
|
|
76
168
|
}>;
|
|
169
|
+
/** Register with email + password. No auth required. */
|
|
170
|
+
register: (email: string, password: string, firstName?: string, ref?: string) => Promise<{
|
|
171
|
+
success: boolean;
|
|
172
|
+
token: string;
|
|
173
|
+
user: User;
|
|
174
|
+
}>;
|
|
175
|
+
/** Login with email + password. No auth required. */
|
|
176
|
+
login: (email: string, password: string) => Promise<{
|
|
177
|
+
success: boolean;
|
|
178
|
+
token: string;
|
|
179
|
+
user: User;
|
|
180
|
+
}>;
|
|
181
|
+
/** Change password (requires auth). Revokes all other sessions. */
|
|
182
|
+
changePassword: (currentPassword: string, newPassword: string) => Promise<{
|
|
183
|
+
success: boolean;
|
|
184
|
+
}>;
|
|
77
185
|
/** Get current authenticated user */
|
|
78
186
|
getMe: () => Promise<User>;
|
|
79
187
|
/** Logout and clear session */
|
|
@@ -88,6 +196,22 @@ export declare class GameCoreClient {
|
|
|
88
196
|
}>;
|
|
89
197
|
/** Link VK account to current user */
|
|
90
198
|
linkVk: (accessToken: string) => Promise<void>;
|
|
199
|
+
/**
|
|
200
|
+
* Attach an email + password identity to the currently
|
|
201
|
+
* authenticated user. Use this for Telegram-only / VK-only
|
|
202
|
+
* accounts that want a backup login method. The user must
|
|
203
|
+
* not already have an email set — update flows go through
|
|
204
|
+
* `changePassword()` or a future `changeEmail()` method.
|
|
205
|
+
*
|
|
206
|
+
* Rate-limited to the same bucket as `/auth/register`.
|
|
207
|
+
* Returns the normalised email on success; throws 409 if the
|
|
208
|
+
* user already has an email or if another account on this
|
|
209
|
+
* site owns the address.
|
|
210
|
+
*/
|
|
211
|
+
linkEmail: (email: string, password: string) => Promise<{
|
|
212
|
+
success: boolean;
|
|
213
|
+
email: string;
|
|
214
|
+
}>;
|
|
91
215
|
/** Unlink auth provider */
|
|
92
216
|
unlinkProvider: (provider: string) => Promise<void>;
|
|
93
217
|
/** Preview VK account merge (before confirming) */
|
|
@@ -102,20 +226,49 @@ export declare class GameCoreClient {
|
|
|
102
226
|
}>;
|
|
103
227
|
};
|
|
104
228
|
catalog: {
|
|
105
|
-
/**
|
|
229
|
+
/**
|
|
230
|
+
* Get paginated games catalog.
|
|
231
|
+
*
|
|
232
|
+
* Returns `{ data: Game[], pagination: { page, limit, total, totalPages, hasMore } }`.
|
|
233
|
+
*
|
|
234
|
+
* @param params.page - Page number (1-based, default 1)
|
|
235
|
+
* @param params.limit - Items per page (1-200, default 50)
|
|
236
|
+
* @param params.inStockOnly - Only games that have products in stock
|
|
237
|
+
* @param params.include - "meta" to include categories/deliveryTypes
|
|
238
|
+
* @param params.sort - Sort order: "popular" | "name" | "new" | "soldCount"
|
|
239
|
+
* @param params.q - Search query (Meilisearch or fallback)
|
|
240
|
+
*/
|
|
106
241
|
getGames: (params?: {
|
|
242
|
+
page?: number;
|
|
243
|
+
limit?: number;
|
|
107
244
|
locale?: string;
|
|
108
245
|
type?: string;
|
|
109
246
|
deliveryType?: string;
|
|
110
247
|
include?: string;
|
|
111
248
|
inStockOnly?: boolean;
|
|
112
249
|
sort?: "popular" | "name" | "new" | "soldCount";
|
|
113
|
-
|
|
250
|
+
q?: string;
|
|
251
|
+
}) => Promise<PagedGamesResponse>;
|
|
114
252
|
/** Get homepage ranked games */
|
|
115
253
|
getHomepageGames: () => Promise<Game[]>;
|
|
116
254
|
/** Get single game with categories */
|
|
117
255
|
getGame: (slug: string, locale?: string) => Promise<GameDetail>;
|
|
118
|
-
/**
|
|
256
|
+
/**
|
|
257
|
+
* Get recommended games for a game detail page
|
|
258
|
+
* ("you might also like" / "related games").
|
|
259
|
+
*
|
|
260
|
+
* Returns games of the same `type` as the source game, randomly
|
|
261
|
+
* selected and filtered by per-site visibility overrides.
|
|
262
|
+
*
|
|
263
|
+
* @param gameSlug - Source game slug. Must be the **canonical**
|
|
264
|
+
* slug — this endpoint does NOT resolve aliases and returns an
|
|
265
|
+
* empty array for alias inputs. If you only have an alias,
|
|
266
|
+
* call `getGame()` first and use
|
|
267
|
+
* `result.canonicalSlug ?? result.slug`.
|
|
268
|
+
* @param limit - Max recommendations (default 8). The backend
|
|
269
|
+
* caps the effective limit; very large values are trimmed
|
|
270
|
+
* server-side.
|
|
271
|
+
*/
|
|
119
272
|
getRecommendations: (gameSlug: string, limit?: number) => Promise<Game[]>;
|
|
120
273
|
/** Get categories for a game with product counts and delivery metadata */
|
|
121
274
|
getCategories: (gameSlug: string) => Promise<Category[]>;
|
|
@@ -148,17 +301,22 @@ export declare class GameCoreClient {
|
|
|
148
301
|
minItems: number;
|
|
149
302
|
discountPercent: number;
|
|
150
303
|
}[]>;
|
|
151
|
-
/**
|
|
304
|
+
/**
|
|
305
|
+
* Get active promo campaigns. `targetUrl` is the clickable
|
|
306
|
+
* destination for the banner artwork (nullable — null means
|
|
307
|
+
* display-only).
|
|
308
|
+
*/
|
|
152
309
|
getPromos: () => Promise<{
|
|
153
310
|
id: number;
|
|
154
311
|
name: string;
|
|
155
312
|
type: string;
|
|
156
313
|
value: number;
|
|
157
314
|
scope: string;
|
|
158
|
-
bannerTitle?: string;
|
|
159
|
-
bannerDescription?: string;
|
|
160
|
-
bannerImageUrl?: string;
|
|
161
|
-
bannerColor?: string;
|
|
315
|
+
bannerTitle?: string | null;
|
|
316
|
+
bannerDescription?: string | null;
|
|
317
|
+
bannerImageUrl?: string | null;
|
|
318
|
+
bannerColor?: string | null;
|
|
319
|
+
targetUrl?: string | null;
|
|
162
320
|
endsAt?: string;
|
|
163
321
|
}[]>;
|
|
164
322
|
/** Get all games with full metadata (categories, delivery types) */
|
|
@@ -173,24 +331,64 @@ export declare class GameCoreClient {
|
|
|
173
331
|
}>;
|
|
174
332
|
};
|
|
175
333
|
cart: {
|
|
176
|
-
/**
|
|
334
|
+
/**
|
|
335
|
+
* Get cart items for the authenticated user. Each row comes
|
|
336
|
+
* back with `quantity`, `addedAt`, and `gameIcon` /
|
|
337
|
+
* `productIcon` populated by the server (2 extra lookups for
|
|
338
|
+
* the whole cart, not per row).
|
|
339
|
+
*/
|
|
177
340
|
get: () => Promise<CartItem[]>;
|
|
178
|
-
/**
|
|
341
|
+
/**
|
|
342
|
+
* Add a single item to the cart. `quantity` is optional and
|
|
343
|
+
* defaults to `1`. The server caps per-row quantity at 999.
|
|
344
|
+
*/
|
|
179
345
|
add: (item: Omit<CartItem, "id">) => Promise<CartItem>;
|
|
180
|
-
/**
|
|
346
|
+
/**
|
|
347
|
+
* Replace the server cart with the given list. Kept for
|
|
348
|
+
* backwards compatibility with SDK <= 0.12 and for the
|
|
349
|
+
* "clear everything and insert fresh" use case. Prefer
|
|
350
|
+
* `cart.merge()` when handling the guest → authed handoff so
|
|
351
|
+
* an existing server cart is not wiped.
|
|
352
|
+
*/
|
|
181
353
|
sync: (items: Omit<CartItem, "id">[]) => Promise<CartItem[]>;
|
|
354
|
+
/**
|
|
355
|
+
* Merge the given items into the server cart without wiping
|
|
356
|
+
* it. Items colliding on `(productId, deliveryData)` add
|
|
357
|
+
* their quantities (capped at 999 per row); new rows are
|
|
358
|
+
* inserted. Use this when a guest with a localStorage cart
|
|
359
|
+
* logs in and we want to keep both the old server rows and
|
|
360
|
+
* the newly collected ones.
|
|
361
|
+
*/
|
|
362
|
+
merge: (items: Omit<CartItem, "id">[]) => Promise<CartItem[]>;
|
|
182
363
|
/** Remove item from cart by ID */
|
|
183
364
|
remove: (id: number) => Promise<void>;
|
|
184
365
|
/** Clear all cart items */
|
|
185
366
|
clear: () => Promise<void>;
|
|
186
367
|
};
|
|
187
368
|
checkout: {
|
|
188
|
-
/**
|
|
369
|
+
/**
|
|
370
|
+
* Create checkout (payment + orders). Auto-generates idempotency key.
|
|
371
|
+
*
|
|
372
|
+
* **Guest checkout:** This method works WITHOUT authentication when
|
|
373
|
+
* `data.email` is provided and `data.paymentMethod` is a gateway
|
|
374
|
+
* (not "balance"). The API creates a guest order tied to the email.
|
|
375
|
+
* No Telegram/VK login required. Balance payments still require auth.
|
|
376
|
+
*/
|
|
189
377
|
create: (data: CheckoutRequest, idempotencyKey?: string) => Promise<CheckoutResponse>;
|
|
190
|
-
/**
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
378
|
+
/**
|
|
379
|
+
* Complete a pending payment by deducting the amount from the
|
|
380
|
+
* user's balance (bonus first, then permanent). Returns the
|
|
381
|
+
* deduction breakdown and the post-deduction balance so the
|
|
382
|
+
* success page can render the receipt without a second
|
|
383
|
+
* `profile.getBalance()` fetch (which is race-prone right
|
|
384
|
+
* after a completion).
|
|
385
|
+
*
|
|
386
|
+
* Idempotent replay: a second call for an already-completed
|
|
387
|
+
* payment still succeeds and returns the current `newBalance`,
|
|
388
|
+
* but the deduction breakdown is absent because the original
|
|
389
|
+
* move is not re-derivable from persisted state.
|
|
390
|
+
*/
|
|
391
|
+
completeWithBalance: (paymentCode: string) => Promise<CompleteWithBalanceResult>;
|
|
194
392
|
/** Get available payment methods for checkout */
|
|
195
393
|
getPaymentMethods: () => Promise<PaymentMethod[]>;
|
|
196
394
|
};
|
|
@@ -199,9 +397,18 @@ export declare class GameCoreClient {
|
|
|
199
397
|
list: () => Promise<Order[]>;
|
|
200
398
|
/** Get single order by code (includes items + payment) */
|
|
201
399
|
get: (code: string) => Promise<Order>;
|
|
202
|
-
/**
|
|
203
|
-
|
|
204
|
-
|
|
400
|
+
/**
|
|
401
|
+
* Get orders by payment code (route is under /checkout prefix).
|
|
402
|
+
*
|
|
403
|
+
* Authenticated users are verified via the session cookie.
|
|
404
|
+
* Guest callers must pass the `guestEmail` used at checkout — the
|
|
405
|
+
* server enforces a case-insensitive match against the payment
|
|
406
|
+
* email before returning any order data. Without it, a guest
|
|
407
|
+
* request returns 404 (the same response as a missing code, so
|
|
408
|
+
* the endpoint does not leak existence of valid codes).
|
|
409
|
+
*/
|
|
410
|
+
getByPayment: (paymentCode: string, guestEmail?: string) => Promise<{
|
|
411
|
+
payment: PaymentInfo;
|
|
205
412
|
orders: Order[];
|
|
206
413
|
}>;
|
|
207
414
|
/** Preview cancel — check if cancellable and refund amount */
|
|
@@ -263,6 +470,57 @@ export declare class GameCoreClient {
|
|
|
263
470
|
getBroadcastStatus: () => Promise<{
|
|
264
471
|
subscribed: boolean;
|
|
265
472
|
}>;
|
|
473
|
+
/** List the current user's conversations (most-recent first). */
|
|
474
|
+
getConversations: () => Promise<Conversation[]>;
|
|
475
|
+
/**
|
|
476
|
+
* Fetch a conversation header plus its messages. Marks any
|
|
477
|
+
* unread admin/system messages as read as a side effect.
|
|
478
|
+
*/
|
|
479
|
+
getConversationMessages: (conversationId: number, params?: {
|
|
480
|
+
limit?: number;
|
|
481
|
+
offset?: number;
|
|
482
|
+
}) => Promise<ConversationDetail>;
|
|
483
|
+
/**
|
|
484
|
+
* Submit a code to fulfill an open "code requested" request.
|
|
485
|
+
* Rate-limited to 5 submissions/minute per IP.
|
|
486
|
+
*/
|
|
487
|
+
submitCode: (conversationId: number, requestId: number, code: string) => Promise<{
|
|
488
|
+
success: boolean;
|
|
489
|
+
data?: {
|
|
490
|
+
requestId: number;
|
|
491
|
+
};
|
|
492
|
+
}>;
|
|
493
|
+
/**
|
|
494
|
+
* Submit a screenshot file to fulfill an open "screenshot
|
|
495
|
+
* requested" request. Accepts a browser `File` object and
|
|
496
|
+
* delivers it via multipart upload. Rate-limited to 3
|
|
497
|
+
* submissions/minute per IP.
|
|
498
|
+
*/
|
|
499
|
+
submitScreenshot: (conversationId: number, requestId: number, file: File) => Promise<{
|
|
500
|
+
success: boolean;
|
|
501
|
+
data?: {
|
|
502
|
+
requestId: number;
|
|
503
|
+
};
|
|
504
|
+
}>;
|
|
505
|
+
/** Get the VAPID public key needed to create a PushSubscription. */
|
|
506
|
+
getPushPublicKey: () => Promise<{
|
|
507
|
+
publicKey: string;
|
|
508
|
+
}>;
|
|
509
|
+
/**
|
|
510
|
+
* Register a push subscription for the current user + site.
|
|
511
|
+
* Call `PushSubscription.toJSON()` in the browser and pass the
|
|
512
|
+
* result directly.
|
|
513
|
+
*/
|
|
514
|
+
subscribePush: (subscription: WebPushSubscriptionInput) => Promise<{
|
|
515
|
+
success: boolean;
|
|
516
|
+
}>;
|
|
517
|
+
/**
|
|
518
|
+
* Remove a push subscription by its endpoint. Call this when
|
|
519
|
+
* the user opts out or changes devices.
|
|
520
|
+
*/
|
|
521
|
+
unsubscribePush: (endpoint: string) => Promise<{
|
|
522
|
+
success: boolean;
|
|
523
|
+
}>;
|
|
266
524
|
};
|
|
267
525
|
favorites: {
|
|
268
526
|
/** List user's favorite products */
|
|
@@ -311,6 +569,38 @@ export declare class GameCoreClient {
|
|
|
311
569
|
}>;
|
|
312
570
|
/** Get commission history */
|
|
313
571
|
getCommissions: () => Promise<ReferralCommission[]>;
|
|
572
|
+
/**
|
|
573
|
+
* Get a small grid of popular products so referrers can
|
|
574
|
+
* create a one-click reflink without hunting through the
|
|
575
|
+
* catalog. Sorted primarily by referral transaction count on
|
|
576
|
+
* the current site — i.e. "games that other referrers are
|
|
577
|
+
* actually earning commission on". Falls back to the homepage
|
|
578
|
+
* ranking on brand-new sites that have no referral history
|
|
579
|
+
* yet, so the grid is never empty for a new referrer.
|
|
580
|
+
*
|
|
581
|
+
* @param limit - Max number of entries to return (default 10,
|
|
582
|
+
* capped at 50 server-side).
|
|
583
|
+
*/
|
|
584
|
+
getPopularProducts: (limit?: number) => Promise<{
|
|
585
|
+
slug: string;
|
|
586
|
+
name: string;
|
|
587
|
+
icon: string | null;
|
|
588
|
+
}[]>;
|
|
589
|
+
/**
|
|
590
|
+
* Get performance stats aggregated over an optional date range.
|
|
591
|
+
*
|
|
592
|
+
* Pass `from` / `to` as Date or ISO-8601 string to filter
|
|
593
|
+
* commissions, transactions, and new-member counts. Clicks
|
|
594
|
+
* remain lifetime — see `ReferralPerformance` docstring for
|
|
595
|
+
* the rationale. Omit both to get all-time totals.
|
|
596
|
+
*
|
|
597
|
+
* Typical usage: wire to 7d / 30d / 90d / all buttons on the
|
|
598
|
+
* profile referrals dashboard.
|
|
599
|
+
*/
|
|
600
|
+
getPerformance: (params?: {
|
|
601
|
+
from?: Date | string;
|
|
602
|
+
to?: Date | string;
|
|
603
|
+
}) => Promise<ReferralPerformance>;
|
|
314
604
|
};
|
|
315
605
|
reviews: {
|
|
316
606
|
/** Get public reviews (paginated) */
|
|
@@ -328,8 +618,14 @@ export declare class GameCoreClient {
|
|
|
328
618
|
getMine: () => Promise<Review[]>;
|
|
329
619
|
/** Get orders eligible for review */
|
|
330
620
|
getPending: () => Promise<Order[]>;
|
|
331
|
-
/**
|
|
332
|
-
|
|
621
|
+
/**
|
|
622
|
+
* Submit a review for a completed order. Returns a narrow
|
|
623
|
+
* {@link ReviewCreateResult} with the new id, rating, text echo,
|
|
624
|
+
* and optional bonus grant. To fetch the full review record
|
|
625
|
+
* (including `createdAt`, `authorName`, `adminReply`, etc.),
|
|
626
|
+
* call `reviews.getMine()` after the create completes.
|
|
627
|
+
*/
|
|
628
|
+
create: (orderId: number, rating: number, text?: string) => Promise<ReviewCreateResult>;
|
|
333
629
|
};
|
|
334
630
|
topup: {
|
|
335
631
|
/** Get available topup payment methods */
|
|
@@ -340,8 +636,19 @@ export declare class GameCoreClient {
|
|
|
340
636
|
getStatus: (code: string) => Promise<TopupStatus>;
|
|
341
637
|
};
|
|
342
638
|
giftCards: {
|
|
343
|
-
/**
|
|
344
|
-
|
|
639
|
+
/**
|
|
640
|
+
* Purchase a gift card. The amount is in RUB (despite the
|
|
641
|
+
* legacy SDK parameter name — the column was misnamed and has
|
|
642
|
+
* always held RUB values, see Wave 3 audit tasks/112a). The
|
|
643
|
+
* method accepts either a plain number for backwards
|
|
644
|
+
* compatibility or an options object with an explicit message.
|
|
645
|
+
*
|
|
646
|
+
* @param amountRub - RUB amount to deduct from the user's
|
|
647
|
+
* balance and encode into the gift card.
|
|
648
|
+
* @param message - Optional personal note shown to the
|
|
649
|
+
* redeeming user.
|
|
650
|
+
*/
|
|
651
|
+
purchase: (amountRub: number, message?: string) => Promise<GiftCard>;
|
|
345
652
|
/** Redeem a gift card code */
|
|
346
653
|
redeem: (code: string) => Promise<{
|
|
347
654
|
amount: number;
|
package/dist/index.js
CHANGED
|
@@ -84,7 +84,9 @@ class GameCoreClient {
|
|
|
84
84
|
getCookieConsent: () => this.request("GET", "/site/cookie-consent"),
|
|
85
85
|
getCatalogSections: () => this.request("GET", "/site/catalog-sections"),
|
|
86
86
|
getBanners: () => this.request("GET", "/site/banners"),
|
|
87
|
-
getAnnouncementBar: () => this.request("GET", "/site/announcement-bar")
|
|
87
|
+
getAnnouncementBar: () => this.request("GET", "/site/announcement-bar"),
|
|
88
|
+
getSitemapData: () => this.request("GET", "/seo/sitemap-data"),
|
|
89
|
+
requestGame: (data) => this.request("POST", "/site/request-game", data)
|
|
88
90
|
};
|
|
89
91
|
auth = {
|
|
90
92
|
initTelegram: () => this.request("POST", "/auth/telegram/init"),
|
|
@@ -105,12 +107,25 @@ class GameCoreClient {
|
|
|
105
107
|
}
|
|
106
108
|
}, intervalMs);
|
|
107
109
|
}),
|
|
108
|
-
|
|
110
|
+
verifyMiniApp: (initData, ref) => this.request("POST", "/auth/telegram/miniapp", { initData, ref }, { rawResponse: true }),
|
|
111
|
+
verifyTelegramWidget: (data, ref) => this.request("POST", "/auth/telegram/widget", { ...data, ref }, { rawResponse: true }),
|
|
112
|
+
getVkAuthUrl: (redirectUri, ref) => {
|
|
113
|
+
const params = new URLSearchParams;
|
|
114
|
+
params.set("redirect", redirectUri);
|
|
115
|
+
if (ref)
|
|
116
|
+
params.set("ref", ref);
|
|
117
|
+
return this.request("GET", `/auth/vk/url?${params.toString()}`, undefined, { rawResponse: true });
|
|
118
|
+
},
|
|
119
|
+
vkCallback: (code, state) => this.request("POST", "/auth/vk/callback", { code, state }, { rawResponse: true }),
|
|
109
120
|
verifyVk: (accessToken, ref) => this.request("POST", "/auth/vk/verify", { accessToken, ref }, { rawResponse: true }),
|
|
121
|
+
register: (email, password, firstName, ref) => this.request("POST", "/auth/register", { email, password, firstName, ref }, { rawResponse: true }),
|
|
122
|
+
login: (email, password) => this.request("POST", "/auth/login", { email, password }, { rawResponse: true }),
|
|
123
|
+
changePassword: (currentPassword, newPassword) => this.request("POST", "/auth/change-password", { currentPassword, newPassword }),
|
|
110
124
|
getMe: () => this.request("GET", "/auth/me", undefined, { rawResponse: true }),
|
|
111
125
|
logout: () => this.request("POST", "/auth/logout"),
|
|
112
126
|
getIdentities: () => this.request("GET", "/auth/identities", undefined, { rawResponse: true }),
|
|
113
127
|
linkVk: (accessToken) => this.request("POST", "/auth/link/vk", { accessToken }),
|
|
128
|
+
linkEmail: (email, password) => this.request("POST", "/auth/link-email", { email, password }),
|
|
114
129
|
unlinkProvider: (provider) => this.request("POST", `/auth/unlink/${provider}`),
|
|
115
130
|
mergePreview: (accessToken) => this.request("POST", "/auth/merge/preview", { accessToken }),
|
|
116
131
|
mergeConfirm: (accessToken) => this.request("POST", "/auth/merge/confirm", { accessToken })
|
|
@@ -118,6 +133,10 @@ class GameCoreClient {
|
|
|
118
133
|
catalog = {
|
|
119
134
|
getGames: (params) => {
|
|
120
135
|
const qs = new URLSearchParams;
|
|
136
|
+
if (params?.page)
|
|
137
|
+
qs.set("page", String(params.page));
|
|
138
|
+
if (params?.limit)
|
|
139
|
+
qs.set("limit", String(params.limit));
|
|
121
140
|
if (params?.locale)
|
|
122
141
|
qs.set("locale", params.locale);
|
|
123
142
|
if (params?.type)
|
|
@@ -130,6 +149,8 @@ class GameCoreClient {
|
|
|
130
149
|
qs.set("inStockOnly", "true");
|
|
131
150
|
if (params?.sort)
|
|
132
151
|
qs.set("sort", params.sort);
|
|
152
|
+
if (params?.q)
|
|
153
|
+
qs.set("q", params.q);
|
|
133
154
|
const q = qs.toString();
|
|
134
155
|
return this.request("GET", `/catalog/games${q ? `?${q}` : ""}`);
|
|
135
156
|
},
|
|
@@ -173,6 +194,7 @@ class GameCoreClient {
|
|
|
173
194
|
get: () => this.request("GET", "/cart"),
|
|
174
195
|
add: (item) => this.request("POST", "/cart", item),
|
|
175
196
|
sync: (items) => this.request("POST", "/cart/sync", { items }),
|
|
197
|
+
merge: (items) => this.request("POST", "/cart/merge", { items }),
|
|
176
198
|
remove: (id) => this.request("DELETE", `/cart/${id}`),
|
|
177
199
|
clear: () => this.request("DELETE", "/cart")
|
|
178
200
|
};
|
|
@@ -189,7 +211,10 @@ class GameCoreClient {
|
|
|
189
211
|
orders = {
|
|
190
212
|
list: () => this.request("GET", "/orders"),
|
|
191
213
|
get: (code) => this.request("GET", `/orders/${code}`),
|
|
192
|
-
getByPayment: (paymentCode) =>
|
|
214
|
+
getByPayment: (paymentCode, guestEmail) => {
|
|
215
|
+
const qs = guestEmail ? `?email=${encodeURIComponent(guestEmail)}` : "";
|
|
216
|
+
return this.request("GET", `/checkout/orders/payment/${paymentCode}${qs}`, undefined, { rawResponse: true });
|
|
217
|
+
},
|
|
193
218
|
cancelPreview: (code) => this.request("GET", `/orders/${code}/cancel-preview`),
|
|
194
219
|
cancel: (code) => this.request("POST", `/orders/${code}/cancel`)
|
|
195
220
|
};
|
|
@@ -216,7 +241,27 @@ class GameCoreClient {
|
|
|
216
241
|
updateSettings: (data) => this.request("PUT", "/profile/settings", data),
|
|
217
242
|
subscribeBroadcast: () => this.request("POST", "/profile/broadcast/subscribe"),
|
|
218
243
|
unsubscribeBroadcast: () => this.request("POST", "/profile/broadcast/unsubscribe"),
|
|
219
|
-
getBroadcastStatus: () => this.request("GET", "/profile/broadcast/status")
|
|
244
|
+
getBroadcastStatus: () => this.request("GET", "/profile/broadcast/status"),
|
|
245
|
+
getConversations: () => this.request("GET", "/profile/conversations"),
|
|
246
|
+
getConversationMessages: (conversationId, params) => {
|
|
247
|
+
const qs = new URLSearchParams;
|
|
248
|
+
if (params?.limit)
|
|
249
|
+
qs.set("limit", String(params.limit));
|
|
250
|
+
if (params?.offset)
|
|
251
|
+
qs.set("offset", String(params.offset));
|
|
252
|
+
const q = qs.toString();
|
|
253
|
+
return this.request("GET", `/profile/conversations/${conversationId}/messages${q ? `?${q}` : ""}`);
|
|
254
|
+
},
|
|
255
|
+
submitCode: (conversationId, requestId, code) => this.request("POST", `/profile/conversations/${conversationId}/submit-code`, { requestId, code }),
|
|
256
|
+
submitScreenshot: (conversationId, requestId, file) => {
|
|
257
|
+
const form = new FormData;
|
|
258
|
+
form.append("requestId", String(requestId));
|
|
259
|
+
form.append("file", file);
|
|
260
|
+
return this.request("POST", `/profile/conversations/${conversationId}/submit-screenshot`, form);
|
|
261
|
+
},
|
|
262
|
+
getPushPublicKey: () => this.request("GET", "/profile/push/public-key"),
|
|
263
|
+
subscribePush: (subscription) => this.request("POST", "/profile/push/subscribe", subscription),
|
|
264
|
+
unsubscribePush: (endpoint) => this.request("POST", "/profile/push/unsubscribe", { endpoint })
|
|
220
265
|
};
|
|
221
266
|
favorites = {
|
|
222
267
|
list: () => this.request("GET", "/favorites"),
|
|
@@ -236,7 +281,22 @@ class GameCoreClient {
|
|
|
236
281
|
updateLink: (id, data) => this.request("PUT", `/referral/links/${id}`, data),
|
|
237
282
|
deleteLink: (id) => this.request("DELETE", `/referral/links/${id}`),
|
|
238
283
|
getLinkStats: (id) => this.request("GET", `/referral/links/${id}/stats`),
|
|
239
|
-
getCommissions: () => this.request("GET", "/referral/commissions")
|
|
284
|
+
getCommissions: () => this.request("GET", "/referral/commissions"),
|
|
285
|
+
getPopularProducts: (limit) => {
|
|
286
|
+
const qs = limit ? `?limit=${limit}` : "";
|
|
287
|
+
return this.request("GET", `/referral/popular-products${qs}`);
|
|
288
|
+
},
|
|
289
|
+
getPerformance: (params) => {
|
|
290
|
+
const qs = new URLSearchParams;
|
|
291
|
+
if (params?.from) {
|
|
292
|
+
qs.set("from", params.from instanceof Date ? params.from.toISOString() : params.from);
|
|
293
|
+
}
|
|
294
|
+
if (params?.to) {
|
|
295
|
+
qs.set("to", params.to instanceof Date ? params.to.toISOString() : params.to);
|
|
296
|
+
}
|
|
297
|
+
const q = qs.toString();
|
|
298
|
+
return this.request("GET", `/referral/performance${q ? `?${q}` : ""}`);
|
|
299
|
+
}
|
|
240
300
|
};
|
|
241
301
|
reviews = {
|
|
242
302
|
listPublic: (params) => {
|
|
@@ -259,7 +319,11 @@ class GameCoreClient {
|
|
|
259
319
|
getRandom: (limit = 5) => this.request("GET", `/reviews/public/random?limit=${limit}`),
|
|
260
320
|
getMine: () => this.request("GET", "/reviews/mine"),
|
|
261
321
|
getPending: () => this.request("GET", "/reviews/pending"),
|
|
262
|
-
create: (orderId, rating, text) => this.request("POST", "/reviews", {
|
|
322
|
+
create: (orderId, rating, text) => this.request("POST", "/reviews", {
|
|
323
|
+
orderId,
|
|
324
|
+
rating,
|
|
325
|
+
text
|
|
326
|
+
})
|
|
263
327
|
};
|
|
264
328
|
topup = {
|
|
265
329
|
getPaymentMethods: () => this.request("GET", "/topup/payment-methods"),
|
|
@@ -267,7 +331,10 @@ class GameCoreClient {
|
|
|
267
331
|
getStatus: (code) => this.request("GET", `/topup/${code}`)
|
|
268
332
|
};
|
|
269
333
|
giftCards = {
|
|
270
|
-
purchase: (
|
|
334
|
+
purchase: (amountRub, message) => this.request("POST", "/gift-cards/purchase", {
|
|
335
|
+
amountRub,
|
|
336
|
+
message
|
|
337
|
+
}),
|
|
271
338
|
redeem: (code) => this.request("POST", "/gift-cards/redeem", { code }),
|
|
272
339
|
check: (code) => this.request("GET", `/gift-cards/check/${code}`),
|
|
273
340
|
getMine: () => this.request("GET", "/profile/gift-cards")
|
package/dist/types.d.ts
CHANGED
|
@@ -8,6 +8,47 @@ export interface AuthStatusResponse {
|
|
|
8
8
|
status: "pending" | "verified" | "authenticated" | "expired" | "used";
|
|
9
9
|
user?: User;
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Payload returned by Telegram Login Widget when the user completes
|
|
13
|
+
* authentication. Same shape as Telegram's official docs — you can hand
|
|
14
|
+
* this object directly to auth.verifyTelegramWidget().
|
|
15
|
+
* https://core.telegram.org/widgets/login
|
|
16
|
+
*/
|
|
17
|
+
export interface TelegramWidgetUser {
|
|
18
|
+
id: number;
|
|
19
|
+
first_name: string;
|
|
20
|
+
last_name?: string;
|
|
21
|
+
username?: string;
|
|
22
|
+
photo_url?: string;
|
|
23
|
+
auth_date: number;
|
|
24
|
+
hash: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Narrow user DTO returned by /auth/telegram/miniapp and /auth/telegram/widget.
|
|
28
|
+
* This is intentionally a subset of the full {@link User} type — the auth
|
|
29
|
+
* endpoints only echo identity + role, not balance/level/email fields, so
|
|
30
|
+
* typing it as `User` would lie to SDK consumers. Call auth.getMe() after
|
|
31
|
+
* login if the storefront needs the full profile.
|
|
32
|
+
*/
|
|
33
|
+
export interface TelegramAuthUser {
|
|
34
|
+
id: number;
|
|
35
|
+
telegramId: string | null;
|
|
36
|
+
firstName: string | null;
|
|
37
|
+
lastName: string | null;
|
|
38
|
+
username: string | null;
|
|
39
|
+
photoUrl: string | null;
|
|
40
|
+
role: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Response from the Mini App / Widget POST verification endpoints.
|
|
44
|
+
* Body includes success, status and (on success) the authenticated user.
|
|
45
|
+
*/
|
|
46
|
+
export interface TelegramAuthResponse {
|
|
47
|
+
success: boolean;
|
|
48
|
+
status?: "authenticated";
|
|
49
|
+
user?: TelegramAuthUser;
|
|
50
|
+
error?: string;
|
|
51
|
+
}
|
|
11
52
|
export interface User {
|
|
12
53
|
id: number;
|
|
13
54
|
firstName: string;
|
|
@@ -84,13 +125,36 @@ export interface GameDetail {
|
|
|
84
125
|
name: string;
|
|
85
126
|
icon: string | null;
|
|
86
127
|
localIcon?: string | null;
|
|
128
|
+
/** Landscape hero image (1200x630). Null if no gallery is available. */
|
|
87
129
|
coverImage?: string | null;
|
|
130
|
+
/** Gallery of product screenshots (resized to 800x600). */
|
|
88
131
|
images?: string[];
|
|
89
132
|
description: string | null;
|
|
133
|
+
/** Editorial badges like "hit", "new", "popular", "sale". */
|
|
134
|
+
tags?: string[];
|
|
135
|
+
/** Availability lifecycle. Shares the union from {@link Game}. */
|
|
136
|
+
availabilityStatus?: "available" | "coming_soon" | "maintenance" | "discontinued";
|
|
137
|
+
/** Human-readable message for non-available games. */
|
|
138
|
+
availabilityMessage?: string | null;
|
|
90
139
|
inStock?: boolean;
|
|
91
140
|
productCount?: number;
|
|
92
141
|
categories: Category[];
|
|
93
142
|
seo?: SeoContent | null;
|
|
143
|
+
/**
|
|
144
|
+
* Present only when the request used an alias slug and the backend
|
|
145
|
+
* resolved it to a different canonical slug. When set, the storefront
|
|
146
|
+
* should issue a 301 redirect to `/games/${canonicalSlug}` instead
|
|
147
|
+
* of rendering the page. Absent when the requested slug is already
|
|
148
|
+
* canonical.
|
|
149
|
+
*/
|
|
150
|
+
canonicalSlug?: string;
|
|
151
|
+
/**
|
|
152
|
+
* ISO-8601 timestamp of the last meaningful edit on this canonical
|
|
153
|
+
* game — bumped on catalog changes (products, pricing, metadata).
|
|
154
|
+
* Storefronts should use this as `lastModified` in sitemap entries
|
|
155
|
+
* so Google doesn't refetch pages that haven't changed.
|
|
156
|
+
*/
|
|
157
|
+
updatedAt?: string;
|
|
94
158
|
}
|
|
95
159
|
/**
|
|
96
160
|
* Per-site SEO content for a game page.
|
|
@@ -188,6 +252,29 @@ export interface CartItem {
|
|
|
188
252
|
productName: string;
|
|
189
253
|
price: number;
|
|
190
254
|
deliveryData: Record<string, string>;
|
|
255
|
+
/**
|
|
256
|
+
* Quantity for multi-amount products (e.g. N × 500 Robux).
|
|
257
|
+
* Optional when writing (server defaults to `1`); always
|
|
258
|
+
* present on server responses.
|
|
259
|
+
*/
|
|
260
|
+
quantity?: number;
|
|
261
|
+
/**
|
|
262
|
+
* ISO-8601 timestamp of when the row was inserted. Absent when
|
|
263
|
+
* the item was freshly constructed client-side and hasn't been
|
|
264
|
+
* sent to the server yet.
|
|
265
|
+
*/
|
|
266
|
+
addedAt?: string;
|
|
267
|
+
/**
|
|
268
|
+
* Canonical game icon (localIcon → icon fallback). May be `null`
|
|
269
|
+
* if the underlying game has no artwork. Never present on
|
|
270
|
+
* client-authored items — only populated on server responses.
|
|
271
|
+
*/
|
|
272
|
+
gameIcon?: string | null;
|
|
273
|
+
/**
|
|
274
|
+
* Supplier product icon (localIcon → icon fallback). Same
|
|
275
|
+
* semantics as `gameIcon`.
|
|
276
|
+
*/
|
|
277
|
+
productIcon?: string | null;
|
|
191
278
|
}
|
|
192
279
|
export interface CheckoutRequest {
|
|
193
280
|
email?: string;
|
|
@@ -215,6 +302,46 @@ export interface CheckoutResponse {
|
|
|
215
302
|
}>;
|
|
216
303
|
}
|
|
217
304
|
export type OrderStatus = "pending" | "paid" | "processing" | "completed" | "cancelled" | "refunded" | "failed";
|
|
305
|
+
/**
|
|
306
|
+
* Payment record returned by `checkout.getByPayment()`.
|
|
307
|
+
*
|
|
308
|
+
* A payment groups one or more orders created in the same checkout
|
|
309
|
+
* call. The `code` is the external identifier exposed to the
|
|
310
|
+
* payment gateway and returned via the success URL query string.
|
|
311
|
+
*
|
|
312
|
+
* `paymentMethod` and `gatewayType` are `null` when the payment is
|
|
313
|
+
* fully settled from the user's balance (no external gateway is
|
|
314
|
+
* involved). `completedAt` is set when the payment transitions to
|
|
315
|
+
* `completed` via webhook confirmation or balance settlement; it
|
|
316
|
+
* remains `null` for `pending`, `failed`, and `cancelled` payments
|
|
317
|
+
* (the failure/cancellation timestamp is tracked separately by
|
|
318
|
+
* the stale-payment scanner and not surfaced on this shape).
|
|
319
|
+
*/
|
|
320
|
+
export interface PaymentInfo {
|
|
321
|
+
code: string;
|
|
322
|
+
totalAmount: number;
|
|
323
|
+
status: "pending" | "completed" | "failed" | "cancelled";
|
|
324
|
+
paymentMethod: string | null;
|
|
325
|
+
gatewayType: string | null;
|
|
326
|
+
createdAt: string;
|
|
327
|
+
completedAt: string | null;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Normalised delivery hint attached to an order. Used by the
|
|
331
|
+
* storefront "My Orders" page to decide which CTA to show
|
|
332
|
+
* (robux-via-pass → "Check Roblox transactions"; gift card →
|
|
333
|
+
* "Copy code"; login delivery → "Waiting for credentials"; etc).
|
|
334
|
+
*
|
|
335
|
+
* `helpTextKey` is an i18n key — the storefront owns the
|
|
336
|
+
* translation layer, so copy changes do not require a backend
|
|
337
|
+
* deploy. Unknown `kind` values should render a generic
|
|
338
|
+
* "processing" message as a fallback.
|
|
339
|
+
*/
|
|
340
|
+
export interface OrderDeliveryMeta {
|
|
341
|
+
kind: "cdkey" | "login" | "pass_based" | "service" | "manual" | (string & {});
|
|
342
|
+
helpTextKey: string;
|
|
343
|
+
checkTransactionsUrl?: string;
|
|
344
|
+
}
|
|
218
345
|
export interface Order {
|
|
219
346
|
id: number;
|
|
220
347
|
code: string;
|
|
@@ -231,6 +358,13 @@ export interface Order {
|
|
|
231
358
|
};
|
|
232
359
|
createdAt: string;
|
|
233
360
|
completedAt?: string;
|
|
361
|
+
/**
|
|
362
|
+
* Delivery hint for the storefront UI — present on responses
|
|
363
|
+
* from `/profile/orders` and `/orders/:code` starting with
|
|
364
|
+
* SDK 0.13. Absent on legacy responses and on endpoints that
|
|
365
|
+
* do not currently surface it.
|
|
366
|
+
*/
|
|
367
|
+
deliveryMeta?: OrderDeliveryMeta;
|
|
234
368
|
}
|
|
235
369
|
export interface OrderItem {
|
|
236
370
|
id: number;
|
|
@@ -257,6 +391,20 @@ export interface UserBalance {
|
|
|
257
391
|
expiresAt: string;
|
|
258
392
|
}>;
|
|
259
393
|
}
|
|
394
|
+
/**
|
|
395
|
+
* One rung of the loyalty level ladder — used by the "how levels
|
|
396
|
+
* work" explainer on the profile page. Shape matches what the
|
|
397
|
+
* server computes from `loyalty_levels` (per-site custom) or the
|
|
398
|
+
* hardcoded default ladder.
|
|
399
|
+
*/
|
|
400
|
+
export interface LevelSystemLevel {
|
|
401
|
+
level: number;
|
|
402
|
+
name: string;
|
|
403
|
+
discountPercent: number;
|
|
404
|
+
minSpendingUsd: number;
|
|
405
|
+
minReviews: number;
|
|
406
|
+
minReferrals: number;
|
|
407
|
+
}
|
|
260
408
|
export interface LevelStatus {
|
|
261
409
|
currentLevel: number;
|
|
262
410
|
currentDiscount: number;
|
|
@@ -280,6 +428,19 @@ export interface LevelStatus {
|
|
|
280
428
|
met: boolean;
|
|
281
429
|
};
|
|
282
430
|
};
|
|
431
|
+
/**
|
|
432
|
+
* Highest level in the ladder. Storefronts should use this
|
|
433
|
+
* instead of hardcoding "15" so per-site custom ladders render
|
|
434
|
+
* correctly. Always present on responses from SDK 0.13+.
|
|
435
|
+
*/
|
|
436
|
+
maxLevel?: number;
|
|
437
|
+
/** Highest discount percent in the ladder. */
|
|
438
|
+
maxDiscount?: number;
|
|
439
|
+
/**
|
|
440
|
+
* Full ordered ladder. Use this to render the explainer table
|
|
441
|
+
* or a progress timeline. Omitted on very old responses.
|
|
442
|
+
*/
|
|
443
|
+
allLevels?: LevelSystemLevel[];
|
|
283
444
|
}
|
|
284
445
|
export interface Transaction {
|
|
285
446
|
id: number;
|
|
@@ -311,27 +472,212 @@ export interface Favorite {
|
|
|
311
472
|
categorySlug?: string;
|
|
312
473
|
createdAt: string;
|
|
313
474
|
}
|
|
475
|
+
/**
|
|
476
|
+
* Review record. Fields are endpoint-specific — this interface is a
|
|
477
|
+
* union of everything any review endpoint may return, and real-world
|
|
478
|
+
* shape depends on which route you call:
|
|
479
|
+
*
|
|
480
|
+
* - `reviews.listPublic()` → `id`, `rating`, `text`, `authorName`,
|
|
481
|
+
* `gameName`, `adminReply`, `adminReplyAt`,
|
|
482
|
+
* `createdAt`
|
|
483
|
+
* - `reviews.mine()` → `id`, `rating`, `text`, `adminReply`,
|
|
484
|
+
* `adminReplyAt`, `createdAt`, `order`
|
|
485
|
+
* - `reviews.create()` → the freshly-created review + `bonus`
|
|
486
|
+
*
|
|
487
|
+
* Fields that are not relevant to a given endpoint are `undefined`. Do
|
|
488
|
+
* not assume any single field is always present.
|
|
489
|
+
*/
|
|
314
490
|
export interface Review {
|
|
315
491
|
id: number;
|
|
316
|
-
userId: number;
|
|
317
|
-
userName?: string;
|
|
318
|
-
orderId: number;
|
|
319
|
-
orderCode?: string;
|
|
320
492
|
rating: number;
|
|
321
493
|
text?: string;
|
|
494
|
+
createdAt: string;
|
|
495
|
+
/** Public display name (author). Returned by `listPublic()`. */
|
|
496
|
+
authorName?: string;
|
|
497
|
+
/** Legacy alias for `authorName`. Prefer `authorName` on new code. */
|
|
498
|
+
userName?: string;
|
|
499
|
+
/** Owner of the review. Returned only to authenticated admins. */
|
|
500
|
+
userId?: number;
|
|
501
|
+
/** Link back to the order the review was left for. */
|
|
502
|
+
orderId?: number;
|
|
503
|
+
orderCode?: string;
|
|
322
504
|
gameName?: string;
|
|
505
|
+
/**
|
|
506
|
+
* Public reply from site support. Rendered under the review body
|
|
507
|
+
* as "Ответ поддержки". `null` if support has not replied or the
|
|
508
|
+
* reply was removed. Included in both the public listing and the
|
|
509
|
+
* authenticated profile reviews list.
|
|
510
|
+
*/
|
|
511
|
+
adminReply?: string | null;
|
|
512
|
+
/**
|
|
513
|
+
* ISO-8601 timestamp of when the support reply was created or last
|
|
514
|
+
* updated. `null` when no reply is present.
|
|
515
|
+
*/
|
|
516
|
+
adminReplyAt?: string | null;
|
|
517
|
+
/**
|
|
518
|
+
* Nested order summary, returned only by `reviews.mine()` so the
|
|
519
|
+
* profile "My reviews" page can show game + order code without a
|
|
520
|
+
* second fetch. `null` when the underlying order was deleted.
|
|
521
|
+
*/
|
|
522
|
+
order?: {
|
|
523
|
+
code: string;
|
|
524
|
+
gameName: string;
|
|
525
|
+
createdAt: string;
|
|
526
|
+
} | null;
|
|
527
|
+
/** Bonus granted for leaving the review, if any. */
|
|
323
528
|
bonus?: {
|
|
324
529
|
amount: number;
|
|
325
530
|
percent: number;
|
|
326
531
|
expiresAt: string;
|
|
327
532
|
};
|
|
328
|
-
createdAt: string;
|
|
329
533
|
}
|
|
330
534
|
export interface ReviewStats {
|
|
331
535
|
averageRating: number;
|
|
332
536
|
totalCount: number;
|
|
333
537
|
distribution?: Record<string, number>;
|
|
334
538
|
}
|
|
539
|
+
/**
|
|
540
|
+
* Response shape returned by `checkout.completeWithBalance()`.
|
|
541
|
+
*
|
|
542
|
+
* The post-deduction balance (`newBalance`) is always present on a
|
|
543
|
+
* successful response — the storefront success page can render
|
|
544
|
+
* "new balance: X" without a second `profile.getBalance()` fetch
|
|
545
|
+
* (which is race-prone right after completion).
|
|
546
|
+
*
|
|
547
|
+
* The deduction breakdown (`balanceUsed`, `balanceDeduction`) is
|
|
548
|
+
* present **only on the first successful call** — it reflects what
|
|
549
|
+
* was actually moved by this request. If the client retries the
|
|
550
|
+
* endpoint for an already-completed payment (idempotent replay),
|
|
551
|
+
* those fields are `undefined` because the original breakdown is
|
|
552
|
+
* not re-derivable from persisted state. The `newBalance` is still
|
|
553
|
+
* included in that case so the receipt UI has something to render.
|
|
554
|
+
*
|
|
555
|
+
* When present, `balanceUsed` equals
|
|
556
|
+
* `balanceDeduction.fromBonus + balanceDeduction.fromPermanent`.
|
|
557
|
+
*/
|
|
558
|
+
export interface CompleteWithBalanceResult {
|
|
559
|
+
paymentCode: string;
|
|
560
|
+
status: "completed";
|
|
561
|
+
balanceUsed?: number;
|
|
562
|
+
balanceDeduction?: {
|
|
563
|
+
fromBonus: number;
|
|
564
|
+
fromPermanent: number;
|
|
565
|
+
};
|
|
566
|
+
newBalance: {
|
|
567
|
+
total: number;
|
|
568
|
+
permanent: number;
|
|
569
|
+
bonus: number;
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Short summary of a conversation as returned by
|
|
574
|
+
* `profile.getConversations()` — one row per user-owned order
|
|
575
|
+
* thread. Use the `id` to fetch full messages via
|
|
576
|
+
* `profile.getConversationMessages(id)`.
|
|
577
|
+
*/
|
|
578
|
+
export interface Conversation {
|
|
579
|
+
id: number;
|
|
580
|
+
orderId: number;
|
|
581
|
+
orderCode: string | null;
|
|
582
|
+
gameName: string | null;
|
|
583
|
+
orderStatus: string | null;
|
|
584
|
+
/** Number of unread system / admin messages. User messages don't count. */
|
|
585
|
+
unreadCount: number;
|
|
586
|
+
/**
|
|
587
|
+
* Preview of the most recent message. `body` is truncated to ~100
|
|
588
|
+
* chars. `null` if the conversation has no messages yet.
|
|
589
|
+
*/
|
|
590
|
+
lastMessage: {
|
|
591
|
+
body: string;
|
|
592
|
+
authorType: "user" | "admin" | "system";
|
|
593
|
+
messageType: "text" | "status_change" | "code_requested" | "screenshot_requested" | (string & {});
|
|
594
|
+
createdAt: string;
|
|
595
|
+
} | null;
|
|
596
|
+
/** Last time either party posted a message, ISO-8601. */
|
|
597
|
+
lastMessageAt: string;
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Single message inside a conversation. `metadata` is parsed JSON —
|
|
601
|
+
* system messages may carry status-change payloads, request ids, etc.
|
|
602
|
+
* Free chat (user-authored `text` messages) is currently disabled —
|
|
603
|
+
* expect only `admin`, `system`, and request-response messages.
|
|
604
|
+
*/
|
|
605
|
+
export interface ConversationMessage {
|
|
606
|
+
id: number;
|
|
607
|
+
authorType: "user" | "admin" | "system";
|
|
608
|
+
authorId: number | null;
|
|
609
|
+
messageType: "text" | "status_change" | "code_requested" | "screenshot_requested" | (string & {});
|
|
610
|
+
body: string;
|
|
611
|
+
metadata: Record<string, unknown> | null;
|
|
612
|
+
/** Set when the current viewer marked the message as read. */
|
|
613
|
+
readAt: string | null;
|
|
614
|
+
createdAt: string;
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Open supplier-initiated request inside a conversation. The UI
|
|
618
|
+
* decides which input to show the user based on `requestType`.
|
|
619
|
+
*/
|
|
620
|
+
export interface ConversationRequest {
|
|
621
|
+
id: number;
|
|
622
|
+
conversationId: number;
|
|
623
|
+
orderId: number;
|
|
624
|
+
orderItemId: number;
|
|
625
|
+
requestType: "code" | "screenshot";
|
|
626
|
+
status: "open" | "fulfilled" | "cancelled" | "expired";
|
|
627
|
+
requestedAt: string;
|
|
628
|
+
fulfilledAt: string | null;
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* Full detail returned by `profile.getConversationMessages(id)`.
|
|
632
|
+
* The conversation header is included so the UI does not need a
|
|
633
|
+
* separate fetch to render the page title / order summary.
|
|
634
|
+
*/
|
|
635
|
+
export interface ConversationDetail {
|
|
636
|
+
conversation: {
|
|
637
|
+
id: number;
|
|
638
|
+
orderId: number;
|
|
639
|
+
orderCode: string | null;
|
|
640
|
+
gameName: string | null;
|
|
641
|
+
orderStatus: string | null;
|
|
642
|
+
};
|
|
643
|
+
messages: ConversationMessage[];
|
|
644
|
+
/** Open supplier requests the user can respond to right now. */
|
|
645
|
+
openRequests: ConversationRequest[];
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* Web Push subscription payload returned by the browser's
|
|
649
|
+
* `PushSubscription.toJSON()`. Pass this to
|
|
650
|
+
* `profile.subscribePush()` to start receiving push notifications
|
|
651
|
+
* for order status updates and conversation replies.
|
|
652
|
+
*/
|
|
653
|
+
export interface WebPushSubscriptionInput {
|
|
654
|
+
endpoint: string;
|
|
655
|
+
keys: {
|
|
656
|
+
p256dh: string;
|
|
657
|
+
auth: string;
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Narrow response returned by `reviews.create()`.
|
|
662
|
+
*
|
|
663
|
+
* The create endpoint deliberately returns less than a full `Review`
|
|
664
|
+
* — only the fields the storefront needs to acknowledge the
|
|
665
|
+
* submission: the new review id, the numeric rating, the text echo,
|
|
666
|
+
* and the optional bonus grant metadata.
|
|
667
|
+
*
|
|
668
|
+
* Callers who need the full review (with `createdAt`, `authorName`,
|
|
669
|
+
* etc.) should re-fetch via `reviews.getMine()` after the create.
|
|
670
|
+
*/
|
|
671
|
+
export interface ReviewCreateResult {
|
|
672
|
+
id: number;
|
|
673
|
+
rating: number;
|
|
674
|
+
text: string | null;
|
|
675
|
+
bonus: {
|
|
676
|
+
amount: number;
|
|
677
|
+
percent: number;
|
|
678
|
+
expiresAt: string;
|
|
679
|
+
} | null;
|
|
680
|
+
}
|
|
335
681
|
export interface CouponResult {
|
|
336
682
|
type: string;
|
|
337
683
|
value: number;
|
|
@@ -366,13 +712,50 @@ export interface ReferralCommission {
|
|
|
366
712
|
commissionPercent: number;
|
|
367
713
|
createdAt: string;
|
|
368
714
|
}
|
|
715
|
+
/**
|
|
716
|
+
* Date-range aggregated performance metrics for a referrer.
|
|
717
|
+
*
|
|
718
|
+
* Commission, transaction and member counts honour the `from` /
|
|
719
|
+
* `to` range passed to `referrals.getPerformance()`. `totalClicks`
|
|
720
|
+
* is **lifetime across all of the referrer's links** and is NOT
|
|
721
|
+
* date-filtered — click events are not individually timestamped in
|
|
722
|
+
* the current schema. Storefronts should label the clicks metric
|
|
723
|
+
* accordingly ("all-time clicks" vs. "period earnings").
|
|
724
|
+
*/
|
|
725
|
+
export interface ReferralPerformance {
|
|
726
|
+
totalCommission: number;
|
|
727
|
+
totalClicks: number;
|
|
728
|
+
totalTransactions: number;
|
|
729
|
+
newMembers: number;
|
|
730
|
+
}
|
|
369
731
|
export interface TopupMethod {
|
|
370
732
|
type: string;
|
|
371
733
|
label: string;
|
|
372
734
|
description?: string;
|
|
373
735
|
feePercent?: number;
|
|
374
736
|
gatewayType?: string;
|
|
375
|
-
invoiceCurrency?: string;
|
|
737
|
+
invoiceCurrency?: string | null;
|
|
738
|
+
/**
|
|
739
|
+
* Minimum topup amount in RUB. `null` means the storefront
|
|
740
|
+
* should use its global minimum (typically 50 RUB). The topup
|
|
741
|
+
* route enforces this server-side too.
|
|
742
|
+
*/
|
|
743
|
+
minAmount?: number | null;
|
|
744
|
+
/**
|
|
745
|
+
* Maximum topup amount in RUB. `null` means "use global cap".
|
|
746
|
+
*/
|
|
747
|
+
maxAmount?: number | null;
|
|
748
|
+
/**
|
|
749
|
+
* Grouping bucket for collapsible UIs. Known values: `"direct"`,
|
|
750
|
+
* `"p2p"`, `"intl"`. Unknown values should render as a
|
|
751
|
+
* generic "Other" group.
|
|
752
|
+
*/
|
|
753
|
+
group?: "direct" | "p2p" | "intl" | (string & {}) | null;
|
|
754
|
+
/**
|
|
755
|
+
* Optional warning text rendered underneath the method
|
|
756
|
+
* selector (e.g. "Временно нестабильно"). `null` means no note.
|
|
757
|
+
*/
|
|
758
|
+
stabilityNote?: string | null;
|
|
376
759
|
}
|
|
377
760
|
export interface TopupResponse {
|
|
378
761
|
code: string;
|
|
@@ -385,13 +768,48 @@ export interface TopupStatus {
|
|
|
385
768
|
amount: number;
|
|
386
769
|
createdAt?: string;
|
|
387
770
|
}
|
|
771
|
+
/**
|
|
772
|
+
* Gift card voucher. Stored in RUB; the field was historically
|
|
773
|
+
* called `denomination` in the SDK and `amount_usd` in the DB
|
|
774
|
+
* column, but both were misnomers — the value has always been RUB
|
|
775
|
+
* (see Wave 3 #34 audit `tasks/112a-giftcard-currency-audit.md`).
|
|
776
|
+
* Use `amountRub` on new code; `amountUsd` and `denomination` are
|
|
777
|
+
* deprecated aliases that echo the same value.
|
|
778
|
+
*/
|
|
388
779
|
export interface GiftCard {
|
|
389
780
|
id: number;
|
|
390
781
|
code: string;
|
|
391
|
-
|
|
392
|
-
|
|
782
|
+
/** Canonical RUB value. Use this on new code. */
|
|
783
|
+
amountRub: number;
|
|
784
|
+
/**
|
|
785
|
+
* @deprecated Legacy alias echoing `amountRub`. The name was
|
|
786
|
+
* wrong historically — the value was always RUB despite the
|
|
787
|
+
* `Usd` suffix. Remove once storefronts upgrade past SDK 0.13.x.
|
|
788
|
+
*/
|
|
789
|
+
amountUsd?: number;
|
|
790
|
+
/**
|
|
791
|
+
* @deprecated Legacy alias echoing `amountRub`. Kept for
|
|
792
|
+
* storefronts that were reading this field from typed code; at
|
|
793
|
+
* runtime the backend never emitted `denomination`, so most
|
|
794
|
+
* consumers were already getting `undefined`.
|
|
795
|
+
*/
|
|
796
|
+
denomination?: number;
|
|
797
|
+
/** Currency of `amountRub`. Always `"RUB"` for now. */
|
|
798
|
+
currency: "RUB";
|
|
799
|
+
/**
|
|
800
|
+
* Remaining balance if the card supports partial redemption.
|
|
801
|
+
* For active and expired cards this equals `amountRub`. For
|
|
802
|
+
* redeemed or cancelled cards it is `0`. Partial redemption is
|
|
803
|
+
* not implemented yet — the field is reserved so storefronts
|
|
804
|
+
* can start rendering it now without a future breaking change.
|
|
805
|
+
*/
|
|
806
|
+
remainingBalance: number;
|
|
807
|
+
status: "active" | "redeemed" | "expired" | "cancelled" | (string & {});
|
|
808
|
+
message?: string | null;
|
|
809
|
+
/** ISO-8601 expiry timestamp; `null` if the card never expires. */
|
|
810
|
+
expiresAt?: string | null;
|
|
393
811
|
createdAt: string;
|
|
394
|
-
redeemedAt?: string;
|
|
812
|
+
redeemedAt?: string | null;
|
|
395
813
|
}
|
|
396
814
|
export interface Announcement {
|
|
397
815
|
id: number;
|
|
@@ -496,6 +914,17 @@ export interface PaginatedResponse<T> {
|
|
|
496
914
|
hasMore: boolean;
|
|
497
915
|
};
|
|
498
916
|
}
|
|
917
|
+
/** Catalog games use page-based pagination (page 1, 2, ...) */
|
|
918
|
+
export interface PagedGamesResponse {
|
|
919
|
+
data: Game[];
|
|
920
|
+
pagination: {
|
|
921
|
+
page: number;
|
|
922
|
+
limit: number;
|
|
923
|
+
total: number;
|
|
924
|
+
totalPages: number;
|
|
925
|
+
hasMore: boolean;
|
|
926
|
+
};
|
|
927
|
+
}
|
|
499
928
|
export declare class GameCoreError extends Error {
|
|
500
929
|
status: number;
|
|
501
930
|
code?: string;
|
package/package.json
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gamecore-api/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "TypeScript SDK for GameCore API — browser-safe, zero dependencies",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
-
"module": "dist/index.mjs",
|
|
8
7
|
"exports": {
|
|
9
8
|
".": {
|
|
10
9
|
"import": "./dist/index.js",
|