@condorinst/mobile-bridge 0.18.0 → 0.19.0

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/dist/index.d.ts CHANGED
@@ -1,21 +1,21 @@
1
1
  import * as v from 'valibot';
2
2
 
3
3
  /**
4
- * Mock adapter — ativo quando `window.flutter_inappwebview` não é
5
- * detectado (browser dev, jsdom sem host instalado, Storybook etc.).
4
+ * Mock adapter — active when no native host is detected: a plain browser,
5
+ * jsdom without an installed host, Storybook, and so on.
6
6
  *
7
- * Comportamento:
8
- * - `callHandler` grava `{handlerName, payload, timestamp}` em buffer
9
- * interno (cap 100, FIFO), loga via `console.debug` e dispatcha
10
- * listeners registrados via `onCallHandler`.
11
- * - `triggerEmit` dispatcha via `window.CondorBridge.emit` — bridge real
12
- * trata como se viesse do nativo (handshake-ack resolve handshake;
13
- * demais chaves vão pros subscribers).
14
- * - `getMessages` retorna snapshot read-only do buffer.
15
- * - `clearMessages` esvazia o buffer (útil em testes).
16
- * - `onCallHandler(listener)` — registra listener invocado a cada send.
17
- * Retorna função de unsubscribe. Útil para dev panel reagir a sends
18
- * (v0.3.0+ auto-respond toggle) ou análise em testes.
7
+ * Behaviour:
8
+ * - `callHandler` records `{ handlerName, payload, timestamp }` in an internal
9
+ * buffer (capped at 100, FIFO), logs through `console.debug`, and dispatches
10
+ * to listeners registered with `onCallHandler`.
11
+ * - `triggerEmit` dispatches through `window.CondorBridge.emit`, so the real
12
+ * bridge treats it as if it came from the native side: `handshake-ack`
13
+ * resolves the handshake, every other key reaches its subscribers.
14
+ * - `getMessages` returns a read-only snapshot of the buffer.
15
+ * - `clearMessages` empties it, which is useful in tests.
16
+ * - `onCallHandler(listener)` registers a listener invoked on every send and
17
+ * returns an unsubscribe function — used by the dev panel's auto-respond
18
+ * toggle, and for assertions in tests.
19
19
  */
20
20
  interface MockMessage {
21
21
  handlerName: string;
@@ -24,27 +24,26 @@ interface MockMessage {
24
24
  }
25
25
 
26
26
  /**
27
- * Dev panel — UI flutuante para inspecionar o bridge em mock mode.
27
+ * Dev panel — a floating UI for inspecting the bridge in mock mode.
28
28
  *
29
- * **Opt-in:** chamar `Bridge.installDevPanel(opts?)` quando quiser ver
30
- * o painel. Só funciona em mock mode (throws em modo real). Injeta no
31
- * `document.body`; idempotente (re-install remove o anterior).
29
+ * **Opt-in:** call `Bridge.installDevPanel(opts?)` when you want it. It only
30
+ * works in mock mode and throws in real mode. It injects into `document.body`
31
+ * and is idempotent — re-installing removes the previous panel.
32
32
  *
33
- * Conteúdo:
34
- * - Header com badge "MOCK", contador de sends, botão minimizar/maximizar.
35
- * - Sent log — últimas N mensagens (timestamp, type, payload truncado).
36
- * - Trigger emit — dropdown com `BRIDGE_KEYS` + textarea payload + botão.
33
+ * Contents:
34
+ * - a header with a "MOCK" badge, a send counter, and a minimise button;
35
+ * - a sent log with the last N messages (timestamp, type, truncated payload);
36
+ * - a trigger-emit control: a `BRIDGE_KEYS` dropdown, a payload textarea, and
37
+ * a button.
37
38
  *
38
- * Estilos inline + classes prefixadas `condor-mock-panel-*` para reduzir
39
- * conflito com CSS do cliente.
39
+ * Styles are inline and classes are prefixed `condor-mock-panel-*`, to reduce
40
+ * collisions with the client's own CSS.
40
41
  */
41
42
 
42
43
  /**
43
- * Resposta auto-emitida em reação a um `Bridge.send`, retornada pela
44
- * policy `onSendForAutoRespond` do cliente. `null` significa "não
45
- * responder a este send".
46
- *
47
- * @since v0.3.0
44
+ * A reply emitted automatically in reaction to a `Bridge.send`, returned by the
45
+ * client's `onSendForAutoRespond` policy. `null` means "do not answer this
46
+ * send".
48
47
  */
49
48
  interface AutoRespondResponse {
50
49
  key: string;
@@ -56,55 +55,51 @@ interface DevPanelOptions {
56
55
  theme?: 'dark' | 'light';
57
56
  startCollapsed?: boolean;
58
57
  /**
59
- * Policy de auto-respond: invocada a cada `Bridge.send` quando o
60
- * toggle "Auto-respond" está ligado no painel. Retorna
61
- * `{key, payload}` para disparar `Bridge.mockEmit(key, payload)`
62
- * após delay, ou `null` para não responder.
63
- *
64
- * Sem esta callback, o checkbox "Auto-respond" não aparece no painel.
58
+ * Auto-respond policy: invoked on every `Bridge.send` while the panel's
59
+ * "Auto-respond" toggle is on. Return `{ key, payload }` to fire
60
+ * `Bridge.mockEmit(key, payload)` after the delay, or `null` to stay silent.
65
61
  *
66
- * @since v0.3.0
62
+ * Without this callback the "Auto-respond" checkbox does not appear.
67
63
  */
68
64
  onSendForAutoRespond?: (msg: MockMessage) => AutoRespondResponse | null;
69
65
  /**
70
- * Estado inicial do toggle "Auto-respond". Default: `false`
71
- * (manual permanece padrão; cliente decide quando ligar).
72
- *
73
- * @since v0.3.0
66
+ * Initial state of the "Auto-respond" toggle. Defaults to `false` — manual
67
+ * stays the default, and the client decides when to turn it on.
74
68
  */
75
69
  startAutoRespondEnabled?: boolean;
76
70
  /**
77
- * Delay em ms entre o `send` e o `mockEmit` da auto-resposta.
78
- * Default: `50` — aproxima latência de IPC real de native bridge.
79
- *
80
- * @since v0.3.0
71
+ * Delay in milliseconds between the `send` and the auto-response `mockEmit`.
72
+ * Defaults to `50`, which approximates the IPC latency of the real native
73
+ * bridge.
81
74
  */
82
75
  autoRespondDelayMs?: number;
83
76
  }
84
77
 
85
78
  /**
86
- * Detecção do host nativo + adapter pattern.
79
+ * Native host detection, behind an adapter.
87
80
  *
88
- * **v0.1.0:** lançava erro quando `window.flutter_inappwebview` ausente.
89
- * **v0.2.0:** ativa mock adapter (`createMockAdapter`) — destrava dev em
90
- * browser comum sem buildar APK.
91
- * **v0.18.0:** canal `window.CondorNative` (JavaScript channel do
92
- * `webview_flutter`) — detectado **antes** do `flutter_inappwebview`, que
93
- * segue suportado por transição. O canal só aceita string: a mensagem vai
94
- * serializada em JSON. E o gancho `setOutgoingStamp` permite ao shell
95
- * carimbar toda mensagem de saída (ex.: nonce da Camada 3) sem monkey-patch
96
- * do host.
81
+ * Detection order: the `window.CondorNative` JavaScript channel
82
+ * (`webview_flutter`) first, then the legacy `window.flutter_inappwebview`,
83
+ * then the mock. The channel only accepts strings, so the message travels as
84
+ * JSON. `setOutgoingStamp` lets the shell stamp every outgoing message — the
85
+ * nonce — without monkey-patching the host.
97
86
  *
98
- * Adapter ativo é cached na primeira chamada de `getActiveAdapter()`.
99
- * Tests devem chamar `__resetAdapterForTests()` no `beforeEach` para
100
- * forçar re-detecção (ex.: após instalar/remover `window.CondorNative`).
87
+ * With no host at all the mock adapter activates, which is what makes browser
88
+ * development possible without building an APK.
89
+ *
90
+ * The active adapter is cached on the first `getActiveAdapter()` call. Tests
91
+ * should call `__resetAdapterForTests()` in `beforeEach` to force
92
+ * re-detection, for instance after installing or removing
93
+ * `window.CondorNative`.
101
94
  */
102
95
 
103
96
  /**
104
- * Nome do JavaScript channel registrado pelo nativo
105
- * (`WebViewController.addJavaScriptChannel`). Não pode ser `CondorBridge`: o
106
- * plugin publica o canal como `window.<nome>`, o que colidiria com o emitter
107
- * `window.CondorBridge` instalado por este SDK.
97
+ * Name of the JavaScript channel the native side registers with
98
+ * `WebViewController.addJavaScriptChannel`.
99
+ *
100
+ * It cannot be `CondorBridge`: the plugin publishes the channel as
101
+ * `window.<name>`, which would collide with the `window.CondorBridge` emitter
102
+ * this SDK installs.
108
103
  */
109
104
  declare const NATIVE_CHANNEL_NAME = "CondorNative";
110
105
  interface FlutterInAppWebView {
@@ -126,16 +121,15 @@ declare global {
126
121
  type OutgoingStamp = (message: Record<string, unknown>) => Record<string, unknown>;
127
122
 
128
123
  /**
129
- * Catálogo das chaves do bridge JS↔Native.
124
+ * Catalogue of the JS↔Native bridge keys.
130
125
  *
131
- * Espelha o lado JS-facing de `ForegroundComCoreKeys` do `condor_core`
132
- * (monorepo `mobile_applications`). As strings aqui são o que o JS recebe
133
- * via `window.CondorBridge.emit(key, payload)`.
126
+ * Mirrors the JS-facing side of `ForegroundComCoreKeys` in `condor_core`.
127
+ * The strings here are what JavaScript receives through
128
+ * `window.CondorBridge.emit(key, payload)`.
134
129
  *
135
- * Camada 1 (v0.1.0): catálogo declarativo. Apenas `pingPong` está
136
- * efetivamente emitida pelo lado Dart no Trio B; as outras 8 são
137
- * reservadas para o Trio C (`sleep-whitelabel-bridge-keys`) e ficam
138
- * aqui como contrato forward-looking.
130
+ * Thirteen keys exist. A sandboxed client can subscribe to twelve of them:
131
+ * `dfu` is denied by the shell policy and skipped natively. See
132
+ * `docs/bridge-contract.md` for what each one carries and when it is emitted.
139
133
  */
140
134
  declare const BRIDGE_KEYS: {
141
135
  readonly pingPong: "pingPong";
@@ -150,10 +144,10 @@ declare const BRIDGE_KEYS: {
150
144
  readonly dfu: "dfu";
151
145
  readonly systemStatus: "systemStatus";
152
146
  /**
153
- * Native → client: o back do SO foi pressionado e o cliente reportou
154
- * ter histórico interno (`reportNavigation(true)`). O cliente deve voltar
155
- * UMA página interna. Emitido só quando o nativo decidiu delegar o back
156
- * ao cliente. Vide `BridgeClient.onBack`.
147
+ * Native → client: the OS back button was pressed and the client had
148
+ * reported internal history via `reportNavigation(true)`. Go back exactly
149
+ * ONE internal page. Emitted only when the native side decided to delegate
150
+ * the back gesture. See `BridgeClient.onBack`.
157
151
  */
158
152
  readonly navigationBack: "navigationBack";
159
153
  /**
@@ -161,22 +155,24 @@ declare const BRIDGE_KEYS: {
161
155
  * AND the language explicitly chosen in the app Settings, so the client can
162
156
  * apply its own precedence rule — including rendering a language the native
163
157
  * chrome does not support. Emitted on attach, after `handshake-ack`, and on
164
- * every change in Settings. Vide `LanguagePayload`.
158
+ * every change in Settings. See `LanguagePayload`.
165
159
  */
166
160
  readonly language: "language";
167
161
  };
168
162
  type BridgeKey = (typeof BRIDGE_KEYS)[keyof typeof BRIDGE_KEYS];
169
163
 
170
164
  /**
171
- * Mensagens do protocolo do bridge.
165
+ * Wire messages of the bridge protocol.
172
166
  *
173
- * Espelha o lado Dart (`BridgeIncomingMessage`/`BridgeOutgoingEvent` em
174
- * `apps/sleep_whitelabel/lib/ui/pages/home/bridge/bridge_message.dart`).
167
+ * Mirrors the Dart side (`BridgeIncomingMessage` / `BridgeOutgoingEvent` in
168
+ * the Canvas app's `bridge_message.dart`).
175
169
  */
176
170
  /**
177
- * Mensagem JS → Native, enviada via
178
- * `window.CondorNative.postMessage(JSON.stringify(msg))` (v0.18.0+) ou, no
179
- * host legado, `window.flutter_inappwebview.callHandler('CondorBridge', msg)`.
171
+ * JS → native message, sent over
172
+ * `window.CondorNative.postMessage(JSON.stringify(msg))` (0.18.0+) or, on a
173
+ * legacy host, `window.flutter_inappwebview.callHandler('CondorBridge', msg)`.
174
+ *
175
+ * Anything above 64 KB is discarded by the native side without a reply.
180
176
  */
181
177
  interface BridgeIncomingMessage {
182
178
  type: string;
@@ -184,56 +180,60 @@ interface BridgeIncomingMessage {
184
180
  payload?: Record<string, unknown>;
185
181
  }
186
182
  /**
187
- * Evento Native → JS, recebido via
188
- * `window.CondorBridge.emit(key, payload)`.
183
+ * Native → JS event, delivered through `window.CondorBridge.emit(key, payload)`.
189
184
  */
190
185
  interface BridgeOutgoingEvent {
191
186
  key: string;
192
187
  payload: unknown;
193
188
  }
194
189
  /**
195
- * Resposta do handshake (`handshake-ack`).
190
+ * Handshake reply (`handshake-ack`).
196
191
  *
197
- * `nativeVersion`: versão semver do schema declarada pelo nativo.
198
- * `accepted`: nativo aceita o `clientVersion` enviado. v0.1.0 não impõe
199
- * validação semver dura — nativo retorna `accepted: true` sempre.
192
+ * - `nativeVersion`: the semver schema version the native side declares. This
193
+ * is the ONLY capability signal available; compare it against the minimum
194
+ * version of the feature you want to use.
195
+ * - `accepted`: whether the native side accepted the `clientVersion` you sent.
196
+ * There is no hard semver validation — it is **always** `true`, so it carries
197
+ * no information. Never branch on it.
200
198
  */
201
199
  interface HandshakeAck {
202
200
  nativeVersion: string;
203
201
  accepted: boolean;
204
202
  }
203
+ /** Options for {@link CondorBridge.handshake}. */
205
204
  interface HandshakeOptions {
205
+ /** Your own client version, for the native logs. Not validated. */
206
206
  clientVersion: string;
207
207
  }
208
208
 
209
209
  /**
210
- * Catálogo de payloads tipados por chave (v0.4.0+).
210
+ * Per-key typed payload catalogue.
211
211
  *
212
- * Shapes derivadas autoritativamente do source code do `condor_core` no
213
- * monorepo `mobile_applications` (ver §"Shapes derivadas" no execution
214
- * log do step2 do trio `2026-06-04_sleep-whitelabel-bridge-keys`).
212
+ * Shapes are derived from the `condor_core` source in the
213
+ * `mobile_applications` monorepo, and are authoritative for what arrives on
214
+ * each key.
215
215
  *
216
- * **Direção:** BG → JS (observáveis). Os comandos JS → BG (`Bridge.send`)
217
- * continuam permissivos (`Record<string, unknown>`) na v0.4.0 — sua
218
- * tipagem estrita é trabalho separado e fora do MVP atual.
216
+ * **Direction:** native → JS (observable events). JS → native commands
217
+ * (`send`) stay permissive (`Record<string, unknown>`); the typed helpers on
218
+ * `BridgeClient` are the ergonomic path for the ones that matter.
219
219
  *
220
- * **Migração da v0.3.0:** o tipo `PayloadOf<K>` era `Record<string, unknown>`
221
- * para qualquer K. Agora é mapeado pelas chaves do catálogo, com
222
- * fallback permissivo para chaves não-catalogadas (e.g., `dfu` continua
223
- * `Record<string, unknown>` — hub-only, reservado).
220
+ * `PayloadOf<K>` maps a catalogued key to its payload, with a permissive
221
+ * fallback for uncatalogued keys (`dfu` stays `Record<string, unknown>` — it
222
+ * is hub-only and a sandboxed client never receives it).
224
223
  */
225
- /** Loop heartbeat boot/keepalive. */
224
+ /** Boot / keepalive heartbeat. */
226
225
  interface PingPongPayload {
227
226
  data: 'ping' | 'pong';
228
227
  }
229
228
  /**
230
- * Snapshot do device store do usuário. Espelha `UserDevices.toMap()`
231
- * (`packages/condor_core/lib/src/domain/entities/user_devices_entity.dart:144-151`).
229
+ * Snapshot of the user's device store. Mirrors `UserDevices.toMap()` in
230
+ * `condor_core`.
231
+ *
232
+ * The inner arrays are `Record<string, unknown>`: each item has its own
233
+ * `toMap()` on the Dart side (device config, telemetry, user config), and
234
+ * strict typing for them is deferred until a client needs it.
232
235
  *
233
- * Os arrays internos são `Record<string, unknown>` no MVP — cada item
234
- * tem seu próprio `toMap()` (DeviceConfig, DeviceTelemetry,
235
- * DeviceUserConfig) cujo strict typing fica para release futura quando
236
- * consumidor JS precisar.
236
+ * There is no device cap in the app. Do not assume this list is bounded.
237
237
  */
238
238
  interface UserDevicePayload {
239
239
  lastUpdate: number;
@@ -242,23 +242,22 @@ interface UserDevicePayload {
242
242
  devicesUserConfig: Array<Record<string, unknown>>;
243
243
  }
244
244
  /**
245
- * Canais crus do sensor de luz, com os nomes que o backend usa no
246
- * `user_cmd=log` — mesmo vocabulário para histórico e tempo real.
245
+ * Raw light-sensor channels, under the names the backend uses in
246
+ * `user_cmd=log` — the same vocabulary for history and for real time.
247
247
  *
248
- * Presentes a partir da **nativeVersion 0.16.0**. Um bundle compilado contra
249
- * este SDK pode rodar num app nativo mais velho, que não os emite: cheque o
250
- * `nativeVersion` do `handshake-ack` antes de depender deles, ou leia
251
- * defensivamente. Não são opcionais no tipo de propósito — opcional
252
- * esconderia o skew de versão em vez de deixá-lo explícito.
248
+ * Present from **nativeVersion 0.16.0**. A bundle compiled against this SDK can
249
+ * run on an older native app that does not emit them: check `nativeVersion`
250
+ * from the handshake ack before depending on them, or read defensively. They
251
+ * are deliberately **not** optional in the type — optional would hide the
252
+ * version skew instead of making it explicit.
253
253
  *
254
- * ⚠️ O `nativeVersion` só chega ao cliente a partir do **SDK 0.17.0**: até a
255
- * `0.16.x` o shell respondia o handshake do cliente apenas com o
256
- * `shellVersion`, então essa checagem era impossível de cumprir de dentro do
257
- * iframe.
254
+ * ⚠️ `nativeVersion` only reaches the client from **SDK 0.17.0**: up to
255
+ * `0.16.x` the shell answered the client handshake with `shellVersion` alone,
256
+ * so this check was impossible to satisfy from inside the iframe.
258
257
  *
259
- * `null` significa **canal ausente nesta geração de hardware**, nunca "leitura
260
- * zero": `0.0` é leitura válida. Mesma distinção que o backend faz com
261
- * `float | null`.
258
+ * `null` means **the channel does not exist on this hardware generation**,
259
+ * never "the reading was zero" — `0.0` is a valid reading. Coercing `null` to
260
+ * `0` fabricates data.
262
261
  */
263
262
  type LightSensorsRawChannels = {
264
263
  light_sensor_f1: number;
@@ -269,18 +268,18 @@ type LightSensorsRawChannels = {
269
268
  light_sensor_f6: number;
270
269
  light_sensor_f7: number;
271
270
  light_sensor_f8: number;
272
- /** Luz total (`visible` no wire do device). */
271
+ /** Total light (`visible` on the device wire format). */
273
272
  light_sensor_clear: number;
274
- /** Infravermelho próximo. */
273
+ /** Near infrared. */
275
274
  light_sensor_nir: number;
276
275
  };
277
276
  /**
278
- * Leitura de tempo real de um ActLumus gen1 (`type: 'actlumus'`).
277
+ * A real-time reading from an ActLumus gen1 (`type: 'actlumus'`).
279
278
  *
280
- * Espelha `LightSensorsActlumus1GraphicData.toMap()`
281
- * (`packages/condor_interactors/lib/src/domain/entities/actlumus/1/light_sensors1_graphic_data_entity.dart`).
282
- * O gen1 não tem as tristimulus nem o flicker detect — as quatro chaves vêm
283
- * como `null`, presentes no schema para que ele não mude entre gerações.
279
+ * Mirrors `LightSensorsActlumus1GraphicData.toMap()` in `condor_interactors`.
280
+ * Gen1 has neither the tristimulus channels nor flicker detect — those four
281
+ * keys arrive as `null`, present in the schema so that its shape does not
282
+ * change between hardware generations.
284
283
  */
285
284
  type LightSensorsActlumus1Data = LightSensorsRawChannels & {
286
285
  time: number;
@@ -302,17 +301,17 @@ type LightSensorsActlumus1Data = LightSensorsRawChannels & {
302
301
  light_sensor_fd: null;
303
302
  };
304
303
  /**
305
- * Leitura de tempo real de um ActLumus Plus / gen2 (`type: 'actlumus2'`).
304
+ * A real-time reading from an ActLumus Plus / gen2 (`type: 'actlumus2'`).
306
305
  *
307
- * Espelha `LightSensorsActlumus2GraphicData.toMap()`
308
- * (`packages/condor_interactors/lib/src/domain/entities/actlumus/2/light_sensors2_graphic_data_entity.dart`).
309
- * ⚠️ Os comprimentos de onda **não** são os mesmos do gen1 — são 14 (395…800)
310
- * contra 10 (390…750), sem nenhum valor em comum. Um gráfico que leia a lista
311
- * do gen1 num device gen2 encontra `undefined` em todas as séries e renderiza
312
- * vazio; discrimine sempre pelo `type`.
306
+ * Mirrors `LightSensorsActlumus2GraphicData.toMap()` in `condor_interactors`.
313
307
  *
314
- * `light_sensor_z/_y/_x` são as tristimulus CIE 1931 — Z no azul, Y no verde,
315
- * X no vermelho.
308
+ * ⚠️ The wavelengths are **not** the gen1 ones: 14 of them (395…800) against
309
+ * 10 (390…750), with no value in common. A chart that reads the gen1 list on a
310
+ * gen2 device finds `undefined` in every series and renders empty. Always
311
+ * discriminate on `type`.
312
+ *
313
+ * `light_sensor_z/_y/_x` are the CIE 1931 tristimulus values — Z in the blue,
314
+ * Y in the green, X in the red.
316
315
  */
317
316
  type LightSensorsActlumus2Data = LightSensorsRawChannels & {
318
317
  time: number;
@@ -335,17 +334,20 @@ type LightSensorsActlumus2Data = LightSensorsRawChannels & {
335
334
  light_sensor_z: number;
336
335
  light_sensor_y: number;
337
336
  light_sensor_x: number;
338
- /** Flicker detect. Não entra na matriz do espectro. */
337
+ /** Flicker detect. Not part of the spectrum matrix. */
339
338
  light_sensor_fd: number;
340
339
  };
341
340
  /**
342
- * Stream real-time de sensores de luz (FEST). Shape:
343
- * `{serialNo, type, data: <lightSensors.toMap()>}`.
341
+ * Real-time light-sensor stream. Shape:
342
+ * `{ serialNo, type, data }`.
343
+ *
344
+ * A union discriminated by `type`, which is the `DeviceType.name` on the Dart
345
+ * side. `data` carries **both the derived spectrum and the raw channels it came
346
+ * from** — before 0.16.0 only the spectrum crossed the bridge, and a probe
347
+ * looking up a raw channel by name read `undefined`.
344
348
  *
345
- * União discriminada pelo `type`, que é o `DeviceType.name` do lado Dart. O
346
- * `data` carrega **o espectro derivado e os canais crus que o originaram** —
347
- * até a `0.16.0` só o espectro atravessava, e uma sonda que procurasse um canal
348
- * cru pelo nome lia `undefined`.
349
+ * This stream only flows while real-time is on for that device; it is off by
350
+ * default. See the `realTime` command.
349
351
  */
350
352
  type DeviceLightSensorsPayload = {
351
353
  serialNo: number;
@@ -373,16 +375,17 @@ interface DeleteMemoryAckPayload {
373
375
  success: boolean;
374
376
  }
375
377
  /**
376
- * Status de conexão BLE. Espelha `_userDevicesService.openConnection`
377
- * subscriber (`devices_notification_service.dart:38-44`).
378
+ * BLE connection status. Mirrors the `openConnection` subscriber in the app's
379
+ * device notification service.
378
380
  */
379
381
  interface DeviceConnectionPayload {
380
382
  serialNo: number;
381
383
  isConnect: boolean;
382
384
  }
383
385
  /**
384
- * Evento/status de device (logs). Espelha `DevicesNotification.toMap()`
385
- * (`devices_notification_entity.dart:33-41`).
386
+ * Device event or status notice. Mirrors `DevicesNotification.toMap()`.
387
+ * `message` is already localized by the app; `messageCode` is the stable
388
+ * identifier to branch on.
386
389
  */
387
390
  interface DeviceNotificationPayload {
388
391
  serialNo: number;
@@ -392,46 +395,52 @@ interface DeviceNotificationPayload {
392
395
  isError: boolean;
393
396
  }
394
397
  /**
395
- * Parâmetros do comando `sensorLog` (GET `user_cmd=log` do Mobile Lambda).
398
+ * Parameters of the `sensorLog` command.
396
399
  *
397
- * `startTime`/`endTime` delimitam um período — `startTime` é **inclusivo** e
398
- * `endTime` **exclusivo**, ambos no formato estrito `YYYY-MM-DD HH:MM:SS`
399
- * (sem `T`, sem offset, sem date-only).
400
+ * `startTime` / `endTime` delimit a period — `startTime` is **inclusive**,
401
+ * `endTime` **exclusive**, both in the strict format `YYYY-MM-DD HH:MM:SS`
402
+ * (no `T`, no offset, no date-only form). Requires nativeVersion >= 0.15.0.
400
403
  *
401
- * ⚠️ Os timestamps do contrato são **hora local do dispositivo**, não UTC:
402
- * `log_time` é passthrough do RTC do aparelho. Monte o range com os getters
403
- * locais do `Date` (`getFullYear()`, `getHours()`, …) e **nunca** com
404
- * `toISOString()` — converter para UTC desloca as séries pelo offset do fuso,
405
- * com dados plausíveis e nenhum erro visível.
404
+ * ⚠️ These timestamps are **device-local time, not UTC**: `log_time` passes
405
+ * through from the device RTC. Build the range with local `Date` getters
406
+ * (`getFullYear()`, `getHours()`, …) and **never** with `toISOString()` —
407
+ * converting to UTC shifts every series by the timezone offset, producing
408
+ * plausible data and no visible error.
406
409
  *
407
- * Os cursores `startingAfter`/`endingBefore` são **opacos** e mutuamente
408
- * exclusivos: ecoe o valor recebido, nunca construa um.
410
+ * The `startingAfter` / `endingBefore` cursors are **opaque** and mutually
411
+ * exclusive: echo back the value you received, never construct one.
409
412
  */
410
413
  interface SensorLogQueryPayload {
411
- /** Ecoado na resposta — correlaciona requisições concorrentes. */
414
+ /** Echoed back in the reply — correlates concurrent requests. */
412
415
  requestId: string;
413
416
  serialNo: number;
414
- /** `wrist` ou `necklace`. Omita para não filtrar. */
417
+ /** `wrist` or `necklace`. Omit for no filter. */
415
418
  bodyPart?: string;
416
- /** 1..1000 (default do backend = 10). */
419
+ /** 1..1000 (backend default is 10). Outside the range: `INVALID_LIMIT`. */
417
420
  limit?: number;
418
421
  startingAfter?: string;
419
422
  endingBefore?: string;
420
- /** Inclusivo, `YYYY-MM-DD HH:MM:SS` em hora local do dispositivo. */
423
+ /** Inclusive, `YYYY-MM-DD HH:MM:SS`, in device-local time. */
421
424
  startTime?: string;
422
- /** Exclusivo, `YYYY-MM-DD HH:MM:SS` em hora local do dispositivo. */
425
+ /** Exclusive, `YYYY-MM-DD HH:MM:SS`, in device-local time. */
423
426
  endTime?: string;
424
427
  }
425
428
  /**
426
- * Resposta do comando `sensorLog` (GET `user_cmd=log` do Mobile Lambda).
427
- * Envelope com `requestId` ecoado para correlação JS (suporta paginação
428
- * keyset concorrente) + `success`/`error`. No sucesso traz a página de logs
429
- * (ordem cronológica ASC, temperatura em °C, timestamps naive em **hora local
430
- * do dispositivo**) e os cursores opacos. Com range, `hasMore`/`hasPrevious`
431
- * são calculados **dentro do período**, então `hasMore: false` significa
432
- * "período completo". No erro, `error` carrega o código do contrato (ex.:
433
- * `CONFLICTING_CURSORS`, `INVALID_TIME_RANGE`, `invalid session`) — código de
434
- * diagnóstico, **nunca** texto para exibir ao usuário.
429
+ * Reply to the `sensorLog` command.
430
+ *
431
+ * An envelope carrying the echoed `requestId` for correlation (so concurrent
432
+ * keyset pagination works) plus `success` / `error`. On success it brings the
433
+ * page of logs — chronological ascending, temperature in °C, naive timestamps
434
+ * in **device-local time** — and the opaque cursors.
435
+ *
436
+ * With a time range, `hasMore` / `hasPrevious` are computed **within the
437
+ * period**, so `hasMore: false` means "this period is complete", not "no more
438
+ * data exists".
439
+ *
440
+ * On failure, `error` carries the contract code (`CONFLICTING_CURSORS`,
441
+ * `INVALID_TIME_RANGE`, `invalid session`, …) — a **diagnostic code, never
442
+ * text to show a user**. Note that `fetchSensorLog` RESOLVES with
443
+ * `success: false`; it only rejects on timeout.
435
444
  */
436
445
  interface SensorLogPayload {
437
446
  requestId: string;
@@ -444,13 +453,13 @@ interface SensorLogPayload {
444
453
  error?: string;
445
454
  }
446
455
  /**
447
- * Status agregado do sistema (BG → JS). Espelha `SysNotification` do app
448
- * (`apps/sleep_whitelabel/lib/domain/entities/sys_notification_entity.dart`):
449
- * flags de ambiente que o cliente pode usar para renderizar avisos na home
450
- * (ex.: Bluetooth desligado impede o scan/conexão dos devices).
456
+ * Aggregate environment status (native → JS). Mirrors `SysNotification` in the
457
+ * app: the flags a client uses to explain why things are not working — for
458
+ * instance, Bluetooth being off prevents scanning and connecting to devices.
451
459
  *
452
- * Emitido na mudança + snapshot no handshake. `deviceSyncError` mapeia
453
- * `serialNo` → mensagem de erro já localizada pelo app.
460
+ * Emitted on attach (before your bundle exists), again right after
461
+ * `handshake-ack`, and on every change. `deviceSyncError` maps `serialNo` to an
462
+ * error message the app has already localized.
454
463
  */
455
464
  interface SystemStatusPayload {
456
465
  bluetooth: boolean;
@@ -476,29 +485,38 @@ interface SystemStatusPayload {
476
485
  deviceSyncError: Record<number, string>;
477
486
  }
478
487
  /**
479
- * Args do comando `requestPermission` (JS → nativo).
480
- *
481
- * Dispara o **diálogo de permissão nativo in-app** para UMA permissão
482
- * (`AppPermission`), diferente de `openSettings` (que só abre as Configurações
483
- * do sistema). Use para o botão "Conceder" do card de permissões Necessárias,
484
- * passando um dos nomes vindos de `systemStatus.missingEssentialPermissions`
485
- * (ex.: `'bluetoothScan'`).
488
+ * Arguments of the `requestPermission` command (JS → native).
486
489
  *
487
- * Não há chave observável de resultado: o nativo re-emite `systemStatus` após a
488
- * concessão, então o card some quando `missingEssentialPermissions` esvazia.
490
+ * Triggers the **in-app native permission dialog** for ONE permission, unlike
491
+ * `openSettings`, which only opens the system Settings. Use it for the "Grant"
492
+ * button of your required-permissions card, passing a name taken from
493
+ * `systemStatus.missingEssentialPermissions` (for example `'bluetoothScan'`).
489
494
  *
490
- * NOTA: comandos JS → nativo seguem permissivos em `send(command, args)`; este
491
- * tipo é oferecido para DX/tipagem do helper `requestPermission`.
495
+ * **There is no result key.** The native side re-emits `systemStatus` after the
496
+ * person answers, so your card disappears when the array empties. Waiting for a
497
+ * dedicated ack means waiting forever. A name outside the native enum is
498
+ * dropped in silence.
492
499
  */
493
500
  interface RequestPermissionPayload {
494
- /** Nome do `AppPermission` a solicitar (ex.: `'bluetoothScan'`). */
501
+ /** Name of the permission to request, e.g. `'bluetoothScan'`. */
495
502
  permission: string;
496
503
  }
497
504
  /**
498
- * Payload do evento `navigationBack` (native → client). Vazio — o pedido de
499
- * back não carrega dados; o cliente só reage voltando uma página interna.
505
+ * Payload of the `navigationBack` event (native → client). Empty — the request
506
+ * carries no data; react by going back exactly one internal page.
500
507
  */
501
508
  type NavigationBackPayload = Record<string, never>;
509
+ /**
510
+ * Arguments of the `navigationState` command (client → native). The client
511
+ * reports whether it has internal history to go back to; the native side caches
512
+ * it and uses it to decide what the OS back button does. See
513
+ * `BridgeClient.reportNavigation`, and call it on every internal navigation —
514
+ * not once at startup.
515
+ */
516
+ interface NavigationStatePayload {
517
+ /** `true` when the client has a previous internal page to return to. */
518
+ canGoBack: boolean;
519
+ }
502
520
  /**
503
521
  * Language state of the native app (native → client).
504
522
  *
@@ -557,10 +575,10 @@ interface LanguagePayload {
557
575
  resolvedLanguage: string;
558
576
  }
559
577
  /**
560
- * Mapa discriminado de payloads por chave do catálogo. Usado por
561
- * `PayloadOf<K>` para inferência automática no `Bridge.on`.
578
+ * Discriminated map of payloads by catalogue key. Used by `PayloadOf<K>` for
579
+ * automatic inference in `on`.
562
580
  *
563
- * `dfu` é hub-only — sleep_whitelabel não trata; mantido permissivo.
581
+ * `dfu` is hub-only and stays permissive — a sandboxed client never receives it.
564
582
  */
565
583
  interface KeyPayloads {
566
584
  pingPong: PingPongPayload;
@@ -578,15 +596,13 @@ interface KeyPayloads {
578
596
  language: LanguagePayload;
579
597
  }
580
598
  /**
581
- * Payload tipado por chave. Distributivo:
582
- * - Chaves catalogadas em `KeyPayloads` → payload estrito.
583
- * - Demais chaves (futuras / extras do cliente) → `Record<string, unknown>`
584
- * permissivo para preservar extensibilidade.
599
+ * Payload typed by key. Distributive:
600
+ * - keys catalogued in `KeyPayloads` resolve to their strict payload;
601
+ * - any other key resolves to a permissive `Record<string, unknown>`, to keep
602
+ * the catalogue extensible.
585
603
  *
586
- * **v0.3.0 → v0.4.0:** quebra build-time (não runtime) para clientes
587
- * que usavam payload `unknown` em `Bridge.on` — agora vem tipado.
588
- * Cliente que precisa do shape permissivo pode usar
589
- * `(payload: Record<string, unknown>) => ...` explicitamente.
604
+ * A client that wants the permissive shape can annotate the callback
605
+ * explicitly: `(payload: Record<string, unknown>) => …`.
590
606
  */
591
607
  type PayloadOf<K extends BridgeKey = BridgeKey> = K extends keyof KeyPayloads ? KeyPayloads[K] : Record<string, unknown>;
592
608
 
@@ -605,198 +621,222 @@ interface MockState {
605
621
  }
606
622
  interface CondorBridge {
607
623
  /**
608
- * `true` quando o adapter ativo é mock (browser dev, sem
609
- * `window.CondorNative` nem `window.flutter_inappwebview`). `false` quando
610
- * rodando dentro do WebView Flutter.
624
+ * `true` when the active adapter is the mock — a plain browser, with neither
625
+ * `window.CondorNative` nor `window.flutter_inappwebview`. `false` inside the
626
+ * Flutter WebView.
611
627
  */
612
628
  readonly isMock: boolean;
613
629
  /**
614
- * Envia handshake versionado ao nativo e aguarda `handshake-ack`.
630
+ * Sends a versioned handshake to the native side and awaits `handshake-ack`.
615
631
  *
616
- * Apenas um handshake pode estar pendente por vez. Chamadas paralelas
617
- * antes do primeiro `ack` chegar são rejeitadas com erro claro.
632
+ * Only one handshake may be in flight; a parallel call before the first ack
633
+ * arrives is rejected with an explicit error.
618
634
  *
619
- * **Em mock mode:** NÃO resolve sozinho. Cliente/teste deve chamar
620
- * `Bridge.mockEmit('handshake-ack', {nativeVersion, accepted})` para
621
- * destravar a Promise. Esta decisão (`Explícito`) força testes a serem
622
- * intencionais sobre o estado nativo.
635
+ * **In mock mode it does not resolve on its own.** The caller must emit
636
+ * `Bridge.mockEmit('handshake-ack', { nativeVersion, accepted })` to unblock
637
+ * the promise. That is deliberate: it forces tests to be explicit about the
638
+ * native state they are simulating.
623
639
  */
624
640
  handshake(opts: HandshakeOptions): Promise<HandshakeAck>;
625
641
  /**
626
- * Subscreve a uma chave observável. Retorna função `unsubscribe`.
642
+ * Subscribes to an observable key. Returns an `unsubscribe` function.
627
643
  *
628
- * Múltiplos subscribers por chave são permitidos. Erro em um subscriber
629
- * não afeta os outros (capturado e logado em `console.error`).
644
+ * Multiple subscribers per key are allowed; a throw in one does not affect
645
+ * the others (it is caught and logged with `console.error`).
630
646
  */
631
647
  on<K extends BridgeKey>(key: K, cb: (payload: PayloadOf<K>) => void): () => void;
632
648
  /**
633
- * Envia mensagem genérica ao nativo. Use para comandos UI→BG que não
634
- * tenham helper dedicado. `type` é a string que o native usa para
635
- * roteamento no `_onJsMessage`.
649
+ * Sends a generic message to the native side, for commands without a
650
+ * dedicated helper. `type` is the string the native side routes on.
651
+ *
652
+ * Fire-and-forget: no return value and no delivery confirmation. A payload
653
+ * above 64 KB, or an unknown `type`, is dropped natively without a reply.
636
654
  *
637
- * Em mock mode: grava no buffer interno + `console.debug`.
655
+ * In mock mode it is recorded in the internal buffer and logged with
656
+ * `console.debug`.
638
657
  */
639
658
  send(type: string, payload?: Record<string, unknown>): void;
640
659
  /**
641
- * Abre a tela nativa de Settings do app. Equivalente a
660
+ * Opens the app's native Settings screen. Equivalent to
642
661
  * `Bridge.send('openSettings')`.
643
662
  */
644
663
  openSettings(): void;
645
664
  /**
646
- * Registra uma transformação aplicada a **toda** mensagem JS → Native
647
- * (`handshake` inclusive) imediatamente antes do envio. `null` remove.
665
+ * Registers a transform applied to **every** JS → native message, the
666
+ * handshake included, immediately before it is sent. Pass `null` to remove.
648
667
  *
649
- * Existe para o shell carimbar o nonce da Camada 3
650
- * (`payload._shellNonce`) num ponto único — antes da 0.18.0 isso exigia
651
- * monkey-patch de `flutter_inappwebview.callHandler`, que não existe no
652
- * canal `CondorNative`. Código de cliente não deve usar.
668
+ * It exists so the shell can stamp its nonce (`payload._shellNonce`) at a
669
+ * single chokepoint. Wrapping `send` alone is not enough — `handshake` calls
670
+ * the native layer directly, and a message without the nonce is dropped and
671
+ * logged as a security event.
672
+ *
673
+ * **Client code must not use this.**
653
674
  */
654
675
  setOutgoingStamp(stamp: OutgoingStamp | null): void;
655
676
  /**
656
- * Dispara `window.CondorBridge.emit(key, payload)` programaticamente —
657
- * útil para simular eventos nativos em testes e dev em browser.
677
+ * Fires `window.CondorBridge.emit(key, payload)` programmatically — useful to
678
+ * simulate native events in tests and in browser development.
658
679
  *
659
- * **Throws** se o adapter ativo não for mock.
680
+ * **Throws** when the active adapter is not the mock.
660
681
  */
661
682
  mockEmit(key: string, payload?: unknown): void;
662
683
  /**
663
- * Snapshot do estado do mock adapter (mensagens enviadas + chaves com
664
- * subscribers ativos). Useful para asserts em testes de cliente.
684
+ * Snapshot of the mock adapter state: messages sent, and keys with active
685
+ * subscribers. Useful for assertions in client tests.
665
686
  *
666
- * **Throws** se o adapter ativo não for mock.
687
+ * **Throws** when the active adapter is not the mock.
667
688
  */
668
689
  getMockState(): MockState;
669
690
  /**
670
- * Injeta painel HTML flutuante no `document.body` para inspecionar o
671
- * bridge em mock mode. Idempotente — re-install substitui o anterior.
691
+ * Injects a floating HTML panel into `document.body` for inspecting the
692
+ * bridge in mock mode. Idempotent — re-installing replaces the previous one.
672
693
  *
673
- * **Throws** se o adapter ativo não for mock OU se `document` não existir.
694
+ * **Throws** when the active adapter is not the mock, or `document` does not
695
+ * exist.
674
696
  */
675
697
  installDevPanel(options?: DevPanelOptions): void;
676
698
  }
677
699
  declare const Bridge: CondorBridge;
678
700
 
679
701
  /**
680
- * `BridgeClient` (v0.5.0) — API para código do cliente externo rodando
681
- * dentro de `<iframe sandbox="allow-scripts">` no `sleep_whitelabel`.
702
+ * `BridgeClient` — **the API for client code**, running inside
703
+ * `<iframe sandbox="allow-scripts">` in the Condor Canvas app.
682
704
  *
683
- * Surface idêntica ao `Bridge` legado (`on`/`send`/`openSettings`/`handshake`)
684
- * — cliente importa e não percebe que está em sandbox. Internamente,
685
- * todas as chamadas viram `window.parent.postMessage(...)` com schema
686
- * validado pelo shell antes de chegar ao nativo.
705
+ * This is what you want if you are building the bundle that renders as the
706
+ * app's Home. Every call becomes a `window.parent.postMessage(...)` that the
707
+ * Condor shell validates against a schema and a default-deny policy before it
708
+ * reaches the native layer. You never touch the native globals — the shell
709
+ * deletes them before your bundle runs.
687
710
  *
688
- * **Não expõe** `installDevPanel`, `mockEmit`, `isMock`, `getMockState` —
689
- * essas APIs são responsabilidade do shell (`BridgeShell`).
711
+ * It deliberately does **not** expose `installDevPanel`, `mockEmit`, `isMock`
712
+ * or `getMockState`: those belong to the shell (`BridgeShell`).
690
713
  *
691
- * **Threat model & Camada 2 do Risco 1** (vide
692
- * `sleep-white-label-content-transport-and-security.md`): este módulo
693
- * também responde ao `verify-sandbox` do shell — função de attestation
694
- * do próprio iframe sobre se ainda enxerga `window.flutter_inappwebview`
695
- * ou `window.CondorBridge` (que deveriam ter sido deletados pela Camada 1).
696
- * Se vier `true` em algum, o shell aborta o boot do app.
714
+ * The module also answers the shell's `verify-sandbox` probe — the iframe
715
+ * attesting whether it can still see the native globals. If any is reachable,
716
+ * the shell aborts the boot rather than render client code with a path to the
717
+ * native layer.
697
718
  */
698
719
 
699
720
  interface BridgeClientHandshakeAck {
700
721
  shellVersion: string;
701
722
  /**
702
- * Versão do schema do **nativo**, repassada pelo shell — `null` se o nativo
703
- * ainda não respondeu ou não existe (mock de browser).
723
+ * Schema version of the **native** side, relayed by the shell. `null` when
724
+ * the native side has not answered, does not exist (browser mock mode), or
725
+ * the shell is older than 0.6.0.
704
726
  *
705
- * É por este número que um cliente decide se pode depender de capacidade
706
- * nova: não há negociação de versão, e o cliente sandboxed não alcança o
707
- * nativo por nenhum outro caminho. Ex.: canais crus de luz
708
- * (`light_sensor_*` em `deviceLightSensors`) existem a partir da `0.16.0`.
727
+ * **This number is the only capability signal a client gets.** There is no
728
+ * version negotiation, and a sandboxed client reaches the native side by no
729
+ * other path. For example, the raw light channels (`light_sensor_*` in
730
+ * `deviceLightSensors`) exist from `0.16.0`. Always keep a working branch
731
+ * for `null`: your browser development environment always hits it.
709
732
  */
710
733
  nativeVersion: string | null;
734
+ /**
735
+ * Whether the native side accepted your `clientVersion`. It is **always
736
+ * `true`** — there is no hard validation — so it carries no information.
737
+ * Never branch on it; branch on {@link nativeVersion}.
738
+ */
711
739
  accepted: boolean;
712
740
  }
713
741
  interface CondorBridgeClient {
714
- /**
715
- * Versão do protocolo do client.
716
- */
742
+ /** Version of the client-side postMessage protocol. */
717
743
  readonly protocolVersion: string;
718
744
  /**
719
- * Subscreve a uma chave observável. Retorna função `unsubscribe`.
720
- * Múltiplos subscribers por chave permitidos. Erro em um subscriber
721
- * não afeta os outros.
745
+ * Subscribes to an observable key. Returns an `unsubscribe` function —
746
+ * call it when a view unmounts, or handlers accumulate and every one of them
747
+ * re-renders.
748
+ *
749
+ * Multiple subscribers per key are allowed, and a throw in one does not
750
+ * affect the others. Subscribe *before* sending the command that triggers
751
+ * the reply: the reply can arrive before your next statement runs.
722
752
  */
723
753
  on<K extends BridgeKey>(key: K, cb: (payload: PayloadOf<K>) => void): () => void;
724
754
  /**
725
- * Envia comando para o shell. Shell valida contra `ShellPolicy` antes
726
- * de tocar o nativo. Comandos não permitidos → `nack` (logado em
727
- * `console.warn` na v0.5.0).
755
+ * Sends a command to the shell, which validates it against the policy before
756
+ * it touches the native layer.
757
+ *
758
+ * **Fire-and-forget: no return value, no throw, no delivery confirmation.**
759
+ * A command that is not allowed produces a `nack` that surfaces only as a
760
+ * `console.warn`. A malformed one is dropped in silence by the native side.
761
+ * Replies, when a command has one, arrive on the corresponding key — see
762
+ * `docs/bridge-contract.md`.
728
763
  */
729
764
  send(command: string, args?: Record<string, unknown>): void;
730
- /**
731
- * Abre Settings nativa. Equivalente a `send('openSettings')`.
732
- */
765
+ /** Opens the native Settings screen. Equivalent to `send('openSettings')`. */
733
766
  openSettings(): void;
734
767
  /**
735
- * Pede UMA página de sensor logs e resolve com a resposta correlacionada
736
- * pelo `requestId` — inclusive quando ela traz `success: false`, que é
737
- * resposta e não falha de transporte. A Promise só **rejeita** por timeout.
768
+ * Requests ONE page of sensor logs and resolves with the reply correlated by
769
+ * `requestId` — **including when it carries `success: false`**, which is an
770
+ * answer, not a transport failure. The promise only **rejects** on timeout,
771
+ * so always check `success` before reading `logs`.
738
772
  *
739
- * Dispensa o cliente de manter o mapa `requestId → resolve` à mão. Para
740
- * varrer um período, encadeie as chamadas usando o `startingAfter` devolvido
741
- * até `hasMore` virar `false`: os cursores são dependentes, então as páginas
742
- * **não** podem ser buscadas em paralelo.
773
+ * Saves you from keeping a `requestId → resolve` map by hand. To sweep a
774
+ * period, chain calls using the returned `startingAfter` until `hasMore`
775
+ * becomes `false`: the cursors are dependent, so pages **cannot** be fetched
776
+ * in parallel.
743
777
  */
744
778
  fetchSensorLog(query: SensorLogQueryPayload, opts?: {
745
779
  timeoutMs?: number;
746
780
  }): Promise<SensorLogPayload>;
747
781
  /**
748
- * Solicita UMA permissão via **diálogo nativo in-app** (não abre Settings).
749
- * Equivalente a `send('requestPermission', { permission })`. Use no botão
750
- * "Conceder" do card Necessárias, com um nome vindo de
751
- * `systemStatus.missingEssentialPermissions` (ex.: `'bluetoothScan'`).
752
- * O resultado chega via re-emissão de `systemStatus` (sem chave dedicada).
782
+ * Requests ONE permission through the **in-app native dialog** (it does not
783
+ * open Settings). Use it for the "Grant" button of your required-permissions
784
+ * card, with a name taken from `systemStatus.missingEssentialPermissions`,
785
+ * e.g. `'bluetoothScan'`.
786
+ *
787
+ * **There is no result key.** The outcome arrives as a fresh `systemStatus`
788
+ * emission; your card disappears when the array empties. A name outside the
789
+ * native enum is dropped in silence.
753
790
  */
754
791
  requestPermission(permission: string): void;
755
792
  /**
756
- * Handshake com o shell. Resolve com `{ shellVersion, accepted }`.
757
- * Timeout em 5s se shell não responder.
793
+ * Handshakes with the shell. Resolves with
794
+ * `{ shellVersion, nativeVersion, accepted }` — read `nativeVersion` to learn
795
+ * what this device can do, and ignore `accepted`, which is always `true`.
758
796
  *
759
- * Apenas um handshake pode estar pendente por vez.
797
+ * Rejects after 5 s if the shell does not answer. Only one handshake may be
798
+ * in flight at a time.
760
799
  */
761
800
  handshake(opts: {
762
801
  clientVersion: string;
763
802
  }): Promise<BridgeClientHandshakeAck>;
764
803
  /**
765
- * Reporta ao nativo se o cliente tem histórico interno para voltar.
766
- * **Chame a cada mudança de rota interna** (e no boot). O nativo cacheia
767
- * este estado e o usa para decidir o botão/gesture de voltar do SO:
768
- * - `true` → o back do SO pede uma volta interna (evento `navigationBack`,
769
- * vide `onBack`).
770
- * - `false` → o back do SO fica na home (não sai da página).
804
+ * Reports to the native side whether the client has internal history to go
805
+ * back to. **Call it on every internal navigation**, and at boot — not once.
806
+ * The native side caches the value and uses it to decide what the OS back
807
+ * button does:
808
+ * - `true` — back asks you to go back one page (the `navigationBack` event,
809
+ * see {@link onBack});
810
+ * - `false` — back stays with the app and does not leave the Home.
771
811
  *
772
- * Equivalente a `send('navigationState', { canGoBack })`.
812
+ * Equivalent to `send('navigationState', { canGoBack })`.
773
813
  */
774
814
  reportNavigation(canGoBack: boolean): void;
775
815
  /**
776
- * Assina o pedido de back do SO (evento `navigationBack`). O callback deve
777
- * voltar **uma** página interna do cliente e então chamar
778
- * `reportNavigation(...)` com o novo estado. Só é chamado quando o cliente
779
- * havia reportado `reportNavigation(true)`. Retorna função `unsubscribe`.
816
+ * Subscribes to the OS back request (the `navigationBack` event). The
817
+ * callback must go back **one** internal page and then call
818
+ * {@link reportNavigation} with the new state. It only fires when you had
819
+ * reported `reportNavigation(true)`. Returns an `unsubscribe` function.
780
820
  */
781
821
  onBack(cb: () => void): () => void;
782
822
  }
783
823
  declare const BridgeClient: CondorBridgeClient;
784
824
 
785
825
  /**
786
- * Schemas Valibot dos `postMessage` shell↔client (v0.5.0).
826
+ * Valibot schemas for the shell↔client `postMessage` protocol.
787
827
  *
788
- * Quando o conteúdo do cliente roda dentro de `<iframe sandbox="allow-scripts">`
789
- * (origem null), a comunicação com o shell Condor-controlado acontece via
790
- * `window.postMessage`. Estes schemas são o **único contrato aceito** —
791
- * qualquer mensagem mal-formada é descartada silenciosamente pelo shell.
828
+ * Client content runs inside `<iframe sandbox="allow-scripts">` with a `null`
829
+ * origin, so it talks to the Condor-controlled shell over `window.postMessage`.
830
+ * These schemas are the **only accepted contract** — any malformed message is
831
+ * discarded by the shell in silence, which is why hand-rolled `postMessage`
832
+ * calls appear to do nothing. Use `BridgeClient`.
792
833
  *
793
- * **Threat model:** o iframe pode ser hostil (supply-chain comprometida,
794
- * XSS no código do cliente). Estes schemas + a `ShellPolicy` aplicada
795
- * no `BridgeShell` formam o boundary estrutural — vide
796
- * `condor_wiki/cross-cutting/sleep-white-label-content-transport-and-security.md`.
834
+ * **Threat model:** the iframe may be hostile (a compromised supply chain, XSS
835
+ * in the client code). These schemas plus the `ShellPolicy` enforced by
836
+ * `BridgeShell` form the structural boundary.
797
837
  */
798
838
 
799
- declare const ClientToShellMessage: v.VariantSchema<"type", [v.ObjectSchema<{
839
+ declare const ClientToShellMessageSchema: v.VariantSchema<"type", [v.ObjectSchema<{
800
840
  readonly type: v.LiteralSchema<"subscribe", undefined>;
801
841
  readonly key: v.PicklistSchema<[string, ...string[]], undefined>;
802
842
  }, undefined>, v.ObjectSchema<{
@@ -826,8 +866,9 @@ declare const ClientToShellMessage: v.VariantSchema<"type", [v.ObjectSchema<{
826
866
  readonly condorBridgeReachable: v.BooleanSchema<undefined>;
827
867
  readonly nativeChannelReachable: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
828
868
  }, undefined>], undefined>;
829
- type ClientToShellMessage = v.InferOutput<typeof ClientToShellMessage>;
830
- declare const ShellToClientMessage: v.VariantSchema<"type", [v.ObjectSchema<{
869
+ /** Union of every client → shell message. Type only; the runtime schema is `ClientToShellMessageSchema`, which is not part of the public API. */
870
+ type ClientToShellMessage = v.InferOutput<typeof ClientToShellMessageSchema>;
871
+ declare const ShellToClientMessageSchema: v.VariantSchema<"type", [v.ObjectSchema<{
831
872
  readonly type: v.LiteralSchema<"event", undefined>;
832
873
  readonly key: v.PicklistSchema<[string, ...string[]], undefined>;
833
874
  readonly payload: v.UnknownSchema;
@@ -836,12 +877,12 @@ declare const ShellToClientMessage: v.VariantSchema<"type", [v.ObjectSchema<{
836
877
  readonly ack: v.ObjectSchema<{
837
878
  readonly shellVersion: v.StringSchema<undefined>;
838
879
  /**
839
- * Versão do schema declarada pelo **nativo**, repassada pelo shell.
880
+ * Schema version declared by the **native** side, relayed by the shell.
840
881
  *
841
- * `null` quando o nativo ainda não respondeu (ou não existe, como no
842
- * mock de browser). O cliente roda dentro de um iframe sandboxed e não
843
- * fala com o nativo diretamente, então este é o **único** caminho pelo
844
- * qual ele descobre de qual versão são as capacidades disponíveis.
882
+ * `null` when the native side has not answered, or does not exist (browser
883
+ * mock mode). The client runs inside a sandboxed iframe and never talks to
884
+ * the native side directly, so this is the **only** way it can learn which
885
+ * capabilities are available.
845
886
  */
846
887
  readonly nativeVersion: v.NullableSchema<v.StringSchema<undefined>, undefined>;
847
888
  readonly accepted: v.BooleanSchema<undefined>;
@@ -854,22 +895,23 @@ declare const ShellToClientMessage: v.VariantSchema<"type", [v.ObjectSchema<{
854
895
  }, undefined>, v.ObjectSchema<{
855
896
  readonly type: v.LiteralSchema<"verify-sandbox", undefined>;
856
897
  }, undefined>], undefined>;
857
- type ShellToClientMessage = v.InferOutput<typeof ShellToClientMessage>;
898
+ /** Union of every shell → client message. Type only; the runtime schema is `ShellToClientMessageSchema`, which is not part of the public API. */
899
+ type ShellToClientMessage = v.InferOutput<typeof ShellToClientMessageSchema>;
858
900
  /**
859
- * Policy default-deny aplicada pelo `BridgeShell`. Toda chave/comando
860
- * vindo do iframe é validado contra estas listas antes de tocar o
861
- * bridge nativo.
901
+ * Default-deny policy enforced by `BridgeShell`. Every key and command coming
902
+ * from the iframe is checked against these lists before it touches the native
903
+ * bridge.
862
904
  *
863
- * - `readOnlyKeys`: chaves que o cliente pode subscrever (observáveis).
864
- * - `allowedCommands`: comandos pass-through (sem confirmação humana).
865
- * - `requiresConfirmation`: comandos que disparam callback `onConfirmationRequest`
866
- * no shell — usuário decide aprovar/recusar via UI nativa do shell.
867
- * - `deniedCommands`: bloqueio explícito (defesa em profundidade — comandos
868
- * destrutivos como `dfu` que nunca devem fluir do iframe).
905
+ * - `readOnlyKeys` — keys the client may subscribe to.
906
+ * - `allowedCommands` — pass-through commands, no human confirmation.
907
+ * - `requiresConfirmation` — commands that fire the shell's
908
+ * `onConfirmationRequest` callback, so a person approves or declines.
909
+ * - `deniedCommands` — explicit block, defence in depth: destructive commands
910
+ * such as `dfu` that must never flow from the iframe.
869
911
  *
870
- * **Não embedada no package** — cliente do `BridgeShell` (no monorepo
871
- * `sleep_whitelabel`) provê a policy concreta. Mantém o package agnóstico
872
- * ao catálogo e permite policy evoluir sem novo release.
912
+ * **Not embedded in the package** — the `BridgeShell` host supplies the
913
+ * concrete policy. That keeps the package agnostic to the catalogue and lets
914
+ * the policy evolve without a release.
873
915
  */
874
916
  interface ShellPolicy {
875
917
  readOnlyKeys: string[];
@@ -878,68 +920,73 @@ interface ShellPolicy {
878
920
  deniedCommands: string[];
879
921
  }
880
922
  /**
881
- * Resposta do callback `onConfirmationRequest` do `BridgeShell`.
923
+ * Argument of the `BridgeShell` `onConfirmationRequest` callback.
882
924
  *
883
- * `approve: true` → comando flui para o nativo.
884
- * `approve: false` → shell envia `nack` ao iframe com `reason: 'user-rejected'`.
925
+ * Resolving `approve: true` lets the command flow to the native side.
926
+ * Resolving `approve: false` makes the shell send the iframe a `nack` with
927
+ * `reason: 'user-rejected'` — which client code only ever sees as a console
928
+ * warning, so the ack it was waiting for simply never arrives.
885
929
  */
886
930
  interface ConfirmationRequest {
887
931
  command: string;
888
932
  args: Record<string, unknown>;
889
933
  }
890
934
  /**
891
- * Estado retornado pelo `verifySandbox()` do `BridgeShell` após
892
- * round-trip com o iframe. Se algum dos `*Reachable` vier `true`, o
893
- * boundary está furado — Camada 1 (`bootstrapClientIframe` com override
894
- * prefix) falhou e a Camada 4 (dual WebView) deve ser acionada.
935
+ * Result of `BridgeShell.verifySandbox()` after a round trip with the iframe.
936
+ * If any `*Reachable` flag comes back `true`, the boundary is leaking: the
937
+ * override prefix injected by `bootstrapClientIframe` failed, and the app must
938
+ * not render client code with a path to the native layer.
895
939
  */
896
940
  interface SandboxVerifyResult {
897
941
  flutterBridgeReachable: boolean;
898
942
  condorBridgeReachable: boolean;
899
- /** `window.CondorNative` visível no iframe (v0.18.0). */
943
+ /** Whether `window.CondorNative` is visible inside the iframe. */
900
944
  nativeChannelReachable: boolean;
945
+ /** `true` only when none of the three is reachable. */
901
946
  ok: boolean;
902
947
  }
903
948
 
904
949
  /**
905
- * `BridgeShell` (v0.5.0) — API para o shell Condor-controlado que envolve
906
- * o conteúdo do cliente externo dentro de `<iframe sandbox="allow-scripts">`.
950
+ * `BridgeShell` — the API for the **Condor-controlled shell** that wraps
951
+ * external client content inside `<iframe sandbox="allow-scripts">`.
907
952
  *
908
- * Responsabilidades:
909
- * 1. **Camada 1 do Risco 1** — `bootstrapClientIframe(iframe, clientPath)`:
910
- * busca HTML do cliente via `fetch`, prepende script de override que
911
- * deleta `window.flutter_inappwebview` e `window.CondorBridge` do
912
- * iframe, e seta como `srcdoc`. Override roda em parse-time, antes
913
- * de qualquer outro script.
914
- * 2. **Camada 2 do Risco 1** — `verifySandbox(iframe)`: round-trip
915
- * `postMessage` que pede ao iframe atestation autoritativa de que
916
- * `window.flutter_inappwebview` e `window.CondorBridge` são `undefined`.
917
- * 3. **Roteamento postMessage iframe ↔ nativo:** escuta `message` events
918
- * do iframe, valida com Valibot, aplica `ShellPolicy` default-deny,
919
- * e propaga para o `Bridge` legado (que fala com o nativo). Eventos
920
- * nativos voltam para o iframe via `postMessage`.
921
- * 4. **Confirmação humana para comandos sensíveis:** comandos em
922
- * `policy.requiresConfirmation` disparam callback
923
- * `onConfirmationRequest` antes de tocar o nativo — shell apresenta UI.
953
+ * This is not client-facing. If you are writing the bundle that renders as the
954
+ * app's Home, you want `BridgeClient`.
955
+ *
956
+ * Responsibilities:
957
+ * 1. **Layer 1 — `bootstrapClientIframe(iframe, clientPath)`:** fetches the
958
+ * client HTML, prepends an override script that removes the native globals
959
+ * from the iframe, and sets it as `srcdoc`. The override runs at parse time,
960
+ * before any other script.
961
+ * 2. **Layer 2 — `verifySandbox(iframe)`:** a `postMessage` round trip asking
962
+ * the iframe to attest that the native globals really are `undefined`.
963
+ * 3. **Routing between iframe and native:** listens for `message` events from
964
+ * the iframe, validates them with Valibot, applies the default-deny
965
+ * `ShellPolicy`, and forwards to `Bridge`. Native events go back to the
966
+ * iframe over `postMessage`.
967
+ * 4. **Human confirmation for sensitive commands:** commands listed in
968
+ * `policy.requiresConfirmation` fire the `onConfirmationRequest` callback
969
+ * before touching the native side, so the shell can present UI.
924
970
  */
925
971
 
926
972
  interface BridgeShellOptions {
927
973
  /**
928
- * Iframe que hospeda o cliente. Pode estar vazio no momento da
929
- * construção — `bootstrapClientIframe` será chamado depois para popular.
974
+ * The iframe hosting the client. It may be empty at construction time —
975
+ * `bootstrapClientIframe` is called later to populate it.
930
976
  */
931
977
  iframe: HTMLIFrameElement;
932
978
  /**
933
- * Policy default-deny. Toda chave/comando vindo do iframe é validado
934
- * contra estas listas. Vide `ShellPolicy`.
979
+ * The default-deny policy. Every key and command arriving from the iframe is
980
+ * checked against these lists. See `ShellPolicy`.
935
981
  */
936
982
  policy: ShellPolicy;
937
983
  /**
938
- * Callback síncrono ou assíncrono chamado quando o cliente pede um
939
- * comando em `policy.requiresConfirmation`. Shell apresenta UI de
940
- * confirmação; resolve com `true` (aprovar) ou `false` (recusar).
941
- * Se não fornecido, comandos `requiresConfirmation` são **negados**
942
- * automaticamente — fail-safe.
984
+ * Synchronous or asynchronous callback invoked when the client issues a
985
+ * command listed in `policy.requiresConfirmation`. The shell presents its
986
+ * confirmation UI and resolves `true` to approve or `false` to decline.
987
+ *
988
+ * If it is not provided, such commands are **denied** automatically —
989
+ * fail-safe.
943
990
  */
944
991
  onConfirmationRequest?: (req: ConfirmationRequest) => boolean | Promise<boolean>;
945
992
  }
@@ -950,61 +997,60 @@ declare class BridgeShell {
950
997
  private readonly subscriptions;
951
998
  private detached;
952
999
  /**
953
- * Versão do nativo, obtida uma vez e cacheada. `null` até o nativo
954
- * responder — e permanentemente `null` num browser sem nativo.
1000
+ * The native version, fetched once and cached. `null` until the native side
1001
+ * answers, and permanently `null` in a browser with no native host.
955
1002
  */
956
1003
  private nativeVersion;
957
- /** Handshake com o nativo em voo; garante uma única chamada. */
1004
+ /** In-flight native handshake; guarantees a single call. */
958
1005
  private nativeHandshake;
959
1006
  private pendingVerifies;
960
1007
  constructor(opts: BridgeShellOptions);
961
1008
  /**
962
- * **Camada 1 do Risco 1.** Bootstrap via fetch de URL.
1009
+ * **Layer 1.** Bootstraps by fetching a URL.
963
1010
  *
964
- * Atalho para o caso comum HTTP/HTTPS: faz `fetch(clientPath)` e
965
- * delega para `bootstrapClientIframeWithHtml`.
1011
+ * A shortcut for the common HTTP/HTTPS case: it runs `fetch(clientPath)` and
1012
+ * delegates to `bootstrapClientIframeWithHtml`.
966
1013
  *
967
- * **Não funciona em scheme `file://`** — `fetch` em WebView Android
968
- * (Chromium) bloqueia o scheme com "URL scheme 'file' is not supported".
969
- * Para asset bundled em APK ou bundle inlined no build-time, use
970
- * `bootstrapClientIframeWithHtml(htmlString)`.
1014
+ * **It does not work on the `file://` scheme** — Android's Chromium WebView
1015
+ * blocks it with "URL scheme 'file' is not supported". For an asset bundled
1016
+ * in the APK, or a bundle inlined at build time, use
1017
+ * `bootstrapClientIframeWithHtml(htmlString)` instead.
971
1018
  *
972
- * **Devo ser chamado uma vez no boot do shell**, antes de qualquer
973
- * outra interação. Após retornar, `verifySandbox()` deve ser invocado
974
- * para atestation (Camada 2).
1019
+ * **Call it once at shell boot**, before any other interaction. After it
1020
+ * returns, invoke `verifySandbox()` for attestation (Layer 2).
975
1021
  */
976
1022
  bootstrapClientIframe(clientPath?: string): Promise<void>;
977
1023
  /**
978
- * **Camada 1 do Risco 1.** Bootstrap a partir de HTML string.
1024
+ * **Layer 1.** Bootstraps from an HTML string.
979
1025
  *
980
- * Aceita HTML do cliente diretamente (já lido de arquivo, embedado em
981
- * build-time via `esbuild.define`, lido de IndexedDB, etc.) e seta
982
- * como `srcdoc` do iframe prefixado pelo override script. Override
983
- * roda em parse-time, antes de qualquer outro script do cliente.
1026
+ * Takes the client HTML directly — already read from a file, embedded at
1027
+ * build time, read from storage — and sets it as the iframe's `srcdoc`,
1028
+ * prefixed by the override script, which runs at parse time before any
1029
+ * client script.
984
1030
  *
985
- * Use quando `fetch` não é aplicável (asset bundled em `file://`,
986
- * bundle inlined no build, qualquer cenário sem rede). Para HTTP
987
- * use `bootstrapClientIframe(clientPath)`.
1031
+ * Use this when `fetch` does not apply: an asset bundled under `file://`, a
1032
+ * bundle inlined at build time, any scenario without network. Android
1033
+ * WebView blocks `fetch` on the `file://` scheme, so this is the path the
1034
+ * app actually takes. For HTTP, use `bootstrapClientIframe(clientPath)`.
988
1035
  *
989
- * **Devo ser chamado uma vez no boot do shell**, antes de qualquer
990
- * outra interação. Após retornar, `verifySandbox()` deve ser invocado
991
- * para atestation (Camada 2).
1036
+ * **Call it once at shell boot**, before any other interaction. After it
1037
+ * returns, invoke `verifySandbox()` for attestation (Layer 2).
992
1038
  */
993
1039
  bootstrapClientIframeWithHtml(clientHtml: string): Promise<void>;
994
1040
  private waitForIframeLoad;
995
1041
  /**
996
- * **Camada 2 do Risco 1.** Round-trip `postMessage` que pede ao iframe
997
- * atestation autoritativa do estado de `window.flutter_inappwebview`
998
- * e `window.CondorBridge`. Timeout em 2s.
1042
+ * **Layer 2.** A `postMessage` round trip asking the iframe for an
1043
+ * authoritative attestation of whether the native globals are reachable.
1044
+ * Times out after 2 s.
999
1045
  *
1000
- * `ok` é `true` apenas se ambos forem `undefined` no iframe. Se vier
1001
- * `false`, **shell deve abortar o boot do app** — Camada 1 falhou e
1002
- * Camada 4 (dual WebView) precisa ser acionada manualmente.
1046
+ * `ok` is `true` only when none of them is reachable. If it comes back
1047
+ * `false`, **the shell must abort the app boot**: Layer 1 failed, and client
1048
+ * code would run with a path to the native layer.
1003
1049
  */
1004
1050
  verifySandbox(): Promise<SandboxVerifyResult>;
1005
1051
  /**
1006
- * Encerra o shell — remove listener `message`, cancela subscriptions
1007
- * pendentes no `Bridge` nativo, limpa estado interno.
1052
+ * Tears the shell down: removes the `message` listener, cancels pending
1053
+ * subscriptions on the native `Bridge`, and clears internal state.
1008
1054
  */
1009
1055
  detach(): void;
1010
1056
  private onMessage;
@@ -1012,16 +1058,16 @@ declare class BridgeShell {
1012
1058
  private handleUnsubscribe;
1013
1059
  private handleSend;
1014
1060
  /**
1015
- * Obtém o `nativeVersion`, disparando o handshake com o nativo na primeira
1016
- * vez e cacheando o resultado.
1061
+ * Resolves `nativeVersion`, firing the native handshake the first time and
1062
+ * caching the result.
1017
1063
  *
1018
- * ⚠️ `Bridge.handshake` **não tem timeout**: a Promise só resolve quando o
1019
- * nativo emite `handshake-ack`. Num browser sem nativo ela nunca resolve,
1020
- * então o `race` abaixo é o que garante que o cliente sempre receba
1021
- * resposta — com `null` — em vez de ficar pendurado.
1064
+ * ⚠️ `Bridge.handshake` has **no timeout**: its promise only settles when the
1065
+ * native side emits `handshake-ack`. In a browser with no native host it
1066
+ * never settles, so the race below is what guarantees the client always gets
1067
+ * an answer — `null` — instead of hanging.
1022
1068
  */
1023
1069
  private resolveNativeVersion;
1024
1070
  private postToClient;
1025
1071
  }
1026
1072
 
1027
- export { type AutoRespondResponse, BRIDGE_KEYS, Bridge, BridgeClient, type BridgeClientHandshakeAck, type BridgeIncomingMessage, type BridgeKey, type BridgeOutgoingEvent, BridgeShell, type BridgeShellOptions, ClientToShellMessage, type CondorBridge, type CondorBridgeClient, type ConfirmationRequest, type DeleteMemoryAckPayload, type DevPanelOptions, type DeviceConnectionPayload, type DeviceLightSensorsPayload, type DeviceNotificationPayload, type HandshakeAck, type HandshakeOptions, type KeyPayloads, type LanguagePayload, type LightSensorsActlumus1Data, type LightSensorsActlumus2Data, type LightSensorsRawChannels, type MockMessage, type MockState, NATIVE_CHANNEL_NAME, type OutgoingStamp, type PayloadOf, type PingPongPayload, type RealTimeAckPayload, type RequestPermissionPayload, type SandboxVerifyResult, type SensorLogPayload, type SensorLogQueryPayload, type ShellPolicy, ShellToClientMessage, type SyncTimeAckPayload, type SystemStatusPayload, type UserDevicePayload };
1073
+ export { type AutoRespondResponse, BRIDGE_KEYS, Bridge, BridgeClient, type BridgeClientHandshakeAck, type BridgeIncomingMessage, type BridgeKey, type BridgeOutgoingEvent, BridgeShell, type BridgeShellOptions, type ClientToShellMessage, type CondorBridge, type CondorBridgeClient, type ConfirmationRequest, type DeleteMemoryAckPayload, type DevPanelOptions, type DeviceConnectionPayload, type DeviceLightSensorsPayload, type DeviceNotificationPayload, type HandshakeAck, type HandshakeOptions, type KeyPayloads, type LanguagePayload, type LightSensorsActlumus1Data, type LightSensorsActlumus2Data, type LightSensorsRawChannels, type MockMessage, type MockState, NATIVE_CHANNEL_NAME, type NavigationBackPayload, type NavigationStatePayload, type OutgoingStamp, type PayloadOf, type PingPongPayload, type RealTimeAckPayload, type RequestPermissionPayload, type SandboxVerifyResult, type SensorLogPayload, type SensorLogQueryPayload, type ShellPolicy, type ShellToClientMessage, type SyncTimeAckPayload, type SystemStatusPayload, type UserDevicePayload };