@neosianexus/super-tebex 3.0.3 → 3.0.4
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 +404 -125
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,27 +1,33 @@
|
|
|
1
|
-
# @
|
|
1
|
+
# @neosianexus/super-tebex
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@neosianexus/super-tebex)
|
|
4
|
+
[](https://www.npmjs.com/package/@neosianexus/super-tebex)
|
|
5
|
+
[](https://github.com/NeosiaNexus/super-tebex)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
|
|
9
|
+
> Tebex Headless SDK optimized for Next.js App Router with TanStack Query and Zustand.
|
|
4
10
|
|
|
5
11
|
## Features
|
|
6
12
|
|
|
7
13
|
- **TanStack Query v5** - Automatic caching, retry, stale-while-revalidate
|
|
8
|
-
- **Zustand v5** - Persisted client state (basket, user)
|
|
14
|
+
- **Zustand v5** - Persisted client state (basket, user) in localStorage
|
|
9
15
|
- **TypeScript First** - Zero `any`, strict mode, exhaustive types
|
|
10
16
|
- **Provider Pattern** - Single provider, granular hooks
|
|
11
|
-
- **Error Codes** - i18n-friendly error handling with `TebexErrorCode`
|
|
17
|
+
- **Error Codes** - i18n-friendly error handling with `TebexErrorCode` enum
|
|
12
18
|
- **Optimistic Updates** - Instant UI feedback on basket mutations
|
|
13
19
|
- **React Query DevTools** - Automatic in development mode
|
|
14
20
|
|
|
15
21
|
## Installation
|
|
16
22
|
|
|
17
23
|
```bash
|
|
18
|
-
npm install @
|
|
24
|
+
npm install @neosianexus/super-tebex
|
|
19
25
|
# or
|
|
20
|
-
yarn add @
|
|
26
|
+
yarn add @neosianexus/super-tebex
|
|
21
27
|
# or
|
|
22
|
-
pnpm add @
|
|
28
|
+
pnpm add @neosianexus/super-tebex
|
|
23
29
|
# or
|
|
24
|
-
bun add @
|
|
30
|
+
bun add @neosianexus/super-tebex
|
|
25
31
|
```
|
|
26
32
|
|
|
27
33
|
### Peer Dependencies
|
|
@@ -47,7 +53,7 @@ Wrap your app with `TebexProvider` in your root layout:
|
|
|
47
53
|
|
|
48
54
|
```tsx
|
|
49
55
|
// app/layout.tsx
|
|
50
|
-
import { TebexProvider } from '@
|
|
56
|
+
import { TebexProvider } from '@neosianexus/super-tebex';
|
|
51
57
|
|
|
52
58
|
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
53
59
|
return (
|
|
@@ -80,7 +86,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|
|
80
86
|
```tsx
|
|
81
87
|
'use client';
|
|
82
88
|
|
|
83
|
-
import { useCategories, useBasket, useUser } from '@
|
|
89
|
+
import { useCategories, useBasket, useUser } from '@neosianexus/super-tebex';
|
|
84
90
|
|
|
85
91
|
export function Shop() {
|
|
86
92
|
const { username, setUsername } = useUser();
|
|
@@ -111,44 +117,79 @@ export function Shop() {
|
|
|
111
117
|
}
|
|
112
118
|
```
|
|
113
119
|
|
|
114
|
-
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## API Reference
|
|
123
|
+
|
|
124
|
+
### Provider & Configuration
|
|
125
|
+
|
|
126
|
+
| Export | Description |
|
|
127
|
+
|--------|-------------|
|
|
128
|
+
| `TebexProvider` | Main provider component - wrap your app with this |
|
|
129
|
+
| `useTebexContext()` | Access QueryClient and config from context |
|
|
130
|
+
| `useTebexConfig()` | Access just the Tebex configuration |
|
|
131
|
+
|
|
132
|
+
#### TebexConfig
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
interface TebexConfig {
|
|
136
|
+
publicKey: string; // Your Tebex public key
|
|
137
|
+
baseUrl: string; // Your site URL (for checkout redirects)
|
|
138
|
+
urls?: {
|
|
139
|
+
complete?: string; // Success redirect path (default: '/shop/complete')
|
|
140
|
+
cancel?: string; // Cancel redirect path (default: '/shop/cancel')
|
|
141
|
+
};
|
|
142
|
+
onError?: (error: TebexError) => void; // Global error callback
|
|
143
|
+
devtools?: boolean; // Enable React Query DevTools (default: true in dev)
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
### Hooks
|
|
115
150
|
|
|
116
|
-
|
|
151
|
+
#### Data Fetching Hooks
|
|
117
152
|
|
|
118
153
|
| Hook | Description |
|
|
119
154
|
|------|-------------|
|
|
120
|
-
| `useCategories()` | Fetch all categories (with optional packages) |
|
|
121
|
-
| `useCategory(
|
|
122
|
-
| `usePackages()` | Fetch all packages |
|
|
123
|
-
| `usePackage(
|
|
155
|
+
| `useCategories(options?)` | Fetch all categories (with optional packages) |
|
|
156
|
+
| `useCategory(options)` | Fetch a single category by ID |
|
|
157
|
+
| `usePackages(options?)` | Fetch all packages (optionally by category) |
|
|
158
|
+
| `usePackage(options)` | Fetch a single package by ID |
|
|
124
159
|
| `useWebstore()` | Fetch webstore info (name, currency, domain) |
|
|
125
160
|
|
|
126
|
-
|
|
161
|
+
#### Basket Management Hooks
|
|
127
162
|
|
|
128
163
|
| Hook | Description |
|
|
129
164
|
|------|-------------|
|
|
130
165
|
| `useBasket()` | Full basket management with optimistic updates |
|
|
131
|
-
| `useCheckout()` | Launch Tebex.js checkout modal |
|
|
166
|
+
| `useCheckout(options?)` | Launch Tebex.js checkout modal |
|
|
132
167
|
| `useCoupons()` | Apply/remove coupon codes |
|
|
133
168
|
| `useGiftCards()` | Apply/remove gift cards |
|
|
134
169
|
| `useCreatorCodes()` | Apply/remove creator codes |
|
|
135
170
|
| `useGiftPackage()` | Gift a package to another user |
|
|
136
171
|
|
|
137
|
-
|
|
172
|
+
#### User Management Hooks
|
|
138
173
|
|
|
139
174
|
| Hook | Description |
|
|
140
175
|
|------|-------------|
|
|
141
176
|
| `useUser()` | Username management (persisted in localStorage) |
|
|
142
177
|
|
|
143
|
-
|
|
178
|
+
---
|
|
144
179
|
|
|
145
|
-
###
|
|
180
|
+
### Hook Details
|
|
146
181
|
|
|
147
|
-
|
|
182
|
+
#### useBasket
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
148
185
|
const {
|
|
186
|
+
// Data
|
|
149
187
|
basket, // Basket | null
|
|
150
188
|
packages, // BasketPackage[]
|
|
151
189
|
basketIdent, // string | null
|
|
190
|
+
itemCount, // number
|
|
191
|
+
total, // number
|
|
192
|
+
isEmpty, // boolean
|
|
152
193
|
|
|
153
194
|
// Loading states
|
|
154
195
|
isLoading,
|
|
@@ -167,25 +208,20 @@ const {
|
|
|
167
208
|
updateQuantity, // (params: UpdateQuantityParams) => Promise<void>
|
|
168
209
|
clearBasket, // () => void
|
|
169
210
|
refetch, // () => Promise<...>
|
|
170
|
-
|
|
171
|
-
// Computed
|
|
172
|
-
itemCount, // number
|
|
173
|
-
total, // number
|
|
174
|
-
isEmpty, // boolean
|
|
175
211
|
} = useBasket();
|
|
176
212
|
|
|
177
213
|
// Add package with options
|
|
178
214
|
await addPackage({
|
|
179
215
|
packageId: 123,
|
|
180
|
-
quantity: 2,
|
|
181
|
-
type: 'single',
|
|
182
|
-
variableData: { server: 'survival' },
|
|
216
|
+
quantity: 2, // optional, default: 1
|
|
217
|
+
type: 'single', // optional: 'single' | 'subscription'
|
|
218
|
+
variableData: { server: 'survival' }, // optional
|
|
183
219
|
});
|
|
184
220
|
```
|
|
185
221
|
|
|
186
|
-
|
|
222
|
+
#### useCategories
|
|
187
223
|
|
|
188
|
-
```
|
|
224
|
+
```typescript
|
|
189
225
|
const {
|
|
190
226
|
categories, // Category[] | null
|
|
191
227
|
data, // same as categories
|
|
@@ -204,9 +240,30 @@ const {
|
|
|
204
240
|
});
|
|
205
241
|
```
|
|
206
242
|
|
|
207
|
-
|
|
243
|
+
#### usePackages
|
|
208
244
|
|
|
209
|
-
```
|
|
245
|
+
```typescript
|
|
246
|
+
const {
|
|
247
|
+
packages, // Package[] | null
|
|
248
|
+
data, // same as packages
|
|
249
|
+
isLoading,
|
|
250
|
+
isFetching,
|
|
251
|
+
error,
|
|
252
|
+
errorCode,
|
|
253
|
+
refetch,
|
|
254
|
+
|
|
255
|
+
// Helpers
|
|
256
|
+
getById, // (id: number) => Package | undefined
|
|
257
|
+
getByName, // (name: string) => Package | undefined
|
|
258
|
+
} = usePackages({
|
|
259
|
+
categoryId: 123, // optional: filter by category
|
|
260
|
+
enabled: true, // default: true
|
|
261
|
+
});
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
#### useCheckout
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
210
267
|
const {
|
|
211
268
|
launch, // () => Promise<void>
|
|
212
269
|
isLaunching,
|
|
@@ -220,13 +277,13 @@ const {
|
|
|
220
277
|
onClose: () => console.log('Checkout closed'),
|
|
221
278
|
});
|
|
222
279
|
|
|
223
|
-
// Requires Tebex.js script in your page
|
|
224
|
-
// <script src="https://js.tebex.io/v/1.js" />
|
|
280
|
+
// IMPORTANT: Requires Tebex.js script in your page
|
|
281
|
+
// <script src="https://js.tebex.io/v/1.1.js" async />
|
|
225
282
|
```
|
|
226
283
|
|
|
227
|
-
|
|
284
|
+
#### useUser
|
|
228
285
|
|
|
229
|
-
```
|
|
286
|
+
```typescript
|
|
230
287
|
const {
|
|
231
288
|
username, // string | null
|
|
232
289
|
setUsername, // (username: string) => void
|
|
@@ -235,9 +292,9 @@ const {
|
|
|
235
292
|
} = useUser();
|
|
236
293
|
```
|
|
237
294
|
|
|
238
|
-
|
|
295
|
+
#### useCoupons
|
|
239
296
|
|
|
240
|
-
```
|
|
297
|
+
```typescript
|
|
241
298
|
const {
|
|
242
299
|
coupons, // Code[]
|
|
243
300
|
apply, // (code: string) => Promise<void>
|
|
@@ -249,12 +306,75 @@ const {
|
|
|
249
306
|
} = useCoupons();
|
|
250
307
|
```
|
|
251
308
|
|
|
309
|
+
#### useGiftCards
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
const {
|
|
313
|
+
giftCards, // GiftCardCode[]
|
|
314
|
+
apply, // (code: string) => Promise<void>
|
|
315
|
+
remove, // (code: string) => Promise<void>
|
|
316
|
+
isApplying,
|
|
317
|
+
isRemoving,
|
|
318
|
+
error,
|
|
319
|
+
errorCode,
|
|
320
|
+
} = useGiftCards();
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
#### useCreatorCodes
|
|
324
|
+
|
|
325
|
+
```typescript
|
|
326
|
+
const {
|
|
327
|
+
creatorCode, // string | null
|
|
328
|
+
apply, // (code: string) => Promise<void>
|
|
329
|
+
remove, // () => Promise<void>
|
|
330
|
+
isApplying,
|
|
331
|
+
isRemoving,
|
|
332
|
+
error,
|
|
333
|
+
errorCode,
|
|
334
|
+
} = useCreatorCodes();
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
#### useGiftPackage
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
const {
|
|
341
|
+
gift, // (params: GiftPackageParams) => Promise<void>
|
|
342
|
+
isGifting,
|
|
343
|
+
error,
|
|
344
|
+
errorCode,
|
|
345
|
+
} = useGiftPackage();
|
|
346
|
+
|
|
347
|
+
// Gift a package to another player
|
|
348
|
+
await gift({
|
|
349
|
+
packageId: 123,
|
|
350
|
+
targetUsername: 'friend_username',
|
|
351
|
+
});
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
#### useWebstore
|
|
355
|
+
|
|
356
|
+
```typescript
|
|
357
|
+
const {
|
|
358
|
+
webstore, // Webstore | null
|
|
359
|
+
name, // string | null
|
|
360
|
+
currency, // string | null
|
|
361
|
+
domain, // string | null
|
|
362
|
+
isLoading,
|
|
363
|
+
isFetching,
|
|
364
|
+
error,
|
|
365
|
+
errorCode,
|
|
366
|
+
refetch,
|
|
367
|
+
} = useWebstore();
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
252
372
|
## Error Handling
|
|
253
373
|
|
|
254
374
|
All hooks expose `error` (TebexError) and `errorCode` (TebexErrorCode) for i18n-friendly error handling:
|
|
255
375
|
|
|
256
|
-
```
|
|
257
|
-
import { TebexErrorCode } from '@
|
|
376
|
+
```typescript
|
|
377
|
+
import { TebexErrorCode } from '@neosianexus/super-tebex';
|
|
258
378
|
|
|
259
379
|
const { error, errorCode } = useBasket();
|
|
260
380
|
|
|
@@ -271,112 +391,184 @@ if (errorCode) {
|
|
|
271
391
|
}
|
|
272
392
|
```
|
|
273
393
|
|
|
274
|
-
###
|
|
394
|
+
### All Error Codes
|
|
275
395
|
|
|
276
396
|
| Category | Codes |
|
|
277
397
|
|----------|-------|
|
|
278
|
-
| Provider | `PROVIDER_NOT_FOUND`, `INVALID_CONFIG` |
|
|
279
|
-
| Auth | `NOT_AUTHENTICATED`, `INVALID_USERNAME` |
|
|
280
|
-
| Basket | `BASKET_NOT_FOUND`, `BASKET_CREATION_FAILED`, `BASKET_EXPIRED` |
|
|
281
|
-
| Package | `PACKAGE_NOT_FOUND`, `PACKAGE_OUT_OF_STOCK`, `PACKAGE_ALREADY_OWNED`, `INVALID_QUANTITY` |
|
|
282
|
-
| Category | `CATEGORY_NOT_FOUND` |
|
|
283
|
-
| Coupon | `COUPON_INVALID`, `COUPON_EXPIRED`, `COUPON_ALREADY_USED` |
|
|
284
|
-
| Gift Card | `GIFTCARD_INVALID`, `GIFTCARD_INSUFFICIENT_BALANCE` |
|
|
285
|
-
| Creator Code | `CREATOR_CODE_INVALID` |
|
|
286
|
-
| Checkout | `CHECKOUT_FAILED`, `CHECKOUT_CANCELLED` |
|
|
287
|
-
| Network | `NETWORK_ERROR`, `TIMEOUT`, `RATE_LIMITED` |
|
|
288
|
-
| Unknown | `UNKNOWN` |
|
|
398
|
+
| **Provider** | `PROVIDER_NOT_FOUND`, `INVALID_CONFIG` |
|
|
399
|
+
| **Auth** | `NOT_AUTHENTICATED`, `INVALID_USERNAME` |
|
|
400
|
+
| **Basket** | `BASKET_NOT_FOUND`, `BASKET_CREATION_FAILED`, `BASKET_EXPIRED`, `BASKET_EMPTY` |
|
|
401
|
+
| **Package** | `PACKAGE_NOT_FOUND`, `PACKAGE_OUT_OF_STOCK`, `PACKAGE_ALREADY_OWNED`, `INVALID_QUANTITY` |
|
|
402
|
+
| **Category** | `CATEGORY_NOT_FOUND` |
|
|
403
|
+
| **Coupon** | `COUPON_INVALID`, `COUPON_EXPIRED`, `COUPON_ALREADY_USED` |
|
|
404
|
+
| **Gift Card** | `GIFTCARD_INVALID`, `GIFTCARD_INSUFFICIENT_BALANCE` |
|
|
405
|
+
| **Creator Code** | `CREATOR_CODE_INVALID` |
|
|
406
|
+
| **Checkout** | `CHECKOUT_FAILED`, `CHECKOUT_CANCELLED`, `TEBEX_JS_NOT_LOADED` |
|
|
407
|
+
| **Network** | `NETWORK_ERROR`, `TIMEOUT`, `RATE_LIMITED` |
|
|
408
|
+
| **Unknown** | `UNKNOWN` |
|
|
409
|
+
|
|
410
|
+
---
|
|
289
411
|
|
|
290
412
|
## TypeScript
|
|
291
413
|
|
|
292
414
|
All types are exported:
|
|
293
415
|
|
|
294
|
-
```
|
|
416
|
+
```typescript
|
|
295
417
|
import type {
|
|
296
418
|
// Config
|
|
297
419
|
TebexConfig,
|
|
298
420
|
TebexUrls,
|
|
421
|
+
ResolvedTebexConfig,
|
|
299
422
|
|
|
300
423
|
// Hook Returns
|
|
301
424
|
UseBasketReturn,
|
|
302
425
|
UseCategoriesReturn,
|
|
426
|
+
UseCategoriesOptions,
|
|
427
|
+
UseCategoryReturn,
|
|
428
|
+
UseCategoryOptions,
|
|
429
|
+
UsePackagesReturn,
|
|
430
|
+
UsePackagesOptions,
|
|
431
|
+
UsePackageReturn,
|
|
432
|
+
UsePackageOptions,
|
|
303
433
|
UseCheckoutReturn,
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
434
|
+
UseCheckoutOptions,
|
|
435
|
+
UseCouponsReturn,
|
|
436
|
+
UseGiftCardsReturn,
|
|
437
|
+
UseCreatorCodesReturn,
|
|
438
|
+
UseGiftPackageReturn,
|
|
439
|
+
UseWebstoreReturn,
|
|
440
|
+
UseUserReturn,
|
|
441
|
+
|
|
442
|
+
// Params
|
|
443
|
+
AddPackageParams,
|
|
444
|
+
UpdateQuantityParams,
|
|
445
|
+
GiftPackageParams,
|
|
446
|
+
|
|
447
|
+
// Base types
|
|
448
|
+
BaseQueryReturn,
|
|
449
|
+
BaseMutationReturn,
|
|
450
|
+
|
|
451
|
+
// Tebex API types (re-exported from tebex_headless)
|
|
307
452
|
Basket,
|
|
308
453
|
BasketPackage,
|
|
309
454
|
Category,
|
|
310
455
|
Package,
|
|
456
|
+
PackageType,
|
|
311
457
|
Webstore,
|
|
458
|
+
Code,
|
|
459
|
+
GiftCardCode,
|
|
312
460
|
|
|
313
461
|
// Utilities
|
|
314
462
|
Result,
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
463
|
+
} from '@neosianexus/super-tebex';
|
|
464
|
+
|
|
465
|
+
// Error handling
|
|
466
|
+
import { TebexError, TebexErrorCode } from '@neosianexus/super-tebex';
|
|
318
467
|
|
|
319
468
|
// Type guards
|
|
320
|
-
import {
|
|
469
|
+
import {
|
|
470
|
+
isTebexError, // (error: unknown) => error is TebexError
|
|
471
|
+
isSuccess, // (result: Result<T,E>) => result is { ok: true, data: T }
|
|
472
|
+
isError, // (result: Result<T,E>) => result is { ok: false, error: E }
|
|
473
|
+
isDefined, // <T>(value: T | null | undefined) => value is T
|
|
474
|
+
} from '@neosianexus/super-tebex';
|
|
475
|
+
|
|
476
|
+
// Result utilities
|
|
477
|
+
import { ok, err } from '@neosianexus/super-tebex';
|
|
321
478
|
```
|
|
322
479
|
|
|
323
|
-
|
|
480
|
+
---
|
|
324
481
|
|
|
325
|
-
|
|
482
|
+
## Zustand Stores
|
|
326
483
|
|
|
327
|
-
|
|
328
|
-
|----|-----|-----------|
|
|
329
|
-
| `initTebex(key)` | `<TebexProvider config={{...}}>` | Wrap app with Provider |
|
|
330
|
-
| `initShopUrls(url)` | `config.baseUrl` + `config.urls` | Pass in config |
|
|
331
|
-
| `useBasket(username)` | `useBasket()` + `useUser()` | User is separate |
|
|
332
|
-
| `error.message` (FR) | `error.code` | Translate codes yourself |
|
|
333
|
-
| `sonner` peer dep | Removed | Handle toasts yourself |
|
|
334
|
-
| `useShopUserStore` | `useUserStore` | Renamed |
|
|
335
|
-
| `useShopBasketStore` | `useBasketStore` | Renamed |
|
|
484
|
+
Direct store access for advanced use cases:
|
|
336
485
|
|
|
337
|
-
|
|
486
|
+
```typescript
|
|
487
|
+
import { useBasketStore, useUserStore } from '@neosianexus/super-tebex';
|
|
338
488
|
|
|
339
|
-
|
|
489
|
+
// Access stores directly (outside of hooks)
|
|
490
|
+
const basketIdent = useBasketStore(state => state.basketIdent);
|
|
491
|
+
const setBasketIdent = useBasketStore(state => state.setBasketIdent);
|
|
492
|
+
const clearBasketIdent = useBasketStore(state => state.clearBasketIdent);
|
|
340
493
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
494
|
+
const username = useUserStore(state => state.username);
|
|
495
|
+
const setUsername = useUserStore(state => state.setUsername);
|
|
496
|
+
const clearUsername = useUserStore(state => state.clearUsername);
|
|
497
|
+
```
|
|
345
498
|
|
|
346
|
-
|
|
347
|
-
const username = useShopUserStore(s => s.username);
|
|
348
|
-
const { basket, addPackageToBasket, error } = useBasket(username);
|
|
499
|
+
---
|
|
349
500
|
|
|
350
|
-
|
|
501
|
+
## Query Keys
|
|
502
|
+
|
|
503
|
+
For manual cache invalidation:
|
|
504
|
+
|
|
505
|
+
```typescript
|
|
506
|
+
import { tebexKeys } from '@neosianexus/super-tebex';
|
|
507
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
508
|
+
|
|
509
|
+
const queryClient = useQueryClient();
|
|
510
|
+
|
|
511
|
+
// Available keys
|
|
512
|
+
tebexKeys.all // ['tebex']
|
|
513
|
+
tebexKeys.categories() // ['tebex', 'categories']
|
|
514
|
+
tebexKeys.categoriesList() // ['tebex', 'categories', 'list']
|
|
515
|
+
tebexKeys.category(id) // ['tebex', 'categories', id]
|
|
516
|
+
tebexKeys.packages() // ['tebex', 'packages']
|
|
517
|
+
tebexKeys.packagesList() // ['tebex', 'packages', 'list']
|
|
518
|
+
tebexKeys.package(id) // ['tebex', 'packages', id]
|
|
519
|
+
tebexKeys.baskets() // ['tebex', 'baskets']
|
|
520
|
+
tebexKeys.basket(ident) // ['tebex', 'baskets', ident]
|
|
521
|
+
tebexKeys.webstore() // ['tebex', 'webstore']
|
|
522
|
+
|
|
523
|
+
// Invalidate specific queries
|
|
524
|
+
queryClient.invalidateQueries({ queryKey: tebexKeys.categories() });
|
|
525
|
+
queryClient.invalidateQueries({ queryKey: tebexKeys.basket(basketIdent) });
|
|
351
526
|
```
|
|
352
527
|
|
|
353
|
-
|
|
528
|
+
---
|
|
354
529
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
530
|
+
## Advanced Usage
|
|
531
|
+
|
|
532
|
+
### Custom QueryClient
|
|
533
|
+
|
|
534
|
+
```typescript
|
|
535
|
+
import { QueryClient } from '@tanstack/react-query';
|
|
536
|
+
import { TebexProvider } from '@neosianexus/super-tebex';
|
|
537
|
+
|
|
538
|
+
const queryClient = new QueryClient({
|
|
539
|
+
defaultOptions: {
|
|
540
|
+
queries: {
|
|
541
|
+
staleTime: 30 * 1000, // 30 seconds
|
|
542
|
+
},
|
|
543
|
+
},
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
<TebexProvider config={config} queryClient={queryClient}>
|
|
364
547
|
{children}
|
|
365
548
|
</TebexProvider>
|
|
549
|
+
```
|
|
366
550
|
|
|
367
|
-
|
|
368
|
-
const { username } = useUser();
|
|
369
|
-
const { basket, addPackage, errorCode } = useBasket();
|
|
551
|
+
### Direct API Client Access
|
|
370
552
|
|
|
371
|
-
|
|
553
|
+
For advanced scenarios requiring direct API access:
|
|
554
|
+
|
|
555
|
+
```typescript
|
|
556
|
+
import { getTebexClient, isTebexClientInitialized } from '@neosianexus/super-tebex';
|
|
557
|
+
|
|
558
|
+
if (isTebexClientInitialized()) {
|
|
559
|
+
const client = getTebexClient();
|
|
560
|
+
// Use client directly (advanced usage only)
|
|
561
|
+
}
|
|
372
562
|
```
|
|
373
563
|
|
|
564
|
+
---
|
|
565
|
+
|
|
374
566
|
## Complete Example
|
|
375
567
|
|
|
376
568
|
```tsx
|
|
377
569
|
'use client';
|
|
378
570
|
|
|
379
|
-
import { useCategories, useBasket, useUser, useCheckout } from '@
|
|
571
|
+
import { useCategories, useBasket, useUser, useCheckout } from '@neosianexus/super-tebex';
|
|
380
572
|
import { useState } from 'react';
|
|
381
573
|
|
|
382
574
|
export default function ShopPage() {
|
|
@@ -496,50 +688,137 @@ export default function ShopPage() {
|
|
|
496
688
|
}
|
|
497
689
|
```
|
|
498
690
|
|
|
499
|
-
|
|
691
|
+
---
|
|
500
692
|
|
|
501
|
-
|
|
693
|
+
## Migration from v2
|
|
694
|
+
|
|
695
|
+
### Breaking Changes
|
|
696
|
+
|
|
697
|
+
| v2 | v3 | Migration |
|
|
698
|
+
|----|-----|-----------|
|
|
699
|
+
| `initTebex(key)` | `<TebexProvider config={{...}}>` | Wrap app with Provider |
|
|
700
|
+
| `initShopUrls(url)` | `config.baseUrl` + `config.urls` | Pass in config |
|
|
701
|
+
| `useBasket(username)` | `useBasket()` + `useUser()` | User is separate |
|
|
702
|
+
| `error.message` (FR) | `error.code` | Translate codes yourself |
|
|
703
|
+
| `sonner` peer dep | Removed | Handle toasts yourself |
|
|
704
|
+
| `useShopUserStore` | `useUserStore` | Renamed |
|
|
705
|
+
| `useShopBasketStore` | `useBasketStore` | Renamed |
|
|
706
|
+
|
|
707
|
+
### Migration Example
|
|
708
|
+
|
|
709
|
+
**Before (v2):**
|
|
502
710
|
|
|
503
711
|
```tsx
|
|
504
|
-
|
|
505
|
-
|
|
712
|
+
// lib/tebex.ts
|
|
713
|
+
initTebex(process.env.NEXT_PUBLIC_TEBEX_KEY);
|
|
714
|
+
initShopUrls('https://mysite.com');
|
|
506
715
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
staleTime: 30 * 1000, // 30 seconds
|
|
511
|
-
},
|
|
512
|
-
},
|
|
513
|
-
});
|
|
716
|
+
// Component
|
|
717
|
+
const username = useShopUserStore(s => s.username);
|
|
718
|
+
const { basket, addPackageToBasket, error } = useBasket(username);
|
|
514
719
|
|
|
515
|
-
|
|
516
|
-
{children}
|
|
517
|
-
</TebexProvider>
|
|
720
|
+
if (error) toast.error(error.message); // French message
|
|
518
721
|
```
|
|
519
722
|
|
|
520
|
-
|
|
723
|
+
**After (v3):**
|
|
521
724
|
|
|
522
725
|
```tsx
|
|
523
|
-
|
|
726
|
+
// app/layout.tsx
|
|
727
|
+
<TebexProvider
|
|
728
|
+
config={{
|
|
729
|
+
publicKey: process.env.NEXT_PUBLIC_TEBEX_KEY!,
|
|
730
|
+
baseUrl: 'https://mysite.com',
|
|
731
|
+
onError: (err) => toast.error(t(`errors.${err.code}`)),
|
|
732
|
+
}}
|
|
733
|
+
>
|
|
734
|
+
{children}
|
|
735
|
+
</TebexProvider>
|
|
524
736
|
|
|
525
|
-
//
|
|
526
|
-
const
|
|
527
|
-
const
|
|
737
|
+
// Component
|
|
738
|
+
const { username } = useUser();
|
|
739
|
+
const { basket, addPackage, errorCode } = useBasket();
|
|
740
|
+
|
|
741
|
+
// Errors handled by onError callback or manually with errorCode
|
|
528
742
|
```
|
|
529
743
|
|
|
530
|
-
|
|
744
|
+
---
|
|
531
745
|
|
|
532
|
-
|
|
533
|
-
import { tebexKeys } from '@neosia/tebex-nextjs';
|
|
534
|
-
import { useQueryClient } from '@tanstack/react-query';
|
|
746
|
+
## Quick Reference for AI/LLM
|
|
535
747
|
|
|
536
|
-
|
|
748
|
+
<details>
|
|
749
|
+
<summary><strong>Click to expand - Structured reference for AI assistants</strong></summary>
|
|
537
750
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
751
|
+
### Package Info
|
|
752
|
+
- **Name**: `@neosianexus/super-tebex`
|
|
753
|
+
- **Purpose**: Tebex Headless SDK wrapper for React/Next.js
|
|
754
|
+
- **State**: TanStack Query v5 (server) + Zustand v5 (client)
|
|
755
|
+
|
|
756
|
+
### Common Patterns
|
|
757
|
+
|
|
758
|
+
```typescript
|
|
759
|
+
// 1. Setup (app/layout.tsx)
|
|
760
|
+
<TebexProvider config={{ publicKey, baseUrl }}>{children}</TebexProvider>
|
|
761
|
+
|
|
762
|
+
// 2. Get categories with packages
|
|
763
|
+
const { categories } = useCategories({ includePackages: true });
|
|
764
|
+
|
|
765
|
+
// 3. Add to basket
|
|
766
|
+
const { addPackage } = useBasket();
|
|
767
|
+
await addPackage({ packageId: 123 });
|
|
768
|
+
|
|
769
|
+
// 4. Checkout
|
|
770
|
+
const { launch, canCheckout } = useCheckout();
|
|
771
|
+
if (canCheckout) await launch();
|
|
772
|
+
|
|
773
|
+
// 5. User management
|
|
774
|
+
const { username, setUsername } = useUser();
|
|
775
|
+
setUsername('player_name');
|
|
776
|
+
```
|
|
777
|
+
|
|
778
|
+
### Hook Signatures
|
|
779
|
+
|
|
780
|
+
| Hook | Key Params | Key Returns |
|
|
781
|
+
|------|------------|-------------|
|
|
782
|
+
| `useCategories(opts?)` | `includePackages` | `categories`, `getById`, `getByName` |
|
|
783
|
+
| `useCategory(opts)` | `id` | `category` |
|
|
784
|
+
| `usePackages(opts?)` | `categoryId` | `packages`, `getById`, `getByName` |
|
|
785
|
+
| `usePackage(opts)` | `id` | `package` |
|
|
786
|
+
| `useWebstore()` | - | `webstore`, `name`, `currency`, `domain` |
|
|
787
|
+
| `useBasket()` | - | `basket`, `addPackage`, `removePackage`, `itemCount` |
|
|
788
|
+
| `useCheckout(opts?)` | `onSuccess`, `onError` | `launch`, `canCheckout`, `isLaunching` |
|
|
789
|
+
| `useUser()` | - | `username`, `setUsername`, `isAuthenticated` |
|
|
790
|
+
| `useCoupons()` | - | `coupons`, `apply`, `remove` |
|
|
791
|
+
| `useGiftCards()` | - | `giftCards`, `apply`, `remove` |
|
|
792
|
+
| `useCreatorCodes()` | - | `creatorCode`, `apply`, `remove` |
|
|
793
|
+
| `useGiftPackage()` | - | `gift`, `isGifting` |
|
|
794
|
+
|
|
795
|
+
### Error Handling Pattern
|
|
796
|
+
|
|
797
|
+
```typescript
|
|
798
|
+
const { errorCode } = useBasket();
|
|
799
|
+
if (errorCode === TebexErrorCode.BASKET_NOT_FOUND) {
|
|
800
|
+
// Handle expired basket
|
|
801
|
+
}
|
|
541
802
|
```
|
|
542
803
|
|
|
804
|
+
### Requirements
|
|
805
|
+
- Must wrap app with `TebexProvider`
|
|
806
|
+
- Checkout requires `<script src="https://js.tebex.io/v/1.1.js" async />`
|
|
807
|
+
- Username required before adding to basket
|
|
808
|
+
|
|
809
|
+
</details>
|
|
810
|
+
|
|
811
|
+
---
|
|
812
|
+
|
|
543
813
|
## License
|
|
544
814
|
|
|
545
815
|
MIT
|
|
816
|
+
|
|
817
|
+
---
|
|
818
|
+
|
|
819
|
+
## Links
|
|
820
|
+
|
|
821
|
+
- [GitHub Repository](https://github.com/NeosiaNexus/super-tebex)
|
|
822
|
+
- [NPM Package](https://www.npmjs.com/package/@neosianexus/super-tebex)
|
|
823
|
+
- [Tebex Documentation](https://docs.tebex.io/)
|
|
824
|
+
- [Report Issues](https://github.com/NeosiaNexus/super-tebex/issues)
|