@momo-cloud/gami-sdk 0.0.68 → 0.0.82

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 CHANGED
@@ -1,858 +1,256 @@
1
- # Gami SDK
1
+ # Gami SDK Integration Guide
2
2
 
3
- > A comprehensive TypeScript SDK for building games on the MoMo platform
3
+ `@momo-cloud/gami-sdk` is the integration layer between your web game and MoMo host capabilities.
4
+ It provides:
4
5
 
5
- ## 📋 Overview
6
+ - Game backend APIs (spin, shake, mission, leaderboard, balance, exchange)
7
+ - Platform bridge APIs (toast, share, permission, contacts, deep-link, calendar, clipboard, and more)
8
+ - Runtime utilities (server-time sync, storage helpers, SSE, event bus)
6
9
 
7
- Gami SDK is a powerful TypeScript library that provides a unified interface for developing web-based games on the MoMo platform. It abstracts platform-specific APIs and provides consistent access to authentication, game state management, storage, and platform features.
10
+ This document is written for engineering teams integrating a game into the MoMo ecosystem.
8
11
 
9
- ### Key Features
12
+ ## 1) Integration Architecture
10
13
 
11
- - 🔐 **Authentication & Authorization** - Seamless token exchange and user authentication
12
- - 🎮 **Game Lifecycle Management** - Start, end, and manage game sessions
13
- - 💾 **Storage API** - Client-side storage with automatic key prefixing
14
- - 📊 **Leaderboard & Rankings** - Built-in support for competitive features
15
- - 📅 **Calendar Integration** - Schedule reminders and events
16
- - 🎯 **Mission System** - Track and complete user missions
17
- - 🎲 **Game Events** - Real-time event handling and tracking
18
- - 📈 **Analytics & Tracking** - Built-in event tracking and user behavior analytics
19
- - 🌐 **Cross-Platform** - Works in browser and MoMo app
20
- - 📦 **TypeScript Support** - Full type definitions included
14
+ At runtime, `GamiSDK` composes two API groups:
21
15
 
22
- ## 📦 Installation
16
+ - `platformApi.exposeApi`: host bridge and device/platform functions
17
+ - `gamiApi.exposeApi`: game-domain APIs and session workflow
23
18
 
24
- ```bash
25
- # Using npm
26
- npm install @momo-cloud/gami-sdk
27
-
28
- # Using yarn
29
- yarn add @momo-cloud/gami-sdk
30
-
31
- # Using pnpm
32
- pnpm add @momo-cloud/gami-sdk
33
- ```
34
-
35
- ## 🚀 Quick Start
36
-
37
- ```typescript
38
- import GamiSDK from '@momo-cloud/gami-sdk';
39
-
40
- // Initialize the SDK
41
- await GamiSDK.init({
42
- gameId: 'your-game-id',
43
- appjson: '',
44
- source: 'game-launch-source'
45
- });
46
-
47
- console.log('User ID:', GamiSDK.userId);
48
- console.log('Token:', GamiSDK.token);
49
-
50
- // Start game session
51
- await GamiSDK.startGame();
52
-
53
- // Your game logic here...
54
-
55
- // make spin to get reward
56
- const result = await GamiSDK.spin();
57
-
58
- // End game session
59
- await GamiSDK.endGame();
60
- ```
61
-
62
- ## 📖 API Reference
63
-
64
- ### Initialization
65
-
66
- #### `init(options)`
67
-
68
- Initialize the SDK with your game configuration.
69
-
70
- ```typescript
71
- await GamiSDK.init({
72
- gameId: 'demo',
73
- appjson?: '',
74
- source: 'momo',
75
- userId?: '1234567890' // Optional, for testing
76
- });
77
- ```
78
-
79
- **Parameters:**
80
- - `gameId` (string, optional): Your game identifier. If not provided, uses `featureId` from platform
81
- - `appjson` (string, required): app.json configuration file
82
- - `source` (string, optional): Launch source for analytics
83
- - `userId` (string, optional): Override user ID for testing
84
-
85
- **Returns:** `Promise<void>`
86
-
87
- ---
88
-
89
- ### Game Management
90
-
91
- #### `startGame()`
92
-
93
- Begin a new game session and notify the backend.
94
-
95
- ```typescript
96
- const response = await GamiSDK.startGame();
97
- console.log('Game started:', response);
98
- ```
99
-
100
- **Returns:** `Promise<any>` - Server response with session data
101
-
102
- ---
103
-
104
- #### `endGame()`
105
-
106
- End the current game session and dismiss the app.
107
-
108
- ```typescript
109
- await GamiSDK.endGame();
110
- // App will be dismissed automatically
111
- ```
112
-
113
- **Returns:** `Promise<void>`
114
-
115
- ---
116
-
117
- ### Configuration & Data
118
-
119
- #### `getConfig()`
120
-
121
- Fetch game configuration from the backend.
122
-
123
- ```typescript
124
- const config = await GamiSDK.getConfig();
125
- console.log('Game config:', config);
126
- ```
127
-
128
- **Returns:** `Promise<any>` - Game configuration object
129
-
130
- ---
131
-
132
- #### `getCoinExchangeInfo()`
133
-
134
- Load exchange metadata for the current game (coin → turn). The backend uses the fixed action `exchange_coin_to_turn`; the active `gameId` comes from `init`.
135
-
136
- ```typescript
137
- const res = await GamiSDK.getCoinExchangeInfo();
138
- const { balance, exchangeRate, counter, counterLimit, fromCurrency, toCurrency } = res.result;
139
- ```
140
-
141
- **Returns:** `Promise<TGetExchangeResponse>` - Standard `response_info` plus `result` with rate, balances, counters, and currency pair
142
-
143
- ---
144
-
145
- #### `coinExchange(options)`
146
-
147
- Submit a coin-to-turn exchange for the current game.
148
-
149
- ```typescript
150
- const res = await GamiSDK.coinExchange({ amount: 100 });
151
- const { from, to, counter } = res.result;
152
- ```
153
-
154
- **Parameters:**
155
- - `amount` (number): Coin amount to convert
156
-
157
- **Returns:** `Promise<TPostExchangeResponse>` - Updated `from` / `to` wallet snapshots and `counter` state
158
-
159
- ---
160
-
161
- #### `spin()`
162
-
163
- Perform a spinner spin for the current game. Sends `POST` to the twirler service with the active `gameId` (set via `init`).
164
-
165
- ```typescript
166
- const result = await GamiSDK.spin();
167
- console.log('Spin result:', result);
168
- ```
169
-
170
- **Returns:** `Promise<any>` - Server response with spin outcome (e.g. prize payload); exact shape follows the backend contract
171
-
172
- ---
173
-
174
- #### `getBalance(options)`
175
-
176
- Get user's balance for specified balance IDs.
177
-
178
- ```typescript
179
- const { result: balance } = await GamiSDK.getBalance({
180
- balanceId: ['turn', 'coin', 'gem', 'ticket']
181
- });
182
-
183
- console.log('Coins:', balance.turn);
184
- ```
185
-
186
- **Parameters:**
187
- - `balanceId` (string): Balance Id
188
-
189
- **Returns:** `Promise<TBalance>` - Balance data object
190
-
191
- ---
192
-
193
- #### `getBalanceConfig()`
194
-
195
- Get available balance types (pockets) configuration.
196
-
197
- ```typescript
198
- const pockets = await GamiSDK.getBalanceConfig();
199
- console.log('Available balances:', pockets);
200
- ```
201
-
202
- **Returns:** `Promise<any>` - Pocket configuration
203
-
204
- ---
205
-
206
- #### `getHistory(options)`
207
-
208
- Get user's game history.
209
-
210
- ```typescript
211
- const history = await GamiSDK.getHistory({
212
- page: 1,
213
- limit: 0
214
- });
215
-
216
- console.log('Recent games:', history.items);
217
- ```
218
-
219
- **Returns:** `Promise<THistory>` - History records
220
-
221
- ---
222
-
223
- ### Events & Missions
224
-
225
- #### `getEvent()`
226
-
227
- Fetch active events for the game.
228
-
229
- ```typescript
230
- const events = await GamiSDK.getEvent();
231
-
232
- events.forEach(event => {
233
- console.log(`Event: ${event.name}, Ends: ${event.endTime}`);
234
- });
235
- ```
236
-
237
- **Returns:** `Promise<TEvent>` - Event data
238
-
239
- ---
240
-
241
- #### `mission.get()`
242
-
243
- Get user's mission status.
244
-
245
- ```typescript
246
- import { mission } from '@momo-cloud/gami-sdk';
247
-
248
- const missions = await mission.get();
249
-
250
- missions.forEach(m => {
251
- console.log(`Mission: ${m.name}, Progress: ${m.progress}/${m.target}`);
252
- });
19
+ ```text
20
+ Game UI (React/Preact/Pixi)
21
+ |
22
+ v
23
+ GamiSDK
24
+ +-----------+
25
+ | platform | -> host bridge (toast, share, permission, refId, app events)
26
+ | game api | -> game services (config, balance, spin, shake, mission, ...)
27
+ +-----------+
28
+ |
29
+ v
30
+ MoMo host + backend services
253
31
  ```
254
32
 
255
- **Returns:** `Promise<MissionResponse[]>` - Array of missions
256
-
257
- ---
258
-
259
- #### `mission.sendEvent(eventName, serviceId?)`
33
+ ## 2) Installation
260
34
 
261
- Mark a mission event as completed.
262
-
263
- ```typescript
264
- import { mission } from '@momo-cloud/gami-sdk';
265
-
266
- await mission.done('level_completed', 'service-123');
35
+ ```bash
36
+ npm install @momo-cloud/gami-sdk
267
37
  ```
268
38
 
269
- **Parameters:**
270
- - `eventName` (string): Event identifier
271
- - `serviceId` (string, optional): Related service ID
272
-
273
- **Returns:** `Promise<any>` - Server response
39
+ or
274
40
 
275
- ---
276
-
277
- ### Storage
278
-
279
- #### `saveItem(key, value)`
280
-
281
- Save data to local storage with automatic game ID prefixing.
282
-
283
- ```typescript
284
- import { saveItem } from '@momo-cloud/gami-sdk';
285
-
286
- // Save JSON object
287
- await saveItem('userProgress', {
288
- level: 5,
289
- score: 1200,
290
- items: ['sword', 'shield']
291
- });
292
-
293
- // Save string
294
- await saveItem('playerName', 'MoMoGamer123');
41
+ ```bash
42
+ yarn add @momo-cloud/gami-sdk
295
43
  ```
296
44
 
297
- **Parameters:**
298
- - `key` (string): Storage key (will be prefixed with gameId)
299
- - `value` (any): Data to store (will be JSON stringified)
300
-
301
- **Returns:** `Promise<void>`
302
-
303
- ---
304
-
305
- #### `getItem(key)`
45
+ ## 3) Quick Start (Recommended Bootstrap)
306
46
 
307
- Retrieve data from local storage.
308
-
309
- ```typescript
310
- import { getItem } from '@momo-cloud/gami-sdk';
311
-
312
- const progress = await getItem('userProgress');
313
- console.log('Current level:', progress?.level);
314
-
315
- const name = await getItem('playerName');
316
- console.log('Player name:', name);
47
+ ```ts
48
+ import GamiSDK from '@momo-cloud/gami-sdk';
49
+ import appJson from '../app.json';
50
+
51
+ export async function bootstrapGame() {
52
+ await GamiSDK.init({
53
+ gameId: import.meta.env.VITE_DEFAULT_GAME_ID,
54
+ userId: import.meta.env.VITE_USER_ID, // optional in host runtime
55
+ appjson: JSON.stringify(appJson),
56
+ source: 'momo', // optional analytics source
57
+ });
58
+ }
317
59
  ```
318
60
 
319
- **Parameters:**
320
- - `key` (string): Storage key (gameId prefix added automatically)
61
+ ## 4) Integration Phases
321
62
 
322
- **Returns:** `Promise<any | null>` - Stored data or null if not found
63
+ ### Phase A - Initialize SDK
323
64
 
324
- ---
65
+ Call once at app startup:
325
66
 
326
- #### `cacheFile(url)`
67
+ - `init({ appjson, gameId?, userId?, source? })`
68
+ - `wait()`
327
69
 
328
- Cache remote files and get blob URL.
70
+ Then rely on runtime properties:
329
71
 
330
- ```typescript
331
- import { cacheFile } from '@momo-cloud/gami-sdk';
72
+ - `GamiSDK.userId`
73
+ - `GamiSDK.userInfo`
74
+ - `GamiSDK.token`
75
+ - `GamiSDK.gameId`
76
+ - `GamiSDK.appProfile`
77
+ - `GamiSDK.deviceInfo`
332
78
 
333
- const imageUrl = 'https://img.mservice.io/game/icon.png';
334
- const cachedUrl = await cacheFile(imageUrl);
79
+ ### Phase B - Start Gameplay Session
335
80
 
336
- // Use cachedUrl in your game
337
- document.getElementById('avatar').src = cachedUrl;
81
+ ```ts
82
+ await GamiSDK.startGame();
338
83
  ```
339
84
 
340
- **Parameters:**
341
- - `url` (string): Remote file URL
342
-
343
- **Returns:** `Promise<string>` - Blob URL or original URL if caching fails
344
-
345
- ---
346
-
347
- ### Calendar
348
-
349
- #### `addCalendar(options)`
350
-
351
- Add event to device calendar.
352
-
353
- ```typescript
354
- import { addCalendar } from '@momo-cloud/gami-sdk';
85
+ Typical game loop calls:
355
86
 
356
- const added = await addCalendar({
357
- title: 'Special Event Reminder',
358
- startDate: new Date('2025-12-15T10:00:00'),
359
- endDate: new Date('2025-12-15T12:00:00'),
360
- notes: 'Don\'t miss the limited-time event!',
361
- key: 'event-reminder-dec-15',
362
- alarm: new Date('2025-12-15T09:30:00'), // 30 min before
363
- desc: 'Complete special missions for exclusive rewards',
364
- toast: 'Please grant calendar permission to set reminders'
365
- });
366
-
367
- console.log('Calendar event added:', added);
368
- ```
87
+ - `getConfig()`
88
+ - `getBalance({ balanceId })`
89
+ - `getBalanceConfig()`
90
+ - `spin()`
91
+ - `shake()`
92
+ - `getCoinBalance()`
93
+ - `getCoinExchangeInfo()`
94
+ - `coinExchange({ amount })`
95
+ - `getMission({ viewId? })`
96
+ - `getLeaderboard({ boardId, group?, limit?, page? })`
97
+ - `getHistory({ page, limit })`
98
+ - `getEvent({ eventId })`
369
99
 
370
- **Parameters:**
371
- - `title` (string): Event title
372
- - `startDate` (Date | number): Event start time
373
- - `endDate` (Date | number): Event end time
374
- - `notes` (string): Event notes
375
- - `key` (string): Unique identifier for the event
376
- - `alarm` (Date | number): Alarm/notification time
377
- - `desc` (string): Event description
378
- - `toast` (string, optional): Permission request message
100
+ ### Phase C - Close or Navigate
379
101
 
380
- **Returns:** `Promise<boolean>` - True if added successfully
381
-
382
- ---
102
+ - `await GamiSDK.endGame()` to close session
103
+ - `GamiSDK.closeApp()` to dismiss host view
104
+ - `GamiSDK.goHome()` to return to home
383
105
 
384
- ### Platform APIs
106
+ ## 5) Platform Bridge APIs (Most Used)
385
107
 
386
- The SDK exposes additional platform-specific APIs through `GamiSDK`:
108
+ The SDK exposes host-native actions directly:
387
109
 
388
- #### `showToast(options)`
110
+ - Feedback: `showToast`, `showAlert`
111
+ - Navigation: `openWeb`, `openURL`, `startRefId`
112
+ - Social: `shareExternal`, `shareFacebook`, `shareMessenger`
113
+ - Device: `scanQRCode`, `copyToClipBoard`, `getImage`, `saveImage`
114
+ - Permissions: `requestPermission`, `checkPermission`
115
+ - Contacts and notifications: `getContacts`, `registerNoti`, `unregisterNoti`
116
+ - Calendar: `saveCalendarEvent`
117
+ - Analytics: `trackingEvent`, `screenTracking`
118
+ - Host lifecycle: `onFocusApp`, `onBlurApp`, `listenShaking`
389
119
 
390
- Display a toast notification to the user.
120
+ Example:
391
121
 
392
- ```typescript
122
+ ```ts
393
123
  GamiSDK.showToast({
394
- title: 'Welcome!',
395
- description: 'Thanks for playing',
396
- duration: 3000,
397
- type: 'success' // 'success' | 'failure' | 'info'
398
- });
399
- ```
400
-
401
- **Parameters:**
402
- - `title` (string, optional): Toast title
403
- - `description` (string): Toast message
404
- - `duration` (number): Display duration in milliseconds
405
- - `type` (string, optional): Toast type
406
-
407
- ---
408
-
409
- #### `showAlert(title, message, buttons?)`
410
-
411
- Show a native alert dialog.
412
-
413
- ```typescript
414
- GamiSDK.showAlert(
415
- 'Confirm Action',
416
- 'Are you sure you want to proceed?',
417
- ['Cancel', 'Confirm']
418
- );
419
- ```
420
-
421
- **Parameters:**
422
- - `title` (string): Alert title
423
- - `message` (string): Alert message
424
- - `buttons` (string[], optional): Button labels (default: ['OK'])
425
-
426
- ---
427
-
428
- #### `openWeb(options)`
429
-
430
- Open a URL in an in-app webview.
431
-
432
- ```typescript
433
- GamiSDK.openWeb({
434
- url: 'https://example.com/rules',
435
- title: 'Game Rules'
436
- });
437
-
438
- // Or with custom HTML
439
- GamiSDK.openWeb({
440
- html: '<h1>Custom Content</h1>',
441
- title: 'Info'
442
- });
443
- ```
444
-
445
- **Parameters:**
446
- - `url` (string, optional): URL to open
447
- - `html` (string, optional): Custom HTML content
448
- - `title` (string, optional): Webview title
449
-
450
- **Returns:** `Promise<boolean>`
451
-
452
- ---
453
-
454
- #### `openURL(url)`
455
-
456
- Open a URL in the device's external browser.
457
-
458
- ```typescript
459
- GamiSDK.openURL('https://momo.vn');
460
- ```
461
-
462
- **Parameters:**
463
- - `url` (string): URL to open
464
-
465
- **Returns:** `Promise<boolean>`
466
-
467
- ---
468
-
469
- #### `shareExternal(options)`
470
-
471
- Share content to external apps.
472
-
473
- ```typescript
474
- GamiSDK.shareExternal({
475
- title: 'Check out this game!',
476
- message: 'I just scored 1000 points!',
477
- url: 'https://momo.vn/game',
478
- subject: 'Game Score'
479
- });
480
- ```
481
-
482
- **Parameters:**
483
- - `title` (string, optional): Share title
484
- - `message` (string, optional): Share message
485
- - `url` (string, optional): URL to share
486
- - `subject` (string, optional): Email subject
487
-
488
- **Returns:** `Promise<boolean>`
489
-
490
- ---
491
-
492
- #### `copyToClipBoard(text, message?)`
493
-
494
- Copy text to clipboard.
495
-
496
- ```typescript
497
- GamiSDK.copyToClipBoard(
498
- 'PROMO2025',
499
- 'Promo code copied!'
500
- );
501
- ```
502
-
503
- **Parameters:**
504
- - `text` (string): Text to copy
505
- - `message` (string, optional): Success message to display
506
-
507
- **Returns:** `Promise<boolean>`
508
-
509
- ---
510
-
511
- #### `shareFacebook(url)` / `shareMessenger(url)`
512
-
513
- Share URL to Facebook or Messenger (MoMo app only).
514
-
515
- ```typescript
516
- GamiSDK.shareFacebook('https://momo.vn/game');
517
- GamiSDK.shareMessenger('https://momo.vn/game');
518
- ```
519
-
520
- **Parameters:**
521
- - `url` (string): URL to share
522
-
523
- **Returns:** `Promise<boolean>`
524
-
525
- ---
526
-
527
- #### `requestPermission(permission)` / `checkPermission(permission)`
528
-
529
- Request or check device permissions.
530
-
531
- ```typescript
532
- // Request permission
533
- const status = await GamiSDK.requestPermission('calendars');
534
- console.log('Permission status:', status); // 'granted' | 'denied'
535
-
536
- // Check existing permission
537
- const hasPermission = await GamiSDK.checkPermission('contacts');
538
- ```
539
-
540
- **Parameters:**
541
- - `permission` (string): Permission type ('calendars', 'contacts', etc.)
542
-
543
- **Returns:** `Promise<string>` - Permission status
544
-
545
- ---
546
-
547
- #### `getContacts()`
548
-
549
- Retrieve device contacts (MoMo app only, requires permission).
550
-
551
- ```typescript
552
- const contacts = await GamiSDK.getContacts();
553
- console.log('Contacts:', contacts);
554
- ```
555
-
556
- **Returns:** `Promise<any[] | null>`
557
-
558
- ---
559
-
560
- #### `saveCalendarEvent(options)`
561
-
562
- Save an event to the device calendar (MoMo app only).
563
-
564
- ```typescript
565
- const saved = await GamiSDK.saveCalendarEvent({
566
- title: 'Daily Bonus Available',
567
- startDate: new Date('2025-12-15T10:00:00'),
568
- endDate: new Date('2025-12-15T12:00:00'),
569
- notes: 'Come back to claim your daily bonus!',
570
- key: 'daily_bonus_reminder',
571
- alarm: new Date('2025-12-15T09:45:00'),
572
- des: 'Daily bonus notification',
573
- toast: 'Please grant calendar permission'
124
+ description: 'Reward claimed',
125
+ duration: 2000,
126
+ type: 'success',
574
127
  });
575
128
 
576
- console.log('Event saved:', saved);
577
- ```
578
-
579
- **Parameters:**
580
- - `title` (string): Event title
581
- - `startDate` (Date | number): Event start time
582
- - `endDate` (Date | number): Event end time
583
- - `notes` (string): Event notes
584
- - `key` (string): Storage key for event ID
585
- - `alarm` (Date | number): Reminder time
586
- - `des` (string): Event description
587
- - `toast` (string, optional): Permission request message
588
-
589
- **Returns:** `Promise<boolean>`
590
-
591
- ---
592
-
593
- #### `trackingEvent(event, data)`
594
-
595
- Track analytics events.
596
-
597
- ```typescript
598
- GamiSDK.trackingEvent('level_completed', {
599
- level: 5,
600
- score: 1200,
601
- duration: 45
602
- });
603
- ```
604
-
605
- **Parameters:**
606
- - `event` (string): Event name
607
- - `data` (object): Event data
608
-
609
- ---
610
-
611
- #### `screenTracking(options)`
612
-
613
- Track screen views and user actions.
614
-
615
- ```typescript
616
129
  GamiSDK.screenTracking({
617
- game_id: 'vn.momo.web.luckywheel',
618
130
  event_name: 'screen_view',
619
- action_name: 'view_leaderboard',
620
- screen_name: 'leaderboard_screen',
621
- extra: { tab: 'weekly' },
622
- error_code: 0
131
+ action_name: 'open_home',
132
+ screen_name: 'home',
623
133
  });
624
134
  ```
625
135
 
626
- **Parameters:**
627
- - `game_id` (string, optional): Game identifier
628
- - `event_name` (string): Event name
629
- - `action_name` (string): Action identifier
630
- - `screen_name` (string): Screen identifier
631
- - `extra` (object, optional): Additional data
632
- - `error_code` (number | string, optional): Error code if applicable
136
+ ## 6) Shared Utilities
633
137
 
634
- ---
138
+ Named exports are available for common integration helpers:
635
139
 
636
- #### `startRefId(options)`
140
+ - Storage: `saveItem`, `getItem`, `cacheFile`
141
+ - Calendar wrapper: `addCalendar`
142
+ - Time sync: `setServerTime`, `getServerTime`
143
+ - Event bus: `GameEvent`
144
+ - SSE support: from `features/sse/*`
145
+ - Types: from `features/types/*`
637
146
 
638
- Navigate to another feature/screen by reference ID.
147
+ Example:
639
148
 
640
- ```typescript
641
- // Start feature by code
642
- GamiSDK.startRefId({
643
- refId: 'FEATURE_CODE_123',
644
- refExtra: { source: 'game' }
645
- });
149
+ ```ts
150
+ import { saveItem, getItem, GameEvent } from '@momo-cloud/gami-sdk';
646
151
 
647
- // Open URL
648
- GamiSDK.startRefId({
649
- refId: 'https://example.com',
650
- useWeb: true // Open in webview instead of external browser
651
- });
152
+ await saveItem('progress', { level: 3, stars: 15 });
153
+ const progress = await getItem('progress');
652
154
 
653
- // Navigate to internal path
654
- GamiSDK.startRefId({
655
- refId: '/wallet/topup'
155
+ GameEvent.on('GAME_ON_BACK', () => {
156
+ // route back to your home screen
656
157
  });
657
158
  ```
658
159
 
659
- **Parameters:**
660
- - `refId` (string): Feature code, URL, or internal path
661
- - `refExtra` (object | string, optional): Additional parameters
662
- - `useWeb` (boolean, optional): Open URLs in webview (default: false)
663
-
664
- ---
665
-
666
- #### `listenShaking(options)`
160
+ ## 7) Error Handling Pattern
667
161
 
668
- Listen to device shake events (MoMo app only).
162
+ Most game APIs return payloads with `response_info`.
163
+ Treat non-zero error codes as business failures:
669
164
 
670
- ```typescript
671
- GamiSDK.listenShaking({
672
- onShake: (data) => {
673
- console.log('Device shaken!', data);
674
- // Trigger special action
675
- showBonusReward();
676
- }
677
- });
165
+ ```ts
166
+ const res = await GamiSDK.spin();
167
+ if (res?.response_info?.error_code !== 0) {
168
+ GamiSDK.showToast({
169
+ description: res?.response_info?.error_message || 'Spin failed',
170
+ duration: 2000,
171
+ type: 'failure',
172
+ });
173
+ return;
174
+ }
678
175
  ```
679
176
 
680
- **Parameters:**
681
- - `onShake` (function): Callback when device is shaken
177
+ ## 8) Browser vs Host Runtime
682
178
 
683
- **Returns:** Listener object (for cleanup)
179
+ - In MoMo host: full platform bridge behavior is available.
180
+ - In browser/dev mode: host-only behavior may be mocked, no-op, or limited.
684
181
 
685
- ---
686
-
687
- #### `onFocusApp(callback)` / `onBlurApp(callback)`
182
+ Integration recommendation:
688
183
 
689
- Listen to app focus/blur events.
184
+ - Keep game domain flow independent from host-only APIs.
185
+ - Wrap optional host actions with graceful fallback in browser.
690
186
 
691
- ```typescript
692
- GamiSDK.onFocusApp(() => {
693
- console.log('App is now active');
694
- resumeGame();
695
- });
696
-
697
- GamiSDK.onBlurApp(() => {
698
- console.log('App went to background');
699
- pauseGame();
700
- });
701
- ```
702
-
703
- **Parameters:**
704
- - `callback` (function): Function to call on focus/blur
705
-
706
- ---
187
+ ## 9) Build and Publish Modes
707
188
 
708
- #### `registerNoti(callback)` / `unregisterNoti()`
189
+ This repository supports two build modes:
709
190
 
710
- Register/unregister notification listeners (MoMo app only).
191
+ - Internal build (`src/index.ts`): full internal integration surface
192
+ - Public build (`src/index.public.ts`): limited/public package output
711
193
 
712
- ```typescript
713
- // Register
714
- GamiSDK.registerNoti((data) => {
715
- console.log('Received notification:', data);
716
- handleNotification(data);
717
- });
194
+ Commands:
718
195
 
719
- // Unregister
720
- GamiSDK.unregisterNoti();
196
+ ```bash
197
+ npm run build:internal
198
+ npm run build:public
721
199
  ```
722
200
 
723
- **Parameters:**
724
- - `callback` (function): Notification handler
725
-
726
- ---
727
-
728
- ### Utilities
201
+ Publish scripts:
729
202
 
730
- #### `getServerTime()`
731
-
732
- Get synchronized server time.
733
-
734
- ```typescript
735
- import { getServerTime } from '@momo-cloud/gami-sdk';
736
-
737
- const serverTime = getServerTime();
738
- console.log('Server time:', new Date(serverTime));
203
+ ```bash
204
+ npm run publish:nexus
205
+ npm run publish:npm
206
+ npm run publish:all
739
207
  ```
740
208
 
741
- **Returns:** `number` - Server timestamp in milliseconds
209
+ ## 10) Integration Checklist
742
210
 
743
- ---
211
+ Before releasing a game integration:
744
212
 
745
- #### `setServerTime(time)`
213
+ - `init()` and `wait()` executed exactly once on app bootstrap
214
+ - `startGame()` called on session start, `endGame()` on session end
215
+ - Critical APIs wrapped with business error handling (`response_info`)
216
+ - Host-only APIs guarded for browser fallback
217
+ - Analytics events wired (`trackingEvent` and `screenTracking`)
218
+ - Local cache keys use SDK helpers to avoid collisions
219
+ - Permissions flow validated for calendar/contacts/image capture
746
220
 
747
- Set server time offset manually (usually handled by init).
221
+ ## 11) Minimal End-to-End Example
748
222
 
749
- ```typescript
750
- import { setServerTime } from '@momo-cloud/gami-sdk';
751
-
752
- setServerTime(Date.now() + 1000); // 1 second ahead
753
- ```
754
-
755
- **Parameters:**
756
- - `time` (number): Server timestamp in milliseconds
757
-
758
- ---
759
-
760
- ### Properties
223
+ ```ts
224
+ import GamiSDK from '@momo-cloud/gami-sdk';
225
+ import appJson from '../app.json';
761
226
 
762
- Access SDK state and user information:
227
+ export async function run() {
228
+ await GamiSDK.init({
229
+ appjson: JSON.stringify(appJson),
230
+ gameId: import.meta.env.VITE_DEFAULT_GAME_ID,
231
+ userId: import.meta.env.VITE_USER_ID,
232
+ });
233
+ await GamiSDK.wait();
763
234
 
764
- ```typescript
765
- // User information
766
- console.log(GamiSDK.userId); // string: User ID
767
- console.log(GamiSDK.userInfo); // IUserInfo: Full user profile
768
- console.log(GamiSDK.token); // string: Auth token
769
- console.log(GamiSDK.gameId); // string: Current game ID
235
+ await GamiSDK.startGame();
236
+ const spinResult = await GamiSDK.spin();
770
237
 
771
- // Platform information
772
- console.log(GamiSDK.isBrowser); // boolean: Running in browser
773
- console.log(GamiSDK.isIos); // boolean: iOS device
774
- console.log(GamiSDK.feature); // any: Platform features
775
- ```
238
+ if (spinResult?.response_info?.error_code === 0) {
239
+ GamiSDK.showToast({ description: 'Spin success', duration: 1500, type: 'success' });
240
+ }
776
241
 
777
- **User Info Type:**
778
- ```typescript
779
- interface IUserInfo {
780
- id: string;
781
- name: string;
782
- phone?: string;
783
- avatar?: string;
784
- // ... additional fields
242
+ // Later when leaving the game:
243
+ await GamiSDK.endGame();
785
244
  }
786
245
  ```
787
246
 
788
- ## 🔐 Authentication Flow
247
+ ## 12) Notes for Architects
789
248
 
790
- ```
791
- User Opens Game
792
-
793
- SDK.init() called
794
-
795
- Get user profile and authentication
796
-
797
- Backend: login(appToken) → Exchange for gameToken
798
-
799
- Backend: getProfile(gameToken) → Get game profile
800
-
801
- Backend: getBalance(gameToken) → Get balances
802
-
803
- Backend: getServerTime() → Sync time
804
-
805
- Game Ready ✓
806
- ```
807
-
808
- ## 🌐 Platform Support
809
-
810
- | Feature | Browser | MoMo App | Notes |
811
- |---------|---------|----------|-------|
812
- | Authentication | ✅ | ✅ | Mock in browser |
813
- | Storage | ✅ | ✅ | localStorage / native |
814
- | Calendar | ❌ | ✅ | Native only |
815
- | Notifications | ❌ | ✅ | Native only |
816
- | Game APIs | ✅ | ✅ | Full support |
817
-
818
- ## ⚙️ Configuration
819
-
820
- ### TypeScript
821
-
822
- The SDK is written in TypeScript and includes type definitions:
823
-
824
- ```typescript
825
- import GamiSDK, {
826
- TBalance,
827
- TGetExchangeResponse,
828
- TLeaderboard,
829
- TPostExchangeResponse,
830
- IUserInfo
831
- } from '@momo-cloud/gami-sdk';
832
-
833
- const balance: TBalance = await GamiSDK.getBalance({
834
- balanceIds: ['coin']
835
- });
249
+ - Keep `GamiSDK` behind your own `sdkService` adapter in app code.
250
+ - Separate domain logic from host bridge calls for easier testability.
251
+ - Use typed DTOs from `features/types` in application boundaries.
252
+ - Favor centralized error normalization to avoid duplicated checks.
836
253
 
837
- const exchangeInfo: TGetExchangeResponse = await GamiSDK.getCoinExchangeInfo();
838
- const posted: TPostExchangeResponse = await GamiSDK.coinExchange({ amount: 100 });
839
- ```
840
-
841
- ### Vite Integration
842
-
843
- ```typescript
844
- // vite.config.ts
845
- import { defineConfig } from 'vite';
846
-
847
- export default defineConfig({
848
- resolve: {
849
- alias: {
850
- '@sdk': '@momo-cloud/gami-sdk'
851
- }
852
- }
853
- });
854
- ```
855
-
856
- ## 📄 License
254
+ ---
857
255
 
858
- UNLICENSED
256
+ License: `UNLICENSED`