@jetezra/bridge 0.0.1 → 0.0.2
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/CHANGELOG.md +16 -0
- package/README.md +410 -97
- package/dist/chooga-bridge.cjs +311 -20
- package/dist/chooga-bridge.cjs.map +2 -2
- package/dist/chooga-bridge.d.ts +44 -11
- package/dist/chooga-bridge.min.js +1 -1
- package/dist/chooga-bridge.min.js.map +3 -3
- package/dist/chooga-bridge.mjs +311 -20
- package/dist/chooga-bridge.mjs.map +2 -2
- package/package.json +3 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.0.2
|
|
4
|
+
|
|
5
|
+
- `init({ debug: true })` / `setDebug(true)` — log outbound and inbound bridge messages
|
|
6
|
+
- `init({ allowedOrigins })` — ignore DOM `message` events from unexpected origins
|
|
7
|
+
- `mockHost(options)` — fake host for browser demos and local development
|
|
8
|
+
- `requestCapability(key, options?)` now returns a Promise (awaits `chooga.capabilityResult`)
|
|
9
|
+
- `navigate` accepts `onResult` like other async helpers
|
|
10
|
+
- Extensible `getState()` via `chooga.params` (merge / replace / clear)
|
|
11
|
+
- Preserve extra fields on session, theme, and capability messages
|
|
12
|
+
- Unit tests for params, reject/`no_host`, mock host, debug logs, capability, timeout
|
|
13
|
+
|
|
14
|
+
## 0.0.1
|
|
15
|
+
|
|
16
|
+
- Initial public release of `@jetezra/bridge` (npm + CDN)
|
package/README.md
CHANGED
|
@@ -1,119 +1,407 @@
|
|
|
1
1
|
# `@jetezra/bridge`
|
|
2
2
|
|
|
3
|
-
Client SDK for Chooga mini-apps running inside a host WebView
|
|
4
|
-
|
|
5
|
-
Works in a normal browser too (`hostConnected === false`) so demos still render without a native shell.
|
|
3
|
+
Client SDK for Chooga mini-apps running inside a host WebView. It also runs in a normal browser for demos: `hostConnected` stays `false`, and any call that expects a host reply rejects with `{ ok: false, reason: 'no_host' }`.
|
|
6
4
|
|
|
7
5
|
| Doc | Purpose |
|
|
8
6
|
|-----|---------|
|
|
9
|
-
| This README | API +
|
|
10
|
-
| [`RELEASE.md`](./RELEASE.md) |
|
|
11
|
-
|
|
7
|
+
| This README | API + usage |
|
|
8
|
+
| [`RELEASE.md`](./RELEASE.md) | npm + CDN release |
|
|
9
|
+
|
|
10
|
+
Released version: **`0.0.2`**.
|
|
11
|
+
|
|
12
|
+
See [`CHANGELOG.md`](./CHANGELOG.md) for what changed.
|
|
13
|
+
|
|
14
|
+
---
|
|
12
15
|
|
|
13
16
|
## Install
|
|
14
17
|
|
|
18
|
+
Install from npm:
|
|
19
|
+
|
|
15
20
|
```bash
|
|
16
21
|
npm install @jetezra/bridge
|
|
17
|
-
# or yarn add @jetezra/bridge
|
|
18
22
|
```
|
|
19
23
|
|
|
20
|
-
|
|
24
|
+
```js
|
|
25
|
+
import ChoogaBridge from '@jetezra/bridge';
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or load the CDN build and use the global `ChoogaBridge`. Pin a version in production. unpkg is usually ready first after a publish; jsDelivr mirrors the same npm package.
|
|
21
29
|
|
|
22
30
|
```html
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
<!-- unpkg -->
|
|
26
|
-
<script src="https://unpkg.com/@jetezra/bridge@1.2.0/dist/chooga-bridge.min.js"></script>
|
|
31
|
+
<script src="https://unpkg.com/@jetezra/bridge@0.0.2/dist/chooga-bridge.min.js"></script>
|
|
32
|
+
<!-- or https://cdn.jsdelivr.net/npm/@jetezra/bridge@0.0.2/dist/chooga-bridge.min.js -->
|
|
27
33
|
<script>
|
|
28
|
-
ChoogaBridge.init();
|
|
34
|
+
ChoogaBridge.init({ debug: true });
|
|
29
35
|
</script>
|
|
30
36
|
```
|
|
31
37
|
|
|
32
|
-
Latest (not for production):
|
|
33
|
-
`https://cdn.jsdelivr.net/npm/@jetezra/bridge/dist/chooga-bridge.min.js`
|
|
38
|
+
Latest (not for production): `https://unpkg.com/@jetezra/bridge/dist/chooga-bridge.min.js`
|
|
34
39
|
|
|
35
|
-
|
|
40
|
+
---
|
|
36
41
|
|
|
37
42
|
## Quick start
|
|
38
43
|
|
|
44
|
+
Call `init()` once when your mini-app boots. By default that also posts `chooga.ready` so the host can inject session, user, theme, and host info. Subscribe to state and events, then use the host APIs.
|
|
45
|
+
|
|
39
46
|
```js
|
|
40
47
|
import ChoogaBridge from '@jetezra/bridge';
|
|
41
48
|
|
|
42
|
-
ChoogaBridge.init(); //
|
|
49
|
+
ChoogaBridge.init({ debug: true }); // logs every → host / ← host message
|
|
50
|
+
|
|
51
|
+
ChoogaBridge.subscribe(state => {
|
|
52
|
+
console.log(state.session, state.user, state.theme);
|
|
53
|
+
});
|
|
43
54
|
|
|
44
55
|
ChoogaBridge.on('theme.changed', theme => {
|
|
45
|
-
|
|
56
|
+
console.log('theme updated', theme);
|
|
46
57
|
});
|
|
47
58
|
|
|
48
|
-
const
|
|
49
|
-
|
|
59
|
+
const { user } = await ChoogaBridge.getUser();
|
|
60
|
+
|
|
61
|
+
// Prefer checking host capabilities before host-only APIs
|
|
62
|
+
if (ChoogaBridge.has('wallet.pick')) {
|
|
63
|
+
const wallet = await ChoogaBridge.activity('wallet.pick', { currency: 'ETB' });
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Local browser demos (`mockHost`)
|
|
68
|
+
|
|
69
|
+
Without a real WebView, async APIs reject with `no_host`. For UI work in a normal browser, install a fake host **before** `init()`:
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
ChoogaBridge.mockHost({
|
|
73
|
+
context: {
|
|
74
|
+
user: { id: 'u1', name: 'Demo' },
|
|
75
|
+
params: { locale: 'en' },
|
|
76
|
+
},
|
|
50
77
|
});
|
|
78
|
+
ChoogaBridge.init({ debug: true });
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`mockHost` answers `ready`, activities, `call`, navigate, payments, and capabilities with sensible defaults. Pass `onMessage(msg, reply)` to customize.
|
|
82
|
+
|
|
83
|
+
---
|
|
51
84
|
|
|
52
|
-
|
|
85
|
+
## How the bridge thinks
|
|
86
|
+
|
|
87
|
+
Three interaction styles matter:
|
|
88
|
+
|
|
89
|
+
**Injected state** — After `ready`, the host pushes session, user, theme, safe area, host info, and any custom `params` into the WebView. Read them with `getState()` or `subscribe()`. Custom fields can appear or disappear per host/app without changing this SDK.
|
|
90
|
+
|
|
91
|
+
**Request / response** — Methods like `activity`, `call`, `navigate`, `getUser`, `getHostInfo`, and `payments.initiate` (default mode) send a message with a `requestId`, wait for the host to finish, then settle a Promise with the host’s return payload. That awaited value *is* what the superapp returned.
|
|
92
|
+
|
|
93
|
+
**Fire-and-forget** — `toast`, `showProgress`, `close`, `openExternal` post to the host and do not return a result Promise.
|
|
94
|
+
|
|
95
|
+
**Host capabilities** — `activity`, `payments.initiate`, and some `call` methods only work when the host implements them. After `hostInfo` is injected (or after `getHostInfo()`), check `ChoogaBridge.has('wallet.pick')` / `has('payments')` before calling. Until the mobile shell ships those features, treat them as experimental and use `mockHost` for local demos.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Debug logging
|
|
100
|
+
|
|
101
|
+
Turn on wire logging while integrating:
|
|
102
|
+
|
|
103
|
+
```js
|
|
104
|
+
ChoogaBridge.init({ debug: true });
|
|
105
|
+
// or later:
|
|
106
|
+
ChoogaBridge.setDebug(true);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
You will see console lines like:
|
|
110
|
+
|
|
111
|
+
```text
|
|
112
|
+
[ChoogaBridge → host] { type: 'chooga.ready' }
|
|
113
|
+
[ChoogaBridge ← host] { type: 'chooga.session', token: '…', expires_at: '…' }
|
|
53
114
|
```
|
|
54
115
|
|
|
55
|
-
|
|
116
|
+
Optional `allowedOrigins` filters DOM `message` events (React Native WebView injects often use an opaque/`null` origin, which is still allowed):
|
|
117
|
+
|
|
118
|
+
```js
|
|
119
|
+
ChoogaBridge.init({
|
|
120
|
+
debug: true,
|
|
121
|
+
allowedOrigins: ['https://mini.example'],
|
|
122
|
+
});
|
|
123
|
+
```
|
|
56
124
|
|
|
57
|
-
|
|
58
|
-
|------|-----|-------|
|
|
59
|
-
| **Activities** | `activity(name, params)` | Native UI; Promise result |
|
|
60
|
-
| **Services** | `showProgress`, `toast`, `getUser`, … | No full-screen takeover |
|
|
61
|
-
| **Events** | `on` / `off` | Host → mini-app pushes |
|
|
125
|
+
---
|
|
62
126
|
|
|
63
|
-
##
|
|
127
|
+
## Async calls: await and onResult
|
|
64
128
|
|
|
65
|
-
|
|
66
|
-
|--------|-------------|
|
|
67
|
-
| `init({ autoReady? })` | Bind listeners; optionally send `ready` |
|
|
68
|
-
| `ready()` | Notify host that the mini-app is ready |
|
|
69
|
-
| `close()` | Ask host to dismiss the WebView |
|
|
70
|
-
| `openExternal(url)` | Open `https://` URL outside the WebView |
|
|
71
|
-
| `requestCapability(key)` | Ask host if `key` is granted |
|
|
72
|
-
| `activity(name, params?)` | Open host activity; await result |
|
|
73
|
-
| `getUser()` / `user.get()` | Fresh user claims from host |
|
|
74
|
-
| `toast(message, tone?)` | Host snackbar |
|
|
75
|
-
| `getHostInfo()` | Refresh capabilities / activities / version |
|
|
76
|
-
| `has(key)` | Capability or activity advertised / granted |
|
|
77
|
-
| `hostVersion()` | Host protocol version string |
|
|
78
|
-
| `on(name, fn)` / `off(name, fn)` | Host push events (`*` = all) |
|
|
79
|
-
| `showProgress(opts?)` / `dismissProgress()` | Host loading overlay |
|
|
80
|
-
| `progress.show` / `progress.dismiss` | Same as above (namespaced) |
|
|
81
|
-
| `navigate({ path?, url?, timeoutMs? })` | In-WebView navigation (Promise) |
|
|
82
|
-
| `payments.initiate(options)` | Host-mediated payment (Promise / `onResult`) |
|
|
83
|
-
| `call(method, params?, options?)` | Generic RPC → host method map |
|
|
84
|
-
| `subscribe(fn)` / `getState()` | Observe injected host context |
|
|
129
|
+
For every request/response API, the bridge generates a `requestId`, posts to the host, and waits for a matching result message. When the host is done, the Promise resolves with the host’s payload (routing fields `type` and `requestId` removed).
|
|
85
130
|
|
|
86
|
-
|
|
131
|
+
You can also pass `onResult`. It receives the **same** object as `await`. The callback runs first, then the Promise settles. Use either style, or both.
|
|
87
132
|
|
|
88
133
|
```js
|
|
134
|
+
// await only — result is the host’s return value
|
|
89
135
|
const wallet = await ChoogaBridge.activity('wallet.pick', { currency: 'ETB' });
|
|
90
|
-
// { ok, id, name, currency, … }
|
|
91
136
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
137
|
+
// callback + await
|
|
138
|
+
const result = await ChoogaBridge.call(
|
|
139
|
+
'user.get',
|
|
140
|
+
{},
|
|
141
|
+
{
|
|
142
|
+
onResult: r => console.log('host finished', r),
|
|
143
|
+
timeoutMs: 30000,
|
|
144
|
+
},
|
|
145
|
+
);
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
If the host result has `ok: false`, the Promise rejects after `onResult` still runs. The thrown error includes `.result` with the full host payload. If the host never replies, the Promise rejects with a timeout (default **120 seconds**; `getHostInfo` defaults to **15 seconds**).
|
|
149
|
+
|
|
150
|
+
```js
|
|
151
|
+
try {
|
|
152
|
+
await ChoogaBridge.navigate({ path: '/secret' });
|
|
153
|
+
} catch (err) {
|
|
154
|
+
console.error(err.message, err.result);
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Lifecycle
|
|
161
|
+
|
|
162
|
+
### init
|
|
163
|
+
|
|
164
|
+
`init(options?)` binds host listeners once. Extra calls are safe no-ops for binding, but still update `debug` / `allowedOrigins`. Pass `{ autoReady: false }` if you want to mount UI first and call `ready()` yourself.
|
|
165
|
+
|
|
166
|
+
```js
|
|
167
|
+
ChoogaBridge.init();
|
|
168
|
+
ChoogaBridge.init({
|
|
169
|
+
autoReady: false,
|
|
170
|
+
debug: true,
|
|
171
|
+
allowedOrigins: ['https://mini.example'],
|
|
95
172
|
});
|
|
173
|
+
// …mount UI…
|
|
174
|
+
ChoogaBridge.ready();
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### ready
|
|
178
|
+
|
|
179
|
+
`ready()` posts `{ type: "chooga.ready" }` so the host knows it can inject context. `init()` does this for you unless `autoReady` is `false`.
|
|
180
|
+
|
|
181
|
+
### close
|
|
182
|
+
|
|
183
|
+
`close()` asks the host to dismiss the WebView. Fire-and-forget.
|
|
184
|
+
|
|
185
|
+
```js
|
|
186
|
+
ChoogaBridge.close();
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Reading host state
|
|
192
|
+
|
|
193
|
+
### getState
|
|
194
|
+
|
|
195
|
+
`getState()` returns a snapshot of everything the host has injected so far. Known fields are always present (`session`, `user`, `theme`, `safeArea`, `hostInfo`, and so on). They may be `null` until the host sends them.
|
|
196
|
+
|
|
197
|
+
Hosts can also push **any extra fields** they want via `chooga.params`. Those land in `state.params` and are **spread onto the top level** of the snapshot (reserved keys like `session` always win). That means App B can grow or shrink host context without a bridge schema change:
|
|
198
|
+
|
|
199
|
+
```js
|
|
200
|
+
const { session, user, locale, featureFlags, cartCount } = ChoogaBridge.getState();
|
|
201
|
+
// same extras also live under:
|
|
202
|
+
const { params } = ChoogaBridge.getState();
|
|
203
|
+
console.log(params.locale, params.featureFlags);
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
**Host → mini-app** (merge, default):
|
|
207
|
+
|
|
208
|
+
```json
|
|
209
|
+
{ "type": "chooga.params", "locale": "am", "featureFlags": { "newCheckout": true } }
|
|
96
210
|
```
|
|
97
211
|
|
|
98
|
-
|
|
212
|
+
Or nest them:
|
|
213
|
+
|
|
214
|
+
```json
|
|
215
|
+
{ "type": "chooga.params", "params": { "locale": "am", "cartCount": 3 } }
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Replace the whole bag with `replace: true`. Clear a key on merge by sending `null`:
|
|
219
|
+
|
|
220
|
+
```json
|
|
221
|
+
{ "type": "chooga.params", "replace": true, "params": { "locale": "en" } }
|
|
222
|
+
{ "type": "chooga.params", "cartCount": null }
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Known messages also keep **extra fields** the host attaches (for example extra keys on `chooga.session` or `chooga.theme` are preserved on those objects).
|
|
226
|
+
|
|
227
|
+
```js
|
|
228
|
+
const { session, user, theme, hostInfo, hostConnected, params } = ChoogaBridge.getState();
|
|
229
|
+
|
|
230
|
+
if (session?.token) {
|
|
231
|
+
// use token for your API calls
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### subscribe
|
|
236
|
+
|
|
237
|
+
`subscribe(listener)` runs your listener immediately with the current snapshot, then again on every update. It returns an unsubscribe function.
|
|
238
|
+
|
|
239
|
+
```js
|
|
240
|
+
const unsub = ChoogaBridge.subscribe(state => {
|
|
241
|
+
if (state.user) renderProfile(state.user);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// later
|
|
245
|
+
unsub();
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
After `ready`, the host typically pushes messages such as `chooga.session`, `chooga.user`, `chooga.theme`, `chooga.safeArea`, `chooga.hostInfo`, `chooga.params`, and `chooga.event`. Theme updates also set CSS variables `--chooga-primary` / `--chooga-color-primary` and `data-chooga-theme` on `<html>`.
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Events
|
|
253
|
+
|
|
254
|
+
`on(name, handler)` listens for host pushes delivered as `chooga.event`. These are not request/response and do not use `requestId`. The handler receives the event `detail`. Pass `'*'` to hear every event; the wildcard handler receives `{ name, detail }`.
|
|
255
|
+
|
|
256
|
+
`on` returns an unsubscribe function. You can also call `off(name, handler)`.
|
|
99
257
|
|
|
100
258
|
```js
|
|
101
|
-
const stop = ChoogaBridge.on('user.updated',
|
|
102
|
-
console.log(user);
|
|
259
|
+
const stop = ChoogaBridge.on('user.updated', detail => {
|
|
260
|
+
console.log(detail.user);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
ChoogaBridge.on('*', ({ name, detail }) => {
|
|
264
|
+
console.log(name, detail);
|
|
103
265
|
});
|
|
104
|
-
|
|
266
|
+
|
|
267
|
+
stop();
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## Activities
|
|
273
|
+
|
|
274
|
+
`activity(name, params?, options?)` opens a native host screen and returns a Promise for its result. The resolved value is whatever the host put on `chooga.activityResult`.
|
|
275
|
+
|
|
276
|
+
Only call activities the host advertises (`has(name)` / `hostInfo.activities`). Until the shell implements them, use `mockHost` locally.
|
|
277
|
+
|
|
278
|
+
```js
|
|
279
|
+
const wallet = await ChoogaBridge.activity('wallet.pick', { currency: 'ETB' });
|
|
280
|
+
console.log(wallet.id, wallet.currency);
|
|
281
|
+
|
|
282
|
+
await ChoogaBridge.activity(
|
|
283
|
+
'host.confirm',
|
|
284
|
+
{
|
|
285
|
+
title: 'Delete?',
|
|
286
|
+
message: 'This cannot be undone.',
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
onResult: r => console.log('confirmed?', r),
|
|
290
|
+
},
|
|
291
|
+
);
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Outbound message shape: `{ type: "chooga.activity", requestId, name, params }`. Check `ChoogaBridge.has('wallet.pick')` after host info is available if you need to know whether an activity is advertised.
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## Services
|
|
299
|
+
|
|
300
|
+
### toast
|
|
301
|
+
|
|
302
|
+
`toast(message, tone?)` shows a short host snackbar. Fire-and-forget. Tone defaults to `success`. You can pass a string or an object.
|
|
303
|
+
|
|
304
|
+
```js
|
|
305
|
+
ChoogaBridge.toast('Saved');
|
|
306
|
+
ChoogaBridge.toast('Something went wrong', 'error');
|
|
307
|
+
ChoogaBridge.toast({ message: 'Saved', tone: 'success' });
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Progress overlay
|
|
311
|
+
|
|
312
|
+
`showProgress(options?)` (alias `progress.show`) shows the host loading UI while your mini-app does work. Pass a string as a shorthand for `{ message }`. Always pair it with `dismissProgress()` (`progress.dismiss`) in a `finally` block. Both are fire-and-forget.
|
|
313
|
+
|
|
314
|
+
```js
|
|
315
|
+
ChoogaBridge.showProgress({ message: 'Fetching orders…' });
|
|
316
|
+
try {
|
|
317
|
+
await fetch('/api/orders');
|
|
318
|
+
} finally {
|
|
319
|
+
ChoogaBridge.dismissProgress();
|
|
320
|
+
}
|
|
105
321
|
```
|
|
106
322
|
|
|
107
|
-
###
|
|
323
|
+
### getUser
|
|
324
|
+
|
|
325
|
+
`getUser(options?)` (alias `user.get()`) asks the host for fresh user claims. Await the result; if the payload includes `user`, bridge state is updated too.
|
|
108
326
|
|
|
109
327
|
```js
|
|
110
328
|
const { user } = await ChoogaBridge.getUser();
|
|
111
|
-
|
|
329
|
+
|
|
330
|
+
await ChoogaBridge.user.get({
|
|
331
|
+
onResult: r => console.log(r.user),
|
|
332
|
+
});
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### getHostInfo
|
|
336
|
+
|
|
337
|
+
`getHostInfo(options?)` refreshes capabilities, activities, and version into `state.hostInfo`. Default timeout is 15 seconds.
|
|
338
|
+
|
|
339
|
+
```js
|
|
340
|
+
const info = await ChoogaBridge.getHostInfo();
|
|
341
|
+
console.log(info.activities, info.capabilities, info.granted);
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### has and hostVersion
|
|
345
|
+
|
|
346
|
+
`has(key)` is a local check against `hostInfo` (and the last capability result). It does not round-trip to the host. `hostVersion()` returns the host’s advertised version, or the client `BRIDGE_VERSION` if none is available.
|
|
347
|
+
|
|
348
|
+
```js
|
|
349
|
+
if (ChoogaBridge.has('wallet.pick')) {
|
|
350
|
+
await ChoogaBridge.activity('wallet.pick', { currency: 'ETB' });
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
console.log(ChoogaBridge.hostVersion());
|
|
112
354
|
```
|
|
113
355
|
|
|
114
|
-
###
|
|
356
|
+
### requestCapability
|
|
115
357
|
|
|
116
|
-
|
|
358
|
+
`requestCapability(key, options?)` asks the host whether a permission is granted and **returns a Promise**. It settles when the host posts `chooga.capabilityResult` with the same `requestId`. `granted: false` still **resolves** (it is a valid answer, not a transport failure).
|
|
359
|
+
|
|
360
|
+
```js
|
|
361
|
+
const { granted, reason } = await ChoogaBridge.requestCapability('payments');
|
|
362
|
+
if (granted) {
|
|
363
|
+
await ChoogaBridge.payments.initiate({ amount: '10', currency: 'ETB' });
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
await ChoogaBridge.requestCapability('camera', {
|
|
367
|
+
onResult: r => console.log(r),
|
|
368
|
+
timeoutMs: 15000,
|
|
369
|
+
});
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
You can still watch `state.lastCapability` via `subscribe` if you prefer.
|
|
373
|
+
|
|
374
|
+
### openExternal
|
|
375
|
+
|
|
376
|
+
`openExternal(url)` asks the host to open an `https://` URL outside the WebView. Fire-and-forget.
|
|
377
|
+
|
|
378
|
+
```js
|
|
379
|
+
ChoogaBridge.openExternal('https://example.com/help');
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## Navigate
|
|
385
|
+
|
|
386
|
+
`navigate({ path?, url?, timeoutMs?, onResult? })` navigates inside the WebView. Use a relative `path` under your mini-app origin, or an allowlisted absolute `url`. The Promise resolves with `{ ok, reason? }` from `chooga.navigateResult`.
|
|
387
|
+
|
|
388
|
+
```js
|
|
389
|
+
await ChoogaBridge.navigate({ path: '/orders/1' });
|
|
390
|
+
await ChoogaBridge.navigate({
|
|
391
|
+
url: 'https://mini.example/orders/1',
|
|
392
|
+
onResult: r => console.log(r),
|
|
393
|
+
});
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
## Payments
|
|
399
|
+
|
|
400
|
+
`payments.initiate(options)` starts a host-mediated payment. Check `ChoogaBridge.has('payments')` first — the host must advertise and implement this capability.
|
|
401
|
+
|
|
402
|
+
### Await / callback mode (default)
|
|
403
|
+
|
|
404
|
+
When `deliverResult` is true (the default), the host posts `chooga.payments.result` when payment finishes. `await` and `onResult` both receive that host payload.
|
|
117
405
|
|
|
118
406
|
```js
|
|
119
407
|
const result = await ChoogaBridge.payments.initiate({
|
|
@@ -121,66 +409,91 @@ const result = await ChoogaBridge.payments.initiate({
|
|
|
121
409
|
currency: 'ETB',
|
|
122
410
|
reference: 'ord_123',
|
|
123
411
|
description: 'Checkout',
|
|
124
|
-
onResult: r => console.log(r),
|
|
412
|
+
onResult: r => console.log('payment finished', r),
|
|
125
413
|
});
|
|
126
|
-
|
|
414
|
+
|
|
415
|
+
console.log(result.ok, result.status, result.reference);
|
|
127
416
|
```
|
|
128
417
|
|
|
129
|
-
|
|
418
|
+
### Return-URL mode
|
|
419
|
+
|
|
420
|
+
Set `deliverResult: false` if the host should redirect back to your mini-app (for example with query params) instead of posting a result. The Promise resolves immediately to `{ ok: true, status: 'redirecting' }` and does **not** wait for payment completion. `return_url` must be allowlisted by the host.
|
|
130
421
|
|
|
131
422
|
```js
|
|
132
423
|
await ChoogaBridge.payments.initiate({
|
|
133
424
|
amount: '250.00',
|
|
134
425
|
currency: 'ETB',
|
|
135
426
|
deliverResult: false,
|
|
136
|
-
return_url: 'https://mini.example/paid',
|
|
427
|
+
return_url: 'https://mini.example/paid',
|
|
137
428
|
});
|
|
138
429
|
```
|
|
139
430
|
|
|
140
|
-
|
|
431
|
+
---
|
|
141
432
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
await ChoogaBridge.navigate({ url: 'https://mini.example/orders/1' });
|
|
146
|
-
```
|
|
433
|
+
## call
|
|
434
|
+
|
|
435
|
+
`call(method, params?, options?)` is the generic RPC into the host method map. Prefer dedicated helpers when they exist; use `call` when you want one entry point or a method that only lives on the host map.
|
|
147
436
|
|
|
148
|
-
|
|
437
|
+
The Promise resolves to the host’s return payload from `chooga.callResult`. Pass `onResult` if you want a callback when the host finishes—same object as `await`.
|
|
149
438
|
|
|
150
439
|
```js
|
|
151
|
-
|
|
152
|
-
await ChoogaBridge.call('
|
|
153
|
-
|
|
440
|
+
// Navigate via RPC
|
|
441
|
+
const nav = await ChoogaBridge.call('navigate', { path: '/home' });
|
|
442
|
+
|
|
443
|
+
// Activity via RPC
|
|
444
|
+
const wallet = await ChoogaBridge.call('activity', {
|
|
445
|
+
name: 'wallet.pick',
|
|
446
|
+
currency: 'ETB',
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
// Fresh user
|
|
450
|
+
const { user } = await ChoogaBridge.call('user.get');
|
|
451
|
+
|
|
452
|
+
// Payment with callback + await
|
|
453
|
+
const payment = await ChoogaBridge.call(
|
|
454
|
+
'payments.initiate',
|
|
455
|
+
{
|
|
456
|
+
amount: '250.00',
|
|
457
|
+
currency: 'ETB',
|
|
458
|
+
reference: 'ord_123',
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
onResult: result => {
|
|
462
|
+
// Host finished — this is the superapp’s return value
|
|
463
|
+
console.log(result.ok, result.status);
|
|
464
|
+
},
|
|
465
|
+
timeoutMs: 180000,
|
|
466
|
+
},
|
|
467
|
+
);
|
|
154
468
|
```
|
|
155
469
|
|
|
156
|
-
Supported
|
|
470
|
+
Supported `method` values include: `navigate`, `activity`, `payments.initiate`, `close`, `openExternal`, `requestCapability`, `progress.show`, `showProgress`, `progress.dismiss`, `dismissProgress`, `toast`, `user.get`, and `host.info`. Param shapes are host-defined; keep them aligned with the host bridge contract.
|
|
157
471
|
|
|
158
|
-
|
|
472
|
+
Outbound: `{ type: "chooga.call", requestId, method, params }`.
|
|
473
|
+
Inbound: `{ type: "chooga.callResult", requestId, …hostFields }`.
|
|
159
474
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
475
|
+
---
|
|
476
|
+
|
|
477
|
+
## Message cheat sheet
|
|
478
|
+
|
|
479
|
+
**Host → mini-app (context / pushes):** `chooga.session`, `chooga.user`, `chooga.theme`, `chooga.safeArea`, `chooga.hostInfo`, `chooga.params`, `chooga.event`, `chooga.capabilityResult`.
|
|
480
|
+
|
|
481
|
+
**Host → mini-app (settle Promises):** `chooga.callResult`, `chooga.activityResult`, `chooga.navigateResult`, `chooga.payments.result`. Each must echo the original `requestId`.
|
|
482
|
+
|
|
483
|
+
**Mini-app → host:** `chooga.ready`, `chooga.close`, `chooga.openExternal`, `chooga.requestCapability`, `chooga.navigate`, `chooga.payments.initiate`, `chooga.progress.show`, `chooga.progress.dismiss`, `chooga.activity`, `chooga.toast`, `chooga.user.get`, `chooga.hostInfo.get`, `chooga.call`.
|
|
484
|
+
|
|
485
|
+
All of these strings are also on `ChoogaBridge.BRIDGE` / the exported `BRIDGE` map. `BRIDGE_VERSION` is the client protocol version (`0.0.2`).
|
|
486
|
+
|
|
487
|
+
---
|
|
168
488
|
|
|
169
|
-
##
|
|
489
|
+
## Transport
|
|
170
490
|
|
|
171
|
-
|
|
491
|
+
Outbound messages go through `window.ChoogaHost.postToHost`, which in a React Native WebView becomes `ReactNativeWebView.postMessage(JSON.stringify(msg))`. Inbound messages arrive via `window.ChoogaMiniApp.onHostMessage` and/or DOM `message` events. In a plain browser without a host, outbound posts are no-ops.
|
|
172
492
|
|
|
173
|
-
|
|
174
|
-
- `chooga.user` — sanitized claims
|
|
175
|
-
- `chooga.theme` — `{ mode, primary_color }` (+ CSS vars `--chooga-primary`)
|
|
176
|
-
- `chooga.safeArea` — `{ insets }`
|
|
177
|
-
- `chooga.hostInfo` — `{ version, activities, capabilities, granted }`
|
|
178
|
-
- `chooga.event` — `{ name, detail, at }` (also delivered via `on`)
|
|
493
|
+
---
|
|
179
494
|
|
|
180
495
|
## Versioning & release
|
|
181
496
|
|
|
182
|
-
Keep
|
|
183
|
-
Bump this package when adding client APIs or changing result shapes.
|
|
497
|
+
Keep wire type strings in sync with the host bridge contract. Bump this package when you add client APIs or change result shapes, and keep `BRIDGE_VERSION` in `src/index.js` equal to `package.json` `"version"`.
|
|
184
498
|
|
|
185
|
-
|
|
186
|
-
Full steps, Trusted Publishing, and troubleshooting: **[`RELEASE.md`](./RELEASE.md)**.
|
|
499
|
+
Ship a release by bumping the version, tagging `vX.Y.Z`, and pushing the tag. CI publishes to npm and creates a GitHub Release; CDN mirrors follow. Full steps are in [`RELEASE.md`](./RELEASE.md).
|