@gamecore-api/sdk 0.26.2 → 0.27.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/AGENTS.md +11 -0
- package/README.md +35 -0
- package/dist/client.d.ts +39 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +13 -0
- package/dist/types.d.ts +8 -0
- package/examples/01-quickstart.ts +18 -13
- package/examples/05-currency-switching.ts +74 -0
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -61,6 +61,17 @@ import { verifyWebhookSignature } from "@gamecore-api/sdk/server";
|
|
|
61
61
|
- The backend overlays **game names**, short descriptions, and descriptions in the requested locale. Slugs / IDs never change.
|
|
62
62
|
- Original-language responses: just don't set `locale`.
|
|
63
63
|
|
|
64
|
+
## Display currency (since 0.27.0)
|
|
65
|
+
|
|
66
|
+
- Pass `currency: "USD" | "EUR" | "KZT" | "UAH" | "TRY" | …` in constructor → SDK sends `X-Currency` automatically on every catalog request.
|
|
67
|
+
- Override at runtime: `gc.setCurrency("EUR")` / `gc.getCurrency()`.
|
|
68
|
+
- Per-call override: `gc.catalog.getProducts(slug, { currency: "USD" })`.
|
|
69
|
+
- Every product response carries `product.currency` so the storefront can render the right symbol without tracking the requested code.
|
|
70
|
+
- Server applies **live FX rates** (open.er-api.com, 30-min cache) and rounds per currency convention (whole KZT/UAH/TRY/RUB, 2-decimal USD/EUR/GBP).
|
|
71
|
+
- Default is RUB — existing storefronts keep working unchanged.
|
|
72
|
+
- **Checkout is unrelated**: payments still settle in RUB or USD via the chosen gateway. Display currency is purely catalog-side.
|
|
73
|
+
- See `examples/05-currency-switching.ts`.
|
|
74
|
+
|
|
64
75
|
## Pitfalls
|
|
65
76
|
|
|
66
77
|
- **Don't put `apiKey` in client-side JS bundles** — proxy through your own
|
package/README.md
CHANGED
|
@@ -20,6 +20,7 @@ for a short orientation, then look at runnable code in
|
|
|
20
20
|
| `examples/02-locale-switching.ts` | RU/EN switching: constructor, runtime, per-call |
|
|
21
21
|
| `examples/03-error-handling.ts` | `GameCoreError`, status/code patterns, retries |
|
|
22
22
|
| `examples/04-webhook-verify.ts` | HMAC verification with `/server` entry point |
|
|
23
|
+
| `examples/05-currency-switching.ts` | Display currency (RUB / USD / EUR / KZT / UAH / TRY …) |
|
|
23
24
|
|
|
24
25
|
## Locale switching (RU / EN)
|
|
25
26
|
|
|
@@ -49,6 +50,40 @@ const enGame = await gc.catalog.getGame("afk-journey", "en");
|
|
|
49
50
|
|
|
50
51
|
Supported locales: `"ru"` (default when nothing is passed) and `"en"`.
|
|
51
52
|
|
|
53
|
+
## Display currency (RUB / USD / EUR / KZT / UAH / TRY …)
|
|
54
|
+
|
|
55
|
+
Since 0.27.0 the SDK can quote product prices in any of the supported
|
|
56
|
+
ISO-4217 currencies. The server uses live FX rates (cached 30 minutes)
|
|
57
|
+
and rounds per currency convention (whole KZT/UAH/TRY/RUB, 2-decimal
|
|
58
|
+
USD/EUR/GBP).
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { GameCoreClient, type SdkCurrency } from "@gamecore-api/sdk";
|
|
62
|
+
|
|
63
|
+
const gc = new GameCoreClient({
|
|
64
|
+
apiKey: "gc_live_...",
|
|
65
|
+
baseUrl: "https://api.gamecore-api.tech",
|
|
66
|
+
currency: "USD", // SDK adds X-Currency: USD on every catalog request
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Runtime switch — wire to a storefront currency picker:
|
|
70
|
+
gc.setCurrency("KZT");
|
|
71
|
+
const products = await gc.catalog.getProducts("free-fire");
|
|
72
|
+
console.log(products[0].price, products[0].currency); // 480, "KZT"
|
|
73
|
+
|
|
74
|
+
// Per-call override:
|
|
75
|
+
const usdProducts = await gc.catalog.getProducts("free-fire", { currency: "USD" });
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Supported currencies: `RUB` (default), `USD`, `EUR`, `GBP`, `KZT`,
|
|
79
|
+
`UAH`, `TRY`, `BRL`, `ARS`, `INR`, `PLN`, `CZK`. Every product
|
|
80
|
+
response carries the resolved `currency` field — read that instead of
|
|
81
|
+
tracking the requested code separately.
|
|
82
|
+
|
|
83
|
+
**Checkout is unrelated**: payment gateways still settle in RUB or USD
|
|
84
|
+
depending on the chosen `paymentMethod`. The display currency is a
|
|
85
|
+
catalog-side feature today.
|
|
86
|
+
|
|
52
87
|
## What's new in 0.25.0
|
|
53
88
|
|
|
54
89
|
- **Locale switching (RU / EN).** New `locale` option on `GameCoreClient`
|
package/dist/client.d.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import type { Announcement, AnnouncementBar, CartItem, CashbackPreview, CatalogSection, Category, CategoryInfo, CheckoutRequest, CheckoutResponse, CheckoutStatus, CmsArticleListResponse, CmsArticleLocale, CmsArticleResponse, CmsArticleType, CompleteWithBalanceResult, Conversation, ConversationDetail, CouponResult, DailyBonusClaimResult, DailyBonusStatus, DeliveryHelpResponse, ExchangeRates, FaqListResponse, Favorite, Game, GameDetail, GameRequestList, GiftCard, LegalDocument, LevelStatus, Notification, Order, PagedGamesResponse, PlatformInfo, PaginatedResponse, PaymentInfo, PaymentMethod, Product, ProductFilters, ProfileSummary, PublicCoupon, Quest, QuestCompleteResult, ReferralCommission, ReferralLink, ReferralPerformance, ReferralStats, ReferralTransferResult, Review, ReviewCreateResult, ReviewPolicy, ReviewProof, ReviewStats, ScreenshotsResponse, SearchResult, SiteConfig, SiteStats, SiteUIConfig, SystemRequirementsResponse, TelegramAuthResponse, TelegramBotLoginOptions, TelegramInitResponse, TelegramWidgetRenderOptions, TelegramWidgetUser, TopupMethod, TopupResponse, TopupStatus, Transaction, User, UserBalance, WebPushSubscriptionInput } from "./types";
|
|
2
2
|
/** Supported storefront locales — extend as new languages land. */
|
|
3
3
|
export type SdkLocale = "ru" | "en";
|
|
4
|
+
/**
|
|
5
|
+
* ISO-4217 codes the API can quote prices in. Matches the server-side
|
|
6
|
+
* `DisplayCurrency` union in `apps/api/src/utils/currency.ts`. RUB is
|
|
7
|
+
* the default when nothing is configured; USD is the canonical base
|
|
8
|
+
* price in the DB.
|
|
9
|
+
*/
|
|
10
|
+
export type SdkCurrency = "RUB" | "USD" | "EUR" | "GBP" | "KZT" | "UAH" | "TRY" | "BRL" | "ARS" | "INR" | "PLN" | "CZK";
|
|
4
11
|
export interface GameCoreOptions {
|
|
5
12
|
/** Site API key (gc_live_xxx or gc_test_xxx) */
|
|
6
13
|
apiKey: string;
|
|
@@ -16,12 +23,25 @@ export interface GameCoreOptions {
|
|
|
16
23
|
* Omit to keep the legacy behaviour (server falls back to "ru").
|
|
17
24
|
*/
|
|
18
25
|
locale?: SdkLocale;
|
|
26
|
+
/**
|
|
27
|
+
* Default display currency for catalog product prices. When set,
|
|
28
|
+
* every request sends an `X-Currency` header so the API converts
|
|
29
|
+
* `price` / `priceWithoutDiscount` into that ISO-4217 code (using
|
|
30
|
+
* live FX rates) and stamps the resolved code on each product
|
|
31
|
+
* response under the `currency` field.
|
|
32
|
+
*
|
|
33
|
+
* Per-call `?currency=` overrides this default. Omit to keep RUB
|
|
34
|
+
* (the legacy default — every existing storefront keeps working
|
|
35
|
+
* without a code change).
|
|
36
|
+
*/
|
|
37
|
+
currency?: SdkCurrency;
|
|
19
38
|
}
|
|
20
39
|
export declare class GameCoreClient {
|
|
21
40
|
private apiKey;
|
|
22
41
|
private baseUrl;
|
|
23
42
|
private onAuthError?;
|
|
24
43
|
private defaultLocale?;
|
|
44
|
+
private defaultCurrency?;
|
|
25
45
|
constructor(options: GameCoreOptions);
|
|
26
46
|
/**
|
|
27
47
|
* Switch the client's default locale at runtime — useful for a
|
|
@@ -31,6 +51,14 @@ export declare class GameCoreClient {
|
|
|
31
51
|
setLocale(locale: SdkLocale | undefined): void;
|
|
32
52
|
/** Current default locale (undefined when none set). */
|
|
33
53
|
getLocale(): SdkLocale | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* Switch the client's default display currency at runtime — wire to
|
|
56
|
+
* a storefront currency picker so the next product fetch comes back
|
|
57
|
+
* already converted, without re-instantiating the client.
|
|
58
|
+
*/
|
|
59
|
+
setCurrency(currency: SdkCurrency | undefined): void;
|
|
60
|
+
/** Current default currency (undefined when none set → API returns RUB). */
|
|
61
|
+
getCurrency(): SdkCurrency | undefined;
|
|
34
62
|
private request;
|
|
35
63
|
site: {
|
|
36
64
|
/** Get site configuration (modules, auth methods, payments, currency) */
|
|
@@ -468,8 +496,17 @@ export declare class GameCoreClient {
|
|
|
468
496
|
getDeliveryHelp: (gameSlug: string) => Promise<DeliveryHelpResponse>;
|
|
469
497
|
/** Get categories for a game with product counts and delivery metadata */
|
|
470
498
|
getCategories: (gameSlug: string) => Promise<Category[]>;
|
|
471
|
-
/**
|
|
472
|
-
|
|
499
|
+
/**
|
|
500
|
+
* Get products for a game with optional filters.
|
|
501
|
+
*
|
|
502
|
+
* `filters.currency` overrides the client-level default for
|
|
503
|
+
* this call only — useful for an admin tool that has a
|
|
504
|
+
* Storefront in one currency but needs to preview USD pricing
|
|
505
|
+
* without flipping the whole client.
|
|
506
|
+
*/
|
|
507
|
+
getProducts: (gameSlug: string, filters?: ProductFilters & {
|
|
508
|
+
currency?: SdkCurrency;
|
|
509
|
+
}) => Promise<Product[]>;
|
|
473
510
|
/** Get products grouped by category */
|
|
474
511
|
getProductsGrouped: (gameSlug: string) => Promise<{
|
|
475
512
|
category: Category;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { GameCoreClient } from "./client";
|
|
2
|
-
export type { GameCoreOptions } from "./client";
|
|
2
|
+
export type { GameCoreOptions, SdkCurrency, SdkLocale } from "./client";
|
|
3
3
|
export * from "./types";
|
|
4
4
|
export { convertPrice, formatPrice, generateIdempotencyKey } from "./utils";
|
package/dist/index.js
CHANGED
|
@@ -37,11 +37,13 @@ class GameCoreClient {
|
|
|
37
37
|
baseUrl;
|
|
38
38
|
onAuthError;
|
|
39
39
|
defaultLocale;
|
|
40
|
+
defaultCurrency;
|
|
40
41
|
constructor(options) {
|
|
41
42
|
this.apiKey = options.apiKey;
|
|
42
43
|
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
43
44
|
this.onAuthError = options.onAuthError;
|
|
44
45
|
this.defaultLocale = options.locale;
|
|
46
|
+
this.defaultCurrency = options.currency;
|
|
45
47
|
}
|
|
46
48
|
setLocale(locale) {
|
|
47
49
|
this.defaultLocale = locale;
|
|
@@ -49,6 +51,12 @@ class GameCoreClient {
|
|
|
49
51
|
getLocale() {
|
|
50
52
|
return this.defaultLocale;
|
|
51
53
|
}
|
|
54
|
+
setCurrency(currency) {
|
|
55
|
+
this.defaultCurrency = currency;
|
|
56
|
+
}
|
|
57
|
+
getCurrency() {
|
|
58
|
+
return this.defaultCurrency;
|
|
59
|
+
}
|
|
52
60
|
async request(method, path, body, options) {
|
|
53
61
|
const headers = {
|
|
54
62
|
"X-Api-Key": this.apiKey,
|
|
@@ -57,6 +65,9 @@ class GameCoreClient {
|
|
|
57
65
|
if (this.defaultLocale) {
|
|
58
66
|
headers["Accept-Language"] = this.defaultLocale;
|
|
59
67
|
}
|
|
68
|
+
if (this.defaultCurrency) {
|
|
69
|
+
headers["X-Currency"] = this.defaultCurrency;
|
|
70
|
+
}
|
|
60
71
|
if (options?.idempotencyKey) {
|
|
61
72
|
headers["X-Idempotency-Key"] = options.idempotencyKey;
|
|
62
73
|
}
|
|
@@ -307,6 +318,8 @@ class GameCoreClient {
|
|
|
307
318
|
qs.set("minPrice", String(filters.minPrice));
|
|
308
319
|
if (filters?.maxPrice != null)
|
|
309
320
|
qs.set("maxPrice", String(filters.maxPrice));
|
|
321
|
+
if (filters?.currency)
|
|
322
|
+
qs.set("currency", filters.currency);
|
|
310
323
|
const q = qs.toString();
|
|
311
324
|
return this.request("GET", `/catalog/games/${gameSlug}/products${q ? `?${q}` : ""}`);
|
|
312
325
|
},
|
package/dist/types.d.ts
CHANGED
|
@@ -381,6 +381,14 @@ export interface Product {
|
|
|
381
381
|
estimatedDelivery?: string;
|
|
382
382
|
icon: string | null;
|
|
383
383
|
price: number | null;
|
|
384
|
+
/**
|
|
385
|
+
* ISO-4217 code (`RUB`, `USD`, `EUR`, `KZT`, …) for `price` and
|
|
386
|
+
* `priceWithoutDiscount`. Set by the API on every product response
|
|
387
|
+
* since gamecore-api 2026-05-11 / SDK 0.27 — the storefront should
|
|
388
|
+
* use this directly rather than tracking the requested currency
|
|
389
|
+
* separately. Falls through as `undefined` from older API builds.
|
|
390
|
+
*/
|
|
391
|
+
currency?: string;
|
|
384
392
|
priceWithoutDiscount?: number;
|
|
385
393
|
discountPercent?: number;
|
|
386
394
|
gameId: string;
|
|
@@ -46,25 +46,30 @@ console.log("picked product:", product.id, product.name, "price:", product.price
|
|
|
46
46
|
// 4. Create checkout (guest — pass email; no Telegram/VK login required).
|
|
47
47
|
// For balance-based payment, the user must be authenticated first.
|
|
48
48
|
//
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
// • deliveryData —
|
|
60
|
-
//
|
|
61
|
-
//
|
|
49
|
+
// The SDK's `CheckoutRequest.items` type currently marks several
|
|
50
|
+
// fields optional, but the API's body schema (TypeBox) rejects
|
|
51
|
+
// requests that omit them:
|
|
52
|
+
// • productId — REQUIRED, the supplier product
|
|
53
|
+
// • gameId — REQUIRED, the game slug. Drives routing for
|
|
54
|
+
// Steam top-ups, SuperPass bundles, and
|
|
55
|
+
// Robux-via-pass; the backend also reads it
|
|
56
|
+
// directly outside those paths.
|
|
57
|
+
// • gameName — REQUIRED by body validation (maxLength 500).
|
|
58
|
+
// • productName — REQUIRED by body validation (maxLength 500).
|
|
59
|
+
// • deliveryData — REQUIRED object (can be `{}`). For Steam /
|
|
60
|
+
// Roblox / login-required products it carries
|
|
61
|
+
// account name, server id, top-up currency, etc.
|
|
62
|
+
// • amount — optional. Quantity for fixed-price items
|
|
63
|
+
// (default 1) OR the top-up amount in local
|
|
64
|
+
// currency for Steam / variable-amount products.
|
|
62
65
|
const checkout = await gc.checkout.create({
|
|
63
66
|
email: "buyer@example.com",
|
|
64
67
|
items: [
|
|
65
68
|
{
|
|
66
69
|
productId: product.id,
|
|
67
70
|
gameId: game.slug,
|
|
71
|
+
gameName: game.name,
|
|
72
|
+
productName: product.name,
|
|
68
73
|
amount: 1,
|
|
69
74
|
deliveryData: {},
|
|
70
75
|
},
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 05 — Display-currency switching (RUB / USD / EUR / KZT / UAH / TRY / …)
|
|
3
|
+
*
|
|
4
|
+
* Catalog endpoints quote product prices in any of the supported ISO-4217
|
|
5
|
+
* currencies. RUB is the legacy default — a client that doesn't ask for
|
|
6
|
+
* anything else keeps getting ruble prices, same as before SDK 0.27.
|
|
7
|
+
*
|
|
8
|
+
* Resolution order on the server (highest priority first):
|
|
9
|
+
* 1. `?currency=USD` query param (per-call override)
|
|
10
|
+
* 2. `X-Currency` request header (SDK injects when constructor has
|
|
11
|
+
* `currency: "USD"` configured)
|
|
12
|
+
* 3. RUB default
|
|
13
|
+
*
|
|
14
|
+
* Run with:
|
|
15
|
+
* GAMECORE_API_KEY=gc_live_... bun run examples/05-currency-switching.ts
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { GameCoreClient, type SdkCurrency } from "@gamecore-api/sdk";
|
|
19
|
+
|
|
20
|
+
const apiKey = process.env.GAMECORE_API_KEY!;
|
|
21
|
+
const baseUrl = "https://api.gamecore-api.tech";
|
|
22
|
+
|
|
23
|
+
// Approach A — one client per currency. Simplest for a single-currency
|
|
24
|
+
// storefront (e.g. a US store that always shows USD).
|
|
25
|
+
const ru = new GameCoreClient({ apiKey, baseUrl, currency: "RUB" });
|
|
26
|
+
const usd = new GameCoreClient({ apiKey, baseUrl, currency: "USD" });
|
|
27
|
+
|
|
28
|
+
const gameSlug = "free-fire";
|
|
29
|
+
const ruProducts = await ru.catalog.getProducts(gameSlug);
|
|
30
|
+
const usdProducts = await usd.catalog.getProducts(gameSlug);
|
|
31
|
+
console.log("RUB first product:", {
|
|
32
|
+
name: ruProducts[0]?.name,
|
|
33
|
+
price: ruProducts[0]?.price,
|
|
34
|
+
currency: ruProducts[0]?.currency, // "RUB"
|
|
35
|
+
});
|
|
36
|
+
console.log("USD first product:", {
|
|
37
|
+
name: usdProducts[0]?.name,
|
|
38
|
+
price: usdProducts[0]?.price,
|
|
39
|
+
currency: usdProducts[0]?.currency, // "USD"
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Approach B — single client, switch at runtime. Wire this to a
|
|
43
|
+
// storefront currency picker so the next product fetch comes back
|
|
44
|
+
// already converted.
|
|
45
|
+
const gc = new GameCoreClient({ apiKey, baseUrl });
|
|
46
|
+
console.log("default currency:", gc.getCurrency()); // undefined → RUB
|
|
47
|
+
gc.setCurrency("KZT");
|
|
48
|
+
const kztProducts = await gc.catalog.getProducts(gameSlug);
|
|
49
|
+
console.log(
|
|
50
|
+
"KZT first product:",
|
|
51
|
+
kztProducts[0]?.price,
|
|
52
|
+
kztProducts[0]?.currency,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
// Approach C — per-call override. Admin tool example: a Russian
|
|
56
|
+
// operator inspects an EN/EUR preview of a product without flipping
|
|
57
|
+
// the rest of the session.
|
|
58
|
+
const previewCurrencies: SdkCurrency[] = ["EUR", "TRY", "UAH"];
|
|
59
|
+
for (const ccy of previewCurrencies) {
|
|
60
|
+
const products = await gc.catalog.getProducts(gameSlug, { currency: ccy });
|
|
61
|
+
console.log(`${ccy}:`, products[0]?.price, products[0]?.currency);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Notes for AI agents copying this example:
|
|
65
|
+
// • Don't try to convert prices yourself — the server applies live FX
|
|
66
|
+
// rates from open.er-api.com and rounds per-currency (whole KZT,
|
|
67
|
+
// 2-decimal EUR, etc.). Doing it client-side will drift.
|
|
68
|
+
// • Always use `product.currency` for the display string instead of
|
|
69
|
+
// hardcoding the requested code — the server is the source of
|
|
70
|
+
// truth when an FX rate is missing.
|
|
71
|
+
// • Checkout is unrelated: payment gateways still settle in RUB or
|
|
72
|
+
// USD depending on the chosen `paymentMethod`. The display
|
|
73
|
+
// currency is purely catalog-side until checkout currency support
|
|
74
|
+
// ships.
|