@grabjs/superapp-sdk 2.0.0-beta.38 → 2.0.0-beta.47

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/skills/SKILL.md CHANGED
@@ -42,10 +42,11 @@ import { isSuccess, isError } from '@grabjs/superapp-sdk';
42
42
 
43
43
  #### CDN (UMD Bundle)
44
44
 
45
- If you are not using a bundler, load the SDK from a CDN and access it via the `SuperAppSDK` global:
45
+ If you are not using a bundler, load the SDK from a CDN and access it via the `SuperAppSDK` global.
46
+ **Always pin to a specific version** (e.g., `@x.y.z`) — omitting the version always fetches the latest release, which may contain breaking changes.
46
47
 
47
48
  ```html
48
- <script src="https://cdn.jsdelivr.net/npm/@grabjs/superapp-sdk/dist/index.js"></script>
49
+ <script src="https://cdn.jsdelivr.net/npm/@grabjs/superapp-sdk@x.y.z/dist/index.js"></script>
49
50
  <script>
50
51
  const { ContainerModule, ScopeModule, isSuccess, isError } = window.SuperAppSDK;
51
52
  </script>
@@ -61,25 +62,20 @@ SDK methods communicate with the native Grab SuperApp via JSBridge. They only wo
61
62
  Every SDK method returns a bridge response object with an HTTP-style `status_code`. SDK methods never throw — use type guards instead of try/catch.
62
63
 
63
64
  ```typescript
64
- import { CameraModule, isSuccess, isError } from '@grabjs/superapp-sdk';
65
+ import { ProfileModule, isSuccess, isError } from '@grabjs/superapp-sdk';
65
66
 
66
- const camera = new CameraModule();
67
- const response = await camera.scanQRCode({ title: 'Scan Payment QR' });
67
+ const profile = new ProfileModule();
68
+ const response = await profile.fetchEmail();
68
69
 
69
70
  if (isSuccess(response)) {
70
- switch (response.status_code) {
71
- case 200:
72
- console.log('QR Code scanned:', response.result.qrCode);
73
- break;
74
- case 204:
75
- // operation completed with no content
76
- break;
77
- }
71
+ console.log('Result:', response.result);
78
72
  } else if (isError(response)) {
79
- // response.error: string is guaranteed
80
73
  switch (response.status_code) {
81
74
  case 403:
82
- // call IdentityModule.authorize() then ScopeModule.reloadScopes() before retrying
75
+ // Missing OAuth scope - call IdentityModule.authorize() then ScopeModule.reloadScopes()
76
+ break;
77
+ case 426:
78
+ // Grab app version too old - prompt user to update their app
83
79
  break;
84
80
  default:
85
81
  console.error(`Error ${response.status_code}: ${response.error}`);
@@ -91,19 +87,19 @@ if (isSuccess(response)) {
91
87
 
92
88
  The SDK uses HTTP-style status codes for all responses:
93
89
 
94
- | Code | Type | Description |
95
- | ----- | ----------------- | --------------------------------------------------- |
96
- | `200` | OK | Request successful, `result` contains response data |
97
- | `204` | No Content | Request successful, no data returned |
98
- | `302` | Redirect | Redirect in progress |
99
- | `400` | Bad Request | Invalid request parameters |
100
- | `401` | Unauthorized | Authentication required |
101
- | `403` | Forbidden | Insufficient permissions for this operation |
102
- | `404` | Not Found | Resource not found |
103
- | `424` | Failed Dependency | Underlying native request failed |
104
- | `426` | Upgrade Required | Requires newer Grab app version |
105
- | `500` | Internal Error | Unexpected SDK error |
106
- | `501` | Not Implemented | Method requires Grab SuperApp environment |
90
+ | Code | Type | Description |
91
+ | :---- | :---------------- | :---------------------------------------------------------- |
92
+ | `200` | OK | Request successful, `result` contains response data |
93
+ | `204` | No Content | Request successful, no data returned |
94
+ | `302` | Redirect | Redirect in progress |
95
+ | `400` | Bad Request | Invalid request parameters |
96
+ | `401` | Unauthorized | Authentication required |
97
+ | `403` | Forbidden | Insufficient permission (see `@requiredOAuthScope` tag) |
98
+ | `404` | Not Found | Resource not found |
99
+ | `424` | Failed Dependency | Underlying native request failed |
100
+ | `426` | Upgrade Required | Grab app version too old (see `@minimumGrabAppVersion` tag) |
101
+ | `500` | Internal Error | Unexpected SDK error |
102
+ | `501` | Not Implemented | Outside Grab SuperApp environment |
107
103
 
108
104
  ### Type Guards
109
105
 
@@ -156,44 +152,159 @@ subscription.unsubscribe();
156
152
 
157
153
  You can also `await` a stream method directly to get its first value.
158
154
 
155
+ ### Scopes and Permissions
156
+
157
+ The SDK categorizes permissions into two distinct types based on their execution context:
158
+
159
+ #### Permission Types
160
+
161
+ - **Backend Scopes** (`openid`, `profile.read`, `phone`)
162
+ - **Purpose**: Access protected resources and user data via your server.
163
+ - **Flow**: Requires a backend token exchange after authorization to retrieve data.
164
+ - **Mobile Scopes** (`mobile.geolocation`, `mobile.checkout`)
165
+ - **Purpose**: Access native device capabilities directly within the MiniApp.
166
+ - **Flow**: Grants in-app permission immediately; no backend exchange is necessary.
167
+
168
+ #### Authorization Patterns
169
+
170
+ When designing your MiniApp, you can choose between two common patterns for requesting scopes:
171
+
172
+ - **Upfront Authorization**
173
+ - Request all required scopes during app initialisation, typically alongside backend sign-in.
174
+ - _Best for_: Core permissions essential for the app to function.
175
+ - **Deferred Authorization**
176
+ - Request scopes only when the user triggers a specific feature that requires them.
177
+ - _Best for_: Optional permissions (e.g., location) to improve user experience and build trust.
178
+
179
+ #### Permission Verification Strategies
180
+
181
+ You can verify permissions either proactively before calling a method, or reactively by handling errors.
182
+
183
+ ##### Proactive Checking
184
+
185
+ Proactively verify if the current session has the necessary permissions for a method using `ScopeModule.hasAccessTo()`. This is recommended before calling gated methods, as users can revoke permissions at any time via the Grab app settings.
186
+
187
+ ```typescript
188
+ const scope = new ScopeModule();
189
+ const hasAccess = await scope.hasAccessTo('LocationModule', 'getCoordinate');
190
+
191
+ if (isSuccess(hasAccess) && hasAccess.result) {
192
+ // Permission is available, safe to call the method
193
+ const location = await location.getCoordinate();
194
+ }
195
+ ```
196
+
197
+ ##### Reactive Checking (Handling 403 Forbidden)
198
+
199
+ Methods tagged with `@requiredOAuthScope` require specific permissions. If the user hasn't granted the required scope, the method returns `403`. You must request authorization and reload scopes before retrying:
200
+
201
+ 1. Call `IdentityModule.authorize()` to request the scope.
202
+ 2. Call `ScopeModule.reloadScopes()` to refresh the SDK's internal permission state.
203
+ 3. Retry the original method call.
204
+
205
+ ```typescript
206
+ import {
207
+ LocationModule,
208
+ IdentityModule,
209
+ ScopeModule,
210
+ isSuccess,
211
+ isError,
212
+ } from '@grabjs/superapp-sdk';
213
+
214
+ const location = new LocationModule();
215
+ const identity = new IdentityModule();
216
+ const scope = new ScopeModule();
217
+
218
+ const response = await location.getCoordinate();
219
+
220
+ if (isError(response) && response.status_code === 403) {
221
+ // 1. Request authorization for the required scope
222
+ const auth = await identity.authorize({
223
+ clientId: 'your-client-id',
224
+ redirectUri: 'https://your-app.com/callback',
225
+ scope: 'mobile.geolocation', // The scope defined in @requiredOAuthScope
226
+ environment: 'production',
227
+ responseMode: 'in_place',
228
+ });
229
+
230
+ if (isSuccess(auth)) {
231
+ // 2. Reload scopes so the new permission is available
232
+ await scope.reloadScopes();
233
+
234
+ // 3. Retry the original call
235
+ const retry = await location.getCoordinate();
236
+ if (isSuccess(retry)) {
237
+ console.log('Result:', retry.result);
238
+ }
239
+ }
240
+ }
241
+ ```
242
+
159
243
 
160
244
  ## Integration Guide
161
245
 
162
246
  This guide covers the recommended setup for a MiniApp entry point — loading scopes, configuring the container UI, signalling readiness, and handling permissions.
163
247
 
164
- ### Entry Point Setup
248
+ > **Note:** The [demo](https://github.com/grab/superapp-sdk/tree/master/demo) folder contains two complete MiniApp samples demonstrating these integration patterns in action — one using CDN (vanilla HTML/JS) and one using React. Both implement the same user flow: OAuth authorization, user profile display, deferred location permissions, and checkout payment.
165
249
 
166
- Run these steps once when your MiniApp initialises, before rendering any content.
250
+ ### Initialization
251
+
252
+ Follow these steps when your MiniApp launches to configure the container, authenticate the user, and track the entry event.
167
253
 
168
254
  ```typescript
169
- import { ContainerModule, ScopeModule } from '@grabjs/superapp-sdk';
255
+ import {
256
+ ContainerModule,
257
+ ScopeModule,
258
+ ContainerAnalyticsEventState,
259
+ isSuccess,
260
+ } from '@grabjs/superapp-sdk';
170
261
 
171
262
  const container = new ContainerModule();
172
263
  const scope = new ScopeModule();
173
264
 
174
265
  async function init() {
175
- // 1. Load permission scopes — always do this first
176
- await scope.reloadScopes();
266
+ // 1. Verify the environment
267
+ const connection = await container.isConnected();
268
+ if (!isSuccess(connection) || !connection.result?.connected) {
269
+ // Handle case where app is opened outside Grab SuperApp
270
+ return;
271
+ }
177
272
 
178
273
  // 2. Configure the container UI
179
274
  await container.setTitle('My MiniApp');
180
275
  await container.setBackgroundColor('#FFFFFF');
181
276
  await container.hideBackButton();
277
+ await container.hideRefreshButton();
182
278
 
183
279
  // 3. Dismiss the native loader
184
280
  await container.hideLoader();
281
+
282
+ // 4. Track app launch
283
+ await container.sendAnalyticsEvent({
284
+ state: ContainerAnalyticsEventState.HOMEPAGE,
285
+ name: 'DEFAULT',
286
+ });
287
+
288
+ // 5. Authenticate the user
289
+ // (Implementation detailed in the Authentication section below)
290
+ await signIn();
291
+
292
+ // 6. Load permission scopes — always do this before making module calls
293
+ await scope.reloadScopes();
185
294
  }
186
295
 
187
296
  init();
188
297
  ```
189
298
 
190
- #### Why `reloadScopes()` first?
299
+ ### Authentication
191
300
 
192
- Scopes are not loaded automatically. Any module call that requires a permission will return `403` until scopes are loaded. Always call `reloadScopes()` before making any other module calls.
301
+ Trigger `IdentityModule.authorize()` to start the authorization process and request user permissions.
193
302
 
194
- ### Handling Permissions
303
+ Once the user consents, retrieve the authorization artifacts (which include the `code`, `state`, `nonce`, and PKCE `codeVerifier`) via `IdentityModule.getAuthorizationArtifacts()`.
195
304
 
196
- When a module call returns `403`, your app needs to request the required permission via `IdentityModule.authorize()`, then reload scopes before retrying.
305
+ Forward these artifacts to your backend to exchange the token, validate the `id_token`, fetch user info, and establish the user's session.
306
+
307
+ After the session is established, call `IdentityModule.clearAuthorizationArtifacts()` and `ScopeModule.reloadScopes()` so your MiniApp can begin using the newly granted permissions.
197
308
 
198
309
  ```typescript
199
310
  import { IdentityModule, ScopeModule, isSuccess, isError } from '@grabjs/superapp-sdk';
@@ -201,45 +312,79 @@ import { IdentityModule, ScopeModule, isSuccess, isError } from '@grabjs/superap
201
312
  const identity = new IdentityModule();
202
313
  const scope = new ScopeModule();
203
314
 
204
- async function requestPermission() {
315
+ async function signIn() {
205
316
  const response = await identity.authorize({
206
317
  clientId: 'your-client-id',
207
318
  redirectUri: 'https://your-miniapp.example.com/callback',
208
- scope: 'required_scope',
319
+ scope: 'openid profile.read phone mobile.storage',
209
320
  environment: 'production',
321
+ responseMode: 'in_place',
210
322
  });
211
323
 
212
324
  if (isSuccess(response)) {
213
- // Reload scopes after authorization so the new permission is available
214
- await scope.reloadScopes();
325
+ if (response.status_code === 200) {
326
+ // 1. Retrieve authorization artifacts
327
+ const artifacts = await identity.getAuthorizationArtifacts();
328
+ if (isSuccess(artifacts)) {
329
+ const { codeVerifier, nonce, redirectUri } = artifacts.result;
330
+ const { code } = response.result;
331
+
332
+ // 2. Send the artifacts to your backend for token exchange (see Backend Token Exchange section below)
333
+ // await myBackend.exchangeTokens({ code, codeVerifier, nonce, redirectUri });
334
+
335
+ // 3. Clear artifacts and reload scopes
336
+ await identity.clearAuthorizationArtifacts();
337
+ await scope.reloadScopes();
338
+ }
339
+ } else if (response.status_code === 204) {
340
+ // User cancelled the authorization flow
341
+ await identity.clearAuthorizationArtifacts();
342
+ }
215
343
  } else if (isError(response)) {
216
344
  console.error('Authorization failed:', response.error);
345
+ await identity.clearAuthorizationArtifacts();
217
346
  }
218
347
  }
219
348
  ```
220
349
 
221
- ### Navigation
350
+ ### Container UI & Navigation
351
+
352
+ Control the native container's appearance and behavior to match your MiniApp's branding and navigation flow.
222
353
 
223
- #### Controlling the back button
354
+ #### Title and Background
224
355
 
225
- Hide the back button when your app manages its own navigation stack, and restore it when the user can safely go back:
356
+ Set the title and background color for the native container.
226
357
 
227
358
  ```typescript
359
+ await container.setTitle('My MiniApp');
360
+ await container.setBackgroundColor('#FFFFFF');
361
+ ```
362
+
363
+ #### Back and Refresh Buttons
364
+
365
+ Hide these buttons when your MiniApp manages its own navigation or requires a focused, non-refreshable view. Restore them when appropriate.
366
+
367
+ ```typescript
368
+ // Hide buttons
228
369
  await container.hideBackButton();
370
+ await container.hideRefreshButton();
229
371
 
230
- // ... when the user can go back
372
+ // Restore buttons
231
373
  await container.showBackButton();
374
+ await container.showRefreshButton();
232
375
  ```
233
376
 
234
377
  #### Closing the MiniApp
235
378
 
379
+ Programmatically close the MiniApp and return the user to the Grab SuperApp.
380
+
236
381
  ```typescript
237
382
  await container.close();
238
383
  ```
239
384
 
240
- #### Opening external links
385
+ ### Opening External Links
241
386
 
242
- Use `openExternalLink` to open URLs in the system browser instead of navigating away from the WebView:
387
+ Use `ContainerModule.openExternalLink()` to open URLs in the system browser instead of navigating away from the MiniApp WebView.
243
388
 
244
389
  ```typescript
245
390
  const response = await container.openExternalLink('https://example.com');
@@ -249,6 +394,121 @@ if (isError(response)) {
249
394
  }
250
395
  ```
251
396
 
397
+ ### Analytics Event Tracking
398
+
399
+ Track user interactions to monitor performance and conversion. Events are categorised by journey stage using `ContainerAnalyticsEventState`.
400
+
401
+ ```typescript
402
+ import { ContainerModule, ContainerAnalyticsEventState, isSuccess } from '@grabjs/superapp-sdk';
403
+
404
+ const container = new ContainerModule();
405
+
406
+ // 1. System Event (DEFAULT)
407
+ // Send when a user lands on a key page
408
+ await container.sendAnalyticsEvent({
409
+ state: ContainerAnalyticsEventState.HOMEPAGE,
410
+ name: 'DEFAULT',
411
+ });
412
+
413
+ // 2. Named Action (INITIATE / TRANSACT)
414
+ // Send when a user performs a primary action
415
+ await container.sendAnalyticsEvent({
416
+ state: ContainerAnalyticsEventState.HOMEPAGE,
417
+ name: 'INITIATE',
418
+ });
419
+
420
+ // 3. Custom Interaction
421
+ // Send for specific interactions with additional metadata
422
+ await container.sendAnalyticsEvent({
423
+ state: ContainerAnalyticsEventState.CUSTOM,
424
+ name: 'BANNER_CLICK',
425
+ data: {
426
+ page: 'homepage',
427
+ banner_id: 'promo-summer-2024',
428
+ },
429
+ });
430
+ ```
431
+
432
+ #### Journey Stages
433
+
434
+ | State | Description |
435
+ | :----------------- | :----------------------------------------------- |
436
+ | `HOMEPAGE` | Entry point or main landing page. |
437
+ | `CHECKOUT_PAGE` | Transaction confirmation or payment selection. |
438
+ | `COMPLETION_POINT` | Post-transaction or success page. |
439
+ | `CUSTOM` | Any other interaction outside the standard flow. |
440
+
441
+ #### Best Practices
442
+
443
+ - Track system events automatically when users navigate to the corresponding pages.
444
+ - Always include required data fields for transaction events to enable accurate revenue tracking.
445
+ - Use descriptive names for custom events that clearly indicate the user action being tracked.
446
+ - Never include Personally Identifiable Information (PII) in event data.
447
+
448
+ ### Checkout
449
+
450
+ The checkout flow is a two-step process: your backend first initializes a transaction using your partner credentials, then your frontend triggers the native payment interface using the response from your backend.
451
+
452
+ ```typescript
453
+ import {
454
+ CheckoutModule,
455
+ IdentityModule,
456
+ ScopeModule,
457
+ isSuccess,
458
+ isError,
459
+ } from '@grabjs/superapp-sdk';
460
+
461
+ const checkout = new CheckoutModule();
462
+ const identity = new IdentityModule();
463
+ const scope = new ScopeModule();
464
+
465
+ async function processPayment() {
466
+ // 1. Proactively check for checkout permission
467
+ const hasAccess = await scope.hasAccessTo('CheckoutModule', 'triggerCheckout');
468
+
469
+ if (!isSuccess(hasAccess) || !hasAccess.result) {
470
+ // Request authorization for mobile.checkout
471
+ // Note: mobile.checkout is a mobile scope; no backend exchange is needed for auth.
472
+ const authResponse = await identity.authorize({
473
+ clientId: 'your-client-id',
474
+ redirectUri: window.location.href,
475
+ scope: 'mobile.checkout',
476
+ environment: 'production',
477
+ responseMode: 'in_place',
478
+ });
479
+
480
+ if (isSuccess(authResponse) && authResponse.status_code === 200) {
481
+ await scope.reloadScopes();
482
+ } else {
483
+ return;
484
+ }
485
+ }
486
+
487
+ // 2. Fetch the initialized transaction payload from your backend
488
+ const response = await fetch('https://your-backend.example.com/init-transaction', {
489
+ method: 'POST',
490
+ headers: { 'Content-Type': 'application/json' },
491
+ body: JSON.stringify({ orderId: 'order-123' }),
492
+ });
493
+ const { partnerTxID, request, sessionID } = await response.json();
494
+
495
+ // 3. Trigger checkout with the backend response
496
+ const checkoutResult = await checkout.triggerCheckout({
497
+ partnerTxID,
498
+ request,
499
+ sessionID,
500
+ });
501
+
502
+ if (isSuccess(checkoutResult)) {
503
+ console.log(checkoutResult.result);
504
+ } else if (isError(checkoutResult)) {
505
+ console.error('Checkout error:', checkoutResult.error);
506
+ }
507
+ }
508
+ ```
509
+
510
+ For the complete API reference, see [GrabPay API](https://developer.grab.com/docs/partner-apps/pages/developer-resources/payment/) and [CheckoutModule](https://grab.github.io/superapp-sdk/classes/CheckoutModule.html).
511
+
252
512
 
253
513
  ## API Reference
254
514
 
@@ -260,25 +520,25 @@ JSBridge module for accessing the device camera.
260
520
 
261
521
  #### `CheckoutModule`
262
522
  JSBridge module for triggering native payment flows.
263
- - `triggerCheckout(request: Record<string, unknown>): Promise<{ error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: { status: "success"; transactionID: string } | { errorCode: string; errorMessage: string; status: "failure"; transactionID: string } | { status: "pending"; transactionID: string } | { status: "userInitiatedCancel" }; status_code: 200 }>` — Triggers the native checkout flow for payment processing.
523
+ - `triggerCheckout(request: Record<string, unknown>): Promise<{ error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: { status: "success"; transactionID: string } | { errorCode: string; errorMessage: string; status: "failure"; transactionID: string } | { status: "pending"; transactionID: string } | { status: "userInitiatedCancel" }; status_code: 200 }>` — Triggers the native checkout flow for payment processing. (**OAuth Scope:** mobile.checkout)
264
524
 
265
525
  #### `ContainerModule`
266
526
  JSBridge module for controlling the WebView container.
267
- - `close(): Promise<{ status_code: 204 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: boolean; status_code: 200 }>` — Close the container and return to the previous screen.
527
+ - `close(): Promise<{ status_code: 204 } | { error: string; status_code: 500 } | { error: string; status_code: 501 }>` — Close the container and return to the previous screen.
268
528
  - `getSessionParams(): Promise<{ status_code: 204 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: string; status_code: 200 }>` — Get the session parameters from the container.
269
- - `hideBackButton(): Promise<{ status_code: 204 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: boolean; status_code: 200 }>` — Hide the back button on the container header.
270
- - `hideLoader(): Promise<{ status_code: 204 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: boolean; status_code: 200 }>` — Hide the full-screen loading indicator.
271
- - `hideRefreshButton(): Promise<{ status_code: 204 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: boolean; status_code: 200 }>` — Hide the refresh button on the container header.
529
+ - `hideBackButton(): Promise<{ status_code: 204 } | { error: string; status_code: 500 } | { error: string; status_code: 501 }>` — Hide the back button on the container header.
530
+ - `hideLoader(): Promise<{ status_code: 204 } | { error: string; status_code: 500 } | { error: string; status_code: 501 }>` — Hide the full-screen loading indicator.
531
+ - `hideRefreshButton(): Promise<{ status_code: 204 } | { error: string; status_code: 500 } | { error: string; status_code: 501 }>` — Hide the refresh button on the container header.
272
532
  - `isConnected(): Promise<{ result: { connected: boolean }; status_code: 200 } | { error: string; status_code: 404 }>` — Check if the web app is connected to the Grab SuperApp via JSBridge.
273
533
  - `onContentLoaded(): Promise<{ status_code: 204 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: boolean; status_code: 200 }>` — Notify the Grab SuperApp that the page content has loaded.
274
534
  - `onCtaTap(request: string): Promise<{ error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: boolean; status_code: 200 }>` — Notify the client that the user has tapped a call-to-action (CTA).
275
- - `openExternalLink(request: string): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: boolean; status_code: 200 }>` — Open a link in the external browser.
276
- - `sendAnalyticsEvent(request: { data?: Record<string, unknown>; name: string; state: string }): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: boolean; status_code: 200 }>` — Use this method to track user interactions and page transitions.
277
- - `setBackgroundColor(request: string): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: boolean; status_code: 200 }>` — Set the background color of the container header.
278
- - `setTitle(request: string): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: boolean; status_code: 200 }>` — Set the title of the container header.
279
- - `showBackButton(): Promise<{ status_code: 204 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: boolean; status_code: 200 }>` — Show the back button on the container header.
280
- - `showLoader(): Promise<{ status_code: 204 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: boolean; status_code: 200 }>` — Show the full-screen loading indicator.
281
- - `showRefreshButton(): Promise<{ status_code: 204 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: boolean; status_code: 200 }>` — Show the refresh button on the container header.
535
+ - `openExternalLink(request: string): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 }>` — Open a link in the external browser.
536
+ - `sendAnalyticsEvent(request: { data?: Record<string, unknown>; name: string; state: string }): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 }>` — Use this method to track user interactions and page transitions.
537
+ - `setBackgroundColor(request: string): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 }>` — Set the background color of the container header.
538
+ - `setTitle(request: string): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 }>` — Set the title of the container header.
539
+ - `showBackButton(): Promise<{ status_code: 204 } | { error: string; status_code: 500 } | { error: string; status_code: 501 }>` — Show the back button on the container header.
540
+ - `showLoader(): Promise<{ status_code: 204 } | { error: string; status_code: 500 } | { error: string; status_code: 501 }>` — Show the full-screen loading indicator.
541
+ - `showRefreshButton(): Promise<{ status_code: 204 } | { error: string; status_code: 500 } | { error: string; status_code: 501 }>` — Show the refresh button on the container header.
282
542
 
283
543
  #### `DeviceModule`
284
544
  JSBridge module for querying native device information.
@@ -304,17 +564,17 @@ JSBridge module for accessing device locale settings.
304
564
 
305
565
  #### `LocationModule`
306
566
  JSBridge module for accessing device location services.
307
- - `getCoordinate(): Promise<{ error: string; status_code: 403 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: { latitude: number; longitude: number }; status_code: 200 } | { error: string; status_code: 424 }>` — Get the current geographic coordinates of the device.
308
- - `getCountryCode(): Promise<{ status_code: 204 } | { error: string; status_code: 403 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: string; status_code: 200 } | { error: string; status_code: 424 }>` — Get the country code based on the device's current location.
309
- - `observeLocationChange(): ObserveLocationChangeResponse` — Subscribe to location change updates from the device.
567
+ - `getCoordinate(): Promise<{ error: string; status_code: 403 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: { latitude: number; longitude: number }; status_code: 200 } | { error: string; status_code: 424 }>` — Get the current geographic coordinates of the device. (**OAuth Scope:** mobile.geolocation)
568
+ - `getCountryCode(): Promise<{ status_code: 204 } | { error: string; status_code: 403 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: string; status_code: 200 } | { error: string; status_code: 424 }>` — Get the country code based on the device's current location. (**OAuth Scope:** mobile.geolocation)
569
+ - `observeLocationChange(): ObserveLocationChangeResponse` — Subscribe to location change updates from the device. (**OAuth Scope:** mobile.geolocation)
310
570
 
311
571
  #### `Logger`
312
572
  Provides scoped logging for SDK modules.
313
573
 
314
574
  #### `MediaModule`
315
575
  JSBridge module for playing DRM-protected media content.
316
- - `observePlayDRMContent(data: DRMContentConfig): ObserveDRMPlaybackResponse` — Observes DRM-protected media content playback events.
317
- - `playDRMContent(data: DRMContentConfig): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 } | { result: { length: number; position: number; titleId: string; type: "START_PLAYBACK" | "PROGRESS_PLAYBACK" | "START_SEEK" | "STOP_SEEK" | "STOP_PLAYBACK" | "CLOSE_PLAYBACK" | "PAUSE_PLAYBACK" | "RESUME_PLAYBACK" | "FAST_FORWARD_PLAYBACK" | "REWIND_PLAYBACK" | "ERROR_PLAYBACK" | "CHANGE_VOLUME" }; status_code: 200 }>` — Plays DRM-protected media content in the native media player.
576
+ - `observePlayDRMContent(data: DRMContentConfig): ObserveDRMPlaybackResponse` — Observes DRM-protected media content playback events. (**OAuth Scope:** mobile.media)
577
+ - `playDRMContent(data: DRMContentConfig): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 } | { result: { length: number; position: number; titleId: string; type: "START_PLAYBACK" | "PROGRESS_PLAYBACK" | "START_SEEK" | "STOP_SEEK" | "STOP_PLAYBACK" | "CLOSE_PLAYBACK" | "PAUSE_PLAYBACK" | "RESUME_PLAYBACK" | "FAST_FORWARD_PLAYBACK" | "REWIND_PLAYBACK" | "ERROR_PLAYBACK" | "CHANGE_VOLUME" }; status_code: 200 }>` — Plays DRM-protected media content in the native media player. (**OAuth Scope:** mobile.media)
318
578
 
319
579
  #### `NetworkModule`
320
580
  JSBridge module for making network requests via the native bridge.
@@ -327,8 +587,8 @@ This navigates back in the native navigation stack.
327
587
 
328
588
  #### `ProfileModule`
329
589
  JSBridge module for accessing user profile information.
330
- - `fetchEmail(): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 403 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 426 } | { result: { email: string }; status_code: 200 }>` — Fetches the user's email address from their Grab profile.
331
- - `verifyEmail(request?: { email?: string; skipUserInput?: boolean }): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 403 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 426 } | { result: { email: string }; status_code: 200 }>` — Verifies the user's email address by triggering email capture bottom sheet and OTP verification.
590
+ - `fetchEmail(): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 403 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 426 } | { result: { email: string }; status_code: 200 }>` — Fetches the user's email address from their Grab profile. (**OAuth Scope:** mobile.profile | **Minimum Grab App Version:** Android: 5.399.0, iOS: 5.399.0)
591
+ - `verifyEmail(request?: { email?: string; skipUserInput?: boolean }): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 403 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 426 } | { result: { email: string }; status_code: 200 }>` — Verifies the user's email address by triggering email capture bottom sheet and OTP verification. (**OAuth Scope:** mobile.profile | **Minimum Grab App Version:** Android: 5.399.0, iOS: 5.399.0)
332
592
 
333
593
  #### `ScopeModule`
334
594
  JSBridge module for checking and refreshing API access permissions.
@@ -342,16 +602,16 @@ JSBridge module for controlling the native splash / Lottie loading screen.
342
602
 
343
603
  #### `StorageModule`
344
604
  JSBridge module for persisting key-value data to native storage.
345
- - `getBoolean(key: string): Promise<{ error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 } | { result: { value: boolean | null }; status_code: 200 }>` — Retrieves a boolean value from the native storage.
346
- - `getDouble(key: string): Promise<{ error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 } | { result: { value: number | null }; status_code: 200 }>` — Retrieves a double (floating point) value from the native storage.
347
- - `getInt(key: string): Promise<{ error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 } | { result: { value: number | null }; status_code: 200 }>` — Retrieves an integer value from the native storage.
348
- - `getString(key: string): Promise<{ error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 } | { result: { value: string | null }; status_code: 200 }>` — Retrieves a string value from the native storage.
349
- - `remove(key: string): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 }>` — Removes a single value from the native storage by key.
350
- - `removeAll(): Promise<{ status_code: 204 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 }>` — Removes all values from the native storage.
351
- - `setBoolean(key: string, value: boolean): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 }>` — Stores a boolean value in the native storage.
352
- - `setDouble(key: string, value: number): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 }>` — Stores a double (floating point) value in the native storage.
353
- - `setInt(key: string, value: number): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 }>` — Stores an integer value in the native storage.
354
- - `setString(key: string, value: string): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 }>` — Stores a string value in the native storage.
605
+ - `getBoolean(key: string): Promise<{ error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 } | { result: { value: boolean | null }; status_code: 200 }>` — Retrieves a boolean value from the native storage. (**OAuth Scope:** mobile.storage)
606
+ - `getDouble(key: string): Promise<{ error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 } | { result: { value: number | null }; status_code: 200 }>` — Retrieves a double (floating point) value from the native storage. (**OAuth Scope:** mobile.storage)
607
+ - `getInt(key: string): Promise<{ error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 } | { result: { value: number | null }; status_code: 200 }>` — Retrieves an integer value from the native storage. (**OAuth Scope:** mobile.storage)
608
+ - `getString(key: string): Promise<{ error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 } | { result: { value: string | null }; status_code: 200 }>` — Retrieves a string value from the native storage. (**OAuth Scope:** mobile.storage)
609
+ - `remove(key: string): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 }>` — Removes a single value from the native storage by key. (**OAuth Scope:** mobile.storage)
610
+ - `removeAll(): Promise<{ status_code: 204 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 }>` — Removes all values from the native storage. (**OAuth Scope:** mobile.storage)
611
+ - `setBoolean(key: string, value: boolean): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 }>` — Stores a boolean value in the native storage. (**OAuth Scope:** mobile.storage)
612
+ - `setDouble(key: string, value: number): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 }>` — Stores a double (floating point) value in the native storage. (**OAuth Scope:** mobile.storage)
613
+ - `setInt(key: string, value: number): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 }>` — Stores an integer value in the native storage. (**OAuth Scope:** mobile.storage)
614
+ - `setString(key: string, value: string): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 }>` — Stores a string value in the native storage. (**OAuth Scope:** mobile.storage)
355
615
 
356
616
  #### `SystemWebViewKitModule`
357
617
  JSBridge module for opening URLs in the device's system browser.