@momo-cloud/gami-sdk 0.0.67 → 0.0.78

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