@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 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 (Awash Superapp and other Chooga hosts).
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 + install |
10
- | [`RELEASE.md`](./RELEASE.md) | **npm + CDN CI release** (Trusted Publishing, tags, CDN URLs) |
11
- | Host bridge | Awash `Application/Screens/Superapp/bridge/README.md` |
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
- ### CDN (prefer a pinned version)
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
- <!-- jsDelivr -->
24
- <script src="https://cdn.jsdelivr.net/npm/@jetezra/bridge@1.2.0/dist/chooga-bridge.min.js"></script>
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
- Build locally: `npm run build && npm test` → `dist/chooga-bridge.{mjs,cjs,min.js,d.ts}`.
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(); // posts chooga.ready (disable with { autoReady: false })
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
- // host push
56
+ console.log('theme updated', theme);
46
57
  });
47
58
 
48
- const unsub = ChoogaBridge.subscribe(state => {
49
- // session, user, theme, safeArea, hostInfo, …
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
- const { session, user, theme } = ChoogaBridge.getState();
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
- ## Mental model
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
- | Kind | API | Notes |
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
- ## API
127
+ ## Async calls: await and onResult
64
128
 
65
- | Method | Description |
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
- ### Activity
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
- await ChoogaBridge.activity('host.confirm', {
93
- title: 'Delete?',
94
- message: 'This cannot be undone.',
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
- ### Events
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', ({ user }) => {
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
- // later: stop() or ChoogaBridge.off('user.updated', handler)
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
- ### User + toast
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
- ChoogaBridge.toast('Saved', 'success');
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
- ### Payments
356
+ ### requestCapability
115
357
 
116
- **Callback mode (default)** awaits `chooga.payments.result`:
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), // optional
412
+ onResult: r => console.log('payment finished', r),
125
413
  });
126
- // result: { ok, status, reference?, … }
414
+
415
+ console.log(result.ok, result.status, result.reference);
127
416
  ```
128
417
 
129
- **Return-URL mode** — host redirects after payment; no result message:
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', // must be allowlisted
427
+ return_url: 'https://mini.example/paid',
137
428
  });
138
429
  ```
139
430
 
140
- ### Navigate
431
+ ---
141
432
 
142
- ```js
143
- await ChoogaBridge.navigate({ path: '/orders/1' });
144
- // or absolute URL within allowed_origins
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
- ### Call
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
- await ChoogaBridge.call('navigate', { path: '/home' });
152
- await ChoogaBridge.call('activity', { name: 'wallet.pick', currency: 'ETB' });
153
- await ChoogaBridge.call('user.get');
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 methods: `navigate`, `payments.initiate`, `close`, `openExternal`, `requestCapability`, `progress.show`, `progress.dismiss`, `showProgress`, `dismissProgress`, `activity`, `toast`, `user.get`, `host.info`.
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
- ### Progress (host loading overlay)
472
+ Outbound: `{ type: "chooga.call", requestId, method, params }`.
473
+ Inbound: `{ type: "chooga.callResult", requestId, …hostFields }`.
159
474
 
160
- ```js
161
- ChoogaBridge.showProgress({ message: 'Fetching orders…' });
162
- try {
163
- await fetch('/api/orders');
164
- } finally {
165
- ChoogaBridge.dismissProgress();
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
- ## Host messages (read-only)
489
+ ## Transport
170
490
 
171
- The host injects these after `ready`:
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
- - `chooga.session` — `{ token, expires_at }`
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 message type strings in sync with the host `bridge/types.js`.
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
- **Ship a release:** bump version tag `vX.Y.Z` push tag CI publishes npm + GitHub Release (CDN follows).
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).