@grabjs/superapp-sdk 2.0.0-beta.14 → 2.0.0-beta.28

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.
@@ -0,0 +1,368 @@
1
+ ---
2
+ name: 'grabjs-superapp-sdk'
3
+ description: 'API reference for @grabjs/superapp-sdk. Use when building a MiniApp that runs in the Grab SuperApp WebView and needs to call native features (camera, payments, authorization, authentication, permission, location, device storage, container UI customization) via the Grab JSBridge. Keywords: miniapp, webview, android, ios, jsbridge, grab, superapp.'
4
+ license: 'MIT'
5
+ ---
6
+
7
+ # @grabjs/superapp-sdk
8
+
9
+ Use this SDK to call native Grab SuperApp features from a MiniApp running in the WebView. Each module covers one domain (camera, payments, location, etc.) and communicates with the native layer via JSBridge.
10
+
11
+ ## Core Concepts
12
+
13
+ **Every method returns a bridge response** with an HTTP-style `status_code`. Never use try/catch — SDK methods never throw.
14
+
15
+ Use type guards to narrow the response before accessing fields:
16
+
17
+ ```typescript
18
+ import { isSuccess, isError } from '@grabjs/superapp-sdk'; // isClientError, isServerError, isRedirection also available
19
+
20
+ if (isSuccess(response)) {
21
+ switch (response.status_code) {
22
+ case 200:
23
+ console.log(response.result);
24
+ break;
25
+ case 204:
26
+ // operation completed with no content
27
+ break;
28
+ }
29
+ } else if (isError(response)) {
30
+ // response.error: string is guaranteed
31
+ switch (response.status_code) {
32
+ case 403:
33
+ // call IdentityModule.authorize() then ScopeModule.reloadScopes() before retrying
34
+ break;
35
+ default:
36
+ console.error(`Error ${response.status_code}: ${response.error}`);
37
+ }
38
+ }
39
+ ```
40
+
41
+ **Status codes**:
42
+
43
+ - `400` — invalid request parameters; check inputs before assuming a server error
44
+ - `403` — permission denied; call `IdentityModule.authorize()` for the required scope, then `ScopeModule.reloadScopes()` before retrying
45
+ - `426` — method requires a newer version of the Grab app; advise the user to upgrade
46
+ - `501` — running outside the Grab SuperApp WebView
47
+
48
+ ## Common Patterns
49
+
50
+ **MiniApp initialization**: always call `ScopeModule.reloadScopes()` on launch before making any module calls — scopes are not loaded automatically.
51
+
52
+ **Subscribing to a stream** (location updates, media events):
53
+
54
+ ```typescript
55
+ const subscription = locationModule.observeLocationChange().subscribe({
56
+ next: (response) => {
57
+ if (isSuccess(response)) console.log(response.result);
58
+ },
59
+ complete: () => console.log('Stream ended'),
60
+ });
61
+
62
+ // Always unsubscribe when done to conserve battery and resources:
63
+ subscription.unsubscribe();
64
+ ```
65
+
66
+ You can also `await` a stream method directly to get its first value.
67
+
68
+ **Validating request parameters**: methods that accept a request object return `{ status_code: 400 }` when parameters are invalid.
69
+
70
+ ## Integration Guide
71
+
72
+ This guide covers the recommended setup for a MiniApp entry point — loading scopes, configuring the container UI, signalling readiness, and handling permissions.
73
+
74
+ ### Entry Point Setup
75
+
76
+ Run these steps once when your MiniApp initialises, before rendering any content.
77
+
78
+ ```typescript
79
+ import { ContainerModule, ScopeModule } from '@grabjs/superapp-sdk';
80
+
81
+ const container = new ContainerModule();
82
+ const scope = new ScopeModule();
83
+
84
+ async function init() {
85
+ // 1. Load permission scopes — always do this first
86
+ await scope.reloadScopes();
87
+
88
+ // 2. Configure the container UI
89
+ await container.setTitle('My MiniApp');
90
+ await container.setBackgroundColor('#FFFFFF');
91
+ await container.hideBackButton();
92
+
93
+ // 3. Dismiss the native loader
94
+ await container.hideLoader();
95
+ }
96
+
97
+ init();
98
+ ```
99
+
100
+ #### Why `reloadScopes()` first?
101
+
102
+ 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.
103
+
104
+ ### Handling Permissions
105
+
106
+ When a module call returns `403`, your app needs to request the required permission via `IdentityModule.authorize()`, then reload scopes before retrying.
107
+
108
+ ```typescript
109
+ import { IdentityModule, ScopeModule, isSuccess, isError } from '@grabjs/superapp-sdk';
110
+
111
+ const identity = new IdentityModule();
112
+ const scope = new ScopeModule();
113
+
114
+ async function requestPermission() {
115
+ const response = await identity.authorize({
116
+ clientId: 'your-client-id',
117
+ redirectUri: 'https://your-miniapp.example.com/callback',
118
+ scope: 'required_scope',
119
+ environment: 'production',
120
+ });
121
+
122
+ if (isSuccess(response)) {
123
+ // Reload scopes after authorization so the new permission is available
124
+ await scope.reloadScopes();
125
+ } else if (isError(response)) {
126
+ console.error('Authorization failed:', response.error);
127
+ }
128
+ }
129
+ ```
130
+
131
+ ### Navigation
132
+
133
+ #### Controlling the back button
134
+
135
+ Hide the back button when your app manages its own navigation stack, and restore it when the user can safely go back:
136
+
137
+ ```typescript
138
+ await container.hideBackButton();
139
+
140
+ // ... when the user can go back
141
+ await container.showBackButton();
142
+ ```
143
+
144
+ #### Closing the MiniApp
145
+
146
+ ```typescript
147
+ await container.close();
148
+ ```
149
+
150
+ #### Opening external links
151
+
152
+ Use `openExternalLink` to open URLs in the system browser instead of navigating away from the WebView:
153
+
154
+ ```typescript
155
+ const response = await container.openExternalLink('https://example.com');
156
+
157
+ if (isError(response)) {
158
+ console.error('Failed to open link:', response.error);
159
+ }
160
+ ```
161
+
162
+
163
+ ## Setup
164
+
165
+ ### Installation
166
+
167
+ #### NPM
168
+
169
+ ```bash
170
+ npm install @grabjs/superapp-sdk
171
+ ```
172
+
173
+ #### Yarn
174
+
175
+ ```bash
176
+ yarn add @grabjs/superapp-sdk
177
+ ```
178
+
179
+ ### Importing
180
+
181
+ #### ES Modules (recommended)
182
+
183
+ Import only the modules you need:
184
+
185
+ ```typescript
186
+ import { ContainerModule, ScopeModule } from '@grabjs/superapp-sdk';
187
+ ```
188
+
189
+ Type guards and response types are also available as named exports:
190
+
191
+ ```typescript
192
+ import { isSuccess, isError } from '@grabjs/superapp-sdk';
193
+ ```
194
+
195
+ #### CDN (UMD Bundle)
196
+
197
+ If you are not using a bundler, load the SDK from a CDN and access it via the `SuperAppSDK` global:
198
+
199
+ ```html
200
+ <script src="https://cdn.jsdelivr.net/npm/@grabjs/superapp-sdk/dist/index.js"></script>
201
+ <script>
202
+ const { ContainerModule, ScopeModule, isSuccess, isError } = window.SuperAppSDK;
203
+ </script>
204
+ ```
205
+
206
+ ### Requirements
207
+
208
+ SDK methods communicate with the native Grab SuperApp via JSBridge. They only work when your page is running inside the **Grab SuperApp WebView**. Calling a method outside that environment returns `{ status_code: 501 }`.
209
+
210
+
211
+ ## Classes
212
+
213
+ ### `CameraModule`
214
+ JSBridge module for accessing the device camera.
215
+ - `scanQRCode(request: { title?: string }): Promise<{ result: { qrCode: string }; status_code: 200 } | { status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 403 } | { error: string; status_code: 500 } | { error: string; status_code: 501 }>` — Opens the native camera to scan a QR code.
216
+
217
+ ### `CheckoutModule`
218
+ JSBridge module for triggering native payment flows.
219
+ - `triggerCheckout(request: Record<string, unknown>): Promise<{ error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: { errorCode?: string; errorMessage?: string; status: "success" | "failure" | "pending" | "userInitiatedCancel"; transactionID: string }; status_code: 200 }>` — Triggers the native checkout flow for payment processing.
220
+
221
+ ### `ContainerModule`
222
+ JSBridge module for controlling the WebView container.
223
+ - `close(): Promise<{ error: string; status_code: 500 } | { error: string; status_code: 501 } | { status_code: 200 }>` — Close the container and return to the previous screen.
224
+ - `getSessionParams(): Promise<{ error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: { result: string }; status_code: 200 }>` — Get the session parameters from the container.
225
+ - `hideBackButton(): Promise<{ error: string; status_code: 500 } | { error: string; status_code: 501 } | { status_code: 200 }>` — Hide the back button on the container header.
226
+ - `hideLoader(): Promise<{ error: string; status_code: 500 } | { error: string; status_code: 501 } | { status_code: 200 }>` — Hide the full-screen loading indicator.
227
+ - `hideRefreshButton(): Promise<{ error: string; status_code: 500 } | { error: string; status_code: 501 } | { status_code: 200 }>` — Hide the refresh button on the container header.
228
+ - `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.
229
+ - `onContentLoaded(): Promise<{ error: string; status_code: 500 } | { error: string; status_code: 501 } | { status_code: 200 }>` — Notify the Grab SuperApp that the page content has loaded.
230
+ - `onCtaTap(request: string): Promise<{ error: string; status_code: 500 } | { error: string; status_code: 501 } | { status_code: 200 }>` — Notify the client that the user has tapped a call-to-action (CTA).
231
+ - `openExternalLink(request: string): Promise<{ error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { status_code: 200 }>` — Open a link in the external browser.
232
+ - `sendAnalyticsEvent(request: { data?: Record<string, unknown>; name: string; state: string }): Promise<{ error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { status_code: 200 }>` — Use this method to track user interactions and page transitions.
233
+ - `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.
234
+ - `setTitle(request: string): Promise<{ error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { status_code: 200 }>` — Set the title of the container header.
235
+ - `showBackButton(): Promise<{ error: string; status_code: 500 } | { error: string; status_code: 501 } | { status_code: 200 }>` — Show the back button on the container header.
236
+ - `showLoader(): Promise<{ error: string; status_code: 500 } | { error: string; status_code: 501 } | { status_code: 200 }>` — Show the full-screen loading indicator.
237
+ - `showRefreshButton(): Promise<{ error: string; status_code: 500 } | { error: string; status_code: 501 } | { status_code: 200 }>` — Show the refresh button on the container header.
238
+
239
+ ### `DeviceCapabilityModule`
240
+ JSBridge module for querying native device capability information.
241
+ - `isEsimSupported(): Promise<{ error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: boolean; status_code: 200 }>` — Checks whether the current device supports eSIM.
242
+
243
+ ### `FileModule`
244
+ JSBridge module for downloading files to the user's device.
245
+ - `downloadFile(request: { fileName: string; fileUrl: string }): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 }>` — Downloads a file via the native bridge.
246
+
247
+ ### `IdentityModule`
248
+ JSBridge module for authenticating users via GrabID.
249
+ - `authorize(request: { clientId: string; environment: "staging" | "production"; redirectUri: string; responseMode?: "redirect" | "in_place"; scope: string }): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 403 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: { code: string; state: string }; status_code: 200 } | { status_code: 302 } | { error: string; status_code: 401 }>` — Initiates an OAuth2 authorization flow with PKCE (Proof Key for Code Exchange).
250
+ This method handles both native in-app consent and web-based fallback flows.
251
+ - `clearAuthorizationArtifacts(): Promise<{ status_code: 204 }>` — Clears all stored PKCE authorization artifacts from local storage.
252
+ This should be called after a successful token exchange or when you need to
253
+ reset the authorization state (e.g., on error or logout).
254
+ - `getAuthorizationArtifacts(): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { result: { codeVerifier: string; nonce: string; redirectUri: string; state: string }; status_code: 200 }>` — Retrieves stored PKCE authorization artifacts from local storage.
255
+ These artifacts are used to complete the OAuth2 authorization code exchange.
256
+
257
+ ### `LocaleModule`
258
+ JSBridge module for accessing device locale settings.
259
+ - `getLanguageLocaleIdentifier(): Promise<{ error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: string; status_code: 200 }>` — Retrieves the current language locale identifier from the device.
260
+
261
+ ### `LocationModule`
262
+ JSBridge module for accessing device location services.
263
+ - `getCoordinate(): Promise<{ error: string; status_code: 403 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: { lat: number; lng: number }; status_code: 200 } | { error: string; status_code: 424 }>` — Get the current geographic coordinates of the device.
264
+ - `getCountryCode(): Promise<{ error: string; status_code: 403 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 } | { result: { countryCode: string }; status_code: 200 }>` — Get the country code based on the device's current location.
265
+ - `observeLocationChange(): ObserveLocationChangeResponse` — Subscribe to location change updates from the device.
266
+
267
+ ### `MediaModule`
268
+ JSBridge module for playing DRM-protected media content.
269
+ - `observePlayDRMContent(data: DRMContentConfig): ObserveDRMPlaybackResponse` — Observes DRM-protected media content playback events.
270
+ - `playDRMContent(data: DRMContentConfig): Promise<{ status_code: 204 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { status_code: 200 }>` — Plays DRM-protected media content in the native media player.
271
+
272
+ ### `PlatformModule`
273
+ JSBridge module for controlling platform navigation.
274
+ - `back(): Promise<{ status_code: 204 } | { error: string; status_code: 500 } | { error: string; status_code: 501 }>` — Triggers the native platform back navigation.
275
+ This navigates back in the native navigation stack.
276
+
277
+ ### `ProfileModule`
278
+ JSBridge module for accessing user profile information.
279
+ - `fetchEmail(): Promise<{ error: string; status_code: 400 } | { error: string; status_code: 403 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: { email: string }; status_code: 200 } | { error: string; status_code: 426 }>` — Fetches the user's email address from their Grab profile.
280
+ - `verifyEmail(request: { email: string; otp: string }): Promise<{ error: string; status_code: 400 } | { error: string; status_code: 403 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { status_code: 200 } | { error: string; status_code: 426 }>` — Verifies the user's email address using a one-time password (OTP).
281
+
282
+ ### `ScopeModule`
283
+ JSBridge module for checking and refreshing API access permissions.
284
+ - `hasAccessTo(module: string, method: string): Promise<{ error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { error: string; status_code: 424 } | { result: { hasAccess: boolean }; status_code: 200 }>` — Checks if the current client has access to a specific JSBridge API method.
285
+ - `reloadScopes(): Promise<{ error: string; status_code: 500 } | { error: string; status_code: 501 } | { status_code: 200 } | { error: string; status_code: 424 }>` — Requests to reload the consented OAuth scopes for the current client.
286
+ This refreshes the permissions from the server.
287
+
288
+ ### `SplashScreenModule`
289
+ JSBridge module for controlling the native splash / Lottie loading screen.
290
+ - `dismiss(): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 403 } | { error: string; status_code: 500 } | { error: string; status_code: 501 }>` — Dismisses the native splash (Lottie) loading view if it is presented.
291
+
292
+ ### `StorageModule`
293
+ JSBridge module for persisting key-value data to native storage.
294
+ - `getBoolean(key: string): Promise<{ error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: { value: boolean | null }; status_code: 200 }>` — Retrieves a boolean value from the native storage.
295
+ - `getDouble(key: string): Promise<{ error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: { value: number | null }; status_code: 200 }>` — Retrieves a double (floating point) value from the native storage.
296
+ - `getInt(key: string): Promise<{ error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: { value: number | null }; status_code: 200 }>` — Retrieves an integer value from the native storage.
297
+ - `getString(key: string): Promise<{ error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: { value: string | null }; status_code: 200 }>` — Retrieves a string value from the native storage.
298
+ - `remove(key: string): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 }>` — Removes a single value from the native storage by key.
299
+ - `removeAll(): Promise<{ status_code: 204 } | { error: string; status_code: 500 } | { error: string; status_code: 501 }>` — Removes all values from the native storage.
300
+ - `setBoolean(key: string, value: boolean): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 }>` — Stores a boolean value in the native storage.
301
+ - `setDouble(key: string, value: number): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 }>` — Stores a double (floating point) value in the native storage.
302
+ - `setInt(key: string, value: number): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 }>` — Stores an integer value in the native storage.
303
+ - `setString(key: string, value: string): Promise<{ status_code: 204 } | { error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 }>` — Stores a string value in the native storage.
304
+
305
+ ### `SystemWebViewKitModule`
306
+ JSBridge module for opening URLs in the device's system browser.
307
+ - `redirectToSystemWebView(request: { url: string }): Promise<{ error: string; status_code: 400 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { status_code: 200 } | { error: string; status_code: 424 }>` — Opens a URL in the device's system web browser or web view.
308
+
309
+ ### `UserAttributesModule`
310
+ JSBridge module for reading user-related attributes from native code.
311
+ - `getSelectedTravelDestination(): Promise<{ status_code: 204 } | { error: string; status_code: 500 } | { error: string; status_code: 501 } | { result: string; status_code: 200 }>` — Returns the currently selected travel destination as a lowercase ISO 3166-1 alpha-2 country code.
312
+
313
+ ## Functions
314
+
315
+ ### `isClientError`
316
+ Type guard to check if a JSBridge response is a client error (4xx status codes).
317
+ ```ts
318
+ isClientError<T>(response: T): response is Extract<T, { status_code: 400 | 401 | 403 | 404 | 424 | 426 }>
319
+ ```
320
+
321
+ ### `isError`
322
+ Type guard to check if a JSBridge response is an error (4xx or 5xx status codes).
323
+ ```ts
324
+ isError<T>(response: T): response is Extract<T, { error: string }>
325
+ ```
326
+
327
+ ### `isErrorWithMessage`
328
+ Type guard to check if an error has a message property.
329
+ Use this to safely narrow errors in catch blocks.
330
+ ```ts
331
+ isErrorWithMessage(error: unknown): error is { message: string }
332
+ ```
333
+
334
+ ### `isFound`
335
+ Type guard to check if a JSBridge response is a 302 Found redirect.
336
+ ```ts
337
+ isFound<T>(response: T): response is Extract<T, { status_code: 302 }>
338
+ ```
339
+
340
+ ### `isNoContent`
341
+ Type guard to check if a JSBridge response is a 204 No Content (operation succeeded with no result).
342
+ ```ts
343
+ isNoContent<T>(response: T): response is Extract<T, { status_code: 204 }>
344
+ ```
345
+
346
+ ### `isOk`
347
+ Type guard to check if a JSBridge response is a 200 OK (operation succeeded with a result).
348
+ ```ts
349
+ isOk<T>(response: T): response is Extract<T, { status_code: 200 }>
350
+ ```
351
+
352
+ ### `isRedirection`
353
+ Type guard to check if a JSBridge response is a redirect (status code 302).
354
+ ```ts
355
+ isRedirection<T>(response: T): response is Extract<T, { status_code: 302 }>
356
+ ```
357
+
358
+ ### `isServerError`
359
+ Type guard to check if a JSBridge response is a server error (5xx status codes).
360
+ ```ts
361
+ isServerError<T>(response: T): response is Extract<T, { status_code: 500 | 501 }>
362
+ ```
363
+
364
+ ### `isSuccess`
365
+ Type guard to check if a JSBridge response is successful (status codes 200 or 204).
366
+ ```ts
367
+ isSuccess<T>(response: T): response is Extract<T, { status_code: 200 | 204 }>
368
+ ```